¿Cómo manejas las diferencias de relación de aspecto con Unity 2D?

67

He recibido muchas respuestas a esta pregunta, pero todas son genéricas y, en general, no son muy útiles. Ninguno de los tutoriales habla sobre la relación de aspecto y el manejo de dispositivos móviles y hay muchísimas formas de hacerlo, todos parecen tener problemas y fallas.

Realmente me encantaría saber qué juegos exitosos han utilizado para manejar diferentes relaciones de aspecto en iOS y Android sin hacer un millón de activos de diferentes tamaños.

Estoy hablando estrictamente de dispositivos móviles, no de escritorio, específicamente con Unity y no me importa la interfaz de usuario, solo me importa el lienzo del juego.

Los problemas que tengo en mente es cuando hay cosas clave que tienen que estar en ciertos lugares y no pueden caerse de la pantalla. El uso de barras negras en la parte superior o inferior es inaceptable en estos días.

Miguel
fuente
3
Esta pregunta es muy amplia, ya que la forma correcta depende de casi cualquier cosa. Que has intentado ¿Por qué no funcionó?
Anko
3
He intentado todo tipo de cosas, he intentado ajustar el tamaño de la cámara orto, he intentado adjuntar todos los sprites a la lista y escalarlos por la diferencia en la relación de aspecto, configurando el tamaño ortho a la pantalla. Altura / 2/100, muchos otros ideas Algunos funcionan, pero todos tienen problemas. Sé que diferentes juegos lo manejan de manera diferente, pero no hay absolutamente ninguna discusión sobre este tema en ningún lado y no es tan fácil como "simplemente dejar que la unidad lo maneje" como muchos afirman.
Michael
1
Entonces, ¿por qué no funcionaron? ¿Cómo sería una buena solución? (Por cierto, también puedes editar la pregunta para aclarar).
Anko
77
Algunos distorsionaron las imágenes, algunos no se alinearon correctamente. Muchos problemas diferentes, pero el 65% de los juegos desarrollados con Unity son 2D, y lo hicieron funcionar. Solo quiero saber qué usan las personas y no tener que reinventar la rueda. Nadie habla de eso y no hay guías o documentos sobre cómo manejarlo. Sin embargo, no puede llegar lejos en un proyecto móvil sin tener un sistema para hacerlo.
Michael
1
"Los problemas que tengo en mente es cuando hay cosas clave que deben estar en ciertos lugares y no pueden caerse de la pantalla. El uso de barras negras en la parte superior o inferior es inaceptable en estos días". Garantía de elementos que no se caen de la pantalla, distorsión cero, pero sin letra / pilar-box (barras negras y similares) Estos requisitos son irreconciliables. El último requisito es probablemente el menos importante, o puede ocultarse rellenando el lienzo más allá de lo que debe estar en la pantalla. La mayoría de los juegos que he visto con requisitos tan estrictos tendrán pillarbox / bordes decorados.
Jibb Smart

Respuestas:

36

Lo que desea es restringir la vista de la cámara en vertical u horizontal (según sus necesidades), mediante la camera.orthographicSizepropiedad informática , para que pueda construir su escena 2D sin importar la relación de aspecto y la resolución:

// Attach this script on your main ortohgraphic camera:

/* The MIT License (MIT)

Copyright (c) 2014, Marcel Căşvan

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */

using System;
using System.Collections;
using UnityEngine;

[ExecuteInEditMode]
[RequireComponent (typeof (Camera))]
public class ViewportHandler : MonoBehaviour
{
    #region FIELDS
    public Color wireColor = Color.white;
    public float UnitsSize = 1; // size of your scene in unity units
    public Constraint constraint = Constraint.Portrait;
    public static ViewportHandler Instance;
    public new Camera camera;

    private float _width;
    private float _height;
    //*** bottom screen
    private Vector3 _bl;
    private Vector3 _bc;
    private Vector3 _br;
    //*** middle screen
    private Vector3 _ml;
    private Vector3 _mc;
    private Vector3 _mr;
    //*** top screen
    private Vector3 _tl;
    private Vector3 _tc;
    private Vector3 _tr;
    #endregion

