Comment gérez-vous les différences de rapport d'aspect avec Unity 2D?


67

J'ai eu beaucoup de réponses à cette question, mais elles sont toutes génériques et généralement pas très utiles. Aucun des didacticiels ne parle de rapport de format et de gestion des appareils mobiles. Il existe une multitude de façons de le faire. Tous semblent avoir eu des défauts et des imperfections.

J'aimerais vraiment savoir quels jeux à succès ont l'habitude de gérer différents formats d'aspect sur iOS et Android sans créer un zillion d'actifs de tailles différentes.

Je suis à proprement parler mobile, pas de bureau, en particulier avec Unity et je me fiche de l'interface utilisateur, je me soucie uniquement de la toile de gameplay.

Les problèmes auxquels je pense, sont quand il y a des choses clés qui doivent être à certains endroits et qui ne peuvent pas tomber de l'écran. L'utilisation de barres noires en haut ou en bas est inacceptable de nos jours.


3
Cette question est très large, car la bonne manière dépend de presque tout. Qu'as-tu essayé? Pourquoi cela n'a-t-il pas fonctionné?
Anko

3
J'ai essayé toutes sortes de choses, j'ai essayé d'ajuster la taille de l'ortho camera, j'ai essayé de joindre tous les sprites à la liste et de les redimensionner par différence de format d'image, en réglant la taille d'ortho sur screen.height / 2/100, et bien d'autres des idées. Certains fonctionnent, mais tous ont des problèmes. Je sais que différents jeux gèrent les choses différemment, mais il n’ya absolument aucune discussion sur ce sujet où que ce soit et ce n’est pas aussi facile que de «laisser simplement l’unité le gérer», comme beaucoup le prétendent.
Michael

1
Alors, pourquoi n'ont-ils pas travaillé? À quoi ressemblerait une bonne solution? (Au fait, vous pouvez éditer la question pour clarifier aussi.)
Anko

7
Certains ont déformé les images, d'autres ne se sont pas alignés correctement. Beaucoup de problèmes différents, mais 65% des jeux développés avec Unity sont en 2D, et ils l'ont fait fonctionner. Je veux juste savoir ce que les gens utilisent et ne pas avoir à réinventer la roue. Personne n'en parle et il n'y a pas de guides ou de documents sur la façon de le gérer. Pourtant, vous ne pouvez pas aller loin dans un projet mobile sans un système en place pour le faire.
Michael

1
"Les problèmes auxquels je pense, sont quand il y a des choses clés qui doivent être à certains endroits et qui ne peuvent pas tomber de l'écran. Utiliser des barres noires en haut ou en bas est inacceptable de nos jours." Garantie que les éléments ne tombent pas à l’écran, zéro distorsion, mais pas de lettres / piliers (barres noires et autres). Ces exigences sont inconciliables. La dernière exigence est probablement la moins importante, ou peut être masquée en affichant le canevas au-delà de ce qui doit être affiché à l'écran. La plupart des jeux que j'ai vus avec des exigences aussi strictes auront une boîte à lettres décorée.
Jibb Smart

Réponses:


36

Ce que vous voulez, c'est contraindre la fenêtre de la caméra sur portrait ou paysage (en fonction de vos besoins), en calculant les camera.orthographicSizepropriétés, de sorte que vous puissiez créer votre scène 2D quels que soient le rapport de format et la résolution:

// 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 vous avez besoin de plus d'informations à ce sujet s'il vous plaît demander et je vous répondrai. ;) Cordialement et acclamations.

