支持Unity中的多个宽高比

时间:2014-10-06 06:18:29

标签: android ios unity3d 2d aspect-ratio

我一直在努力创建一个Unity 2D游戏,支持Android和平板电脑的各种设备宽高比。有没有办法这样做是由Unity提供或推荐的?

6 个答案:

答案 0 :(得分:1)

有一些事情应该考虑。首先是应该允许哪些元素扩展?有两个类别,即UI和游戏元素。

游戏元素部分可能意味着很多事情。如果游戏空间有限,则关键通常是包括“负空间”的大部分,或者图像中不显着影响游戏的部分。例如,可以从左侧和右侧裁剪下面的图像而不会显着影响图像。将图像的中心部分作为关键元素或一侧。

enter image description here

也可以拉伸元素,尽管这可能会导致不良影响。拥有多余的图像并使用不同的方面配给进行测试是此类背景元素的最佳选择。这些背景元素可以放置在背景中,画布设置为“按屏幕缩放比例”,并将“屏幕匹配模式”设置为最适合您图像的效果。有关详细信息,请参阅“Canvas Scaler”。

至于其他UI元素,关键是使用锚点。放置时,您可以告诉UI元素采用多个像素,或填充屏幕的一部分。查看每个此类UI对象中包含的“Rect Transform”组件。您也可以在屏幕上调整这些。

最后,您可以通过编程方式执行此操作。存在Screen.heightScreen.width。您可以在运行时根据需要调整对象以使其工作。我建议你不要为所有事情做这件事,但在某些情况下可能有所帮助。

答案 1 :(得分:0)

在我的情况下,我的工作是将其全部创建为比例

所以,无论屏幕是什么都可以支持

//Find Screen resolution at the splash or loading screen
    float scalex = DataFactory.SCREEN_WIDTH / (float)DataFactory.OUR_FIXED_GAME_SCREEN;
    float scaley = DataFactory.SCREEN_HEIGHT / (float)DataFactory.OUR_FIXED_GAME_SCREEN;
    if (scalex >= scaley)
        DataFactory.SCALE = scalex;
    else 
        DataFactory.SCALE = scaley;

//Set all size in game at the start
private int gameWidth = (int) (1400 * DataFactory.SCALE);
private int gameHeight = (int) (800 * DataFactory.SCALE);


private int startGameX = (int) (300 * DataFactory.SCALE);
private int startGameY = (int) (280 * DataFactory.SCALE);

private int objectX = (int) (410  * DataFactory.SCALE) + DataFactory.BEGIN_X;
private int objectY = (int) (979 * DataFactory.SCALE) + DataFactory.BEGIN_Y;

private int objectGapX = (int) (400 * DataFactory.SCALE);
private int objectGapY = (int) (180 * DataFactory.SCALE);
private int objectWidth = (int) (560 * DataFactory.SCALE);
private int objectHeight = (int) (400 * DataFactory.SCALE);


private int xRing = (int) (1005 * DataFactory.SCALE) +  DataFactory.BEGIN_X;
private int yRing = (int) (1020 * DataFactory.SCALE) + DataFactory.BEGIN_Y;
private int radiusOutside = (int) (740 * DataFactory.SCALE);
private int radiusInside = (int) (480 * DataFactory.SCALE);
private int radiusObject = (int) (600 * DataFactory.SCALE);
private int yObjectRing = (int) (920 * DataFactory.SCALE) + DataFactory.BEGIN_Y;

*所有固定价值都是我在单一屏幕上创建的价值*

这是我制作的3D游戏的一些示例,但是,我仍然在GUI部分使用相同的概念

enter image description here

这是我使用这个概念的2D游戏的一些样本

enter image description here

enter image description here

答案 2 :(得分:0)

我知道这是一个老帖子,想为此展示一个替代方案。您可以尝试定义要扩展游戏的轴(例如,所有宽度应始终可见,高度应分别缩放到宽度):将所有场景对象存储在父级中并缩放父级。 防爆。 (我的宽度是固定的,高度被切断了宽度)

bottomRightPosition  = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, - Camera.main.transform.position.z));
topLeftPosition  = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, -Camera.main.transform.position.z));

