前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >NGUI AnchorPoint与Camera CullingMask的结合之痛

NGUI AnchorPoint与Camera CullingMask的结合之痛

作者头像
用户2615200
发布2018-08-02 16:39:40
4720
发布2018-08-02 16:39:40
举报

问题

NGUI内建的Anchor系统可以方便的定位UI(底层的一个支持结构是AnchorPoint),例如一些需要全屏显示的游戏界面一般都需要借助这项功能;另外的,对于稍复杂的UI设计,我们可能会将UI进行分层处理,一些游戏状态下我们可能也会主动显示或者隐藏其中的某些层级.而要实现这种UI的分层显示,一种自然的方式便是采用Camera的CullingMask. 两个系统单独来看好像都没有什么问题,但是结合起来使用却容易出现岔子~

原因

原因在于NGUI的Anchor系统并不能很好的支持Camera CullingMask的切换,我们简单来看一段NGUI实现Anchor的代码片段:

代码语言:javascript
复制
public void ResetAnchors ()
{
    mAnchorsCached = true;

    leftAnchor.rect     = (leftAnchor.target)   ? leftAnchor.target.GetComponent<UIRect>()   : null;
    bottomAnchor.rect   = (bottomAnchor.target) ? bottomAnchor.target.GetComponent<UIRect>() : null;
    rightAnchor.rect    = (rightAnchor.target)  ? rightAnchor.target.GetComponent<UIRect>()  : null;
    topAnchor.rect      = (topAnchor.target)    ? topAnchor.target.GetComponent<UIRect>()    : null;

    mCam = NGUITools.FindCameraForLayer(cachedGameObject.layer);

    FindCameraFor(leftAnchor);
    FindCameraFor(bottomAnchor);
    FindCameraFor(rightAnchor);
    FindCameraFor(topAnchor);

    mUpdateAnchors = true;
}

代码的大意便是重置一些Anchor相关的数据,其中重要的有两处: 第一个是 mAnchorsCached,他是缓存标记,用以标记Anchor数据是否已经重置; 第二个则是 NGUITools.FindCameraForLayer ,该接口会返回CullingMask包含指定layer的Camera对象. 一般而言,对于Camera CullingMask不会变动的情况,ResetAnchors的实现是没有问题的,但是正如上面所说,如果我们通过改变CullingMask来实现UI分层显示的话,某些被隐藏层级的UI可能会因为查找不到Camera而导致Anchor出错,而此时缓存标记又已设置,后面的逻辑便再不会主动重置Anchor数据,导致定位出错~

方法

解决方法可能有以下一些: 一是避免使用NGUI的Anchor系统,转而自己实现UI的定位,一般来讲并不推荐. 二是改造NGUI Anchor系统,以使其支持Camera的CullingMask变动,譬如实现某种CullingMask的变动通知机制,然后主动重置更新相应的Anchor~ 而对于一些全屏性质的UI(需要通过整个屏幕来定位的UI),则有一个比较简单的改动方法,原理则是实现一种特定的UIRect,使其一直保持全屏大小,即便找不到对应layer的Camera也是如此,而UI则根据这个定制的UIRect来进行定位. 一个简单的参考实现大概是这个样子:

代码语言:javascript
复制
// desc UIScreenRect is for handling problem NGUI anchor system does not fit Camera culling mask changes
// maintainer hugoyu

using UnityEngine;

public class UIScreenRect : UIRect
{

    Vector3[] m_invalidWorldCorners = new Vector3[] { Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero };

    public override float alpha 
    { 
        get
        {
            return 0;
        }

        set
        {
            Debug.LogWarning("[UIScreenRect]Do not support set UIScreenRect's alpha");
        }
    }

    public override float CalculateFinalAlpha(int frameID)
    {
        return 0;
    }

    public override Vector3[] localCorners 
    { 
        get
        {
            Vector3[] corners = worldCorners;
            Transform wt = cachedTransform;
            for (int i = 0; i < 4; ++i)
            {
                corners[i] = wt.InverseTransformPoint(corners[i]);
            }
            return corners;
        }
    }

    public override Vector3[] worldCorners 
    { 
        get
        {
            var anchorCam = GetAnchorCamera();
            if (anchorCam != null)
            {
                return anchorCam.GetWorldCorners(cameraRayDistance);
            }
            else
            {
                return m_invalidWorldCorners;
            }
        }
    }

    protected override void OnAnchor()
    {
    }

    protected override void OnStart()
    {
    }

    public override void SetRect(float x, float y, float width, float height)
    {
        Debug.LogWarning("[UIScreenRect]Do not support set UIScreenRect's rect");
    }

    public override bool canBeAnchored
    {
        get
        {
            return false;
        }
    }

    public override Vector3[] GetSides(Transform relativeTo)
    {
        GetAnchorCamera();
        return base.GetSides(relativeTo);
    }

    public Camera GetAnchorCamera()
    {
        if (!anchorCamera)
        {
            // when anchor camera is missing, we set to first UICamera
            if (UICamera.list.size > 0)
            {
                mCam = UICamera.list.buffer[0].cachedCamera;
            }
        }

        if (!mCam)
        {
            Debug.LogWarning("[UIScreenRect]Error to get anchor camera");
        }

        return mCam;
    }

}

OK,下次再见吧~

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年09月04日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题
  • 原因
  • 方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档