Bagaimana Anda menangani perbedaan rasio aspek dengan Unity 2D?

67

Saya mendapat banyak jawaban untuk pertanyaan ini, tetapi semuanya generik dan umumnya tidak terlalu berguna. Tak satu pun dari tutorial berbicara tentang rasio aspek dan berurusan dengan perangkat mobile dan ada banyak cara untuk melakukannya, semua tampaknya punya gotcha dan kekurangan.

Saya benar-benar ingin tahu game apa yang berhasil digunakan untuk menangani rasio aspek berbeda di iOS dan Android tanpa membuat miliaran aset dengan ukuran berbeda.

Saya benar-benar berbicara mobile, bukan desktop, khususnya dengan Unity dan saya tidak peduli dengan UI, saya hanya peduli dengan kanvas gameplay.

Masalah yang ada dalam pikiran saya adalah ketika ada hal-hal penting yang harus ada di tempat-tempat tertentu dan tidak dapat jatuh dari layar. Menggunakan bilah hitam di bagian atas atau bawah tidak dapat diterima hari ini.

Michael
sumber
3
Pertanyaan ini sangat luas, karena cara yang benar tergantung pada hampir semua hal. Apa yang sudah kamu coba? Mengapa itu tidak berhasil?
Anko
3
Saya sudah mencoba segala macam hal, saya sudah mencoba menyesuaikan ukuran kamera orto, saya sudah mencoba melampirkan semua sprite ke daftar dan menskalakannya dengan perbedaan dalam aspek rasio, mengatur ukuran orto ke layar.tinggi / 2/100, banyak lainnya ide ide. Beberapa bekerja, tetapi semuanya memiliki masalah. Saya tahu permainan yang berbeda menanganinya berbeda tetapi sama sekali tidak ada diskusi tentang topik ini di mana pun dan itu tidak semudah "membiarkan persatuan menanganinya" seperti yang diklaim banyak orang.
Michael
1
Jadi, mengapa mereka tidak bekerja? Seperti apa solusi yang baik? (Omong-omong, Anda dapat mengedit pertanyaan untuk mengklarifikasi juga.)
Anko
7
Beberapa mengubah gambar, beberapa tidak berbaris dengan benar. Banyak masalah yang berbeda, tetapi 65% game yang dikembangkan dengan Unity adalah 2D, dan mereka membuatnya bekerja. Saya hanya ingin tahu apa yang orang gunakan, dan tidak harus menemukan kembali kemudi. Tidak ada yang membicarakannya dan tidak ada panduan atau dokumen tentang cara menanganinya. Namun Anda tidak dapat melangkah jauh dalam proyek seluler tanpa memiliki sistem untuk melakukannya.
Michael
1
"Masalah yang ada dalam pikiran saya adalah ketika ada hal-hal penting yang harus ada di tempat-tempat tertentu dan tidak dapat jatuh dari layar. Menggunakan bilah hitam di bagian atas atau bawah tidak dapat diterima hari ini." Jaminan elemen tidak jatuh dari layar, nol distorsi, tetapi tidak ada huruf / pilar-tinju (bilah hitam dan sejenisnya). Persyaratan ini tidak dapat didamaikan. Persyaratan terakhir mungkin yang paling tidak penting, atau dapat disembunyikan dengan melapisi kanvas di luar apa yang seharusnya ada di layar. Sebagian besar permainan yang saya lihat dengan persyaratan ketat akan dihiasi dengan pillarbox / borders.
Jibb Smart

Jawaban:

36

Apa yang Anda inginkan adalah membatasi viewport kamera pada potret atau lanskap (tergantung pada kebutuhan Anda), dengan menghitung camera.orthographicSizeproperti, sehingga Anda dapat membangun adegan 2d Anda terlepas dari rasio aspek dan resolusi:

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

Jika Anda memerlukan info lebih lanjut tentang ini, silakan bertanya dan saya akan membalas. ;) Salam dan tepuk tangan.

PEMBARUAN: Gunakan skrip penahan objek Eliot Lash bersamaan dengan yang ini untuk menempatkan objek pada posisi kunci di layar jika diperlukan (relatif terhadap sudut / batas layar). Jika ya, ubah nama "CameraFit" menjadi "ViewportHandler".

Pratinjau mensimulasikan berbagai layar rasio aspek: masukkan deskripsi gambar di sini