    #region PROPERTIES
    public float Width {
        get {
            return _width;
        }
    }
    public float Height {
        get {
            return _height;
        }
    }

    // helper points:
    public Vector3 BottomLeft {
        get {
            return _bl;
        }
    }
    public Vector3 BottomCenter {
        get {
            return _bc;
        }
    }
    public Vector3 BottomRight {
        get {
            return _br;
        }
    }
    public Vector3 MiddleLeft {
        get {
            return _ml;
        }
    }
    public Vector3 MiddleCenter {
        get {
            return _mc;
        }
    }
    public Vector3 MiddleRight {
        get {
            return _mr;
        }
    }
    public Vector3 TopLeft {
        get {
            return _tl;
        }
    }
    public Vector3 TopCenter {
        get {
            return _tc;
        }
    }
    public Vector3 TopRight {
        get {
            return _tr;
        }
    }
    #endregion

    #region METHODS
    private void Awake()
    {
        camera = GetComponent<Camera>();
        Instance = this;
        ComputeResolution();
    }

    private void ComputeResolution()
    {
        float leftX, rightX, topY, bottomY;

        if(constraint == Constraint.Landscape){
            camera.orthographicSize = 1f / camera.aspect * UnitsSize / 2f;    
        }else{
            camera.orthographicSize = UnitsSize / 2f;
        }

        _height = 2f * camera.orthographicSize;
        _width = _height * camera.aspect;

        float cameraX, cameraY;
        cameraX = camera.transform.position.x;
        cameraY = camera.transform.position.y;

        leftX = cameraX - _width / 2;
        rightX = cameraX + _width / 2;
        topY = cameraY + _height / 2;
        bottomY = cameraY - _height / 2;

        //*** bottom
        _bl = new Vector3(leftX, bottomY, 0);
        _bc = new Vector3(cameraX, bottomY, 0);
        _br = new Vector3(rightX, bottomY, 0);
        //*** middle
        _ml = new Vector3(leftX, cameraY, 0);
        _mc = new Vector3(cameraX, cameraY, 0);
        _mr = new Vector3(rightX, cameraY, 0);
        //*** top
        _tl = new Vector3(leftX, topY, 0);
        _tc = new Vector3(cameraX, topY , 0);
        _tr = new Vector3(rightX, topY, 0);           
    }

    private void Update()
    {
        #if UNITY_EDITOR
        ComputeResolution();
        #endif
    }

    void OnDrawGizmos() {
        Gizmos.color = wireColor;

        Matrix4x4 temp = Gizmos.matrix;
        Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
        if (camera.orthographic) {
            float spread = camera.farClipPlane - camera.nearClipPlane;
            float center = (camera.farClipPlane + camera.nearClipPlane)*0.5f;
            Gizmos.DrawWireCube(new Vector3(0,0,center), new Vector3(camera.orthographicSize*2*camera.aspect, camera.orthographicSize*2, spread));
        } else {
            Gizmos.DrawFrustum(Vector3.zero, camera.fieldOfView, camera.farClipPlane, camera.nearClipPlane, camera.aspect);
        }
        Gizmos.matrix = temp;
    }
    #endregion

    public enum Constraint { Landscape, Portrait }
}

Si necesita más información sobre esto, pregunte y le responderé. ;) Saludos y vítores.

ACTUALIZACIÓN: use el script de anclaje de objetos de Eliot Lash junto con este para colocar objetos en las posiciones clave de la pantalla si es necesario (en relación con las esquinas / bordes de la pantalla). Si lo hace, cambie el nombre de "CameraFit" a "ViewportHandler".

Vista previa que simula varias pantallas de relaciones de aspecto: ingrese la descripción de la imagen aquí

