unity ugui 与不同屏幕进行像素适配的问题

来源:互联网 发布:大数据前沿技术与应用 编辑:程序博客网 时间:2024/05/21 04:25

unity的ugui其实严格意义上是不需要我们去进行适配的,它确实帮助我们做了很多很多的工作,我们只要简单的拖拉几下就可以搞定适配的问题(这点在比ngui强了不是一点半点,不愧是unity提供的从底层开始的解决方案)。
但是总是会有那么些特殊的蛋痛需求,还是需要让我们来考虑适配的问题的。
假设我们要做一个类似iphone的AssistiveTouch悬浮窗时,这个东西有个特点,那就是它不能出屏,出屏之后需要再弹回到屏幕范围内,这个时候,你想不处理适配的问题都不行了。。。

如图那个黑边白球:
这里写图片描述

那么ugui里我们要怎么办呢?
首先我们要考虑2点。
1,我们的ui资源比例是什么?
2,我们要适配的屏幕比例又是什么?

假设我们资源的图是按照960x640(3:2)来绘制的,而我们的屏幕是1920x1080(16:9),我们是不能单纯的用1920x1080屏幕的尺寸来限定运动范围,因为这2种屏幕的比例是不同的,我们在960x640屏幕上 (50,50) 像素的点,跟在1920x1080屏幕上的位置那是2个地方,所以你会蛋痛的发现,你的位置永远的都对不上。。。

但是我们来看看我们知道哪些有用的信息,我们知道2个屏幕的尺寸呀,所以我们可以根据它们之间的差距来转换呀!
思路很简单,就是如果我用 960 / 1920 = ? 宽的比乘以一个1920元素的尺寸或位置,那不就是等于960的尺寸和位置了。

道理很简单,但是谁除谁,也不是能随随便便那么来的,因为我们的屏幕适配是由ugui来处理的,所以我们算比的方式,一定要跟ugui的适配是相一致的,才能保证最后的结果是没有偏差的。
如果ugui是以高为适配的,你算得是宽的比,你觉得这2屏幕能对的上吗?

这里写图片描述

以上这些重要的信息都是来自于 Canvas Scaler 这个组件上,它负责了ugui中对各种尺寸屏幕的像素适配(这里我用的是Scale with Screen Size模式,自建单独的ui摄像机)

说了这么多,这里就上个我写的浮动球的代码:

