Làm thế nào để bạn xử lý sự khác biệt tỷ lệ khung hình với Unity 2D?


67

Tôi đã nhận được rất nhiều câu trả lời cho câu hỏi này, nhưng chúng đều chung chung và thường không hữu ích lắm. Không có hướng dẫn nào nói về tỷ lệ khung hình và xử lý các thiết bị di động và có hàng trăm cách để làm điều đó, tất cả dường như đều có lỗi và lỗi.

Tôi thực sự rất muốn biết những trò chơi thành công nào đã sử dụng để xử lý các tỷ lệ khung hình khác nhau trên iOS và Android mà không tạo ra hàng tỷ tài sản có kích thước khác nhau.

Tôi nói đúng về điện thoại di động, không phải máy tính để bàn, cụ thể là với Unity và tôi không quan tâm đến giao diện người dùng, tôi chỉ quan tâm đến khung hình chơi trò chơi.

Vấn đề tôi có trong đầu là khi có những điều quan trọng phải ở một số nơi nhất định và không thể rơi ra khỏi màn hình. Sử dụng các thanh màu đen trên hoặc dưới là không thể chấp nhận những ngày này.


3
Câu hỏi này rất rộng, vì cách đúng phụ thuộc vào hầu hết mọi thứ. Bạn đã thử những gì? Tại sao nó không hoạt động?
Anko

3
Tôi đã thử tất cả mọi thứ, tôi đã thử điều chỉnh kích thước máy ảnh ortho, tôi đã thử gắn tất cả các họa tiết vào danh sách và điều chỉnh chúng theo tỷ lệ khung hình, đặt kích thước ortho thành screen.height / 2/100, nhiều thứ khác ý tưởng. Một số công việc, nhưng tất cả chúng đều có vấn đề. Tôi biết các trò chơi khác nhau xử lý nó khác nhau nhưng hoàn toàn không có cuộc thảo luận nào về chủ đề này ở bất cứ đâu và nó không dễ như "chỉ để cho sự thống nhất xử lý nó" như nhiều người tuyên bố.
Michael

1
Vậy tại sao họ không làm việc? Một giải pháp tốt sẽ trông như thế nào? (Nhân tiện, bạn cũng có thể chỉnh sửa câu hỏi để làm rõ.)
Anko

7
Một số hình ảnh bị bóp méo, một số không xếp hàng đúng. Nhiều vấn đề khác nhau, nhưng 65% trò chơi được phát triển với Unity là 2D và họ đã làm cho nó hoạt động. Tôi chỉ muốn biết những gì mọi người đang sử dụng, và không phải phát minh lại bánh xe. Không ai nói về nó và không có hướng dẫn hay tài liệu nào về cách xử lý nó. Tuy nhiên, bạn không thể tiến xa trong một dự án di động mà không có hệ thống để thực hiện.
Michael

1
"Vấn đề tôi có trong đầu là khi có những thứ quan trọng phải ở một số nơi nhất định và không thể rơi ra khỏi màn hình. Sử dụng các thanh màu đen ở trên hoặc dưới là không thể chấp nhận được trong những ngày này." Đảm bảo các yếu tố không rơi ra khỏi màn hình, độ méo bằng 0, nhưng không có chữ cái / cột trụ-quyền anh (thanh màu đen và tương tự). Những yêu cầu này là không thể hòa giải. Yêu cầu cuối cùng có lẽ là ít quan trọng nhất, hoặc có thể được ẩn bằng cách điền vào khung vẽ ngoài những gì phải có trên màn hình. Hầu hết các trò chơi tôi đã thấy với các yêu cầu nghiêm ngặt như vậy sẽ có các cột / viền trang trí.
Jibb thông minh

Câu trả lời:


36

Những gì bạn muốn là hạn chế chế độ xem camera trên chế độ dọc hoặc ngang (tùy theo nhu cầu của bạn), bằng tính toán camera.orthographicSize, để bạn có thể xây dựng cảnh 2d của mình bất kể tỷ lệ khung hình và độ phân giải:

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

Nếu bạn cần thêm thông tin về điều này xin vui lòng hỏi và tôi sẽ trả lời. ;) Trân trọng và chúc mừng.

CẬP NHẬT: Sử dụng tập lệnh neo đối tượng của Eliot Lash cùng với tập lệnh này để đặt các đối tượng vào các vị trí quan trọng trên màn hình nếu cần (liên quan đến các góc / viền màn hình). Nếu bạn làm như vậy, đổi tên "CameraFit" thành "ViewportHandler".

