คุณจะจัดการกับความแตกต่างของอัตราส่วนด้วย Unity 2D ได้อย่างไร


67

ฉันได้รับคำตอบมากมายสำหรับคำถามนี้ แต่มันเป็นคำทั่วไปและโดยทั่วไปไม่ค่อยมีประโยชน์ ไม่มีบทเรียนใด ๆ ที่พูดถึงอัตราส่วนภาพและการจัดการกับอุปกรณ์มือถือและมีวิธีการหนึ่งล้านที่ทำได้ทุกคนดูเหมือนจะมี gotcha และข้อบกพร่อง

ฉันชอบที่จะรู้ว่าเกมที่ประสบความสำเร็จได้ใช้เพื่อจัดการอัตราส่วนกว้างยาวที่แตกต่างกันใน iOS และ Android โดยไม่ต้องสร้างสินทรัพย์ขนาดแตกต่างกัน zillion

ฉันกำลังพูดอย่างมือถือไม่ใช่บนเดสก์ท็อปโดยเฉพาะกับ Unity และฉันไม่สนใจ UI ฉันเพียง แต่ใส่ใจเกี่ยวกับเกมเพลย์

ปัญหาที่ฉันมีอยู่ในใจคือเมื่อมีสิ่งสำคัญที่ต้องอยู่ในบางสถานที่และไม่สามารถหลุดออกจากหน้าจอได้ วันนี้การใช้แถบสีดำที่ด้านบนหรือด้านล่างเป็นที่ยอมรับไม่ได้


3
คำถามนี้กว้างมากเนื่องจากวิธีที่ถูกต้องขึ้นอยู่กับเกือบทุกอย่าง คุณลองทำอะไร ทำไมมันไม่ทำงาน
Anko

3
ฉันลองทุกสิ่งฉันพยายามปรับขนาดกล้อง ortho ฉันพยายามแนบ sprite ทั้งหมดเพื่อแสดงรายการและปรับอัตราส่วนตามความแตกต่างของสัดส่วนภาพการตั้งค่าขนาด ortho เป็น screen.height / 2/100 ความคิด งานบางอย่าง แต่ทั้งหมดมีปัญหา ฉันรู้ว่าเกมที่แตกต่างกันจัดการกับมันแตกต่างกัน แต่ไม่มีการอภิปรายในหัวข้อนี้อย่างแน่นอนและมันก็ไม่ง่ายเหมือน "เพียงแค่ให้เอกภาพจัดการกับมัน" เป็นข้อเรียกร้องมากมาย
ไมเคิล

1
ดังนั้นทำไมพวกเขาไม่ทำงาน คำตอบที่ดีจะมีหน้าตาเป็นอย่างไร? (โดยวิธีการที่คุณสามารถแก้ไขคำถามเพื่อชี้แจงเช่นกัน)
Anko

7
บางคนบิดเบือนภาพบางคนไม่เข้าแถวกัน ปัญหาที่แตกต่างกันมากมาย แต่ 65% ของเกมที่พัฒนาโดย Unity นั้นเป็นแบบ 2 มิติและทำให้มันใช้งานได้ ฉันแค่อยากรู้ว่าผู้คนใช้อะไรและไม่ต้องพลิกโฉมพวงมาลัย ไม่มีใครพูดถึงมันและไม่มีไกด์หรือเอกสารเกี่ยวกับวิธีจัดการกับมัน แต่คุณไม่สามารถไปไกลได้ในโครงการมือถือหากไม่มีระบบในการดำเนินการ
ไมเคิล