using UnityEngine;using System.Collections;using UnityEngine.EventSystems;using UnityEngine.UI;using UnityEngine.Events;public class UIBtnCloud : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler, IBeginDragHandler, IDragHandler, IEndDragHandler{    /// <summary>    /// 按下后超过这个时间则认定为"长按"    /// </summary>    public float interval = 0.1f;    /// <summary>    /// 是否只调用一次    /// </summary>    public bool invokeOnce = false;    // 按下标志    private bool isPointerDown = false;    // 记录时间    private float recordTime;    //是否已经调用过    private bool hadInvoke = false;    // 点击事件    public UnityEvent onClick = new UnityEvent();    // 按住事件    public UnityEvent onPress = new UnityEvent();    private RectTransform m_rectTransform;    private float m_scale;    private float m_minX, m_minY, m_maxX, m_maxY;    void Start()    {        m_rectTransform = gameObject.GetComponent<RectTransform>();        // 计算分辨率的比例        CanvasScaler cs = XXX.GetInstance().CanvasScaler;        m_scale = cs.matchWidthOrHeight == 1 ?             (float)Screen.height / cs.referenceResolution.y :             (float)Screen.width / cs.referenceResolution.x;        // 范围        m_minX = m_rectTransform.sizeDelta.x / 2 * m_scale;        m_minY = m_rectTransform.sizeDelta.y / 2 * m_scale;        m_maxX = Screen.width - m_minX;        m_maxY = Screen.height - m_minY;    }    void Update()    {        // 一次机会已用完        if (invokeOnce && hadInvoke) return;        // 按下        if (isPointerDown)        {            // 算按住            if ((Time.time - recordTime) > interval)            {                hadInvoke = true;                onPress.Invoke();            }        }    }    #region 处理点击    // 按下    void IPointerDownHandler.OnPointerDown(PointerEventData eventData)    {        isPointerDown = true;        recordTime = Time.time;    }    // 抬起    void IPointerUpHandler.OnPointerUp(PointerEventData eventData)    {        isPointerDown = false;        hadInvoke = false;        // 算点击        if ((Time.time - recordTime) < interval)        {            onClick.Invoke();        }    }    // 离开    void IPointerExitHandler.OnPointerExit(PointerEventData eventData)    {        isPointerDown = false;        hadInvoke = false;    }    #endregion 处理点击 -------------------------------------    #region 处理拖拽    private void SetRectTransformPos(Vector2 position, Camera camera)    {        Vector3 globalMousePos;        if (RectTransformUtility.ScreenPointToWorldPointInRectangle(m_rectTransform, position, camera, out globalMousePos))        {            m_rectTransform.position = globalMousePos;        }    }    // 开始拖拽    void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)    {    }    // 拖拽中    void IDragHandler.OnDrag(PointerEventData eventData)    {        //transform.position = eventData.position;        this.SetRectTransformPos(eventData.position, eventData.pressEventCamera);    }    // 结束拖拽    void IEndDragHandler.OnEndDrag(PointerEventData eventData)    {        // 位置        float x = m_rectTransform.position.x;        float y = m_rectTransform.position.y;        // 超出范围处理        if (x < m_minX)        {            x = m_minX;        }        else if (x > m_maxX)        {            x = m_maxX;        }        if (y < m_minY)        {            y = m_minY;        }        else if (y > m_maxY)        {            y = m_maxY;        }        Vector2 currentPosition = new Vector2(x, y);        // 设置坐标        this.SetRectTransformPos(currentPosition, eventData.pressEventCamera);    }    #endregion 处理拖拽 -------------------------------------}

以上脚本挂在普通窗的button上就好了,很简单的。
外加没有做差值效果,只是生把出屏的球给拉回来,需要的同学可以自己给加上。

CanvasScaler cs = XXX.GetInstance().CanvasScaler;

获取 CanvasScaler 组件的方法,根据自己的项目去修改就好了,你的位置肯定不会跟我的一样~
这里我的资源都是按着960x640的标准来制作的(其实并不是,只是我瞎j8设的。。。),你要根据你自己的资源去调整参数,剩下的,就全是程序的事了。

PS:
顺便这里安利一下ugui,确实是比ngui好用,不过缺点是好多东西是需要自己手写的,像ngui里,对于这种出屏回弹的功能,其实就有现成的组件的,调参数就好。
这无形中其实增加了使用的门槛,不利于新手入门,尤其是不了解差值动画这个概念的同学,会限制他们制作各种各样精美动画的能力。(不是开玩笑,真有好多人搞不清楚差值动画这个概念。。。)
不过还是那句话,提高自己最重要,你也不能总靠别人不是?

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 空间被别人知道了密码登录了怎么办 三星手机显示解析包出现问题怎么办 三星手机下载解析包出现问题怎么办 两万的流动大棚给整坏了怎么办 劲舞团抽奖领了一样的衣服怎么办 win系统ps界面字体太小怎么办 任何网页都变成监控登录界面怎么办 微信启动录音的尝试被拒绝怎么办 微信传到电脑的文件打不开怎么办 转转网账号出租时遇到防沉迷怎么办 如果买了王者号结果有防沉迷怎么办 苹果手机一直显示验证失败怎么办呢 安装包证书异常导致安装失败怎么办 qq飞车忘了几区的怎么办 5e在游戏里卡住不动怎么办 别人发的cdr文件打开太慢怎么办 qq红包充值话费未到账怎么办 qq飞车充值至尊皇冠不到账怎么办 微信支付金额超过单日限制怎么办 不小心在qq钱包中充错话费怎么办 衣服质量不好穿了几次就坏了怎么办 手机丢了找到手机店的人怎么办 在手机店买手机买贵了怎么办 王者荣耀好多没对的东西怎么办 用电脑玩游戏键盘不管用怎么办? 王者荣耀跨系统送皮肤领不到怎么办 电脑使用迅雷时提示缓存过高怎么办 扣扣安全中心动态密码忘记了怎么办 pu管两头固定了中间换截怎么办 自己架设的传奇不能注册帐号怎么办 天堂2第八章读取服务端错误怎么办 苹果手机王者荣耀下了不能玩怎么办 苹果手机摔了一下触屏失灵怎么办 华为机回复出厂设置帐号忘了怎么办 华为手机里突然有个pp助手怎么办 华为手机与电脑连接不上怎么办 买房交了首付贷不了款怎么办 手机买贵了实体店不肯退怎么办 在实体店里手机买贵了怎么办 红米手机开启不了安装系统怎么办? 捡个荣耀8双清后要账号怎么办