Unity3d:一个简单的画圈圈手势判断
2018-04-11 04:31
316 查看
因为最近制作了一款儿童教育游戏,所以涉及到不少操作手势,其中比较有意思的是这样一个手势如图:
在游戏中这个画圈的手势往往位于一个可操作物体之上,并绕着中心顺时针旋转.这个物体可能是一个转盘,也可能是一个打蛋用搅拌器等等,意思是提示用户手指按照这个轨迹操作就可以得到正确的反馈,比如顺时针转动转盘实现开关…
在参考了unity商店的LogViewer插件以后(插件的开启手势正巧是在屏幕上画圈),我写了一个测试脚本如下:
想要看上面代码的效果,只需要新建一个带摄像机的空场景,建立一个cube,放在屏幕可见的位置,然后脚本挂在摄像机上并拖上参数(如图)运行:
运行以后试着在物体的周围逆时针画圈,物体就能开始转动啦.
因为是测试,所以代码中只有mouse的检测而没有涉及到Input.Touch的逻辑,如果要支持移动端操作,这方面我在正式代码中采用了LeanTouch插件,是免费而且开源的,有兴趣的话可以检索unity商店下载并自行替换.
现在来解释一下代码的大概思路:
1.当点击屏幕且未松开的情况下,只要手指移动一段距离,就把这个路径记录在list内.
2.当list中有两个元素以后,计算这两条路径的角度和角度的方向.
3.如果满足期望,就认为是在画圈的操作中,否则就认为用户没有按照期望来画圈,清空所有路径.
看了上面三条以后,可以知道代码的核心算法其实就是求向量的点积和叉积:
点积可以判断向量的角度,而叉积可以知道这个角度的方向,也就是说是顺时针方向的角还是逆时针方向的角.
当我们的操作通过了距离,角度,方向的种种判断之后,可以认为用户的操作是正确的,因此,代码中将目标物体旋转了一个小小的角度.当用户持续操作,我们创建的cube就可以旋转完整的360度了.
在实际的开发中,可能我们遇到的情况会比这个更复杂,比如无论正逆都可以接受,或者逻辑和表现剥离后加入各类回调,或者是范围的控制这些其实都好解决,只要在对应的if判断前后做出修改即可.
在游戏中这个画圈的手势往往位于一个可操作物体之上,并绕着中心顺时针旋转.这个物体可能是一个转盘,也可能是一个打蛋用搅拌器等等,意思是提示用户手指按照这个轨迹操作就可以得到正确的反馈,比如顺时针转动转盘实现开关…
在参考了unity商店的LogViewer插件以后(插件的开启手势正巧是在屏幕上画圈),我写了一个测试脚本如下:
using UnityEngine; using System.Collections; using System.Collections.Generic; public class TestGestureAround : MonoBehaviour { public bool bIsClockWise; public Camera camGestureTest; public GameObject objRotateTarget; public float fGestureRadius = 50; public float fGestureRadiusFix = 10; public float fRotateFactor = 500f;//旋转系数 private Vector3 _v3AroundCenterPoint; private bool _bGesturing; private Vector3 _v3LastStarPoint; private float _fSampleDisThreshold; private List<Vector3> _inputGesturePhases = new List<Vector3>(); private float _fTotalRotate; System.Action OnRotateFinish; // Use this for initialization void Awake () { _fSampleDisThreshold = fGestureRadius / 4f;//(2*PI/24),PI~=3 _v3AroundCenterPoint = camGestureTest.WorldToScreenPoint(objRotateTarget.transform.position); _fTotalRotate = 0; } // Update is called once per frame void Update () { if (Input.GetMouseButtonDown(0)) { _bGesturing = true; _v3LastStarPoint = Input.mousePosition; } else if (Input.GetMouseButtonUp(0)) { _bGesturing = false; } if (_bGesturing) { //支持一个大概的圆形区,空心处理的小一点,就用修正值了 if (Vector3.Distance(_v3AroundCenterPoint, Input.mousePosition) < fGestureRadius + fGestureRadiusFix && Vector3.Distance(_v3AroundCenterPoint, Input.mousePosition) > fGestureRadiusFix) { var deltaVec = Input.mousePosition - _v3LastStarPoint; if (deltaVec.sqrMagnitude > _fSampleDisThreshold * _fSampleDisThreshold)//超过阈值,记录一下 { _inputGesturePhases.Add(deltaVec); if (_inputGesturePhases.Count > 1) { int curCount = _inputGesturePhases.Count; float multiDot = Vector3.Dot(_inputGesturePhases[curCount - 1], _inputGesturePhases[curCount - 2]); Vector3 multiCross = Vector3.Cross(_inputGesturePhases[curCount - 1], _inputGesturePhases[curCount - 2]); if (multiDot <= 0)//画圆只能是锐角 { _inputGesturePhases.Clear(); } else if (multiCross.z == 0 || (multiCross.z > 0 && !bIsClockWise) || (multiCross.z < 0 && bIsClockWise))//叉积右手法则,顺时针后一条叉前一条,z应该是正,z是0表示平行 { _inputGesturePhases.Clear(); } else { //通过上面几个条件测试表示是正在画一个圆,可以转动物体了 float rotateZ = bIsClockWise ? -1 * fRotateFactor * Time.deltaTime : 1 * fRotateFactor * Time.deltaTime; _fTotalRotate += rotateZ; objRotateTarget.transform.Rotate(new Vector3(0, 0, rotateZ)); _v3LastStarPoint = Input.mousePosition; if (Mathf.Abs(_fTotalRotate) > 360) { Debug.Log("Around callbakc here"); _fTotalRotate = 0; } } } } } else { _inputGesturePhases.Clear();//乱画就清除路径,重新来过 } } } }
想要看上面代码的效果,只需要新建一个带摄像机的空场景,建立一个cube,放在屏幕可见的位置,然后脚本挂在摄像机上并拖上参数(如图)运行:
运行以后试着在物体的周围逆时针画圈,物体就能开始转动啦.
因为是测试,所以代码中只有mouse的检测而没有涉及到Input.Touch的逻辑,如果要支持移动端操作,这方面我在正式代码中采用了LeanTouch插件,是免费而且开源的,有兴趣的话可以检索unity商店下载并自行替换.
现在来解释一下代码的大概思路:
1.当点击屏幕且未松开的情况下,只要手指移动一段距离,就把这个路径记录在list内.
2.当list中有两个元素以后,计算这两条路径的角度和角度的方向.
3.如果满足期望,就认为是在画圈的操作中,否则就认为用户没有按照期望来画圈,清空所有路径.
看了上面三条以后,可以知道代码的核心算法其实就是求向量的点积和叉积:
float multiDot = Vector3.Dot(_inputGesturePhases[curCount - 1], _inputGesturePhases[curCount - 2]); Vector3 multiCross = Vector3.Cross(_inputGesturePhases[curCount - 1], _inputGesturePhases[curCount - 2]);
点积可以判断向量的角度,而叉积可以知道这个角度的方向,也就是说是顺时针方向的角还是逆时针方向的角.
当我们的操作通过了距离,角度,方向的种种判断之后,可以认为用户的操作是正确的,因此,代码中将目标物体旋转了一个小小的角度.当用户持续操作,我们创建的cube就可以旋转完整的360度了.
在实际的开发中,可能我们遇到的情况会比这个更复杂,比如无论正逆都可以接受,或者逻辑和表现剥离后加入各类回调,或者是范围的控制这些其实都好解决,只要在对应的if判断前后做出修改即可.
相关文章推荐
- 用最简单的方式判断一个LONG整形数为2^ N
- Unity3D学习(五):实现一个简单的视觉感知
- 输入两个整数序列。其中一个序列表示栈的push顺序, 判断另一个序列有没有可能是对应的pop顺序。 为了简单起见,我们假设push序列的任意两个整数都是不相等的
- 一个判断点是否在三角形内的简单方法
- 【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!
- JavaScript,一个超级简单的方法判断浏览器的内核前缀
- PureMVC和Unity3D的UGUI制作一个简单的员工管理系统实例
- (iphone/ipad)一个简单的用代码判断当前设备的方法
- 实现一个简单的Unity3D三维拾取——3D Picking (1)
- unity3d射线的原理用法以及一个利用射线实现简单拾取的小例子
- c/c++ 使用boost库实现的一个简单判断字符串编码的方法
- 关于字符串的一个简单的习题--输入一个数字,判断是几位数,打印每个数字及其重复的次数,依次打印个位到最高位
- (转)【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!
- 多线段几何图形—— 简单几何图形(判断一个点是否在图形的内部)
- 【swift3.0】【解决手势冲突问题】【简单的一个方法】
- [Unity3D]手机3D游戏开发:简单的移动和缩放鼠标手势脚本源码
- Unity3d射线的原理用法以及一个利用射线实现简单拾取的小例子
- 【Android游戏开发十六】Android Gesture之【触摸屏手势识别】操作!利用触摸屏手势实现一个简单切换图片的功能!
- 【unity3d游戏开发之基础篇】unity3d射线的原理用法以及一个利用射线实现简单拾取的小例子
- 一个简单的3DTouch、Peek和Pop手势Demo,附github地址