1
"ปัญหาที่ฉันมีอยู่ในใจคือเมื่อมีสิ่งสำคัญที่ต้องอยู่ในบางสถานที่และไม่สามารถหลุดออกจากหน้าจอได้การใช้แถบสีดำที่ด้านบนหรือด้านล่างนั้นเป็นสิ่งที่ยอมรับไม่ได้ในทุกวันนี้" รับประกันองค์ประกอบไม่ตกหน้าจอไม่มีการบิดเบือน แต่ไม่มีตัวอักษร / เสาหลักมวย (แถบสีดำและไม่ชอบ) ข้อกำหนดเหล่านี้ไม่สามารถยกเลิกได้ ความต้องการขั้นสุดท้ายน่าจะมีความสำคัญน้อยที่สุดหรือสามารถซ่อนได้โดยการซ้อนทับผืนผ้าใบเกินกว่าที่จะต้องปรากฏบนหน้าจอ เกมส่วนใหญ่ที่ฉันเคยเห็นด้วยข้อกำหนดที่เข้มงวดดังกล่าวจะได้รับการตกแต่งเสา / ช่อง
Jibb Smart

คำตอบ:


36

สิ่งที่คุณต้องการคือ จำกัด วิวพอร์ตของกล้องในแนวตั้งหรือแนวนอน (ขึ้นอยู่กับความต้องการของคุณ) โดยการคำนวณcamera.orthographicSizeคุณสมบัติเพื่อให้คุณสามารถสร้างฉาก 2 มิติของคุณโดยไม่คำนึงถึงอัตราส่วนและความละเอียด:

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

หากคุณต้องการข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้โปรดถามและฉันจะตอบกลับ ;) ขอแสดงความนับถือและเชียร์

อัปเดต:ใช้สคริปต์ยึดวัตถุของ Eliot Lashร่วมกับวัตถุนี้เพื่อวางวัตถุไว้ที่ตำแหน่งสำคัญบนหน้าจอหากจำเป็น (สัมพันธ์กับมุม / เส้นขอบของหน้าจอ) หากเป็นเช่นนั้นให้เปลี่ยนชื่อ "CameraFit" เป็น "ViewportHandler"

ดูตัวอย่างการจำลองหน้าจออัตราส่วนภาพต่างๆ: ป้อนคำอธิบายรูปภาพที่นี่


4
@Eliot เพิ่มสิทธิ์การใช้งาน MIT ด้านบน ขอให้โชคดีกับโครงการของคุณ!
androidu

7
เยี่ยมมากขอบคุณ! สิ่งหนึ่งที่สมควรได้รับอีกสิ่งหนึ่งดังนั้นนี่คือองค์ประกอบโอเพนซอร์ซฉันเพิ่งเขียนการยึด GameObjects อย่างง่าย ๆ ไปยังจุดผู้ช่วยที่กำหนดโดยสคริปต์ของคุณ: gist.github.com/fadookie/256947788c364400abe1
Eliot

1
MarcelCăşvanสคริปต์ที่ดีมาก! ฉันเพิ่ม enum สำหรับการเลือกหากคุณต้องการกำหนดขนาดของหน่วยสำหรับ potrait สำหรับแนวนอน (ความสูง / ความกว้าง) เพิ่งต้องเพิ่มสองสามบรรทัดในสคริปต์และฉันใช้GetComponent<Camera>().orthographicSize = UnitSize / 2f;สำหรับ potrait / การกำหนดหน่วยความสูง
am_

2
@ MarcelCăşvanสิ่งที่ยอดเยี่ยม! ขอบคุณ ฉันเห็นว่าตัวแปร deviceWidth และ deviceHeight จาก ComputeFunction () ไม่ได้ใช้งาน อาจลองลบสิ่งเหล่านี้
user2313267

1
CameraAnchor กำลังโยนข้อผิดพลาด: "CameraFit ไม่ได้ถูกกำหนดในบริบทนี้" - ในกรณีที่มีคนอื่นพบคำตอบนี้ในภายหลังดูเหมือนว่า "CameraFit" เพิ่งเปลี่ยนชื่อเป็น "ViewportHandler" ตั้งแต่เริ่มโพสต์ครั้งแรก ถ้าคุณเพิ่งเปลี่ยนชื่อชั้นจาก ViewportHandler กลับไปที่ CameraFit
Lenny

5

โดยทั่วไปคุณไม่ต้องการสินทรัพย์ที่มีขนาดแตกต่างกัน - พื้นผิวและสไปรต์ที่นำเข้าพร้อมกับแผนที่ mip ที่สร้างขึ้นโดยอัตโนมัติจะดูดีเมื่อแสดงผลที่ขนาดใด ๆ ที่น้อยกว่าหรือเท่ากับขนาดพิกเซลดั้งเดิมของภาพ

