NGUI不规则碰撞体及防3d碰撞体穿透

最近做到地图功能,地图可以滑动,地图上有各个形状的建筑,大小不一,地图底栏有按钮可以点击。应该是一个比较普遍的需求。首先贴一张图吧,没法放原图,就用画图工具模仿了一下大概情况。

示图

其中矩形黑框为手机屏幕,背景那个特别大的什么颜色是地图,命名为BG,是可拖动的对象。不规则图片ABCD为地图上各个建筑,椭圆形abc分别为界面按钮,注意到因为地图是可以滑动的,建筑随地图滑动而移动,但按钮abc不会动,所以会出现图上那种情况c按钮遮挡到部分D建筑。场景介绍完毕。

因为美术给的图片都是矩形的,如果用boxcollider,必定会出现建筑碰撞体折叠的情况,这也是使用自定义碰撞体polygon collider 2d的原因。注意到这个碰撞体是2d的,所以如果你的ngui 相机event type 选择为3d ui 的话,ngui自带的eventlistenter是监听不到这个2d碰撞体的点击事件的。要监听到2d碰撞体的碰撞事件,需要把相机的event type改为2d ui,这也是比较推荐的处理方法,不需要再去写代码监听。然而我们项目不晓得为什么一开始就用的3d ui模式,所以只能自己去监听这个2d碰撞体。也就是射线,代码比较简单,如下:

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            mouPos = uicamera.ScreenToWorldPoint(Input.mousePosition);
            mou2d.x = mouPos.x;
            mou2d.y = mouPos.y;
            hit = Physics2D.Raycast(mou2d, Vector2.zero);
            if (hit.collider != null) OnClicked(hit.collider.gameObject);
        }
    }

其中moupos为vector3类型,mou2d为vector2类型,注意这里要用2d的物理引擎也就是physics2d,不然是检测不到的。这样就可以在onclicked(自定义的方法)里面处理各个建筑被点击到的逻辑了。

但是当出现示图那种情况的时候,就出现了穿透这种情况,即点击按钮c,D建筑上面的碰撞体也会被监听到碰撞。试了很久没法解决,百度也没有搜到相关的, 没办法只能去看ngui源码了,看一下ngui是怎么响应点击事件的,然后试图在ngui响应之后截断对2d碰撞器的监听。

记一下分析步骤。当然弄懂ngui源码对现在的我来说还是不太现实的,只能尝试寻找有关代码。首先监听了下UIcamera的touchcount,发现无论点击什么地方,都是1,就算点到2d碰撞体上,也是1,说明从2d碰撞体直接穿透了。而UIcamera的touchcount的get方法,是由两个存储MouseOrTouch的列表以及一个MouseOrTouch决定的,断点发现,touchcount的值来源一直是由mMouse的第一个元素的pressed决定的(但是不知道为什么..源码还是看不懂)。所以博主的想法是,点击的时候,监听UIcamera的 mMouse的第一个元素的pressed,如果不为null,就判断为点击到了3d碰撞体,截断2d的监听。刚好UIcamera有这个方法GetMouse(int button),这样就可以了。代码如下,加了一句:

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            if (UICamera.GetMouse(0).pressed != null && UICamera.GetMouse(0).pressed.layer == layer && UICamera.GetMouse(0).pressed!=bg.gameObject) return;
            mouPos = uicamera.ScreenToWorldPoint(Input.mousePosition);
            mou2d.x = mouPos.x;
            mou2d.y = mouPos.y;
            hit = Physics2D.Raycast(mou2d, Vector2.zero);
            if (hit.collider != null) OnClicked(hit.collider.gameObject);
        }
    }

即有点击发生时,先检查下UIcamera是不是点到了某个对象,如果这个对象的layer是ngui的ui。即可判断为点击到ngui层的ui,截断这个2d的碰撞检测。至于最后一个的判断,是因为背景图也是3d的碰撞器,每次点击建筑的时候,都会穿透到背景上,所以这个情况要排除掉。

代码很简单,其中逻辑需要理解的要去看下ngui UIcamera代码,断点看的效果会更好。

 

下午测试的时候,发现一个问题,因为点击2d碰撞体会穿透到3d背景上,所以当拖动背景的起点在某个建筑上的时候,会发生建筑也被点击了的情况,也就是玩家想拖动背景,结果点开了建筑,体验很不好。所以加工了下代码,在mousebuttonup的时候监听,代码如下:

if (Input.GetMouseButtonDown(0))
        {
           
            if (UICamera.GetMouse(0).pressed != null && UICamera.GetMouse(0).pressed.layer == layer && UICamera.GetMouse(0).pressed!=bg.gameObject) return;
            downmouPos = uicamera.ScreenToWorldPoint(Input.mousePosition);
        }

        if (Input.GetMouseButtonUp(0))
        {
            upmouPos = uicamera.ScreenToWorldPoint(Input.mousePosition);
            Debug.Log(Mathf.Abs(Vector3.Distance(downmouPos,upmouPos)));
            if(Mathf.Abs(Vector3.Distance(downmouPos,upmouPos))<=dis)//click
            {
                mou2d.x = downmouPos.x;
                mou2d.y = downmouPos.y;
                hit = Physics2D.Raycast(mou2d, Vector2.zero);
                if (hit.collider != null) OnClicked(hit.collider.gameObject);
            }
            else //drag
            {

            }
        }

原理就是在点击抬起时,计算下点击 下落坐标与抬起坐标 距离,小于一定的范围即判断为点击,大于一定范围为拖拽。这个范围我设置的0.1f,有待商榷。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值