Androidu
sumber
4
@Eliot Menambahkan lisensi MIT di atas. Semoga berhasil dengan proyek Anda!
androidu
7
Fantastis, terima kasih! Satu belokan yang bagus layak mendapatkan yang lain, jadi inilah komponen open-source yang baru saja saya tulis untuk penahan sederhana GameObjects ke poin pembantu yang ditentukan oleh skrip Anda: gist.github.com/fadookie/256947788c364400abe1
Eliot
1
MarcelCăşvan Script yang sangat bagus! Saya menambahkan enum untuk memilih jika Anda ingin menentukan ukuran satuan untuk potrait untuk landscape (tinggi / lebar). Baru saja menambahkan beberapa baris ke skrip, dan saya gunakan GetComponent<Camera>().orthographicSize = UnitSize / 2f;untuk potrait / mendefinisikan satuan ketinggian
am_
2
@ MarcelCăşvan barang hebat! Terima kasih. Saya melihat bahwa variabel deviceWidth dan deviceHeight dari ComputeFunction () tidak digunakan. Mungkin pertimbangkan untuk menghapus ini.
user2313267
1
CameraAnchor melempar kesalahan: "CameraFit tidak didefinisikan dalam konteks ini" - Jika ada orang lain yang menemukan jawaban ini nanti sepertinya "CameraFit" baru saja berganti nama menjadi "ViewportHandler" karena ini awalnya diposting. Jika Anda baru saja mengganti nama kelas dari ViewportHandler kembali ke CameraFit.
Lenny
5

Anda biasanya tidak memerlukan ukuran aset yang berbeda - tekstur dan sprite yang diimpor dengan peta mip yang dibuat secara otomatis akan terlihat bagus ketika ditampilkan pada ukuran apa pun yang kurang dari atau sama dengan ukuran piksel asli gambar.

Tata letak adegan adalah tantangannya. Salah satu pendekatan yang baik adalah sebagai berikut (dan FYI saya menggunakan kamera 3D melihat konten 2D yang diposisikan pada z = 0):

  1. Secara sewenang-wenang memutuskan ukuran tampilan "logis" minimum dalam piksel atau ubin. Ini tidak perlu sesuai dengan resolusi dunia nyata, tetapi harus mencerminkan rasio aspek tersempit / terpendek yang ingin Anda dukung. Misalnya, untuk permainan lanskap saya tidak akan memilih 480x320 karena itu rasio aspek yang lebih luas daripada iPad. Jadi saya mungkin memilih 1024x768 - atau bahkan 480x360, yang memberi saya sistem koordinat ukuran iPhone asli untuk bekerja dan rasio aspek yang sama seperti setiap iPad (termasuk iPad Air 2, dll.). Perhatikan juga bahwa Anda dapat dengan mudah bekerja di koordinat ubin daripada koordinat piksel - 15x11.25 misalnya.
  2. Program logika permainan Anda sehingga segala sesuatu yang penting adalah (atau dapat) diposisikan dalam ukuran tampilan minimum Anda tetapi bersiaplah untuk mengisi ruang tambahan di sisi dengan konten tambahan, bahkan jika itu hanya pengisi dekoratif.
  3. Tentukan seberapa banyak Anda perlu skala konten Anda sehingga lebar atau tinggi sesuai dengan nilai minimum dan sumbu lainnya lebih besar dari atau sama dengan minimum yang dibutuhkan. Untuk melakukan "skala agar sesuai" ini, bagi ukuran piksel layar dengan ukuran tampilan minimum dan ambil yang lebih kecil dari nilai skala yang dihasilkan menjadi skala tampilan keseluruhan.
  4. Gunakan skala tampilan untuk menghitung ukuran tampilan efektif (aktual) untuk tujuan logika game.
  5. Sebenarnya skala konten Anda dengan menggerakkan kamera di sepanjang sumbu Z.

Dalam bentuk kode:

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

Jika Anda menggunakan bilah-bilah itu sebenarnya cukup sederhana untuk diterapkan (saya memposting ini meskipun OP menyatakan pendapatnya bahwa itu tidak dapat diterima karena memiliki manfaat tidak terlalu buruk di ponsel dan ini adalah solusi sederhana yang tidak memerlukan kode apa pun)

Camera.orthographicSizeadalah variabel dalam kamera orto (yang digunakan sebagian besar game 2D) yang sesuai dengan jumlah unit game yang diukur secara vertikal di layar ( dibagi 2 ) ( sumber ). Jadi, pilih rasio aspek yang sesuai dengan sebagian besar perangkat (saya memilih 16: 9 karena sebagian besar layar yang saya teliti adalah 16: 9, 16:10, 3: 2) dan tambahkan topeng yang menutupi itu pada rasio.

Contoh :