UPDATE: Utilisez le script d'ancrage d'objet d'Eliot Lash avec celui-ci pour placer des objets à des positions clés sur l'écran si nécessaire (par rapport aux coins / bords de l'écran). Si vous le faites, renommez "CameraFit" en "ViewportHandler".

Prévisualisez en simulant divers écrans de formats: entrez la description de l'image ici


4
@Eliot Ajouté la licence MIT ci-dessus. Bonne chance dans vos projets!
androidu

7
Fantastique, merci! Un bon tour en mérite un autre, alors voici un composant open-source que je viens d'écrire pour ancrer simplement GameObjects aux points d'assistance définis par votre script: gist.github.com/fadookie/256947788c364400abe1
Eliot

1
MarcelCăvan Très beau script! J'ai ajouté une énumération pour sélectionner si vous souhaitez définir la taille de l'unité pour potrait pour le paysage (hauteur / largeur). Il me GetComponent<Camera>().orthographicSize = UnitSize / 2f;suffisait d'ajouter quelques lignes au script, et je l'utilise pour potrait / définition des unités de hauteur
am_

2
@ MarcelCăşvan super truc! Merci. Je constate que les variables deviceWidth et deviceHeight de ComputeFunction () ne sont pas utilisées. Peut-être envisager de les supprimer.
user2313267

1
CameraAnchor émet le message d'erreur suivant: "CameraFit n'est pas défini dans ce contexte" - Si quelqu'un d'autre trouve cette réponse plus tard, il semble que "CameraFit" ait été renommé "ViewportHandler" depuis sa publication initiale. Si vous venez de renommer la classe de ViewportHandler en CameraFit.
Lenny

5

Généralement, vous n'avez pas besoin de tailles d'actifs différentes: les textures importées et les images-objets générées automatiquement avec des mip maps générées auront une belle apparence lorsqu'elles sont rendues à une taille inférieure ou égale à la taille en pixels d'origine de l'image.

La mise en scène est le défi. Une bonne approche est la suivante (et pour l’instant, j’utilise une caméra 3D examinant un contenu 2D positionné à z = 0):

  1. Décidez arbitrairement d'une taille d'affichage "logique" minimale en pixels ou en mosaïques. Cela ne doit pas nécessairement correspondre à une résolution réelle, mais doit refléter le rapport de format le plus étroit / le plus court que vous souhaitez prendre en charge. Par exemple, pour un jeu de paysage, je ne choisirais pas 480 x 320 car il s'agit d'un format plus large que l'iPad. Donc, je pourrais choisir 1024x768 - ou même 480x360, ce qui me donne un système de coordonnées original de la taille d'un iPhone et le même rapport de format que tout iPad (y compris iPad Air 2, etc.). Notez également que vous pouvez tout aussi facilement travailler en coordonnées de mosaïque plutôt qu'en coordonnées de pixels - 15x11.25 par exemple.
  2. Programmez votre logique de jeu de sorte que tout ce qui est important soit (ou puisse être) positionné dans la taille minimale de votre écran, mais soyez prêt à occuper un espace supplémentaire sur les côtés avec un contenu supplémentaire, même s'il ne s'agit que d'un remplissage décoratif.
  3. Déterminez la quantité dont vous avez besoin pour redimensionner votre contenu de sorte que la largeur ou la hauteur corresponde à la valeur minimale et que l'autre axe soit supérieur ou égal au minimum requis. Pour que cette "échelle soit ajustée", divisez la taille en pixels de l'écran par la taille d'affichage minimale et utilisez la plus petite des valeurs d'échelle résultantes pour correspondre à l'échelle de votre vue.
  4. Utilisez l'échelle de vue pour calculer la taille d'affichage effective (réelle) à des fins de logique de jeu.
  5. Effectuez une mise à l'échelle de votre contenu en déplaçant la caméra le long de l'axe Z.

Sous forme de code:

  // 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

2

Si vous utilisez les barres, il est en fait assez simple à mettre en œuvre (je publie ceci même si le PO a déclaré que c'était inacceptable, car cela présente l'avantage de ne pas être aussi mauvais sur le mobile et c'est une solution simple qui ne nécessite aucun code)

Camera.orthographicSizeest une variable dans l'ortho-caméra (utilisée par la plupart des jeux 2D) qui correspond à la quantité mesurée d'unités de jeu verticalement sur l'écran ( divisé par 2 ) ( source ). Choisissez donc un format d'image qui convient à la grande majorité des appareils (j'ai choisi le format 16: 9, car la plupart des écrans sur lesquels j'ai effectué des recherches sont au format 16: 9, 16:10, 3: 2) et ajoutez un masque qui le recouvre à un rapport.

Exemple :

Dans mon jeu (non répertorié ici car ce n'est pas une annonce, on peut demander dans les commentaires si désiré) on utilise le mode portrait. Pour faire un joli simple 16: 9, j'ai fabriqué ma caméra Ortho en taille 16. Cela signifie que la caméra adaptera 32 unités de jeu de hauteur (y: 16 à -16 dans mon cas) à la verticale de l'écran de l'appareil.

J'ai ensuite placé des masques noirs avec un jeu entre -9 et +9. Voilà, l'écran du jeu a exactement la même apparence sur tous les appareils et un peu plus maigre sur des appareils un peu plus larges. Je n'ai eu absolument aucune réaction négative concernant les masques. Pour faire du paysage, retournez simplement ces valeurs et faites ensuite à la caméra une taille de 9. Modifiez les valeurs pour qu’elles correspondent à la taille que vous avez choisie.

Le seul endroit où nous avons observé la barre noire se manifester de manière significative est sur l'iPad à 3: 2. Même alors, je n'ai eu aucune plainte.


1

Je le fais dans un jeu sur lequel je travaille actuellement. J'ai une image de fond qui est 1140x720. Les bits les plus importants (ceux qui ne devraient jamais être recadrés) sont contenus dans la zone centrale de 960x640. Je lance ce code sur la fonction de démarrage de mon appareil photo:

    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);

Je définis également des tailles autres que la taille de la police pour les boutons, etc. Cela fonctionne bien sur chaque rapport d'aspect que j'ai testé. Cela fait un moment que je ne l'ai pas installée, alors il me manque peut-être une étape. Faites-moi savoir si cela ne fonctionne pas comme prévu et je verrai si j'ai oublié quelque chose.


1

@ La réponse et le code de Marcel sont excellents et m'ont aidé à comprendre ce qui se passait. C'est la réponse définitive. Je pensais que quelqu'un pourrait aussi trouver utile ce que je finissais de faire pour mon cas spécifique: comme je voulais quelque chose de vraiment très simple, un sprite toujours visible à l'écran, j'ai créé ces quelques lignes:

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;
    }
}

