Wie gehen Sie mit Unity 2D mit Unterschieden im Seitenverhältnis um?


67

Ich habe viele Antworten auf diese Frage bekommen, aber sie sind alle allgemein und im Allgemeinen nicht sehr nützlich. In keinem der Tutorials geht es um das Seitenverhältnis und den Umgang mit Mobilgeräten, und es gibt unzählige Möglichkeiten, dies zu tun. Alle scheinen Probleme und Mängel zu haben.

Ich würde wirklich gerne wissen, welche erfolgreichen Spiele verwendet wurden, um verschiedene Seitenverhältnisse auf iOS und Android zu handhaben, ohne dass Millionen von Assets unterschiedlicher Größe erstellt wurden.

Ich spreche streng genommen mobil, nicht desktop, speziell mit Unity, und ich interessiere mich nicht für die Benutzeroberfläche, ich interessiere mich nur für den Gameplay-Canvas.

Ich habe Probleme, wenn es wichtige Dinge gibt, die sich an bestimmten Orten befinden müssen und nicht vom Bildschirm fallen können. Die Verwendung von schwarzen Balken oben oder unten ist heutzutage nicht mehr akzeptabel.


3
Diese Frage ist sehr weit gefasst, da der richtige Weg von fast allem abhängt. Was hast du versucht? Warum hat es nicht funktioniert?
Anko

3
Ich habe alle möglichen Dinge ausprobiert, ich habe versucht, die Größe der Orthokameras anzupassen, ich habe versucht, alle Sprites an die Liste anzuhängen und sie nach dem Seitenverhältnis zu skalieren, und ich habe die Orthogröße auf screen.height / 2/100 gesetzt, viele andere Ideen. Einige arbeiten, aber alle haben Probleme. Ich weiß, dass verschiedene Spiele damit anders umgehen, aber es gibt absolut keine Diskussion zu diesem Thema, und es ist nicht so einfach, wie von vielen behauptet wird, "nur die Einheit damit umgehen zu lassen".
Michael

1
Warum haben sie nicht funktioniert? Wie würde eine gute Lösung aussehen? (Übrigens können Sie die Frage auch bearbeiten, um sie zu klären.)
Anko

7
Einige verzerrten die Bilder, andere richteten sich nicht richtig aus. Viele verschiedene Probleme, aber 65% der mit Unity entwickelten Spiele sind 2D-Spiele, und sie haben es geschafft. Ich möchte nur wissen, was die Leute benutzen und nicht das Rad neu erfinden müssen. Niemand spricht darüber und es gibt keine Anleitungen oder Dokumente, wie man damit umgeht. In einem mobilen Projekt kann man jedoch nicht weiterkommen, ohne ein entsprechendes System zu haben.
Michael

1
"Probleme, an die ich denke, sind, wenn es wichtige Dinge gibt, die sich an bestimmten Stellen befinden müssen und nicht vom Bildschirm fallen können. Die Verwendung von schwarzen Balken oben oder unten ist heutzutage inakzeptabel." Garantie für nicht vom Bildschirm fallende Elemente, keine Verzerrung, aber kein Brief- / Säulen-Boxing (schwarze Balken und ähnliches). Diese Anforderungen sind unvereinbar. Die letzte Forderung ist wahrscheinlich die am wenigsten wichtig, oder kann durch Klotzen aus der Leinwand über versteckt werden , was muss auf dem Bildschirm sein. Die meisten Spiele, die ich mit so strengen Anforderungen gesehen habe, werden Pillarbox / Borders verziert haben.
Jibb Smart

Antworten:


36

Sie möchten das Kamera-Ansichtsfenster auf Hoch- oder Querformat beschränken (je nach Ihren Anforderungen), indem Sie die camera.orthographicSizeEigenschaften berechnen , sodass Sie Ihre 2D-Szene unabhängig von Seitenverhältnis und Auflösung erstellen können:

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

Wenn Sie weitere Informationen dazu benötigen, fragen Sie bitte und ich werde antworten. ;) Grüße und Prost.

