找回密码
 立即注册

ゅ星星点灯°

https://www.u3dchina.com/?211

Unity强制屏幕纵宽比脚本

热度 1已有 2182 次阅读2012-11-28 12:18 |个人分类:脚本| unity, 屏幕, 校正

强制屏幕到所需要的长宽比,可以根据需要自由选择是否应用强制比例.其中包括返回校正后的屏幕宽度,高度(Screen.width/height)和鼠标位置(Input.mousePosition).

将这个脚本放在编译顺序较优先的文件夹中,比如 Standard Assets, (Plugins是最先编译的),因此你可以用Js,C#等语言调用AspectUtility来使用它.首先要将它附加到Camera上,它同样可以附加给其他物体,如果你赋给其他物体,它将主动尝试找到标签为"Main Camera"的相机.对于WantedAspectRatio这个值,常见的是4:3为1.333333,16:10为1.6,16:9为1.777778,如果屏幕的纵宽比与设定的相同,不会有任何变化.如果与设定的纵宽比不同,将用黑色填充缺少的部分.
这样会导致有些方法返回不正确,比如Screen.width和Screen.height会返回实际屏幕尺寸,而不是主相机的尺寸,为了纠正这个问题,可以使用AspectUtility.screenWidth和AspectUtility.screenHeight.

同样的,Input.mousePosition也会有些问题,这种情况可以使用AspectUtility.mousePosition获取需要的值.

有一点要注意,这些变量在脚本刚唤醒的时候可能不能正确获取到,这就需要等待脚本开始后再访问它们.

当屏幕尺寸变化,例如Webplayer,采用4:3的比例,用户切换全屏后变成了16:9,这时候就需要用AspectUtility.SetCamera()重设脚本相机.

OnGUI代码在用AspectRatioEnforcer时需要做一些额外的工作.OnGUI的代码独立于Camera画在屏幕上的.所以相机改变了矩阵尺寸,它不会自动变化.这时候我们要特别处理一下.

如果你是用GUILayout来排列GUI,可以用GUILayout.BeginArea和EndArea来定义一个范围,像下面这样:
程序代码 js 代码

function OnGUI () {
    GUILayout.Label("Hello");
    GUILayout.Label("there");
}


修改它为:

程序代码 js 代码
function OnGUI () {
    GUILayout.BeginArea(AspectUtility.screenRect);

    GUILayout.Label("Hello");
    GUILayout.Label("there");

    GUILayout.EndArea();
}


如果已经用过BeginArea/EndArea,你可以直接在外面再嵌套AspectUtility.screenRect,它仍旧会处理好的.

如果你没有使用GUILayout,那么可以添加x和y的偏移来修正所有GUI的Rect,可以用AspectUtility.xOffset 和 AspectUtility.yOffset来得到偏移量,比如你平时这样写:

程序代码 js 代码

function OnGUI () {
    GUI.Label(Rect(50, 50, 100, 30), "Hello");
    GUI.Label(Rect(75, 75, 100, 30), "there");
}


现在改成:

程序代码 js 代码

function OnGUI () {
    var x = AspectUtility.xOffset;
    var y = AspectUtility.yOffset;

    GUI.Label(Rect(x + 50, y + 50, 100, 30), "Hello");
    GUI.Label(Rect(x + 75, y + 75, 100, 30), "there");
}


通常在OnGUI里获得鼠标位置用的是Event.current.mousePosition,在这里我们应该改使用AspectUtility.guiMousePosition.

AspectUtility.cs脚本
程序代码 csharp 代码
using UnityEngine;

public class AspectUtility : MonoBehaviour {

    public float _wantedAspectRatio = 1.3333333f;
    static float wantedAspectRatio;
    static Camera cam;
    static Camera backgroundCam;

    void Awake () {
        cam = camera;
        if (!cam) {
            cam = Camera.main;
        }
        if (!cam) {
            Debug.LogError ("No camera available");
            return;
        }
        wantedAspectRatio = _wantedAspectRatio;
        SetCamera();
    }

