【小松教你手游开发】【系统模块开发】射线触发按钮

最近在做在一个Scrollview下每个Item要实现长按出现其他效果。
在NGUI上可以正常的这么做。
但是在2D Toolkit上却有问题。

在NGUI上滑动Scrollview其实是通过拖动每一个Item实现拖动效果。
而2D Toolkit上是在Scrollview上有一个一大块碰撞体。通过触发这个碰撞体实现拖动。

这里的区别就导致了当你想在2D Toolkit上实现长按Item时,被前面的Scrollview的碰撞体遮挡。
这时候我就用射线来触发长按功能。(其实原本按钮就是通过射线来触发)


射线触发有个问题就是层次。可能在你想要触发的按钮前面有很多个碰撞体,所以我们需要解决的是如何在很多碰撞体的情况下找到你想要的。

这里我们先说整个逻辑然后看代码。
首先射线是需要每帧射,所以我们在Update函数里写射线逻辑。
射线函数Physics.Raycast(newRay, out hitInfo, 1000, _layerMask)会返回射线中第一个碰到的碰撞体。
所以我们要做的是,首先通过屏幕射出第一个射线,当射线碰到碰撞体后判断这个是否我们需要的。
如果不是的话,我们可以通过这个函数输出的hitInfo中获得碰撞的点和碰撞体的宽
这个点加上这个碰撞体的Collider.size.z获得这个碰撞体后面的点。
我们在这个新点上在向屏幕内发出射线检测下一个碰撞
直到找到我们想要的点为止。

这里我们可以用递归来找。

触发的时候根据点击的点获取这个Vector3,并保存他的x,y以便之后根据这个坐标继续找到自己想要找的Gameobject

当找到之后就发出点击的效果了,所以这里用的是Action,ClickHandler像事件一样通知监听的脚本

可以看到下面开了一个协程。
这个协程的作用是通过时间间隙LongPressIntervalTime来判断这个按钮是否一致按着。

如果在这段时间内没有松开按钮,就会触发长按事件。

而现在还需加入松开按钮的逻辑。也是靠射线来判断

这里是根据之前保留下来的点和目标GameObject来判断是否一直点击


发现松开触发松开的函数

这就完成了一个按钮的点击。松开。和长按功能。

中间还有各种逻辑限制和判断。具体代码看脚本。

using UnityEngine;
using System.Collections;
using System;
public class RaycastGameObject : MonoBehaviour {

    public Action ClickHandler;
    public Action ReleaseHandler;
    public Action LongPressHandler;

    public GameObject TargetGameObject = null;
    public float LongPressIntervalTime = 1.5f;
    public string LayerName = "";

    bool _itemPressing = false;
    bool _checkingPressing = false;
    Vector3 _raycaseOriginVector3 = new Vector3();
    LayerMask _layerMask;
    F_Panel _panel;

    void Awake()
    {
        if (_panel == null)
            GetPanelInParent(transform);
        if (TargetGameObject == null)
            TargetGameObject = gameObject;

        if (LayerName == "")
        {
            _layerMask = 1 << gameObject.layer;
            LayerName = LayerMask.LayerToName(gameObject.layer);
        }
           
        else
            _layerMask = 1 << LayerMask.NameToLayer(LayerName);
    }

    // Update is called once per frame
    void Update()
    {
        if (_panel == null)
        {
            GetPanelInParent(transform);
        }
        else
        {
            if (!_checkingPressing && Input.GetMouseButton(0) && PopUpManager.Get.CurrentPopup.name == _panel.name)
            {
                _checkingPressing = true;
                _raycaseOriginVector3 = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
                RaycastGameObjectClick(Camera.main.ScreenPointToRay(Input.mousePosition), TargetGameObject);

            }
            else if (_itemPressing)
            {
                RaycastGameObjectRelease(new Ray(_raycaseOriginVector3, new Vector3(0, 0, 1)), TargetGameObject);
            }
        }
    }

    void RaycastGameObjectClick(Ray ray, GameObject targetObject)
    {

        Ray newRay = ray;
        RaycastHit hitInfo;
        if (Physics.Raycast(newRay, out hitInfo, 1000, _layerMask))
        {
            Debug.DrawLine(newRay.origin, hitInfo.point);
            if (hitInfo.collider.gameObject == null)
            {
                _checkingPressing = false;
                return;
            }
            else if (hitInfo.collider.gameObject != targetObject)
            {
                _raycaseOriginVector3 = hitInfo.point;
                Vector3 newPoint = new Vector3(hitInfo.point.x, hitInfo.point.y, hitInfo.point.z + hitInfo.transform.GetComponent<BoxCollider>().size.z);
                RaycastGameObjectClick(new Ray(newPoint, new Vector3(0, 0, 1)), targetObject);
            }
            else
            {
                OnItemPressedEnter();
                return;
            }

        }
        else
        {
            _checkingPressing = false;
        }
    }

    void RaycastGameObjectRelease(Ray ray, GameObject targetObject)
    {
        if (Input.GetMouseButton(0))
        {
            Ray newRay = ray;
            RaycastHit hitInfo;
            if (Physics.Raycast(newRay, out hitInfo, _layerMask))
            {
                Debug.DrawLine(newRay.origin, hitInfo.point);
                GameObject gameobj = hitInfo.collider.gameObject;
                if (gameobj != targetObject)
                    OnItemPressedEnd();
            }

        }
        else
        {
            OnItemPressedEnd();
        }
    }

    void OnItemPressedEnter()
    {
        _itemPressing = true;

        if (ClickHandler != null)
            ClickHandler();

        StartCoroutine(WaitAndCheckPress(LongPressIntervalTime));

    }

    void OnItemPressedEnd()
    {
        _checkingPressing = false;
        _itemPressing = false;

        if (ReleaseHandler != null)
            ReleaseHandler();
    }

    IEnumerator WaitAndCheckPress(float seconds)
    {
        yield return new WaitForSeconds(seconds);
        if (_itemPressing)
        {
            if (PopUpManager.Get.CurrentPopup.name == _panel.name)
                LongPressHandler();
        }
    }

    void GetPanelInParent(Transform _t)
    {
        if (_t.parent != null)
        {
            F_Panel getPanel = _t.parent.GetComponent<F_Panel>();
            if (getPanel == null)
            {
                GetPanelInParent(_t.parent);
            }
            else
            {
                _panel = getPanel;
            }
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值