UPDATE: Verwenden Sie das Objektverankerungsskript von Eliot Lash zusammen mit diesem Skript , um Objekte bei Bedarf an Schlüsselpositionen auf dem Bildschirm zu platzieren (relativ zu Bildschirmecken / -rändern). Wenn Sie dies tun, benennen Sie "CameraFit" in "ViewportHandler" um.

Vorschau zur Simulation verschiedener Seitenverhältnisse: Bildbeschreibung hier eingeben


4
@Eliot MIT-Lizenz oben hinzugefügt. Viel Glück bei Ihren Projekten!
Androidu

7
Fantastisch, danke! Eine gute Wendung verdient eine andere, daher hier eine Open-Source-Komponente, die ich gerade geschrieben habe, um GameObjects einfach an den in Ihrem Skript definierten Hilfspunkten zu verankern: gist.github.com/fadookie/256947788c364400abe1
Eliot

1
MarcelCăşvan Sehr schönes Drehbuch! Ich habe eine Aufzählung hinzugefügt, um auszuwählen, ob Sie die Einheitsgröße für das Porträt für das Querformat (Höhe / Breite) definieren möchten. GetComponent<Camera>().orthographicSize = UnitSize / 2f;Musste nur ein paar Zeilen in das Skript einfügen und ich verwende es zum Definieren von Höheneinheiten
am_

2
@ MarcelCăşvan tolle Sachen! Vielen Dank. Ich sehe, dass die Variablen deviceWidth und deviceHeight von ComputeFunction () nicht verwendet werden. Vielleicht sollten Sie diese löschen.
user2313267

1
CameraAnchor löst den Fehler aus: "CameraFit ist in diesem Kontext nicht definiert" - Falls jemand anders diese Antwort später findet, scheint "CameraFit" soeben in "ViewportHandler" umbenannt worden zu sein, da dies ursprünglich gepostet wurde. Wenn Sie die Klasse nur von ViewportHandler zurück zu CameraFit umbenennen.
Lenny

5

Normalerweise benötigen Sie keine unterschiedlichen Größen für Assets - importierte Texturen und Sprites mit automatisch generierten Mip-Maps sehen gut aus, wenn sie in einer Größe gerendert werden, die kleiner oder gleich der ursprünglichen Pixelgröße des Bildes ist.

Das Szenenlayout ist die Herausforderung. Ein guter Ansatz ist folgender (und zu meiner Information verwende ich eine 3D-Kamera, die 2D-Inhalte mit z = 0 betrachtet):

  1. Entscheiden Sie sich willkürlich für eine minimale "logische" Anzeigegröße in Pixeln oder Kacheln. Dies muss keiner realen Auflösung entsprechen, sollte jedoch das engste / kürzeste Seitenverhältnis widerspiegeln, das Sie unterstützen möchten. Zum Beispiel würde ich für ein Landschaftsspiel nicht 480x320 wählen, da dies ein größeres Seitenverhältnis als das iPad darstellt. Vielleicht wähle ich 1024x768 - oder sogar 480x360, wodurch ich ein originales Koordinatensystem in iPhone-Größe habe, mit dem ich arbeiten kann, und dasselbe Seitenverhältnis wie bei jedem iPad (einschließlich iPad Air 2 usw.). Beachten Sie auch, dass Sie genauso einfach in Kachelkoordinaten als in Pixelkoordinaten arbeiten können - beispielsweise 15 x 11,25.
  2. Programmieren Sie Ihre Spielelogik so, dass alles Wichtige innerhalb Ihrer minimalen Anzeigegröße positioniert ist (oder positioniert werden kann), aber Sie müssen bereit sein, zusätzlichen Platz an den Seiten mit zusätzlichen Inhalten zu füllen, auch wenn es sich nur um dekorative Füllstoffe handelt.
  3. Bestimmen Sie, wie stark Sie Ihren Inhalt skalieren müssen, damit entweder die Breite oder die Höhe dem Mindestwert entspricht und die andere Achse größer oder gleich dem erforderlichen Mindestwert ist. Teilen Sie dazu die Bildschirmpixelgröße durch die minimale Anzeigegröße und nehmen Sie den kleineren der resultierenden Skalierungswerte als Ihren Gesamtansichtsmaßstab.
  4. Verwenden Sie die Ansichtsskala, um die effektive (tatsächliche) Anzeigegröße für Spiellogikzwecke zu berechnen.
  5. Skalieren Sie Ihren Inhalt tatsächlich, indem Sie die Kamera entlang der Z-Achse bewegen.