    public static void SetCamera () {
        float currentAspectRatio = (float)Screen.width / Screen.height;
        // If the current aspect ratio is already approximately equal to the desired aspect ratio,
        // use a full-screen Rect (in case it was set to something else previously)
        if ((int)(currentAspectRatio * 100) / 100.0f == (int)(wantedAspectRatio * 100) / 100.0f) {
            cam.rect = new Rect(0.0f, 0.0f, 1.0f, 1.0f);
            if (backgroundCam) {
                Destroy(backgroundCam.gameObject);
            }
            return;
        }
        // Pillarbox
        if (currentAspectRatio > wantedAspectRatio) {
            float inset = 1.0f - wantedAspectRatio/currentAspectRatio;
            cam.rect = new Rect(inset/2, 0.0f, 1.0f-inset, 1.0f);
        }
        // Letterbox
        else {
            float inset = 1.0f - currentAspectRatio/wantedAspectRatio;
            cam.rect = new Rect(0.0f, inset/2, 1.0f, 1.0f-inset);
        }
        if (!backgroundCam) {
            // Make a new camera behind the normal camera which displays black; otherwise the unused space is undefined
            backgroundCam = new GameObject("BackgroundCam", typeof(Camera)).camera;
            backgroundCam.depth = int.MinValue;
            backgroundCam.clearFlags = CameraClearFlags.SolidColor;
            backgroundCam.backgroundColor = Color.black;
            backgroundCam.cullingMask = 0;
        }
    }

    public static int screenHeight {
        get {
            return (int)(Screen.height * cam.rect.height);
        }
    }

    public static int screenWidth {
        get {
            return (int)(Screen.width * cam.rect.width);
        }
    }

    public static int xOffset {
        get {
            return (int)(Screen.width * cam.rect.x);
        }
    }

    public static int yOffset {
        get {
            return (int)(Screen.height * cam.rect.y);
        }
    }

    public static Rect screenRect {
        get {
            return new Rect(cam.rect.x * Screen.width, cam.rect.y * Screen.height, cam.rect.width * Screen.width, cam.rect.height * Screen.height);
        }
    }

    public static Vector3 mousePosition {
        get {
            Vector3 mousePos = Input.mousePosition;
            mousePos.y -= (int)(cam.rect.y * Screen.height);
            mousePos.x -= (int)(cam.rect.x * Screen.width);
            return mousePos;
        }
    }

    public static Vector2 guiMousePosition {
        get {
            Vector2 mousePos = Event.current.mousePosition;
            mousePos.y = Mathf.Clamp(mousePos.y, cam.rect.y * Screen.height, cam.rect.y * Screen.height + cam.rect.height * Screen.height);
            mousePos.x = Mathf.Clamp(mousePos.x, cam.rect.x * Screen.width, cam.rect.x * Screen.width + cam.rect.width * Screen.width);
            return mousePos;
        }
    }
}


AspectUtilityEnhanced.cs脚本:

程序代码 csharp 代码
using UnityEngine;

public class AspectUtility : MonoBehaviour {

    public float _wantedAspectRatio = 1.5f;
    public bool landscapeModeOnly = true;
    static public bool _landscapeModeOnly = true;
    static float wantedAspectRatio;
    static Camera cam;
    static Camera backgroundCam;

    void Awake () {
        _landscapeModeOnly = landscapeModeOnly;
        cam = camera;
        if (!cam) {
            cam = Camera.main;
            Debug.Log ("Setting the main camera " + cam.name);
        }
        else {
            Debug.Log ("Setting the main camera " + cam.name);
        }

        if (!cam) {
            Debug.LogError ("No camera available");
            return;
        }
        wantedAspectRatio = _wantedAspectRatio;
        SetCamera();
    }

