最近遇到的一些问题总结(UIScroll和Tips穿透问题)

时间:2022-08-13 17:16:28

先分享一下,做物品tips时候的穿透问题。

首先,物品tips的关闭规则

 

 

UICamer的原理:

UICamer就是通过在触摸/鼠标移动的位置的地方发射射线(就是UnityRaycast),然后获取射线撞击的碰撞体(collider)信息,然后发射消息(通过UnitySendMessage函数)给该碰撞体关联的GameObject的所有脚本。

 

 

原本的做法是,给tips加一层背景遮罩(遮罩上加上Box Collider),当触发到遮罩Box Collider时,发送关闭tips事件,然后通过UICamera.lastHit.collider.gameObject获取到射线最后的碰撞对象。给这个对象SendMessage("OnClick")

 

 local function onMask()

     EventManager:dispatchEvent(EventName.CloseTips)

     local hoverobject = nil

        local ishit = UICamera.Raycast(Input.mousePosition)

        if ishit then

            hoverobject = UICamera.lastHit.collider.gameObject

            print("-------objectname---",hoverobject)

            if UIEventListener.Get(hoverobject).onClick then

             print(UIEventListener.Get(hoverobject).onClick)

             hoverobject:SendMessage("OnClick")

            end

        end

    end

    self:addUIEvent(self.maskBg, onMask)

 

但是这种做法不能满足文档里面的新需求。

接下来说一下现在的做法,直接把tips的遮罩去掉。

tips界面预设定一个新的Layer

 

 

然后,Camera里面的Culling Mask增加新的Layer

 

这样做的目的是为了让tips界面与其他的UI界面的Layer区分开来。

接下来就是要到TouchManager.lua

 

这个函数里面会不停刷新点击碰撞事件,

我的处理方法是在这个函数里面加入

if (Input.GetMouseButtonDown(0)) then

        if (UICamera.lastHit.collider.gameObject.layer ~= LayerManager.Tips_Layer) and TipsManager.isShow then

            EventManager:dispatchEvent(EventName.CloseTips)

        end

End

 

UICamera.lastHit.collider.gameObject.layer是获取射线最后的碰撞对象的Layer,判断不属于LayerManager.Tips_Layer就发送关闭Tips事件。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

接着说一下Scroll view里面空白处添加滑动的问题。

如下图,有时候scroll view里面的item不足以填充满当前显示的滚动区域(蓝色框为滚动区域)是,在黄色区域空白区进行拖动的时候,并不会进行滚动。

 

 

处理方法是,在scrollviewPanel外面多加一个背景层,

 

添加

 

关键一步是,把UIDrag Scroll View脚本的Scroll View设置为panel

Drag Scroll ViewScroll View属性可以指定特定的带有Scroll View的拖拽层,如果不指定在运行时会自动匹配父节点带有绑定Scroll View的拖拽层。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

NGUI生成ScrollView 有两个重要的类UIScrollviewUIPanelNGUI Version 3.7.8

 

ScrollviewPanel上面挂上UIPanel的作用是用来渲染,当有一块需要特殊处理的模块需要渲染时需要用到UIPanel专门控制。

 

UIPanel上有一个Clipping功能,用作裁剪用。

 

 

 

 

实现可以让某些item显示某些不显示,某些item只显示一部分。

 

首先,可以看UIPanelLateUpdate()函数。

 

 

 

 

UIPanel里面每帧都会更新这个LateUpdate()函数。

 

 

LateUpdate()函数里主要看UpdateSelf()UpdateDrawCalls()

 

 

UpdateSelf()

 

 

 

这里会有好几个的Update函数,主要说一下UpdateWidget()。为什么要UpdateWidget

因为NGUI是根据UIWidget来作为渲染单位。

 

UIWidgetOnStart()函数中,只做了CreatePanel()操作。

 

 

这里有一个panel.AddWidget(this)CreatePanel其实不是真的去Create一个Panel,而是找父节点或者自己节点上的UIPanel,去把自己的Widget添加到PanelWidgetList中。

 

一个UIWidget是不会渲染的,所有的控件是通过找到UIPanel,再在UIPanel去渲染。

这就是要UpdateWidget的原因。

 

接着就是UpdateSelf()里面的FillAllDrawcalls()函数

这个函数是用来合并可以合并的drawcall

 

首先,会调用SortWidgets()排序Widget

 

这里会根据DepthMaterial进行排序

 

 

 

排序之后,会获取每一个widgetMaterialTextureShader

 

 

如果不一样的话就,就调drawCalls.Add(),把这个drawcall加到这个drawcallList中。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

接着看这些属性是否为空,如果为空就去Create一个新的DrawCall

如果不为空就改变这个DrawcallDepthdepthStartdepthEnd

 

 

 

 

接着回来最开始的LateUpdate()函数

看到这个地方,

 

 

不管是什么渲染队列方式,都是调用UpdateDrawCalls().

 

直接看到UpdateDrawCalls()里面,

 

这里会计算出这个transform的位置旋转缩放在显示屏中的各种属性数据还有这个Drawcall的渲染方式队列裁剪方式裁剪范围等。

 

这就完成了每帧刷新每一个widgettransformdrawcall数据刷新。

 

为什么可以让某些item显示某些不显示,某些item只显示一部分。

回到刚刚的FillAllDrawCalls()

 

这里的dc.UpdateGeometry(),一直跟踪下去,最后会到UIDrawcallCreateMaterial()这个函数。

 

 

 

这里进行判断,根据设置好的裁剪来选择不同的shader

由于不同的shader会产生不同的动态材质mDynamicMat

 

 

也是由于这个不同的动态材质使得下一步的渲染裁剪得到实现。