In Codeform:

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

Wenn Sie mit der Verwendung der Leisten anfangen, ist die Implementierung eigentlich recht einfach (ich poste dies, obwohl das OP die Meinung vertrat, dass dies nicht akzeptabel ist, da es den Vorteil hat, dass es auf Mobilgeräten nicht annähernd so schlecht ist, und es ist eine einfache Lösung dafür benötigt überhaupt keinen Code)

Camera.orthographicSizeist eine Variable innerhalb der Orthokamera (die die meisten 2D-Spiele verwenden), die die gemessene Anzahl von Spieleinheiten vertikal auf dem Bildschirm ( geteilt durch 2 ) ( Quelle ) anpasst . Wählen Sie daher ein Seitenverhältnis, das für die meisten Geräte geeignet ist (ich habe 16: 9 gewählt, da die meisten von mir untersuchten Bildschirme 16: 9, 16:10, 3: 2 sind), und fügen Sie eine Maske hinzu, die dieses Seitenverhältnis überlagert.

Beispiel :

In meinem Spiel (hier nicht aufgeführt, da es sich nicht um eine Anzeige handelt, kann bei Bedarf nach Kommentaren gefragt werden) verwenden wir den Porträtmodus. Um ein einfaches 16: 9 zu machen, habe ich meine Ortho-Kamera in Größe 16 erstellt. Dies bedeutet, dass die Kamera 32 Spielhöheneinheiten (y: 16 bis -16 in meinem Fall) an die Vertikale des Geräts auf dem Bildschirm anpasst.

Ich habe dann schwarze Masken mit einem Spiel zwischen -9 und +9 platziert. Voila, der Bildschirm des Spiels sieht auf allen Geräten gleich aus und auf Geräten, die etwas breiter sind, etwas dünner. Ich habe absolut keine negativen Rückmeldungen bezüglich der Masken erhalten. Um Querformat zu erstellen, drehen Sie diese Werte einfach um und stellen Sie die Kamera auf Größe 9 ein. Ändern Sie die Werte so, dass sie mit den von Ihnen gewählten Maßstäben für die Spieleinheiten übereinstimmen.

Der einzige Ort, an dem der schwarze Balken deutlich zu sehen ist, ist auf dem iPad mit 3: 2. Auch dann habe ich keine Beschwerden gehabt.


1

Ich mache das in einem Spiel, an dem ich gerade arbeite. Ich habe ein Hintergrundbild mit einer Größe von 1140 x 720. Die wichtigsten Teile (die niemals abgeschnitten werden sollten) sind im mittleren Bereich von 960 x 640 enthalten. Ich führe diesen Code in der Startfunktion meiner Kamera aus:

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

Ich definiere auch andere Größen als die Schriftgröße für Schaltflächen und dergleichen. Es funktioniert gut mit jedem Seitenverhältnis, das ich getestet habe. Es ist schon eine Weile her, seit ich es eingerichtet habe, daher kann mir ein Schritt fehlen. Lassen Sie mich wissen, wenn es nicht wie erwartet funktioniert, und ich werde sehen, ob ich etwas ausgelassen habe.


1

@ Marcel's Antwort und Code sind großartig und haben mir geholfen zu verstehen, was passiert ist. Es ist die endgültige Antwort. Ich dachte, jemand könnte auch nützlich finden, was ich für meinen speziellen Fall getan habe: Da ich etwas wirklich sehr einfaches wollte, ein Sprite, das immer auf dem Bildschirm zu sehen ist, habe ich mir die folgenden Zeilen ausgedacht:

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

Ich habe dies der Kamera hinzugefügt und mein Sprite (das ist mein Hintergrund) in die einzige Eigenschaft des Skripts gezogen. Wenn Sie keine schwarzen Balken (horizontal oder vertikal) möchten, können Sie einen größeren Hintergrund hinter diesen einfügen ...