Xem trước mô phỏng các màn hình tỷ lệ khung hình khác nhau: nhập mô tả hình ảnh ở đây


4
@Eliot Đã thêm giấy phép MIT ở trên. Chúc may mắn với các dự án của bạn!
androidu

7
Tuyệt vời, cảm ơn! Một bước ngoặt xứng đáng khác, vì vậy đây là một thành phần nguồn mở mà tôi vừa viết để neo đơn giản các GameObjects vào các điểm trợ giúp được xác định bởi tập lệnh của bạn: gist.github.com/fadookie/256947788c364400abe1
Eliot

1
MarcelCăşvan Kịch bản rất hay! Tôi đã thêm một enum để chọn nếu bạn muốn xác định kích thước đơn vị cho vùng chậu cho cảnh quan (chiều cao / chiều rộng). Chỉ cần thêm một vài dòng vào tập lệnh và tôi sử dụng GetComponent<Camera>().orthographicSize = UnitSize / 2f;cho đơn vị chiều cao / xác định đơn vị chiều cao
am_

2
@ MarcelCăşvan thứ tuyệt vời! Cảm ơn. Tôi thấy rằng các biến deviceWidth và deviceHeight từ ComputeFunction () không được sử dụng. Có lẽ xem xét xóa những cái này.
user2313267

1
CameraAnchor đang đưa ra lỗi: "CameraFit không được xác định trong ngữ cảnh này" - Trong trường hợp người khác tìm thấy câu trả lời này sau đó, có vẻ như "CameraFit" đã đổi tên thành "ViewportHandler" vì điều này ban đầu được đăng. Nếu bạn chỉ đổi tên lớp từ ViewportHandler trở lại CameraFit.
Lenny

5

Bạn thường không cần các kích thước khác nhau của tài sản - kết cấu và họa tiết được nhập với bản đồ mip được tạo tự động sẽ trông đẹp khi được hiển thị ở bất kỳ kích thước nào nhỏ hơn hoặc bằng kích thước pixel gốc của hình ảnh.

Bố cục cảnh là thách thức. Một cách tiếp cận tốt như sau (và FYI tôi sử dụng máy ảnh 3D nhìn vào nội dung 2D được định vị ở z = 0):

  1. Tự ý quyết định kích thước hiển thị "logic" tối thiểu bằng pixel hoặc gạch. Điều này không cần phải tương ứng với bất kỳ độ phân giải trong thế giới thực nào, nhưng nó sẽ phản ánh tỷ lệ khung hình hẹp nhất / ngắn nhất mà bạn muốn hỗ trợ. Ví dụ: đối với trò chơi phong cảnh, tôi sẽ không chọn 480x320 vì đó là tỷ lệ khung hình rộng hơn so với iPad. Vì vậy, tôi có thể chọn 1024x768 - hoặc thậm chí 480x360, cung cấp cho tôi hệ thống tọa độ gốc iPhone để hoạt động và tỷ lệ khung hình giống như mọi iPad (bao gồm iPad Air 2, v.v.). Cũng lưu ý rằng bạn có thể dễ dàng làm việc trong tọa độ ô thay vì tọa độ pixel - ví dụ 15x11.25.
  2. Lập trình logic trò chơi của bạn sao cho mọi thứ quan trọng là (hoặc có thể) được định vị trong kích thước hiển thị tối thiểu của bạn nhưng được chuẩn bị để lấp đầy phòng phụ ở hai bên với nội dung bổ sung, ngay cả khi đó chỉ là phụ trang trí.
  3. Xác định mức độ bạn cần để chia tỷ lệ nội dung của mình sao cho chiều rộng hoặc chiều cao khớp với giá trị tối thiểu và trục khác lớn hơn hoặc bằng mức tối thiểu cần thiết. Để thực hiện "tỷ lệ phù hợp" này, hãy chia kích thước pixel màn hình cho kích thước hiển thị tối thiểu và lấy nhỏ hơn các giá trị tỷ lệ kết quả làm tỷ lệ xem tổng thể của bạn.
  4. Sử dụng thang đo để tính kích thước hiển thị (thực tế) hiệu quả cho mục đích logic trò chơi.
  5. Thực tế chia tỷ lệ nội dung của bạn bằng cách di chuyển camera dọc theo trục Z.