androidu
fuente
44
@Eliot Se agregó la licencia MIT arriba. Buena suerte con tus proyectos!
androidu
77
Fantástico, gracias! Un buen giro merece otro, así que aquí hay un componente de código abierto que acabo de escribir para el anclaje simple de GameObjects a los puntos auxiliares definidos por su script: gist.github.com/fadookie/256947788c364400abe1
Eliot
1
MarcelCăşvan Muy buen guión! Agregué una enumeración para seleccionar si desea definir el tamaño de la unidad para retrato para paisaje (alto / ancho). Solo tuve que agregar un par de líneas al guión, y lo uso GetComponent<Camera>().orthographicSize = UnitSize / 2f;para potrait / definir unidades de altura
am_
2
@ MarcelCăşvan grandes cosas! Gracias. Veo que las variables deviceWidth y deviceHeight de ComputeFunction () no se utilizan. Quizás considere eliminarlos.
user2313267
1
CameraAnchor está arrojando el error: "CameraFit no está definido en este contexto" - En caso de que alguien encuentre esta respuesta más tarde, parece que "CameraFit" acaba de cambiar el nombre de "ViewportHandler" ya que esto se publicó originalmente. Si solo cambia el nombre de la clase de ViewportHandler a CameraFit.
Lenny
5

Por lo general, no necesita diferentes tamaños de activos: las texturas y sprites importados con mapas MIP generados automáticamente se verán bien cuando se representen en cualquier tamaño menor o igual al tamaño de píxel original de la imagen.

El diseño de la escena es el desafío. Un buen enfoque es el siguiente (y para su información, uso una cámara 3D que mira contenido 2D posicionado en z = 0):

  1. Decide arbitrariamente un tamaño de visualización "lógico" mínimo en píxeles o mosaicos. Esto no necesita corresponder a ninguna resolución del mundo real, pero debe reflejar la relación de aspecto más estrecha / más corta que desea admitir. Por ejemplo, para un juego de paisajes, no elegiría 480x320 porque es una relación de aspecto más amplia que el iPad. Por lo tanto, podría elegir 1024x768, o incluso 480x360, lo que me da un sistema de coordenadas original del tamaño de un iPhone para trabajar y la misma relación de aspecto que todos los iPad (incluido iPad Air 2, etc.). También tenga en cuenta que puede trabajar fácilmente en coordenadas de mosaico en lugar de coordenadas de píxel, por ejemplo, 15x11.25.
  2. Programe la lógica de su juego para que todo lo importante esté (o pueda) ubicarse dentro de su tamaño mínimo de pantalla, pero esté preparado para llenar espacio adicional en los lados con contenido adicional, incluso si es solo relleno decorativo.
  3. Determine cuánto necesita escalar su contenido para que el ancho o la altura coincidan con el valor mínimo y el otro eje sea mayor o igual al mínimo necesario. Para hacer esta "escala para ajustarse", divida el tamaño de píxel de la pantalla por el tamaño mínimo de visualización y tome el menor de los valores de escala resultantes como su escala de vista general.
  4. Use la escala de vista para calcular el tamaño de visualización efectivo (real) para fines de lógica de juego.
  5. Realmente escale su contenido moviendo la cámara a lo largo del eje Z.