0

Es gibt ein paar Möglichkeiten, um dieses Problem anzugehen, und es gibt keine perfekte Lösung (zumindest habe ich noch keine gefunden), und die Art der Lösung, mit der Sie arbeiten, hängt stark von der Art des Spiels ab, das Sie spielen Entwicklung.

Unabhängig davon, was Sie tun, sollten Sie zunächst die niedrigste Auflösung auswählen, die Sie unterstützen möchten, und Ihre Sprites auf diese Auflösung aufbauen. Wenn Sie also an der Entwicklung für iOS interessiert sind, beträgt die niedrigste iOS-Geräteauflösung laut http://www.iosres.com/ 480 x 320.

Von dort aus können Sie die Sprites skalieren, um die höheren Auflösungen zu erreichen. Der Nachteil dabei ist, dass Sie mit der Zeit bemerken werden, dass die Sprites mit zunehmender Skalierung verschwimmen. In diesem Fall können Sie zu einer anderen Gruppe von Sprites wechseln, die für höhere Auflösungen entwickelt wurden.

Oder Sie können die Skalierung komplett ignorieren und einfach entscheiden, mehr Spielbildschirm für höhere Auflösungen anzuzeigen (ich glaube, Terraria macht das zum Beispiel so). Für viele Spiele ist dies jedoch nicht angemessen. Wettbewerbsspiele zum Beispiel.

Die Verwendung von schwarzen Balken oben oder unten ist heutzutage nicht mehr akzeptabel.

Ist es? Viele Spiele, die ein Seitenverhältnis von 4: 3 erzwingen möchten, tun dies. Da Sie Unity verwenden, können Sie das AspectRatioEnforcer- Skript verwenden, um dies zu unterstützen.


Ich bin auf Mobilgeräte ausgerichtet, daher kann ich das Seitenverhältnis oder die Auflösung nicht ändern. Die Verwendung von Assets mit niedriger Auflösung ist keine akzeptable Lösung. Bei manchen Spielen (vor allem 3D) ist es kein Problem, man zeigt nur mehr oder weniger. Aber Spiele wie Kingdom Rush, Tower Defense und andere Spiele wie Alex wollen dasselbe sehen, egal auf welchem ​​Gerät. Wenn die Dinge nicht an den richtigen Stellen auftauchen, funktioniert das Spiel nicht richtig.
Michael


0

Es gibt mehrere Möglichkeiten, um dieses Problem zu lösen. Es hängt von Ihrem Spiel ab und davon, was am besten funktioniert. Zum Beispiel haben wir in unserem Spiel Tyrant Unleashed einfach breite Karten mit unwichtigen Details an den Seiten erstellt, sodass es in Ordnung ist, die Seiten bei schmaleren Geräten abzuschneiden. Andere Spiele sind jedoch möglicherweise besser geeignet, wenn Sie die Schaltflächen verschieben oder etwas, das besser auf den Bildschirm passt.

(Teil unseres Ansatzes ist es auch, auf allen Geräten eine einheitliche Höhe beizubehalten und nur die Breite zu variieren. Dies erleichtert uns sicherlich das Leben, aber auch dies kann für Ihr spezielles Spiel von Vorteil sein oder auch nicht. Es spielt keine Rolle in unser Kunststil, wenn die Bilder auf verschiedenen Bildschirmen ein wenig skaliert werden, während dies für etwas wie Pixelkunst von Bedeutung sein kann. Grundsätzlich ist dies der Ansatz "Unity damit umgehen lassen".


Haben Sie Projekte durchgeführt, bei denen dies keine Option war? Fast alle Tower Defense-Spiele, die ich gesehen habe, und viele andere Stile zeigen die gesamte Spielansicht auf dem Gerät an, ohne zu scrollen. Dies gilt für alle Geräte. Unter IOS können Sie Assets erstellen und austauschen, aber das wird unter Android unmöglich (und eigentlich nur eine große PITA).
Michael

Nein habe ich nicht. Übrigens habe ich gerade ein paar Details über die Bildschirmgröße hinzugefügt
jhocking

0

Ich verwende das folgende Skript, das targetAspectder Kamera einen Parameter hinzufügt und diesen orthographicSizein Bezug auf das Bildschirmverhältnis anpasst (weitere Details in diesem Blog-Beitrag ):

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

Meine Methode ähnelt größtenteils den von anderen angegebenen Lösungen :) Ich werde versuchen, den Ansatz, mit dem ich das Spiel unabhängig von der Bildschirmgröße mache, detailliert zu erklären.