float Width = topLeftPosition.x -bottomRightPosition.x
float scale = width / optimizedWorldDistance

gameHolder.transform.localScale = new Vector3(scale,scale,1); // for 2D

注意:我的gameHolder最初是规模(1,1,1);

答案 3 :(得分:0)

你应该把所有东西都放在一个主游戏对象中,然后使用一个简单的脚本(相机“东西”可以帮助你检测屏幕比例)以差异比例缩放它。 这是我的想法。 抱歉我的英语不好。

答案 4 :(得分:0)

尝试使用锚定的新unity3d ui。

答案 5 :(得分:0)

对于所有UI元素,您必须使用单位UI系统,这是支持多平台和宽高比的最佳方式。

以下内容基于this文章: 这篇文章基本上和我说的一样: 1) 关于高分辨率的设计,文章说:

  

"另一种方法是使用更高分辨率的图形(实际上是   一个具有您想要定位的设备的最高分辨率的那个)和   在所有设备上缩小它。但是,这不是一个好主意,因为   你实际上需要更多的内存并且会失去性能   低端设备。"

因此,设计高分辨率然后缩小它并不是一个好方法。

正如文章所述,最好的方法是为不同的分辨率(SD,HD UD)设置不同的图像,并在加载游戏时加载正确的图像:文章说: "最好的方法是使用具有更高分辨率的不同图像,并在iPhone 4上使用此图像版本,在iPhone 3GS上使用低分辨率版本,这实际上是Apple使用带有@的图像所做的事情。文件名的后缀为2x。

以类似的方式,您可以创建iPad 3所需的超高分辨率的所有图形,并附加另一个后缀,并根据设备的屏幕分辨率加载正确的图像。这称为内容缩放,因为游戏只针对单个"逻辑"场景大小,以及所有图像&字体缩放到设备分辨率。"

因此,通过使用这种方法,我们解决了具有不同分辨率的目标设备的问题。 不像关键词所说,还有另一个问题是针对具有不同宽高比的设备: 来自artichle: &#34;但是,当您想要定位具有不同宽高比的设备时,这种方法是不够的<#34;

为此,我通常选择适合我游戏设计的宽高比,并使用以下脚本在不同设备上保持相同的宽高比:

    /* 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 CameraFit : MonoBehaviour
{
    #region FIELDS
    public float UnitsForWidth = 1; // width of your scene in unity units
    public static CameraFit Instance;

    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()
    {
        try{
            if((bool)GetComponent<Camera>()){
                if (GetComponent<Camera>().orthographic) {
                    ComputeResolution();
                }
            }
        }catch (Exception e){
            Debug.LogException(e, this);
        }
    }

    private void ComputeResolution()
    {
        float deviceWidth;
        float deviceHeight;
        float leftX, rightX, topY, bottomY;
#if UNITY_EDITOR
        deviceWidth = GetGameView().x;
        deviceHeight = GetGameView().y;
#else
        deviceWidth = Screen.width;
        deviceHeight = Screen.height;
#endif
        //Debug.Log("Aspect Ratio " + GetComponent<Camera>().aspect);
        if (GetComponent<Camera>().aspect >= 0.7f)
        {
            UnitsForWidth = 2.2f;
        } 
        else
        {
            UnitsForWidth = 2f;
        }
        /* Set the ortograpish size (shich is half of the vertical size) when we change the ortosize of the camera the item will be scaled 
         * autoamtically to fit the size frame of the camera
         */
        GetComponent<Camera>().orthographicSize = 1f / GetComponent<Camera>().aspect * UnitsForWidth / 2f;

        //Get the new height and Widht based on the new orthographicSize
        _height = 2f * GetComponent<Camera>().orthographicSize;
        _width = _height * GetComponent<Camera>().aspect;

        float cameraX, cameraY;
        cameraX = GetComponent<Camera>().transform.position.x;
        cameraY = GetComponent<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);
        Instance = this;
    }

    private void Update()
    {
        #if UNITY_EDITOR
        ComputeResolution();
        #endif
    }

    private void OnDrawGizmos()
    {
        if (GetComponent<Camera>().orthographic) {
            DrawGizmos();
        }
    }

    private void DrawGizmos()
    {
        //*** bottom
        Gizmos.DrawIcon(_bl, "point.png", false);
        Gizmos.DrawIcon(_bc, "point.png", false);
        Gizmos.DrawIcon(_br, "point.png", false);
        //*** middle
        Gizmos.DrawIcon(_ml, "point.png", false);
        Gizmos.DrawIcon(_mc, "point.png", false);
        Gizmos.DrawIcon(_mr, "point.png", false);
        //*** top
        Gizmos.DrawIcon(_tl, "point.png", false);
        Gizmos.DrawIcon(_tc, "point.png", false);
        Gizmos.DrawIcon(_tr, "point.png", false);

        Gizmos.color = Color.green;
        Gizmos.DrawLine(_bl, _br);
        Gizmos.DrawLine(_br, _tr);
        Gizmos.DrawLine(_tr, _tl);
        Gizmos.DrawLine(_tl, _bl);
    }

    private Vector2 GetGameView()
    {
        System.Type T = System.Type.GetType("UnityEditor.GameView,UnityEditor");
        System.Reflection.MethodInfo getSizeOfMainGameView =
            T.GetMethod("GetSizeOfMainGameView",System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
        System.Object resolution = getSizeOfMainGameView.Invoke(null, null);
        return (Vector2)resolution;
    }
    #endregion
}


  [1]: http://v-play.net/doc/vplay-different-screen-sizes/