Dalam permainan saya (tidak tercantum di sini karena ini bukan iklan, dapat meminta komentar jika diinginkan) kami menggunakan mode potret. Untuk melakukan 16: 9 sederhana yang bagus, saya membuat kamera Ortho saya pada ukuran 16. Ini berarti kamera akan mengadaptasi 32 unit permainan tinggi (y: 16 hingga -16 dalam kasus saya) ke dalam vertikal layar perangkat.

Saya kemudian menempatkan topeng hitam dengan permainan antara -9 dan +9. Voila, layar game terlihat sama persis di semua perangkat dan sedikit lebih kurus pada perangkat yang sedikit lebih lebar. Saya sama sekali tidak punya umpan balik negatif tentang topeng. Untuk melakukan landscape cukup membalikkan nilai-nilai itu dan kemudian Anda akan membuat kamera ukuran 9. Ubah nilai agar sesuai dengan apa pun yang Anda putuskan adalah skala unit game Anda.

Satu-satunya tempat kami mengamati bilah hitam untuk muncul secara signifikan adalah di iPad pada 3: 2. Meski begitu, saya tidak punya keluhan.

McAden
sumber
1

Saya melakukan ini dalam permainan yang saat ini saya kerjakan. Saya memiliki gambar latar belakang yaitu 1140x720. Bit yang paling penting (yang tidak boleh dipotong) terdapat di area tengah 960x640. Saya menjalankan kode ini pada fungsi awal kamera saya:

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

Saya juga menentukan ukuran selain ukuran font untuk tombol dan semacamnya. Ini bekerja dengan baik pada setiap aspek rasio yang saya uji. Sudah lama sejak saya mengaturnya, jadi saya mungkin kehilangan langkah. Beri tahu saya jika itu tidak berfungsi seperti yang diharapkan dan saya akan melihat apakah saya meninggalkan sesuatu.

John
sumber
1

Jawaban dan kode Marcel sangat bagus dan membantu saya memahami apa yang sedang terjadi. Itu jawaban yang pasti. Hanya berpikir seseorang mungkin juga menemukan berguna apa yang akhirnya saya lakukan untuk kasus spesifik saya: karena saya ingin sesuatu yang benar-benar sangat sederhana, satu sprite selalu ada di layar, saya membuat beberapa baris ini:

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

Saya menambahkan ini ke kamera dan menyeret sprite saya (ini adalah latar belakang saya) ke satu-satunya properti skrip. Jika Anda tidak menginginkan bilah hitam (horizontal atau vertikal), Anda dapat menempatkan latar belakang yang lebih besar di belakang ...

maltalef
sumber
0

Ada beberapa cara untuk mengatasi masalah ini, dan belum ada solusi yang sempurna (setidaknya saya belum menemukannya) dan jenis solusi yang Anda gunakan akan sangat bergantung pada jenis permainan yang Anda gunakan. mengembangkan.

Apa pun yang Anda lakukan, Anda harus memulainya dengan memilih resolusi serendah mungkin yang ingin Anda dukung dan membangun sprite Anda ke resolusi itu. Jadi, jika Anda tertarik mengembangkan iOS, menurut http://www.iosres.com/ resolusi perangkat iOS terendah adalah 480x320.

Dari sana, Anda dapat mulai meningkatkan sprite untuk memenuhi resolusi yang lebih tinggi. Peringatan untuk ini adalah bahwa Anda pada akhirnya akan mulai melihat sprite mulai mengaburkan semakin jauh skala Anda, dalam hal ini Anda dapat beralih ke set sprite lain yang dibuat untuk resolusi yang lebih tinggi.

Atau, Anda dapat mengabaikan penskalaan sepenuhnya, dan hanya memutuskan untuk menampilkan lebih banyak layar game untuk resolusi yang lebih tinggi (saya percaya ini adalah bagaimana Terraria melakukannya, misalnya). Namun, untuk banyak game, ini tidak tepat; game kompetitif misalnya.

Menggunakan bilah hitam di bagian atas atau bawah tidak dapat diterima hari ini.

Apakah itu? Banyak game yang ingin memaksakan rasio aspek 4: 3 melakukan ini. Karena Anda menggunakan Unity, Anda dapat menggunakan skrip AspectRatioEnforcer untuk membantu ini.

Cooper
sumber
Saya menargetkan ponsel, jadi saya tidak dapat mengubah rasio aspek atau resolusi. Menggunakan aset beresolusi rendah bukanlah solusi yang dapat diterima. Beberapa game (terutama 3D) bukan masalah, Anda hanya menampilkan lebih atau kurang. Tetapi game seperti Kingdom Rush, tower defense, dan game lain seperti Alex Anda ingin melihat hal yang sama terlepas dari perangkatnya. Jika hal-hal tidak muncul di lokasi yang tepat, permainan tidak akan berfungsi dengan baik.
Michael
0