Ở dạng mã:

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

Nếu bạn bắt đầu sử dụng các quán bar thì thực tế khá đơn giản để thực hiện (Tôi đang đăng bài này mặc dù OP đã nói rằng ý kiến ​​của nó là không thể chấp nhận được vì nó có lợi ích là không quá tệ trên thiết bị di động và đó là một giải pháp đơn giản không yêu cầu mã nào)

Camera.orthographicSizelà một biến trong máy ảnh ortho (mà hầu hết các trò chơi 2D sử dụng) phù hợp với số lượng đơn vị trò chơi đo được theo chiều dọc trên màn hình ( chia cho 2 ) ( nguồn ). Do đó, chọn tỷ lệ khung hình phù hợp với đại đa số thiết bị (Tôi đã chọn 16: 9 vì hầu hết các màn hình tôi đã nghiên cứu là 16: 9, 16:10, 3: 2) và thêm mặt nạ phủ lên tỷ lệ đó.

Ví dụ :

Trong trò chơi của tôi (không được liệt kê ở đây vì đây không phải là quảng cáo, có thể hỏi trong nhận xét nếu muốn) chúng tôi sử dụng chế độ dọc. Để thực hiện một cách đơn giản 16: 9 Tôi đã tạo máy ảnh Ortho của mình ở kích thước 16. Điều này có nghĩa là máy ảnh sẽ điều chỉnh 32 đơn vị chiều cao trò chơi (y: 16 đến -16 trong trường hợp của tôi) vào màn hình dọc của thiết bị.

Sau đó tôi đặt mặt nạ đen với một trò chơi trong khoảng từ -9 đến +9. Voila, màn hình của trò chơi trông giống hệt nhau trên tất cả các thiết bị và mỏng hơn một chút trên các thiết bị rộng hơn một chút. Tôi hoàn toàn không có phản hồi tiêu cực về mặt nạ. Để thực hiện phong cảnh, chỉ cần lật các giá trị đó và sau đó bạn sẽ tạo camera có kích thước 9. Thay đổi các giá trị để khớp với bất cứ điều gì bạn đã quyết định là quy mô đơn vị trò chơi của bạn.

Nơi duy nhất chúng tôi quan sát thấy thanh màu đen hiển thị đáng kể là trên iPad với tỷ lệ 3: 2. Ngay cả sau đó, tôi đã không có khiếu nại.


1

Tôi đang làm điều này trong một trò chơi mà tôi hiện đang làm việc. Tôi có một hình nền là 1140x720. Các bit quan trọng nhất (những bit không bao giờ bị cắt) được chứa trong khu vực giữa 960x640. Tôi chạy mã này trên chức năng bắt đầu của máy ảnh của mình:

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

Tôi cũng xác định kích thước khác với kích thước phông chữ cho các nút và như vậy. Nó hoạt động tốt trên mọi tỷ lệ khung hình mà tôi đã thử nghiệm. Đã được một thời gian kể từ khi tôi thiết lập nó, vì vậy tôi có thể thiếu một bước. Hãy cho tôi biết nếu nó không hoạt động như mong đợi và tôi sẽ xem liệu tôi có để lại bất cứ điều gì không.


1

Câu trả lời và mã của Marcel là tuyệt vời và giúp tôi hiểu những gì đang xảy ra. Đó là câu trả lời dứt khoát. Chỉ cần nghĩ rằng ai đó cũng có thể thấy hữu ích những gì tôi đã làm cho trường hợp cụ thể của mình: vì tôi muốn một cái gì đó thực sự đơn giản, một sprite luôn luôn xuất hiện trên màn hình, tôi đã đưa ra vài dòng sau:

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

Tôi đã thêm nó vào máy ảnh và kéo sprite của tôi (đó là nền của tôi) vào thuộc tính duy nhất của tập lệnh. Nếu bạn không muốn bất kỳ thanh màu đen (ngang hoặc dọc), bạn có thể đặt một nền lớn hơn phía sau cái này ...


0

Có một số cách để giải quyết vấn đề này và không có giải pháp nào hoàn hảo (ít nhất là tôi chưa tìm thấy) và loại giải pháp bạn sử dụng sẽ phụ thuộc rất nhiều vào loại trò chơi mà bạn đang phát triển.