เลย์เอาต์ฉากคือความท้าทาย วิธีการที่ดีวิธีหนึ่งมีดังต่อไปนี้ (และ FYI ฉันใช้กล้อง 3D ดูเนื้อหา 2 มิติที่ตำแหน่ง z = 0):

  1. ตัดสินใจเองในเรื่องขนาดการแสดงผล "ตรรกะ" ขั้นต่ำในพิกเซลหรือไทล์ สิ่งนี้ไม่จำเป็นต้องสอดคล้องกับความละเอียดในโลกแห่งความเป็นจริงใด ๆ แต่ควรสะท้อนอัตราส่วนที่แคบที่สุด / สั้นที่สุดที่คุณต้องการให้การสนับสนุน ตัวอย่างเช่นสำหรับเกมแนวนอนฉันจะไม่เลือก 480x320 เพราะนั่นเป็นอัตราส่วนกว้างกว่า iPad ดังนั้นฉันอาจเลือก 1024x768 - หรือแม้กระทั่ง 480x360 ซึ่งให้ระบบพิกัดขนาด iPhone ดั้งเดิมให้ฉันใช้งานและอัตราส่วนเดียวกันกับ iPad ทุกเครื่อง (รวมถึง iPad Air 2 เป็นต้น) นอกจากนี้โปรดทราบว่าคุณสามารถทำงานได้อย่างง่ายดายในพิกัดไทล์แทนพิกัดพิกเซลเช่น 15x11.25
  2. ตั้งโปรแกรมลอจิกเกมของคุณเพื่อให้ทุกอย่างที่สำคัญคือ (หรือสามารถ) อยู่ในขนาดจอแสดงผลขั้นต่ำของคุณ แต่เตรียมที่จะเติมห้องพิเศษด้านข้างด้วยเนื้อหาเพิ่มเติมแม้ว่ามันจะเป็นเพียงแค่ฟิลเลอร์ตกแต่ง
  3. กำหนดจำนวนเงินที่คุณต้องการในการปรับขนาดเนื้อหาของคุณเพื่อให้ความกว้างหรือความสูงตรงกับค่าต่ำสุดและแกนอื่น ๆ มีขนาดใหญ่กว่าหรือเท่ากับค่าต่ำสุดที่ต้องการ ในการทำเช่นนี้ "ปรับขนาดให้พอดี" ให้แบ่งขนาดพิกเซลของหน้าจอตามขนาดการแสดงผลขั้นต่ำและใช้ค่าขนาดสเกลที่เล็กลงให้เป็นสเกลมุมมองโดยรวมของคุณ
  4. ใช้มาตราส่วนมุมมองเพื่อคำนวณขนาดการแสดงผลที่แท้จริง (จริง) เพื่อวัตถุประสงค์ในเกมตรรกะ
  5. ปรับขนาดเนื้อหาของคุณโดยเลื่อนกล้องไปตามแกน Z

ในรูปแบบรหัส:

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

หากคุณมาใช้บาร์มันค่อนข้างง่ายที่จะติดตั้ง (ฉันโพสต์สิ่งนี้ถึงแม้ว่า OP จะระบุความเห็นว่ามันเป็นที่ยอมรับไม่ได้เพราะมันมีประโยชน์ในการไม่อยู่ใกล้กับมือถือที่ไม่ดี ไม่ต้องใช้รหัสใด ๆ )

Camera.orthographicSizeเป็นตัวแปรภายในกล้องออร์โธ (ซึ่งเกมส่วนใหญ่ใช้ 2D) ที่เหมาะกับจำนวนเงินที่วัดของหน่วยงานเกมแนวตั้งบนหน้าจอ ( หารด้วย 2 ) ( แหล่งที่มา ) ดังนั้นเลือกอัตราส่วนภาพที่เหมาะกับอุปกรณ์ส่วนใหญ่ (ฉันเลือก 16: 9 เนื่องจากหน้าจอส่วนใหญ่ที่ฉันวิจัยคือ 16: 9, 16:10, 3: 2) และเพิ่มหน้ากากที่ซ้อนทับในอัตราส่วน