En forma de código:

  // Adjust the camera to show world position 'centeredAt' - (0,0,0) or other - with
  // the display being at least 480 units wide and 360 units high.

  Vector3 minimumDisplaySize = new Vector3( 480, 360, 0 );

  float pixelsWide = camera.pixelWidth;
  float pixelsHigh = camera.pixelHeight;

  // Calculate the per-axis scaling factor necessary to fill the view with
  // the desired minimum size (in arbitrary units).
  float scaleX = pixelsWide / minimumDisplaySize.x;
  float scaleY = pixelsHigh / minimumDisplaySize.y;

  // Select the smaller of the two scale factors to use.
  // The corresponding axis will have the exact size specified and the other 
  // will be *at least* the required size and probably larger.
  float scale = (scaleX < scaleY) ? scaleX : scaleY;

  Vector3 displaySize = new Vector3( pixelsWide/scale, pixelsHigh/scale, 0 );

  // Use some magic code to get the required distance 'z' from the camera to the content to display
  // at the correct size.
  float z = displaySize.y /
            (2 * Mathf.Tan((float)camera.fieldOfView / 2 * Mathf.Deg2Rad));

  // Set the camera back 'z' from the content.  This assumes that the camera
  // is already oriented towards the content.
  camera.transform.position = centeredAt + new Vector3(0,0,-z);

  // The display is showing the region between coordinates 
  // "centeredAt - displaySize/2" and "centeredAt + displaySize/2".

  // After running this code with minimumDisplaySize 480x360, displaySize will
  // have the following values on different devices (and content will be full-screen
  // on all of them):
  //    iPad Air 2 - 480x360
  //    iPhone 1 - 540x360
  //    iPhone 5 - 639x360
  //    Nexus 6 - 640x360

  // As another example, after running this code with minimumDisplaySize 15x11
  // (tile dimensions for a tile-based game), displaySize will end up with the following 
  // actual tile dimensions on different devices (every device will have a display
  // 11 tiles high and 15+ tiles wide):
  //    iPad Air 2 - 14.667x11
  //    iPhone 1 - 16.5x11
  //    iPhone 5 - 19.525x11
  //    Nexus 6 - 19.556x11
AbePralle
fuente
2

Si llega a usar las barras, en realidad es bastante simple de implementar (estoy publicando esto a pesar de que el OP declaró la opinión de que es inaceptable porque tiene el beneficio de no ser tan malo en el móvil y es una solución simple que no requiere ningún código)

Camera.orthographicSizees una variable dentro de la cámara orto (que utilizan la mayoría de los juegos en 2D) que se ajusta verticalmente a la cantidad medida de unidades de juego en la pantalla ( dividida por 2 ) ( fuente ). Por lo tanto, elija una relación de aspecto que se adapte a la gran mayoría de los dispositivos (elegí 16: 9 ya que la mayoría de las pantallas que investigé son 16: 9, 16:10, 3: 2) y agregue una máscara que se superponga en una relación.

Ejemplo :

En mi juego (no aparece aquí, ya que este no es un anuncio, puede preguntar en los comentarios si lo desea) utilizamos el modo vertical. Para hacer un bonito 16: 9 hice mi cámara Ortho en el tamaño 16. Esto significa que la cámara adaptará 32 unidades de juego de altura (y: 16 a -16 en mi caso) en la vertical del dispositivo de la pantalla.

Luego coloqué máscaras negras con un juego entre -9 y +9. Voila, la pantalla del juego se ve exactamente igual en todos los dispositivos y un poco más delgada en dispositivos que son un poco más anchos. No he tenido absolutamente ningún comentario negativo con respecto a las máscaras. Para hacer un paisaje simplemente voltea esos valores y luego harías la cámara del tamaño 9. Cambia los valores para que coincidan con lo que hayas decidido que es la escala de tu unidad de juego.

El único lugar donde hemos observado que la barra negra se muestra significativamente es en el iPad a 3: 2. Incluso entonces, no he tenido quejas.

McAden
fuente
1

Estoy haciendo esto en un juego en el que estoy trabajando actualmente. Tengo una imagen de fondo de 1140x720. Los bits más importantes (los que nunca deberían recortarse) están contenidos en el área central de 960x640. Ejecuto este código en la función de inicio de mi cámara:

    float aspect = (float)Screen.width / (float)Screen.height;

    if (aspect < 1.5f)
        Camera.main.orthographicSize = 3.6f;
    else
        Camera.main.orthographicSize = 3.2f;

    float vertRatio = Screen.height / 320.0f;
    fontSize = (int)(12 * vertRatio);

También defino tamaños distintos del tamaño de fuente para botones y demás. Funciona bien en cada relación de aspecto que he probado. Ha pasado un tiempo desde que lo configuré, por lo que es posible que me falte un paso. Avíseme si no funciona como se esperaba y veré si omití algo.

John
fuente
1