Bildschirmausrichtung

Abhängig von der Bildschirmausrichtung (Querformat oder Hochformat) müssen Sie überlegen, ob die Kamera mit einer festen Höhe oder einer festen Breite skaliert. Meistens wähle ich eine feste Breite für Spiele im Querformat und eine feste Höhe für Spiele im Hochformat.

Kameraskalierung

Wie bereits erwähnt, kann dies entweder eine feste Höhe oder eine feste Breite sein.

Feste Höhe : Der vertikale Bereich des Spiels passt immer zur Bildschirmhöhe. Und wenn sich das Seitenverhältnis des Bildschirms ändert, wird links und rechts auf dem Bildschirm zusätzlicher Platz hinzugefügt. Um dies zu implementieren, müssen Sie nichts codieren, es ist das Standardverhalten von Unity Camera.

Feste Breite : Der horizontale Bereich des Spiels passt immer zur Bildschirmbreite. Wenn sich das Seitenverhältnis des Bildschirms ändert, wird oben und unten zusätzlicher Platz hinzugefügt. Um dies zu implementieren, müssen Sie ein kleines Stück Code schreiben. Stellen Sie später sicher, dass Sie die Aktualisierungsfunktion für das Code-Formular entfernen und aktivieren.

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

Im Editor können Sie die targetWidth ändern, um den anzuzeigenden Weltraumbereich zu definieren. Dieser Code wird im folgenden Video zusammen mit vielen anderen Methoden für 2D-Spiele erklärt :)

Unite 2014 - 2D-Best Practices in Unity

Seitenverhältnis

Das folgende Seitenverhältnis wird von der breitesten bis zur engsten Seite angezeigt und deckt nahezu alle Bildschirmgrößen für Android und iOS ab

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

Normalerweise stelle ich alle diese Seitenverhältnisse in der angegebenen Reihenfolge unter dem Spielfenster ein, da dies beim Testen auf verschiedene Bildschirmgrößen praktisch ist :)

Verbrauchsfläche

Dies ist der Bereich, der je nach gewählter Kameraskalierung seitlich oder oben / unten zum Bildschirm hinzugefügt wird.

Für eine feste Höhe sollten alle Spielelemente vorzugsweise im Verhältnis 16: 9 passen, das am engsten ist. Und der Hintergrund sollte sich erstrecken, bis er das Verhältnis 5: 4 abdeckt. Das stellt sicher, dass Ihr Spiel niemals schwarze Streifen an den Seiten hat.

Bei fester Breite ist es fast dasselbe, aber hier sollten die Elemente im Verhältnis 5: 4 passen und der HG sollte bis 16: 9 reichen.

Grenzen

Manchmal können wir den Ansatz für den Verbrauchsbereich nicht verwenden, da wir den gesamten verfügbaren Bildschirm für das Spiel nutzen müssen.

Stellen Sie sich beispielsweise ein Porträtspiel mit fester Höhe vor, bei dem die vom Himmel fallenden Münzen aufgefangen werden. In diesem Fall müssen wir dem Player die Möglichkeit geben, sich horizontal über die verfügbare Bildschirmbreite zu bewegen.

Daher müssen wir die Grenzen der Kamera in Bezug auf die Weltkoordinaten kennen, um genau zu wissen, wo sich die linken, rechten, oberen oder unteren Bereiche der Kameraclips an der Weltposition befinden.
Wir können diese Schranken auch verwenden, um Spielelemente oder die Benutzeroberfläche an einer gewünschten Seite der Kamera zu verankern.