Bất kể bạn làm gì, bạn nên bắt đầu bằng cách chọn độ phân giải thấp nhất có thể bạn muốn hỗ trợ và xây dựng các họa tiết của bạn theo độ phân giải đó. Vì vậy, nếu bạn quan tâm đến việc phát triển cho iOS, theo http://www.iosres.com/ độ phân giải thiết bị iOS thấp nhất là 480x320.

Từ đó, bạn có thể bắt đầu nhân rộng các họa tiết để đáp ứng độ phân giải cao hơn. Thông báo trước cho điều này là cuối cùng bạn sẽ bắt đầu nhận thấy các họa tiết bắt đầu làm mờ dần tỷ lệ của bạn, trong trường hợp đó bạn có thể chuyển sang một nhóm các họa tiết khác được tạo cho độ phân giải cao hơn.

Hoặc, bạn có thể bỏ qua việc chia tỷ lệ hoàn toàn và chỉ quyết định hiển thị thêm màn hình trò chơi để có độ phân giải cao hơn (ví dụ, tôi tin rằng đây là cách Terraria làm điều đó). Tuy nhiên, đối với nhiều trò chơi, điều này không phù hợp; trò chơi cạnh tranh chẳng hạn.

Sử dụng các thanh màu đen trên hoặc dưới là không thể chấp nhận những ngày này.

Là nó? Rất nhiều trò chơi muốn buộc tỷ lệ khung hình 4: 3 làm điều này. Vì bạn đang sử dụng Unity, bạn có thể sử dụng tập lệnh AspectRatioEnforcer để hỗ trợ việc này.


Tôi đang nhắm mục tiêu di động, vì vậy tôi không thể thay đổi tỷ lệ khung hình hoặc độ phân giải. Sử dụng tài sản có độ phân giải thấp không phải là một giải pháp chấp nhận được. Một số trò chơi (đặc biệt là 3D) không phải là vấn đề, bạn chỉ hiển thị nhiều hơn hoặc ít hơn. Nhưng các trò chơi như Kingdom Rush, tháp phòng thủ và các trò chơi khác như Alex bạn muốn thấy điều tương tự bất kể thiết bị. Nếu mọi thứ không hiển thị ở đúng vị trí, trò chơi sẽ không hoạt động đúng.
Michael


0

Có nhiều cách để xử lý vấn đề này, nó phụ thuộc vào trò chơi của bạn và cái gì sẽ hoạt động tốt nhất. Ví dụ, trong trò chơi Tyrant Unleashed của chúng tôi, chúng tôi chỉ đơn giản tạo ra các bản đồ rộng với các chi tiết không quan trọng ở hai bên, để có thể cắt bỏ các bên trên các thiết bị hẹp hơn. Tuy nhiên, các trò chơi khác có thể tốt hơn với cách tiếp cận mà bạn thực sự thay đổi các nút xung quanh hoặc một cái gì đó để phù hợp với màn hình tốt hơn.

(cũng là một phần trong cách tiếp cận của chúng tôi cũng giữ chiều cao ổn định trên tất cả các thiết bị, chỉ thay đổi độ rộng. Điều này chắc chắn giúp chúng tôi dễ dàng hơn với cuộc sống, nhưng một lần nữa điều này có thể hoặc không tốt cho trò chơi cụ thể của bạn. phong cách nghệ thuật của chúng tôi nếu hình ảnh được thu nhỏ một chút trên các màn hình khác nhau, trong khi điều này có thể quan trọng đối với một cái gì đó như nghệ thuật pixel. Về cơ bản, đây là cách tiếp cận "hãy để Unity xử lý nó")


Bạn đã thực hiện bất kỳ dự án mà đó không phải là một lựa chọn? Hầu như tất cả các trò chơi theo phong cách phòng thủ tháp tôi đã xem và nhiều kiểu khác bạn có thể thấy toàn bộ chế độ xem trò chơi trên thiết bị mà không cần cuộn và điều này phù hợp trên các thiết bị. Trên iOS, bạn có thể tạo tài sản và trao đổi chúng, nhưng điều đó trở thành không thể (và thực sự chỉ là một PITA lớn) trên Android.
Michael

Không, tôi không có. btw Tôi vừa thêm một số chi tiết về kích thước màn hình
jhocking

0

Tôi đang sử dụng tập lệnh sau có thêm một targetAspecttham số cho máy ảnh và điều chỉnh nó orthographicSizetheo tỷ lệ màn hình (chi tiết hơn trong bài đăng trên blog này ):

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