La respuesta y el código de @ Marcel son geniales y me ayudaron a entender lo que estaba sucediendo. Es la respuesta definitiva. Solo pensé que alguien podría encontrar útil lo que terminé haciendo para mi caso específico: como quería algo realmente simple, un sprite para estar siempre en la pantalla, se me ocurrieron estas pocas líneas:

public class CameraFit : MonoBehaviour {

    public SpriteRenderer spriteToFitTo;

    void Start () { // change to Update to test by resizing the Unity editor window
        var bounds = spriteToFitTo.bounds.extents;
        var height = bounds.x / camera.aspect;
        if (height < bounds.y)
            height = bounds.y;
        camera.orthographicSize = height;
    }
}

Agregué esto a la cámara y arrastré mi sprite (es mi fondo) a la única propiedad del script. Si no quieres barras negras (horizontales o verticales), puedes poner un fondo más grande detrás de esta ...

maltalef
fuente
0

Hay algunas formas de abordar este problema, y ​​no hay una solución perfecta (al menos aún no he encontrado una) y el tipo de solución que elija dependerá en gran medida del tipo de juego que esté utilizando. desarrollando.

Independientemente de lo que haga, debe comenzar eligiendo la resolución más baja posible que le gustaría admitir y construir sus sprites para esa resolución. Entonces, si está interesado en desarrollar para iOS, según http://www.iosres.com/, la resolución más baja del dispositivo iOS es 480x320.

A partir de ahí, puede comenzar a escalar los sprites para cumplir con las resoluciones más altas. La advertencia a esto es que eventualmente comenzarás a notar que los sprites comienzan a difuminarse a medida que escalas, en cuyo caso puedes cambiar a otro conjunto de sprites creados para las resoluciones más altas.

O bien, puede ignorar la escala por completo y simplemente decidir mostrar más de la pantalla del juego para obtener resoluciones más altas (creo que así es como lo hace Terraria, por ejemplo). Sin embargo, para muchos juegos, esto no es apropiado; juegos competitivos por ejemplo.

El uso de barras negras en la parte superior o inferior es inaceptable en estos días.

¿Lo es? Muchos juegos que quieren forzar relaciones de aspecto 4: 3 hacen esto. Como está utilizando Unity, puede utilizar el script AspectRatioEnforcer para ayudar en esto.

cobre
fuente
Estoy apuntando a dispositivos móviles, por lo que no puedo cambiar la relación de aspecto o la resolución. Usar activos de baja resolución no es una solución aceptable. Algunos juegos (especialmente 3D) no son un problema, solo se muestran más o menos. Pero los juegos como Kingdom Rush, tower defense y otros juegos como Alex quieren ver lo mismo independientemente del dispositivo. Si las cosas no aparecen en los lugares correctos, el juego no funcionará correctamente.
Michael
0

Hay varias formas de manejar este problema, depende de tu juego y de lo que funcionará mejor. Por ejemplo, en nuestro juego Tyrant Unleashed simplemente hicimos mapas anchos con detalles sin importancia en los lados, por lo que está bien cortar los lados en dispositivos más estrechos. Sin embargo, otros juegos podrían ser mejores con un enfoque en el que realmente cambias los botones o algo para que se ajuste mejor a la pantalla.

(también parte de nuestro enfoque también es mantener una altura constante en todos los dispositivos, solo variar el ancho. Esto ciertamente nos hace la vida más fácil, pero nuevamente esto puede o no ser bueno para su juego específico. No importa en nuestro estilo de arte si las imágenes se escalan un poco en diferentes pantallas, mientras que esto podría ser importante para algo como pixel art. Básicamente, este es el enfoque de "dejar que Unity lo maneje")

jhocking
fuente
¿Has hecho algún proyecto donde esa no fuera una opción? Casi todos los juegos de estilo de defensa de torre que he visto y muchos otros estilos puedes ver la vista completa del juego en el dispositivo sin desplazarte, y esto es consistente en todos los dispositivos. En IOS puedes hacer activos e intercambiarlos, pero eso se vuelve imposible (y realmente solo una gran PITA de todos modos) en Android.
Michael
No, no lo he hecho. por cierto, acabo de agregar más detalles sobre el tamaño de la pantalla
jhocking el
0