    public static void SetCamera () {
        float currentAspectRatio = 0.0f;
        if(Screen.orientation == ScreenOrientation.LandscapeRight ||
            Screen.orientation == ScreenOrientation.LandscapeLeft) {
            Debug.Log ("Landscape detected...");
            currentAspectRatio = (float)Screen.width / Screen.height;
        }
        else {
            Debug.Log ("Portrait detected...?");
            if(Screen.height  > Screen.width && _landscapeModeOnly) {
                currentAspectRatio = (float)Screen.height / Screen.width;
            }
            else {
                currentAspectRatio = (float)Screen.width / Screen.height;
            }
        }
        // If the current aspect ratio is already approximately equal to the desired aspect ratio,
        // use a full-screen Rect (in case it was set to something else previously)

        Debug.Log ("currentAspectRatio = " + currentAspectRatio + ", wantedAspectRatio = " + wantedAspectRatio);

        if ((int)(currentAspectRatio * 100) / 100.0f == (int)(wantedAspectRatio * 100) / 100.0f) {
            cam.rect = new Rect(0.0f, 0.0f, 1.0f, 1.0f);
            if (backgroundCam) {
                Destroy(backgroundCam.gameObject);
            }
            return;
        }

        // Pillarbox
        if (currentAspectRatio > wantedAspectRatio) {
            float inset = 1.0f - wantedAspectRatio/currentAspectRatio;
            cam.rect = new Rect(inset/2, 0.0f, 1.0f-inset, 1.0f);
        }
        // Letterbox
        else {
            float inset = 1.0f - currentAspectRatio/wantedAspectRatio;
            cam.rect = new Rect(0.0f, inset/2, 1.0f, 1.0f-inset);
        }
        if (!backgroundCam) {
            // Make a new camera behind the normal camera which displays black; otherwise the unused space is undefined
            backgroundCam = new GameObject("BackgroundCam", typeof(Camera)).camera;
            backgroundCam.depth = int.MinValue;
            backgroundCam.clearFlags = CameraClearFlags.SolidColor;
            backgroundCam.backgroundColor = Color.black;
            backgroundCam.cullingMask = 0;
        }
    }

    public static int screenHeight {
        get {
            return (int)(Screen.height * cam.rect.height);
        }
    }

    public static int screenWidth {
        get {
            return (int)(Screen.width * cam.rect.width);
        }
    }

    public static int xOffset {
        get {
            return (int)(Screen.width * cam.rect.x);
        }
    }

    public static int yOffset {
        get {
            return (int)(Screen.height * cam.rect.y);
        }
    }

    public static Rect screenRect {
        get {
            return new Rect(cam.rect.x * Screen.width, cam.rect.y * Screen.height, cam.rect.width * Screen.width, cam.rect.height * Screen.height);
        }
    }

    public static Vector3 mousePosition {
        get {
            Vector3 mousePos = Input.mousePosition;
            mousePos.y -= (int)(cam.rect.y * Screen.height);
            mousePos.x -= (int)(cam.rect.x * Screen.width);
            return mousePos;
        }
    }

    public static Vector2 guiMousePosition {
        get {
            Vector2 mousePos = Event.current.mousePosition;
            mousePos.y = Mathf.Clamp(mousePos.y, cam.rect.y * Screen.height, cam.rect.y * Screen.height + cam.rect.height * Screen.height);
            mousePos.x = Mathf.Clamp(mousePos.x, cam.rect.x * Screen.width, cam.rect.x * Screen.width + cam.rect.width * Screen.width);
            return mousePos;
        }
    }
}


原文:http://wiki.unity3d.com/index.php?title=AspectRatioEnforcer
译者:威阿,转载请注明来自1vr.cn

路过

雷人
1

握手

鲜花

鸡蛋

刚表态过的朋友 (1 人)

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 立即注册

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-4-29 15:03 , Processed in 0.051035 second(s), 16 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

返回顶部