ตัวอย่าง :

ในเกมของฉัน (ไม่ได้อยู่ที่นี่เนื่องจากไม่ใช่โฆษณาสามารถถามความคิดเห็นได้หากต้องการ) เราใช้โหมดแนวตั้ง วิธีง่ายๆในการทำ 16: 9 ฉันทำกล้อง Ortho ของฉันให้มีขนาด 16 ซึ่งหมายความว่ากล้องจะปรับความสูงของเกม 32 หน่วย (y: 16 ถึง -16 ในกรณีของฉัน) ลงในแนวตั้งของอุปกรณ์

ฉันวางหน้ากากสีดำกับเกมระหว่าง -9 ถึง +9 Voila หน้าจอของเกมมีลักษณะเหมือนกันทุกอุปกรณ์และมีขนาดเล็กกว่าบนอุปกรณ์ที่กว้างกว่าเล็กน้อย ฉันไม่มีความคิดเห็นเชิงลบเกี่ยวกับหน้ากาก ในการทำแนวนอนให้พลิกค่าเหล่านั้นจากนั้นคุณจะทำให้กล้องมีขนาด 9 เปลี่ยนค่าเพื่อให้ตรงกับสิ่งที่คุณตัดสินใจคือระดับหน่วยเกมของคุณ

สถานที่เดียวที่เราสังเกตเห็นแถบสีดำเพื่อแสดงอย่างชัดเจนคือบน iPad ที่ 3: 2 ถึงอย่างนั้นฉันก็ไม่มีข้อร้องเรียน


1

ฉันกำลังทำสิ่งนี้ในเกมที่ฉันกำลังทำอยู่ ฉันมีภาพพื้นหลังที่มีขนาด 1140x720 บิตที่สำคัญที่สุด (บิตที่ไม่ควรถูกครอบตัด) มีอยู่ในพื้นที่ส่วนกลาง 960x640 ฉันเรียกใช้รหัสนี้ในฟังก์ชั่นเริ่มต้นของกล้องของฉัน:

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

ฉันยังกำหนดขนาดอื่นนอกเหนือจากขนาดแบบอักษรสำหรับปุ่มและเช่นนั้น มันทำงานได้ดีในทุกอัตราส่วนที่ฉันทดสอบ ไม่นานมานี้ตั้งแต่ฉันตั้งค่าดังนั้นฉันอาจพลาดขั้นตอน แจ้งให้เราทราบว่ามันใช้งานไม่ได้ตามที่คาดหวังหรือไม่และฉันจะดูว่ายังมีอะไรเหลืออีกหรือไม่


1

@ คำตอบและรหัสของ Marcel นั้นยอดเยี่ยมและช่วยให้ฉันเข้าใจว่าเกิดอะไรขึ้น มันเป็นคำตอบที่ชัดเจน แค่คิดว่าบางคนอาจมีประโยชน์กับสิ่งที่ฉันทำลงไปในกรณีเฉพาะของฉัน: เนื่องจากฉันต้องการบางสิ่งที่ง่ายจริงๆสไปรท์หนึ่งอยู่บนหน้าจอตลอดเวลาฉันจึงขึ้นมาด้วยสองสามบรรทัดนี้:

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

ฉันเพิ่มสิ่งนี้ลงในกล้องและลากสไปรต์ของฉัน (เป็นพื้นหลังของฉัน) ไปยังคุณสมบัติเดียวของสคริปต์ หากคุณไม่ต้องการแถบสีดำ (แนวนอนหรือแนวตั้ง) คุณสามารถวางพื้นหลังที่ใหญ่กว่าไว้ข้างหลัง ...


0

มีสองสามวิธีในการแก้ไขปัญหานี้และยังไม่มีวิธีแก้ปัญหาที่สมบูรณ์แบบ (อย่างน้อยฉันยังไม่พบ) และประเภทของโซลูชันที่คุณไปด้วยจะขึ้นอยู่กับประเภทของเกมที่คุณใช้ ที่กำลังพัฒนา