Ada beberapa cara untuk menangani masalah ini, itu tergantung pada gim Anda dan apa yang akan bekerja paling baik. Misalnya, di game kami Tyrant Unleashed, kami hanya membuat peta lebar dengan detail yang tidak penting di sisinya, sehingga tidak apa-apa untuk memotong sisi pada perangkat yang lebih sempit. Namun permainan lain mungkin lebih baik dengan pendekatan di mana Anda benar-benar menggeser tombol atau sesuatu agar sesuai dengan layar lebih baik.

(juga bagian dari pendekatan kami juga menjaga ketinggian yang konsisten pada semua perangkat, hanya memvariasikan lebar. Ini tentu membuat hidup lebih mudah bagi kami, tapi sekali lagi ini mungkin atau mungkin tidak ada gunanya untuk permainan spesifik Anda. Tidak masalah dalam gaya seni kami jika gambar diskalakan sedikit pada layar yang berbeda, sedangkan ini mungkin penting untuk sesuatu seperti seni pixel. Pada dasarnya, ini adalah pendekatan "biarkan Unity menanganinya")

jhocking
sumber
Sudahkah Anda melakukan proyek di mana itu bukan pilihan? Hampir semua gim gaya pertahanan menara yang pernah saya lihat dan banyak gaya lain Anda bisa melihat seluruh tampilan gim di perangkat tanpa menggulir, dan ini konsisten di seluruh perangkat. Di iOS Anda dapat membuat aset dan menukarnya, tetapi itu menjadi tidak mungkin (dan benar-benar hanya PITA besar) di Android.
Michael
Tidak, belum. btw Saya baru saja menambahkan beberapa detail tentang ukuran layar
jhocking
0

Saya menggunakan skrip berikut yang menambahkan targetAspectparameter ke kamera dan menyesuaikannya orthographicSizesehubungan dengan rasio layar (lebih detail dalam posting blog ini ):

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
sumber
0

Metode saya sebagian besar mirip dengan solusi yang diberikan oleh orang lain :) Saya akan mencoba menjelaskan secara rinci pendekatan yang saya ambil untuk membuat game independen dari ukuran layar.

Orientasi layar

Bergantung pada orientasi layar (Lanskap atau Potret), Anda perlu mempertimbangkan apakah kamera akan menskala dengan ketinggian tetap atau lebar tetap. Sebagian besar saya memilih lebar tetap untuk game berorientasi lanskap dan tinggi tetap untuk game berorientasi potret.

Penskalaan Kamera

Seperti yang dibahas ini dapat berupa ketinggian tetap atau lebar tetap.

Fixed Height : Area vertikal game akan selalu pas dengan ketinggian layar. Dan saat rasio aspek layar berubah, akan ada ruang tambahan yang ditambahkan ke kiri dan kanan layar. Untuk menerapkan ini Anda tidak perlu kode apa pun, itu adalah perilaku default kamera persatuan.

Fixed Width : Area horizontal game akan selalu pas dengan lebar layar. Dan ruang ekstra akan ditambahkan ke atas dan bawah saat rasio aspek layar berubah. Untuk mengimplementasikan ini, Anda perlu menulis sepotong kecil kode. Kemudian pastikan Anda menghapus fungsi pembaruan bentuk kode, dan tempatkan di tempat terjaga.

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

Di editor Anda dapat mengubah targetWidth untuk menentukan area ruang dunia yang ingin Anda tampilkan. Kode ini dijelaskan dalam video berikut bersama dengan banyak praktik lainnya untuk game 2D :)

Unite 2014 - Praktik Terbaik 2D Dalam Persatuan

Rasio Aspek

Mengikuti rasio aspek yang terdaftar dari terluas ke tersempit, mencakup hampir semua ukuran layar untuk Android dan iOS

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

Saya biasanya mengatur semua rasio aspek ini dalam urutan yang diberikan di bawah jendela permainan, karena berguna saat menguji ukuran layar yang berbeda :)

Area yang Dapat Terjangkau

Ini adalah area yang ditambahkan ke layar ke samping atau atas / bawah tergantung pada skala kamera yang telah Anda pilih.

Untuk ketinggian tetap, semua elemen permainan sebaiknya sesuai dengan rasio 16: 9 yang merupakan yang tersempit. Dan latar belakang harus diperluas hingga mencakup rasio 5: 4. Yang memastikan bahwa gim Anda tidak pernah memiliki strip hitam ke samping.

Untuk lebar tetap hampir sama tetapi di sini elemen harus sesuai dengan rasio 5: 4 dan BG harus diperpanjang hingga 16: 9.