J'ai ajouté ceci à la caméra et j'ai fait glisser mon sprite (c'est mon arrière-plan) sur la seule propriété du script. Si vous ne voulez pas de barres noires (horizontales ou verticales), vous pouvez placer un fond plus grand derrière celui-ci ...


0

Il existe plusieurs moyens de s’attaquer à ce problème, et il n’existe pas de solution parfaite (du moins je n’en ai pas encore trouvé) et le type de solution dépend du type de jeu auquel vous participez. développement.

Indépendamment de ce que vous faites, vous devez commencer par choisir la résolution la plus basse possible que vous souhaitez prendre en charge et construire vos sprites à cette résolution. Donc, si vous êtes intéressé par le développement pour iOS, selon http://www.iosres.com/, la résolution du périphérique iOS la plus basse est de 480x320.

À partir de là, vous pouvez commencer à redimensionner les sprites pour atteindre les résolutions les plus élevées. La mise en garde à cet égard est que vous finirez par remarquer que les images-objets commencent à s'estomper à une plus grande échelle, auquel cas vous pouvez passer à un autre jeu d'images-objets conçu pour les résolutions plus élevées.

Ou bien, vous pouvez ignorer complètement la mise à l’échelle et décider d’afficher davantage d’écran de jeu pour obtenir des résolutions plus élevées (je pense que c’est ainsi que Terraria le fait, par exemple). Cependant, pour beaucoup de jeux, ce n'est pas approprié; jeux compétitifs par exemple.

L'utilisation de barres noires en haut ou en bas est inacceptable de nos jours.

Est ce C'est ce que font beaucoup de jeux qui veulent forcer les proportions 4: 3. Puisque vous utilisez Unity, vous pouvez utiliser le script AspectRatioEnforcer pour vous aider.


Je cible le mobile, je ne peux donc pas changer le rapport de format ni la résolution. L'utilisation de ressources à faible résolution n'est pas une solution acceptable. Certains jeux (en particulier en 3D) ne sont pas un problème, il suffit d’en montrer plus ou moins. Mais des jeux comme Kingdom Rush, Tower Defence et d’autres comme Alex vous permettent de voir la même chose quel que soit l’appareil. Si les choses ne se présentent pas aux bons endroits, le jeu ne fonctionnera pas correctement.
Michael


0

Il y a plusieurs façons de gérer ce problème, cela dépend de votre jeu et de ce qui fonctionnera le mieux. Par exemple, dans notre jeu, Tyrant Unleashed, nous avons simplement créé des cartes larges avec des détails sans importance sur les côtés, de sorte qu'il est correct de couper les côtés sur des appareils plus étroits. Cependant, d'autres jeux pourraient être meilleurs avec une approche dans laquelle vous déplacez réellement les boutons ou quelque chose qui correspond mieux à l'écran.

Une autre approche consiste également à conserver une hauteur constante sur tous les appareils, en ne modifiant que la largeur. Cela nous facilite certes la vie, mais encore une fois, cela peut ne pas être bon pour votre jeu spécifique. notre style artistique si les images sont légèrement redimensionnées sur différents écrans, alors que cela pourrait être important pour quelque chose comme le pixel art. En gros, c’est l’approche consistant à «laisser l’Unité le gérer»)