ไม่ว่าคุณจะทำอะไรคุณควรเริ่มต้นด้วยการเลือกความละเอียดต่ำสุดที่คุณต้องการสนับสนุนและสร้างสไปรต์ของคุณตามความละเอียดนั้น ดังนั้นหากคุณสนใจที่จะพัฒนาสำหรับ iOS อ้างอิงจากhttp://www.iosres.com/ความละเอียดต่ำสุดของอุปกรณ์ iOS คือ 480x320

จากตรงนั้นคุณสามารถเริ่มปรับสไปรต์เพื่อให้ได้ความละเอียดที่สูงขึ้น ข้อแม้เกี่ยวกับเรื่องนี้คือในที่สุดคุณจะเริ่มสังเกตเห็นว่าสไปรต์เริ่มทำให้เบลอยิ่งมากขึ้นในกรณีนี้คุณสามารถสลับไปที่ชุดสไปรต์อื่นที่สร้างขึ้นเพื่อความละเอียดที่สูงขึ้น

หรือคุณสามารถละเว้นการปรับขนาดได้อย่างสมบูรณ์และเพียงตัดสินใจที่จะแสดงหน้าจอเกมมากขึ้นสำหรับความละเอียดที่สูงขึ้น (ฉันเชื่อว่านี่เป็นวิธีที่ Terraria ทำเช่นนั้น) อย่างไรก็ตามสำหรับหลาย ๆ เกมสิ่งนี้ไม่เหมาะสม เกมการแข่งขันเช่น

วันนี้การใช้แถบสีดำที่ด้านบนหรือด้านล่างเป็นที่ยอมรับไม่ได้

ใช่ไหม? เกมจำนวนมากที่ต้องการบังคับอัตราส่วนภาพ 4: 3 ให้ทำเช่นนี้ เมื่อคุณใช้ Unity คุณสามารถใช้สคริปต์AspectRatioEnforcerเพื่อช่วยในเรื่องนี้


ฉันกำหนดเป้าหมายอุปกรณ์พกพาดังนั้นฉันไม่สามารถเปลี่ยนอัตราส่วนหรือความละเอียดได้ การใช้สินทรัพย์ที่มีความละเอียดต่ำไม่ใช่วิธีแก้ปัญหาที่ยอมรับได้ เกมบางเกม (โดยเฉพาะ 3D) มันไม่ใช่ปัญหาคุณเพียงแค่แสดงมากหรือน้อย แต่เกมอย่าง Kingdom Rush, Tower Defense และเกมอื่น ๆ เช่น Alex ที่คุณต้องการเห็นในสิ่งเดียวกันโดยไม่คำนึงถึงอุปกรณ์ หากสิ่งต่าง ๆ ไม่ปรากฏขึ้นในตำแหน่งที่ถูกต้องเกมจะไม่ทำงานอย่างถูกต้อง
Michael


0

มีหลายวิธีในการจัดการกับปัญหานี้ขึ้นอยู่กับเกมของคุณและสิ่งที่จะทำงานได้ดีที่สุด ตัวอย่างเช่นในเกมของเราTyrant Unleashedเราเพียงสร้างแผนที่กว้างโดยมีรายละเอียดที่ไม่สำคัญอยู่ด้านข้างเพื่อที่จะสามารถตัดด้านข้างออกจากอุปกรณ์ที่แคบกว่าได้ อย่างไรก็ตามเกมอื่น ๆ อาจดีกว่าด้วยวิธีการที่คุณเลื่อนปุ่มไปรอบ ๆ หรือบางสิ่งบางอย่างเพื่อให้พอดีกับหน้าจอที่ดีขึ้น