Mit Camera.ViewportToWorldPoint können wir die Grenzen ermitteln. Der Viewport-Bereich ist normalisiert und relativ zur Kamera. Unten links in der Kamera befindet sich (0,0). oben rechts ist (1,1). Die z-Position wird in Welteinheiten von der Kamera angegeben. Bei 2D / Orthographie spielt das z keine Rolle.

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;

Benutzeroberfläche

Für die Benutzeroberfläche können wir dieselben Konzepte anwenden, die wir für die Spielelemente verwendet haben. Nach der Einführung von Unity5 UI und der Verfügbarkeit von Plugins wie NGUI wird dies kein großes Problem sein :)


0

Ich habe das Unity-Asset "Resolution Magic 2D" erstellt, um dieses Problem zu lösen (Anzeige: Sie können es im Unity-Asset-Store oder unter grogansoft.com abrufen).

Ich ging das Problem folgendermaßen an ...

Definieren Sie einen Bereich des Bildschirms, der unabhängig von Seitenverhältnis / Auflösung immer sichtbar sein muss, und verwenden Sie eine einfache Rechtecktransformation, um diesen Bereich zu "schablonieren". Dies ist Ihre ideale Bildschirmform. Mit einem einfachen Algorithmus zoome ich dann die Kamera, bis der durch das Rechteck ausgeblendete Bereich so groß wie möglich ist, während er für die Kamera immer noch zu 100% sichtbar ist.

Dann nimmt Ihr Hauptspielbereich immer so viel Bildschirm wie möglich ein. Und solange außerhalb des zuvor definierten Rechteckbereichs genügend zusätzlicher Inhalt (z. B. Ihr Hintergrund) vorhanden ist, wird Spielern, deren Bildschirm nicht das gleiche Seitenverhältnis aufweist wie Ihr ideales Rechteck, der zusätzliche Inhalt angezeigt, an dem sonst schwarze Balken angezeigt würden gehen.

Mein Asset enthält auch eine Logik zum Platzieren der Benutzeroberfläche, die jedoch aufgrund des neuen Unity-Benutzeroberflächensystems größtenteils veraltet ist.

Mein Asset bietet dies sofort mit minimalem Setup und es funktioniert wirklich gut auf allen Plattformen.

Wenn Sie diese Technik (oder meinen Vorteil) verwenden, stellen Sie einfach sicher, dass Sie Ihr Spiel so gestalten, dass rundherum "optionaler" Platz für Bildschirme vorhanden ist, die breiter oder höher als Ihr Ideal sind (um schwarze Balken zu vermeiden).

Ich persönlich mache keine 3D-Spiele, daher weiß ich nicht, ob dies in 3D funktionieren würde (oder ob es überhaupt notwendig ist).

Es ist wirklich schwer zu erklären, ohne Bilder, also besuchen Sie bitte meine Website ( Resolution Magic 2D )


0

Die beste Lösung für mich ist, den Satz von sich kreuzenden Linien so zu verwenden, dass es weder zu einem Schnitt an den Seiten noch zu einer Verzerrung der Spielansicht kommt. Das bedeutet, dass Sie je nach Seitenverhältnis einen Schritt zurück oder einen Schritt nach vorne machen müssen.


-3

Ich habe eine AssetStore-Erweiterung namens AspectSwitcher erstellt, die einen einfacheren Aspektwechsel ermöglicht . Es bietet ein System, mit dem Sie einfach verschiedene Eigenschaften für verschiedene Aspekte angeben können. Es gibt im Allgemeinen zwei Methoden, mit denen die meisten Menschen Aspekte wechseln. Zum einen müssen für jeden Aspekt unterschiedliche Spielobjekte bereitgestellt werden. Der andere besteht darin, benutzerdefinierten Code zu erstellen, der die Eigenschaften eines einzelnen Spielobjekts basierend auf dem aktuellen Aspekt ändert. Das erfordert in der Regel viel benutzerdefiniertes Codieren. Meine Erweiterung versucht, eine Menge dieser Schmerzen zu lindern.


2
Diese Antwort wäre besser und scheint weniger Spam zu sein, wenn Sie die tatsächlichen Techniken erläutern würden, die zur Beantwortung der Frage des OP verwendet werden könnten.
Josh
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.