Estoy usando el siguiente script que agrega un targetAspectparámetro a la cámara y lo adapta orthographicSizecon respecto a la relación de pantalla (más detalles en esta publicación de blog ):

using UnityEngine;
using System.Collections;

public class AspectRatioScript : MonoBehaviour {

    public float targetAspect;

    void Start () 
    {
        float windowAspect = (float)Screen.width / (float)Screen.height;
        float scaleHeight = windowAspect / targetAspect;
        Camera camera = GetComponent<Camera>();

        if (scaleHeight < 1.0f)
        {  
            camera.orthographicSize = camera.orthographicSize / scaleHeight;
        }
    }
}
sdabet
fuente
0

Mi método es principalmente similar a las soluciones dadas por otros :) Trataré de explicar en detalle el enfoque que tomo para hacer que el juego sea independiente del tamaño de la pantalla.

Orientación de la pantalla

Dependiendo de la orientación de la pantalla (horizontal o vertical), debe considerar si la cámara escalará con una altura o ancho fijos. Principalmente elijo ancho fijo para juegos orientados al paisaje y altura fija para juegos orientados a retratos.

Escala de cámara

Como se discutió, esto puede ser altura fija o ancho fijo.

Altura fija : el área vertical del juego siempre se ajustará a la altura de la pantalla. Y a medida que cambie la relación de aspecto de la pantalla, se agregará espacio adicional a la izquierda y a la derecha de la pantalla. Para implementar esto no necesita codificar nada, es el comportamiento predeterminado de la cámara de la unidad.

Ancho fijo : el área horizontal del juego siempre se ajustará al ancho de la pantalla. Y se agregará espacio adicional en la parte superior e inferior a medida que cambie la relación de aspecto de la pantalla. Para implementar esto, necesita escribir un pequeño fragmento de código. Más adelante, asegúrese de eliminar la función de actualización del formulario de código y colóquelo en modo despierto.

using UnityEngine;

[ExecuteInEditMode]
public class ScaleWidthCamera : MonoBehaviour {

    public int targetWidth = 640;
    public float pixelsToUnits = 100;

    void Update() {

        int height = Mathf.RoundToInt(targetWidth / (float)Screen.width * Screen.height);

        camera.orthographicSize = height / pixelsToUnits / 2;
    }
}

En el editor, puede cambiar el ancho del objetivo para definir el área del espacio mundial que desea mostrar. Este código se explica en el siguiente video junto con muchas otras prácticas para juegos 2D :)

Unite 2014 - Mejores prácticas 2D en Unity

Relación de aspecto

La siguiente relación de aspecto enumerada del más ancho al más estrecho, cubre casi todos los tamaños de pantalla tanto para Android como para iOS

  • 5: 4
  • 4: 3
  • 3: 2
  • 16:10
  • 16: 9

Por lo general, establezco todas estas relaciones de aspecto en el orden dado en la ventana del juego, ya que es útil al probar diferentes tamaños de pantalla :)

Área de gasto

Esta es el área que se agrega a la pantalla a los lados o arriba / abajo según la escala de la cámara que haya elegido.

Para una altura fija, todos los elementos del juego deben caber preferiblemente en una relación de 16: 9, que es la más estrecha. Y el fondo debe extenderse hasta que cubra la relación 5: 4. Lo que asegura que tu juego nunca tenga franjas negras a los lados.

Para un ancho fijo, es casi lo mismo, pero aquí los elementos deben caber en una relación de 5: 4 y el BG debe extenderse hasta 16: 9.

Límites

A veces no podemos usar el enfoque del área de gastos, ya que necesitamos utilizar toda la pantalla disponible para el juego.

Por ejemplo, considere un juego de retratos con altura fija, atrapando las monedas que caen del cielo. En esto, debemos darle al jugador la capacidad de moverse horizontalmente sobre el ancho de pantalla disponible.