(ส่วนหนึ่งของวิธีการของเราก็คือการรักษาความสูงที่สอดคล้องกันในทุกอุปกรณ์เพียงแค่เปลี่ยนความกว้างเท่านั้นสิ่งนี้ทำให้ชีวิตเราง่ายขึ้น แต่อีกครั้งสิ่งนี้อาจจะใช่หรือไม่ใช่สิ่งที่ดีสำหรับเกมของคุณโดยเฉพาะ สไตล์ศิลปะของเราถ้าภาพถูกปรับขนาดเล็กน้อยบนหน้าจอที่แตกต่างกันในขณะที่สิ่งนี้อาจมีความสำคัญกับสิ่งที่คล้ายกับศิลปะพิกเซลโดยทั่วไปนี่คือวิธี "ให้ Unity จัดการกับมัน")


คุณเคยทำโครงการที่ไม่มีตัวเลือกหรือไม่? เกมสไตล์ป้องกันหอคอยเกือบทั้งหมดที่ฉันเคยเห็นและสไตล์อื่น ๆ อีกมากมายที่คุณสามารถมองเห็นได้ทั้งเกมบนอุปกรณ์โดยไม่ต้องเลื่อนและสิ่งนี้สอดคล้องกันในทุกอุปกรณ์ บน IOS คุณสามารถสร้างสินทรัพย์และแลกเปลี่ยนได้ แต่มันกลายเป็นไปไม่ได้ (และเป็นเพียง PITA ขนาดใหญ่) บน Android
Michael

ไม่ฉันยังไม่ได้ btw ฉันเพิ่งเพิ่มรายละเอียดเพิ่มเติมเกี่ยวกับขนาดหน้าจอ
jhocking

0

ฉันใช้สคริปต์ต่อไปนี้ซึ่งเพิ่มtargetAspectพารามิเตอร์ให้กับกล้องและปรับให้เข้าorthographicSizeกับอัตราส่วนหน้าจอ (รายละเอียดเพิ่มเติมในโพสต์บล็อกนี้ ):

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

วิธีการของฉันส่วนใหญ่จะคล้ายกับวิธีแก้ปัญหาที่ผู้อื่นให้ :) ฉันจะพยายามอธิบายรายละเอียดเกี่ยวกับวิธีการที่ฉันใช้เพื่อทำให้เกมเป็นอิสระจากขนาดหน้าจอ

การวางแนวหน้าจอ

ขึ้นอยู่กับการวางแนวหน้าจอ (แนวนอนหรือแนวตั้ง) คุณต้องพิจารณาว่ากล้องจะปรับขนาดด้วยความสูงคงที่หรือความกว้างคงที่หรือไม่ ส่วนใหญ่ฉันเลือกความกว้างคงที่สำหรับเกมแนวนอนและความสูงคงที่สำหรับเกมแนวตั้ง

การปรับขนาดกล้อง

ตามที่กล่าวไว้นี้อาจเป็นความสูงคงที่หรือความกว้างคงที่

ความสูงคงที่ : พื้นที่แนวตั้งของเกมจะพอดีกับความสูงของหน้าจอ และเมื่อการเปลี่ยนแปลงอัตราส่วนหน้าจอจะมีการเพิ่มพื้นที่พิเศษทางด้านซ้ายและขวาของหน้าจอ ในการใช้สิ่งนี้คุณไม่จำเป็นต้องใช้รหัสอะไรเลยมันเป็นพฤติกรรมเริ่มต้นของกล้องเอกภาพ

ความกว้างคงที่ : พื้นที่แนวนอนของเกมจะพอดีกับความกว้างของหน้าจอเสมอ และจะมีการเพิ่มพื้นที่พิเศษที่ด้านบนและด้านล่างเมื่ออัตราส่วนภาพของหน้าจอเปลี่ยนไป ในการดำเนินการนี้คุณต้องเขียนโค้ดขนาดเล็ก ในภายหลังให้แน่ใจว่าคุณลบฟังก์ชั่นการอัพเดทฟอร์มโค้ดและวางไว้ในโหมดตื่น

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

ในโปรแกรมแก้ไขคุณสามารถเปลี่ยน targetWidth เพื่อกำหนดพื้นที่โลกที่คุณต้องการแสดง รหัสนี้มีการอธิบายในวิดีโอต่อไปนี้พร้อมกับแนวทางปฏิบัติอื่น ๆ อีกมากมายสำหรับเกม 2D :)