这应该是唯一的不同长宽比问题。现在,如果您希望锚定一些游戏对象,如果在具有不同宽高比的设备上调整游戏大小,则始终处于固定位置事件中,您可以使用以下脚本:

/***
 * This script will anchor a GameObject to a relative screen position.
 * This script is intended to be used with CameraFit.cs by Marcel Căşvan, available here: http://gamedev.stackexchange.com/a/89973/50623
 * 
 * Note: For performance reasons it's currently assumed that the game resolution will not change after the game starts.
 * You could not make this assumption by periodically calling UpdateAnchor() in the Update() function or a coroutine, but is left as an exercise to the reader.
 */
/* The MIT License (MIT)

Copyright (c) 2015, Eliot Lash

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 UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class CameraAnchor : MonoBehaviour {
    public enum AnchorType {
        BottomLeft,
        BottomCenter,
        BottomRight,
        MiddleLeft,
        MiddleCenter,
        MiddleRight,
        TopLeft,
        TopCenter,
        TopRight,
    };
    public AnchorType anchorType;
    public Vector3 anchorOffset;

    // Use this for initialization
    void Start () {
        UpdateAnchor();
    }

    void UpdateAnchor() {
        switch(anchorType) {
        case AnchorType.BottomLeft:
            SetAnchor(CameraFit.Instance.BottomLeft);
            break;
        case AnchorType.BottomCenter:
            SetAnchor(CameraFit.Instance.BottomCenter);
            break;
        case AnchorType.BottomRight:
            SetAnchor(CameraFit.Instance.BottomRight);
            break;
        case AnchorType.MiddleLeft:
            SetAnchor(CameraFit.Instance.MiddleLeft);
            break;
        case AnchorType.MiddleCenter:
            SetAnchor(CameraFit.Instance.MiddleCenter);
            break;
        case AnchorType.MiddleRight:
            SetAnchor(CameraFit.Instance.MiddleRight);
            break;
        case AnchorType.TopLeft:
            SetAnchor(CameraFit.Instance.TopLeft);
            break;
        case AnchorType.TopCenter:
            SetAnchor(CameraFit.Instance.TopCenter);
            break;
        case AnchorType.TopRight:
            SetAnchor(CameraFit.Instance.TopRight);
            break;
        }
    }

    void SetAnchor(Vector3 anchor) {
        Vector3 newPos = anchor + anchorOffset;
        if (!transform.position.Equals(newPos)) {
            transform.position = newPos;
        }
    }


    // Update is called once per frame
#if UNITY_EDITOR
    void Update () {
        UpdateAnchor();
    }
#endif
}

希望这可以提供帮助,有关详细信息,请阅读我上面链接的文章。