【小松教你手游开发】【系统模块开发】射线触发按钮
2018-03-10 17:26
483 查看
最近在做在一个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来判断是否一直点击
发现松开触发松开的函数
这就完成了一个按钮的点击。松开。和长按功能。
中间还有各种逻辑限制和判断。具体代码看脚本。
在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; } } } }
相关文章推荐
- 【小松教你手游开发】【系统模块开发】射线触发按钮
- 【小松教你手游开发】【unity系统模块开发】Unity动画系统项目实战
- 【小松教你手游开发】【unity系统模块开发】Unity5.5.2UI打包AssetBundle
- 【小松教你手游开发】【系统模块开发】根据上一个GameObject坐标生成的tips界面
- 【小松教你手游开发】【系统模块开发】ngui做聊天系统
- 【小松教你手游开发】【系统模块开发】ngui做聊天系统
- 【小松教你手游开发】【unity系统模块开发】Unity5.5.2UI打包AssetBundle
- 【小松教你手游开发】【系统模块开发】unity 数据储存到本地为二进制文件(聊天记录本地储存)
- 【小松教你手游开发】【系统模块开发】图文混排 (在label中插入表情)
- 【小松教你手游开发】【系统模块开发】动态可拖动列表DynmicList,ScrollView
- 【小松教你手游开发】【系统模块开发】做一个3d旋转菜单
- 【小松教你手游开发】【unity系统模块开发】热更
- 【小松教你手游开发】【系统模块开发】做一个3d旋转菜单
- 【小松教你手游开发】【系统模块开发】写一个通用倒计时器
- 【小松教你手游开发】【系统模块开发】图文混排 (在label中插入表情)
- 【小松教你手游开发】【unity系统模块开发】自动寻路Navmesh
- 【小松教你手游开发】【unity系统模块开发】unity网络层读写
- 【小松教你手游开发】【unity系统模块开发】Unity Assetbundle打包笔记
- 【小松教你手游开发】【系统模块开发】父节点下的各个子节点居中摆放
- 【小松教你手游开发】【系统模块开发】根据上一个GameObject坐标生成的tips界面