Unite 2014 - แนวทางปฏิบัติ 2 มิติที่ดีที่สุดในความสามัคคี

อัตราส่วนภาพ

อัตราส่วนภาพต่อไปนี้แสดงจากที่กว้างที่สุดถึงแคบที่สุดครอบคลุมขนาดหน้าจอเกือบทั้งหมดสำหรับทั้ง Android และ iOS

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

ฉันมักจะตั้งค่าอัตราส่วนภาพทั้งหมดเหล่านี้ตามลำดับที่กำหนดภายใต้หน้าต่างเกมเนื่องจากสะดวกในขณะทดสอบขนาดหน้าจอที่แตกต่างกัน :)

พื้นที่ที่สามารถใช้ได้

นี่คือพื้นที่ที่เพิ่มลงในหน้าจอไปทางด้านข้างหรือด้านบน / ล่างขึ้นอยู่กับการปรับขนาดกล้องที่คุณเลือก

สำหรับความสูงคงที่องค์ประกอบของเกมทั้งหมดควรจะพอดีกับอัตราส่วน 16: 9 ซึ่งแคบที่สุด และพื้นหลังควรขยายจนครอบคลุมอัตราส่วน 5: 4 ซึ่งทำให้แน่ใจได้ว่าเกมของคุณจะไม่มีแถบสีดำด้านข้าง

สำหรับความกว้างคงที่มันเกือบจะเหมือนกัน แต่ที่นี่องค์ประกอบควรมีอัตราส่วน 5: 4 และ BG ควรขยายจนถึง 16: 9

ขอบเขต

บางครั้งเราไม่สามารถใช้วิธีการใช้พื้นที่ได้เนื่องจากเราจำเป็นต้องใช้หน้าจอทั้งหมดที่มีสำหรับการเล่นเกม

ตัวอย่างเช่นพิจารณาเกมแนวตั้งที่มีความสูงคงที่จับเหรียญที่ตกลงมาจากท้องฟ้า ในเรื่องนี้เราต้องให้ความสามารถของผู้เล่นในการเลื่อนในแนวนอนเหนือความกว้างของหน้าจอที่มีอยู่

ดังนั้นเราจึงต้องการขอบเขตของกล้องในแง่ของพิกัดโลกเพื่อที่จะรู้ว่าคลิปซ้าย, ขวา, บนหรือล่างของตำแหน่งกล้องอยู่ที่ตำแหน่งใดของโลก
นอกจากนี้เรายังสามารถใช้ขอบเขตเหล่านี้เพื่อยึดองค์ประกอบเกมหรือ UI ไปยังด้านที่ต้องการของกล้อง

การใช้ Camera.ViewportToWorldPoint เราสามารถรับขอบเขตพื้นที่การแสดงผลได้ถูกทำให้เป็นมาตรฐานและสัมพันธ์กับกล้อง ด้านล่างซ้ายของกล้องคือ (0,0); ด้านบนขวาคือ (1,1) ตำแหน่ง z อยู่ในหน่วยโลกจากกล้อง สำหรับ 2D / orthographic z ไม่สำคัญ

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

สำหรับ UI เราสามารถใช้แนวคิดเดียวกันกับที่เราใช้สำหรับองค์ประกอบเกม หลังจากแนะนำ Unity5 UI และความพร้อมใช้งานของปลั๊กอินเช่น NGUI สิ่งนี้จะไม่เป็นปัญหามาก :)


0

ฉันสร้าง Unity Asset 'Resolution Magic 2D' เพื่อแก้ปัญหานี้ (โฆษณา: คุณสามารถหาได้จาก Unity Asset Store หรือดูรายละเอียดเพิ่มเติมได้ที่ grogansoft.com)

วิธีที่ฉันจัดการกับปัญหามีดังนี้ ...