Phương pháp của tôi gần giống với các giải pháp do người khác đưa ra :) Tôi sẽ cố gắng giải thích chi tiết cách tiếp cận mà tôi thực hiện để làm cho trò chơi độc lập với kích thước màn hình.

Định hướng màn hình

Tùy thuộc vào hướng màn hình (Phong cảnh hoặc Chân dung), bạn cần xem xét liệu máy ảnh sẽ chia tỷ lệ với chiều cao cố định hay chiều rộng cố định. Chủ yếu tôi chọn chiều rộng cố định cho các trò chơi định hướng theo chiều ngang và chiều cao cố định cho các trò chơi định hướng dọc.

Camera thu nhỏ

Như đã thảo luận, đây có thể là chiều cao cố định hoặc chiều rộng cố định.

Chiều cao cố định : Diện tích dọc của trò chơi sẽ luôn vừa với chiều cao màn hình. Và khi tỷ lệ khung hình màn hình thay đổi, sẽ có thêm không gian được thêm vào bên trái và bên phải màn hình. Để thực hiện điều này, bạn không cần mã hóa bất cứ điều gì, đó là hành vi mặc định của máy ảnh thống nhất.

Chiều rộng cố định : Diện tích ngang của trò chơi sẽ luôn vừa với chiều rộng màn hình. Và không gian thêm sẽ được thêm vào trên cùng và dưới cùng khi tỷ lệ khung hình của màn hình thay đổi. Để thực hiện điều này, bạn cần viết một đoạn mã nhỏ. Sau đó, hãy đảm bảo bạn loại bỏ chức năng cập nhật biểu mẫu mã và đặt nó ở trạng thái thức.

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

Trong trình chỉnh sửa, bạn có thể thay đổi targetWidth để xác định vùng không gian thế giới bạn muốn hiển thị. Mã này được giải thích trong video sau đây cùng với nhiều thực tiễn khác cho trò chơi 2D :)

Đoàn kết 2014 - Thực tiễn tốt nhất 2D trong đoàn kết

Tỷ lệ khung hình

Theo tỷ lệ khung hình được liệt kê từ rộng nhất đến hẹp nhất, bao gồm hầu hết tất cả các kích thước màn hình cho cả Android và iOS

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

Tôi thường đặt tất cả các tỷ lệ khung hình này theo thứ tự nhất định trong cửa sổ trò chơi, vì nó tiện dụng trong khi kiểm tra các kích thước màn hình khác nhau :)

Khu vực mong đợi

Đây là khu vực được thêm vào màn hình sang hai bên hoặc trên / dưới tùy thuộc vào tỷ lệ camera bạn đã chọn.

Đối với chiều cao cố định, tất cả các yếu tố trò chơi tốt nhất nên phù hợp với tỷ lệ 16: 9 là hẹp nhất. Và nền sẽ mở rộng cho đến khi nó bao gồm tỷ lệ 5: 4. Điều này đảm bảo rằng trò chơi của bạn không bao giờ có dải màu đen sang hai bên.

Đối với chiều rộng cố định, nó gần như giống nhau nhưng ở đây các yếu tố phải phù hợp với tỷ lệ 5: 4 và BG sẽ kéo dài đến 16: 9.

Giới hạn

Đôi khi chúng ta không thể sử dụng phương pháp tiếp cận khu vực có thể sử dụng vì chúng ta cần sử dụng toàn bộ màn hình có sẵn để chơi trò chơi.

Ví dụ, hãy xem xét một trò chơi chân dung với chiều cao cố định, bắt những đồng xu rơi từ trên trời xuống. Trong phần này, chúng ta cần cung cấp cho người chơi khả năng di chuyển theo chiều ngang trên chiều rộng màn hình có sẵn.

Do đó, chúng ta cần các giới hạn của máy ảnh theo tọa độ thế giới để biết chính xác vị trí bên trái, bên phải, trên cùng hoặc dưới cùng của các clip camera ở vị trí thế giới.
Chúng tôi cũng có thể sử dụng các giới hạn này để neo các thành phần trò chơi hoặc giao diện người dùng vào một phía mong muốn của máy ảnh.