Avez-vous réalisé des projets pour lesquels ce n'était pas une option? Presque tous les jeux de style tour de défense que j'ai vus et de nombreux autres styles permettent de voir l'intégralité de la vue des jeux sur l'appareil sans défilement, ce qui est cohérent pour tous les appareils. Sur IOS, vous pouvez créer des ressources et les échanger, mais cela devient impossible (et en réalité, ce n'est qu'un gros PITA) sous Android.
Michael

Non je n'ai pas. J'ai ajouté quelques détails supplémentaires sur la taille de l'écran
jhocking

0

J'utilise le script suivant qui ajoute un targetAspectparamètre à la caméra et l'adapte orthographicSizeen fonction du rapport d'écran (plus de détails dans cet article 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;
        }
    }
}

0

Ma méthode est généralement similaire aux solutions proposées par d'autres :). Je vais essayer d'expliquer en détail l'approche que je prends pour rendre le jeu indépendant de la taille de l'écran.

Orientation de l'écran

Selon l'orientation de l'écran (Paysage ou Portrait), vous devez déterminer si la caméra sera mise à l'échelle avec une hauteur ou une largeur fixes. La plupart du temps, je choisis une largeur fixe pour les jeux orientés paysage et une hauteur fixe pour les jeux orientés portrait.

Mise à l'échelle de la caméra

Comme discuté, cela peut être soit à hauteur fixe, soit à largeur fixe.

Hauteur fixe : La zone verticale du jeu sera toujours adaptée à la hauteur de l'écran. Et à mesure que le rapport d'aspect de l'écran change, de l'espace supplémentaire est ajouté à gauche et à droite de l'écran. Pour implémenter cela, vous n'avez besoin de rien coder, c'est le comportement par défaut de la caméra unit.

Largeur fixe : La zone horizontale du jeu correspondra toujours à la largeur de l'écran. Et un espace supplémentaire sera ajouté en haut et en bas au fur et à mesure que le rapport de format de l'écran change. Pour implémenter cela, vous devez écrire un petit morceau de code. Par la suite, assurez-vous de supprimer la fonction de mise à jour du formulaire de code et de l’activer.

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;
    }
}

Dans l'éditeur, vous pouvez modifier targetWidth pour définir la zone d'espace mondial à afficher. Ce code est expliqué dans la vidéo suivante avec de nombreuses autres pratiques pour les jeux en 2D :)

Unite 2014 - Meilleures pratiques 2D dans Unity

Ratio d'aspect

Le format d'image suivant, classé du plus large au plus étroit, couvre presque toutes les tailles d'écran pour Android et iOS.

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

Je règle généralement tous ces proportions dans l'ordre indiqué dans la fenêtre du jeu, car c'est pratique lorsque vous testez différentes tailles d'écran :)

Zone Expendable

C'est la zone qui est ajoutée à l'écran sur les côtés ou en haut / en bas en fonction de la mise à l'échelle de la caméra que vous avez choisie.

Pour une hauteur fixe, tous les éléments du jeu doivent de préférence tenir dans un rapport 16: 9 qui est le plus étroit. Et le fond devrait s'étendre jusqu'à couvrir le rapport 5: 4. Ce qui garantit que votre jeu ne comporte jamais de bandes noires sur les côtés.

Pour une largeur fixe, c'est à peu près la même chose, mais ici, les éléments doivent tenir dans un rapport 5: 4 et le GT doit s'étendre jusqu'à 16: 9.

Bornes

Parfois, nous ne pouvons pas utiliser l’approche des zones consomptibles car nous devons utiliser l’ensemble de l’écran disponible pour le jeu.