กำหนดพื้นที่ของหน้าจอที่จะต้องมองเห็นได้ตลอดเวลาโดยไม่คำนึงถึงอัตราส่วน / ความละเอียดและใช้การแปลงรูปสี่เหลี่ยมผืนผ้าอย่างง่าย ๆ นี่คือรูปร่างหน้าจอในอุดมคติของคุณ ใช้อัลกอริทึมอย่างง่ายจากนั้นฉันซูมกล้องจนพื้นที่ถูกบล็อกโดยสี่เหลี่ยมมีขนาดใหญ่ที่สุดเท่าที่จะเป็นไปได้ในขณะที่กล้องยังคงมองเห็นได้ 100%

จากนั้นพื้นที่เกมหลักของคุณจะจับภาพหน้าจอให้มากที่สุด และตราบใดที่มีเนื้อหา 'พิเศษ' เพียงพอ (เช่นพื้นหลังของคุณ) นอกพื้นที่สี่เหลี่ยมผืนผ้าที่คุณกำหนดไว้ก่อนผู้เล่นที่มีหน้าจอไม่อัตราส่วนเดียวกันกับสี่เหลี่ยมผืนผ้า 'อุดมคติ' ของคุณจะเห็นเนื้อหาพิเศษที่แถบสีดำจะเป็นอย่างอื่น ไป.

เนื้อหาของฉันยังมีตรรกะบางอย่างสำหรับการวาง UI แต่ส่วนใหญ่ล้าสมัยเนื่องจากระบบ UI ใหม่ของ Unity

เนื้อหาของฉันนำเสนอการตั้งค่าที่น้อยที่สุดและใช้งานได้ดีกับทุกแพลตฟอร์ม

หากคุณใช้เทคนิคนี้ (หรือทรัพย์สินของฉัน) เพียงแค่ให้แน่ใจว่าคุณออกแบบเกมของคุณให้มีพื้นที่ 'ไม่จำเป็น' รอบตัวเพื่อรองรับหน้าจอที่กว้างกว่าหรือสูงกว่าอุดมคติของคุณ (เพื่อหลีกเลี่ยงแถบสีดำ)

ฉันไม่ได้สร้างเกม 3 มิติเป็นการส่วนตัวดังนั้นฉันไม่รู้ว่าจะใช้งานได้ในรูปแบบ 3 มิติ (หรือถ้าจำเป็น)

มันยากที่จะอธิบายโดยไม่มีภาพดังนั้นโปรดเยี่ยมชมเว็บไซต์ของฉัน ( Resolution Magic 2D )


0

ทางออกที่ดีที่สุดสำหรับฉันคือการใช้ทฤษฎีบทของการตัดกันเส้นเพื่อไม่ให้ถูกตัดออกด้านข้างหรือบิดเบือนมุมมองของเกม นั่นหมายความว่าคุณต้องถอยกลับหรือส่งต่อทั้งนี้ขึ้นอยู่กับอัตราส่วนภาพที่แตกต่าง


-3

ฉันสร้างส่วนขยาย AssetStore ที่ช่วยให้ง่ายขึ้นด้านสลับเรียกAspectSwitcher มันมีระบบที่ช่วยให้คุณสามารถระบุคุณสมบัติที่แตกต่างกันสำหรับแง่มุมที่แตกต่างกันได้อย่างง่ายดาย โดยทั่วไปมีสองวิธีที่คนส่วนใหญ่ใช้เพื่อเปลี่ยนมุมมอง หนึ่งคือการให้วัตถุเกมที่แตกต่างกันสำหรับแต่ละด้าน อื่น ๆ คือการสร้างรหัสที่กำหนดเองที่ปรับเปลี่ยนคุณสมบัติของวัตถุเกมเดียวตามแง่มุมปัจจุบัน โดยทั่วไปต้องใช้การเข้ารหัสที่กำหนดเองจำนวนมาก ส่วนขยายของฉันพยายามบรรเทาความเจ็บปวดนั้นมากมาย


2
คำตอบนี้จะดีขึ้นและดูเป็นสแปมน้อยลงหากคุณได้อธิบายรายละเอียดเกี่ยวกับเทคนิคจริงที่อาจใช้เพื่อตอบคำถามของ OP
Josh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.