Por lo tanto, necesitamos los límites de la cámara en términos de coordenadas mundiales para saber dónde están exactamente los lados izquierdo, derecho, superior o inferior de los clips de la cámara en la posición mundial.
También podemos usar estos límites para anclar elementos del juego o interfaz de usuario en el lado deseado de la cámara.

Usando Camera.ViewportToWorldPoint podemos obtener los límites. El espacio de Viewport está normalizado y en relación con la cámara. La parte inferior izquierda de la cámara es (0,0); la esquina superior derecha es (1,1). La posición z está en unidades mundiales de la cámara. Para 2D / ortográfico, la z no importa.

Vector3 leftBottom = camera.ViewportToWorldPoint(new Vector3(0, 0, camera.nearClipPlane));
Vector3 rightTop = camera.ViewportToWorldPoint(new Vector3(1, 1, camera.nearClipPlane));

float left = leftBottom.x;
float bottom = leftBottom.y;
float right = rightTop.x;
float top = rightTop.y;

UI

Para la IU podemos aplicar los mismos conceptos que usamos para los elementos del juego. Después de la introducción de Unity5 UI y la disponibilidad de complementos como NGUI, esto no será un gran problema :)

Hash Booy
fuente
0

Creé la 'Resolución Magic 2D' de Unity Asset para resolver este mismo problema (anuncio: puede obtenerlo en Unity Asset Store o ver más detalles en grogansoft.com).

La forma en que abordé el problema fue la siguiente ...

Defina un área de la pantalla que siempre debe estar visible, independientemente de la relación de aspecto / resolución, y use una simple transformación de rectángulo para 'dibujar' esta región. Esta es tu forma de pantalla ideal. Usando un algoritmo simple, luego hago zoom en la cámara hasta que la región bloqueada por el rectángulo sea lo más grande posible y aún sea 100% visible para la cámara.

Entonces, su área de juego principal siempre ocupa la mayor cantidad de pantalla posible. Y siempre que haya suficiente contenido 'extra' (por ejemplo, su fondo) fuera del área del rectángulo que definió anteriormente, los jugadores cuya pantalla no tenga la misma relación de aspecto que su rectángulo 'ideal' verán el contenido adicional donde las barras negras de lo contrario ir.

Mi activo también incluye cierta lógica para colocar la interfaz de usuario, pero eso es en su mayoría obsoleto debido al nuevo sistema de interfaz de usuario de Unity.

Mi activo proporciona esto de fábrica con una configuración mínima, y ​​funciona realmente bien en todas las plataformas.

Si usas esta técnica (o mi activo), solo asegúrate de diseñar tu juego para que tenga espacio 'opcional' alrededor para acomodar pantallas que sean más anchas o más altas que tu ideal (para evitar barras negras).

Yo personalmente no hago juegos en 3D, así que no sé si esto funcionaría en 3D (o si es necesario).

Es realmente difícil de explicar sin imágenes, así que visite mi sitio web ( Resolution Magic 2D )

calabazaszwan
fuente
0

La mejor solución para mí es usar el teorema de las líneas de intersección para que no haya un corte en los lados ni una distorsión de la vista del juego. Eso significa que debe retroceder o avanzar según la relación de aspecto diferente.

fiebre de la unidad
fuente
-3

Creé una extensión AssetStore que permite un cambio de aspecto más fácil llamado AspectSwitcher . Proporciona un sistema para permitirle especificar fácilmente diferentes propiedades para diferentes aspectos. Generalmente hay dos métodos que la mayoría de las personas usan para cambiar de aspecto. Una es proporcionar diferentes objetos de juego para cada aspecto. El otro es crear un código personalizado que modifique las propiedades de un solo objeto de juego en función del aspecto actual. Eso generalmente requiere mucha codificación personalizada. Mi extensión intenta aliviar mucho de ese dolor.

Jason
fuente
2
Esta respuesta sería mejor, y parecería menos spam, si elaboras las técnicas reales que uno podría usar para abordar la pregunta del OP.
Josh