Batas

Kadang-kadang kita tidak bisa menggunakan pendekatan area yang dapat dibuang karena kita perlu memanfaatkan seluruh layar yang tersedia untuk bermain game.

Misalnya, perhatikan permainan potret dengan ketinggian tetap, menangkap koin yang jatuh dari langit. Dalam hal ini kita perlu memberi pemain kemampuan untuk bergerak secara horizontal di atas lebar layar yang tersedia.

Karenanya kita membutuhkan batasan kamera dalam hal koordinat dunia untuk mengetahui di mana tepatnya kiri, kanan, atas atau bawah klip kamera di posisi dunia.
Kami juga dapat menggunakan batas ini untuk menambatkan elemen permainan atau UI ke sisi kamera yang diinginkan.

Menggunakan Camera.ViewportToWorldPoint kita bisa mendapatkan bounds.Viewport space dinormalisasi dan relatif terhadap kamera. Kiri bawah kamera adalah (0,0); kanan atas adalah (1,1). Posisi z berada di unit dunia dari kamera. Untuk 2D / ortografis, z tidak masalah.

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

Untuk UI kami dapat menerapkan konsep yang sama yang kami gunakan untuk elemen game. Setelah pengenalan Unity5 UI dan ketersediaan plugin seperti NGUI ini tidak akan menjadi masalah :)

Pelampung Hash
sumber
0

Saya membuat Unity Asset 'Resolution Magic 2D' untuk menyelesaikan masalah ini (iklan: Anda bisa mendapatkannya dari Unity Asset Store, atau lihat detail selengkapnya di grogansoft.com).

Cara saya mengatasi masalah adalah sebagai berikut ...

Tentukan area layar yang harus selalu terlihat terlepas dari aspek rasio / resolusi, dan gunakan transformasi persegi panjang sederhana untuk 'stencil out' wilayah ini. Ini adalah bentuk layar ideal Anda. Dengan menggunakan algoritma sederhana, saya kemudian memperbesar kamera sampai wilayah yang diblokir oleh persegi panjang sebesar mungkin sementara masih 100% terlihat oleh kamera.

Maka area permainan utama Anda selalu mengambil layar sebanyak mungkin. Dan selama ada cukup konten 'ekstra' (misalnya latar belakang Anda) di luar area persegi panjang yang Anda tetapkan sebelumnya, pemain yang layarnya tidak memiliki rasio aspek yang sama dengan persegi panjang 'ideal' Anda akan melihat konten tambahan di mana bar hitam seharusnya pergi.

Aset saya juga mencakup beberapa logika untuk menempatkan UI, tetapi itu sebagian besar sudah usang karena sistem UI baru Unity.

Aset saya menyediakan ini di luar kotak dengan pengaturan minimal, dan berfungsi dengan sangat baik di semua platform.

Jika Anda menggunakan teknik ini (atau aset saya), pastikan Anda mendesain game Anda agar memiliki ruang 'opsional' untuk mengakomodasi layar yang lebih lebar atau lebih tinggi dari ideal Anda (untuk menghindari bilah hitam).

Saya pribadi tidak membuat game 3D, jadi saya tidak tahu apakah ini akan berhasil dalam 3D (atau bahkan jika itu diperlukan).

Sangat sulit untuk dijelaskan tanpa gambar, jadi silakan kunjungi situs web saya ( Resolution Magic 2D )

pumpkinszwan
sumber
0

Solusi terbaik bagi saya adalah dengan menggunakan teorema garis berpotongan sehingga tidak ada potongan di sisi maupun distorsi dari tampilan permainan. Itu berarti bahwa Anda harus mundur atau maju tergantung pada rasio aspek yang berbeda.

unityfever
sumber
-3

Saya membuat ekstensi AssetStore yang memungkinkan untuk beralih aspek yang lebih mudah disebut AspectSwitcher . Ini menyediakan sistem untuk memungkinkan Anda dengan mudah menentukan properti yang berbeda untuk aspek yang berbeda. Biasanya ada dua metode yang kebanyakan orang gunakan untuk berganti aspek. Pertama adalah menyediakan objek permainan yang berbeda untuk setiap aspek. Yang lainnya adalah membuat kode khusus yang mengubah properti dari satu objek game berdasarkan aspek saat ini. Itu umumnya membutuhkan banyak pengkodean khusus. Perpanjangan saya berusaha untuk meringankan banyak rasa sakit itu.

Jason
sumber
2
Jawaban ini akan lebih baik, dan tampaknya lebih sedikit spam, jika Anda menguraikan teknik aktual yang mungkin digunakan untuk menjawab pertanyaan OP.
Josh