Sử dụng Camera.ViewportToWorldPoint, chúng tôi có thể nhận được giới hạn. Không gian xem cổng được chuẩn hóa và liên quan đến máy ảnh. Phía dưới bên trái của máy ảnh là (0,0); phía trên bên phải là (1,1). Vị trí z là trong các đơn vị thế giới từ máy ảnh. Đối với 2D / orthographic, z không thành vấn đề.

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;

Giao diện người dùng

Đối với UI chúng ta có thể áp dụng các khái niệm tương tự mà chúng ta đã sử dụng cho các yếu tố trò chơi. Sau khi giới thiệu Unity5 UI và các plugin như NGUI, điều này sẽ không có vấn đề gì :)


0

Tôi đã tạo Tài sản Unity 'Độ phân giải 2D' để giải quyết vấn đề này (quảng cáo: bạn có thể lấy nó từ Cửa hàng Tài sản Unity hoặc xem thêm chi tiết tại grogansoft.com).

Cách tôi giải quyết vấn đề như sau ...

Xác định một khu vực của màn hình phải luôn hiển thị bất kể tỷ lệ / độ phân giải của khung hình và sử dụng một biến đổi hình chữ nhật đơn giản để 'stprint out' vùng này. Đây là hình dạng màn hình lý tưởng của bạn. Sau đó, sử dụng thuật toán đơn giản, tôi phóng to camera cho đến khi vùng bị chặn bởi hình chữ nhật càng lớn càng tốt trong khi máy ảnh vẫn hiển thị 100%.

Sau đó, khu vực trò chơi chính của bạn luôn chiếm nhiều màn hình nhất có thể. Và miễn là có đủ nội dung 'phụ' (ví dụ: nền của bạn) bên ngoài khu vực hình chữ nhật bạn đã xác định trước đó, người chơi có màn hình không cùng tỷ lệ với hình chữ nhật 'lý tưởng' của bạn sẽ thấy nội dung bổ sung trong đó các thanh màu đen sẽ khác đi.

Tài sản của tôi cũng bao gồm một số logic để đặt UI, nhưng điều đó chủ yếu là lỗi thời do hệ thống UI mới của Unity.

Tài sản của tôi cung cấp điều này ra khỏi hộp với thiết lập tối thiểu và nó hoạt động thực sự tốt trên tất cả các nền tảng.

Nếu bạn sử dụng kỹ thuật này (hoặc tài sản của tôi), chỉ cần đảm bảo rằng bạn thiết kế trò chơi của mình để có không gian 'tùy chọn' xung quanh để phù hợp với màn hình rộng hơn hoặc cao hơn lý tưởng của bạn (để tránh các thanh màu đen).

Cá nhân tôi không tạo ra các trò chơi 3D, vì vậy tôi không biết liệu trò chơi này có hoạt động ở chế độ 3D không (hoặc thậm chí nếu cần thiết).

Thật khó để giải thích nếu không có hình ảnh, vì vậy vui lòng truy cập trang web của tôi ( Độ phân giải Magic 2D )


0

Giải pháp tốt nhất cho tôi là sử dụng định lý các đường giao nhau để không bị cắt ở hai bên cũng như không bị biến dạng của chế độ xem trò chơi. Điều đó có nghĩa là bạn phải lùi lại hoặc chuyển tiếp tùy thuộc vào tỷ lệ khung hình khác nhau.


-3

Tôi đã tạo một tiện ích mở rộng AssetStore cho phép chuyển đổi khía cạnh dễ dàng hơn được gọi là AspectSwitcher . Nó cung cấp một hệ thống cho phép bạn dễ dàng chỉ định các thuộc tính khác nhau cho các khía cạnh khác nhau. Nhìn chung có hai phương pháp mà hầu hết mọi người sử dụng để chuyển đổi các khía cạnh. Một là cung cấp các đối tượng trò chơi khác nhau cho từng khía cạnh. Hai là để tạo mã tùy chỉnh sửa đổi các thuộc tính của một đối tượng trò chơi duy nhất dựa trên khía cạnh hiện tại. Điều đó thường đòi hỏi rất nhiều mã hóa tùy chỉnh. Phần mở rộng của tôi cố gắng giảm bớt rất nhiều nỗi đau đó.


2
Câu trả lời này sẽ tốt hơn và có vẻ ít spam hơn, nếu bạn xây dựng các kỹ thuật thực tế mà người ta có thể sử dụng để giải quyết câu hỏi của OP.
Josh
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.