Par exemple, considérons un jeu de portrait à hauteur fixe, capturant les pièces tombant du ciel. En cela, nous devons donner au joueur la possibilité de se déplacer horizontalement sur la largeur d'écran disponible.

Par conséquent, nous avons besoin des limites de la caméra en termes de coordonnées du monde pour savoir exactement où la gauche, la droite, le haut ou le bas de la caméra se positionne à la position du monde.
Nous pouvons également utiliser ces limites pour ancrer des éléments de jeu ou une interface utilisateur sur un côté souhaité de la caméra.

En utilisant Camera.ViewportToWorldPoint, nous pouvons obtenir les limites. L'espace Viewport est normalisé et relatif à la caméra. Le coin inférieur gauche de la caméra est (0,0); le coin supérieur droit est (1,1). La position z est en unités mondiales de la caméra. Pour 2D / orthographique, le z importe peu.

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

Pour l'interface utilisateur, nous pouvons appliquer les mêmes concepts que ceux que nous avons utilisés pour les éléments du jeu. Après l'introduction de l'interface utilisateur de Unity5 et la disponibilité de plugins tels que NGUI, le problème ne se posera plus :)


0

J'ai créé le logiciel Unity Asset 'Resolution Magic 2D' pour résoudre ce problème (vous pouvez l'obtenir à partir du logiciel Unity Asset Store ou consulter des informations plus détaillées sur grogansoft.com).

La façon dont j'ai abordé le problème était la suivante ...

Définissez une zone de l'écran qui doit toujours être visible, quel que soit le rapport hauteur / largeur / résolution, et utilisez une simple transformation rectangle pour «masquer» cette région. Ceci est votre forme d'écran idéale. En utilisant un algorithme simple, je fais ensuite un zoom sur la caméra jusqu'à ce que la zone bloquée par le rectangle soit aussi grande que possible tout en restant visible à 100% par la caméra.

Ensuite, votre zone de jeu principale occupe toujours le plus d’écran possible. Et tant qu'il y a suffisamment de contenu "supplémentaire" (par exemple, votre arrière-plan) en dehors de la zone rectangle définie précédemment, les lecteurs dont l'écran n'a pas le même rapport d'aspect que votre rectangle "idéal" verront le contenu supplémentaire où des barres noires seraient sinon aller.

Mon actif inclut également une certaine logique pour placer une interface utilisateur, mais celle-ci est principalement obsolète en raison du nouveau système d'interface utilisateur d'Unity.

Mon actif fournit cette configuration immédiate avec une configuration minimale et fonctionne parfaitement sur toutes les plates-formes.

Si vous utilisez cette technique (ou mon atout), assurez-vous simplement de concevoir votre jeu de manière à ce qu'il y ait un espace «facultatif» pour permettre l'affichage d'écrans plus larges ou plus hauts que votre idéal (pour éviter les barres noires).

Personnellement, je ne fais pas de jeux en 3D, donc je ne sais pas si cela fonctionnerait en 3D (ou même si cela est nécessaire).

C'est vraiment difficile à expliquer sans images, alors s'il vous plaît visitez mon site Web ( Résolution Magic 2D )


0

La meilleure solution pour moi consiste à utiliser le théorème des lignes qui se croisent de manière à ce qu'il n'y ait ni coupure sur les côtés ni distorsion de la vue du jeu. Cela signifie que vous devez avancer ou reculer en fonction des différents formats.


-3

J'ai créé une extension AssetStore qui facilite le changement d'aspect appelé AspectSwitcher . Il fournit un système vous permettant de spécifier facilement différentes propriétés pour différents aspects. Il y a généralement deux méthodes que la plupart des gens utilisent pour changer d'aspect. L'une consiste à fournir différents objets de jeu pour chaque aspect. L'autre consiste à créer un code personnalisé qui modifie les propriétés d'un seul objet de jeu en fonction de l'aspect actuel. Cela nécessite généralement beaucoup de codage personnalisé. Mon extension tente d'atténuer une grande partie de cette douleur.


2
Cette réponse serait meilleure, et semblerait moins spammée, si vous expliquiez les techniques réelles que l'on pourrait utiliser pour répondre à la question du PO.
Josh
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.