Unity转盘抽奖
发表于2018-08-01
多数游戏为了照顾玩家,会推出一个抽奖的机制,本篇文章和大家介绍下在开发中如何实现转盘抽奖。
需求
转盘速度开始速度较慢,然后逐渐加速,达到最大速度保持一段时间,然后减速,保证指针最终可以选择到制定角度。
核心内容
1、计算转盘选择角度,使转盘最终可以在制定角度停止

首先需要获取旋转终点的坐标,通过坐标获取目标方向的向量
在单位圆上任意一点的坐标可以表示为(cos(angle),sin(angle))
目标点的方向向量为
Vector3 calculateDir(float endAngle){ float radiansX = Mathf.Cos( Mathf.PI *(endAngle + 90) / 180); float radiansY = Mathf.Sin( Mathf.PI *(endAngle + 90) / 180); return new Vector3 (radiansX, radiansY, 0); }
endAngle + 90:因为我们采用的是y轴,所以有90度偏差。
这里主要通过控制旋转对象的y方向 与 目标方向的夹角,进行旋转控制,通过Vector3.Angle (dir1, dir2)判断两个向量的夹角,当夹角小于某一值比如5,我们就可以认为已经旋转到了目标位置
但是如果Vector3.Angle返回的角度是在0-180度之间的,而我们需要的角度是在0-360度之间的,因此需要进行修正

dir1是目标方向,dir2是旋转对象y方向
通过获取目标方向与旋转对象y方向的叉乘结果,如果结果大于0,不需要修正,小于0,需要进行取360度的补交修正。
2、转盘速度控制,实现加速、匀速、减速的效果
转盘选择这里采用的是最简单的方式transform.Rotate (new Vector3 (0, 0, speed)) 的方法,通过转盘旋转的时间,动态修改speed的值。
加速:speed初始值为0,通过rotateTimer -= Time.deltaTime进行加速。
匀速:时间控制
if(moveState==1 && (rotateTimer>0 || getAngle()<270)){。。。}
rotateTimer是计时器,计算旋转保持的时间。
moveState是旋转的状态,1表示旋转持续,2表示减速旋转,主要充当标志作用,放置两种状态混淆。
getAngle()<270:当角度在270度以上的时候才开始逐渐减速,否则显示不出来减速的过程。
代码:
using UnityEngine; using System.Collections; /// <summary> /// 通过目标点的角度,计算目标点的位置 /// 计算目标点的位置,计算目标点的方向向量 /// 旋转 转动对象 /// /// 速度控制 /// 减速 /// /// 判断当前y方向与目标向量的夹角 /// 如果夹角小于某一值,认为达到终点,停止旋转 /// /// </summary> public class RotateTest : MonoBehaviour { public float endAngle=100;//旋转停止位置,相对y坐标方向的角度 public Vector3 targetDir;//目标点的方向向量 bool isMoving=false;//是否在旋转 public float speed=0;//当前的旋转速度 public float maxSpeed=10;//最大旋转速度 public float minSpeed=0.8f;//最小旋转速度 float rotateTimer=2;//旋转计时器 public int moveState=0;//旋转状态,旋转,减速 public int keepTime = 3;//旋转减速前消耗的时间 //按照顺时针方向递增 string[] rewards = {"8等奖","7等奖","6等奖","5等奖","4等奖","3等奖","2等奖","1等奖","10等奖","9等奖"}; void Start () { targetDir = new Vector3 (0, 1, 0); // Vector3.Angle (targetDir,transform.up); } void Update () { if(Input.GetKeyDown(KeyCode.A)){ StartMove (); } if(Input.GetKey(KeyCode.S)){ transform.Rotate (new Vector3(0,0,maxSpeed)); } if(isMoving){ if(moveState==1 && (rotateTimer>0 || getAngle()<270)){//如果旋转时间小于旋转保持时间,或者大于旋转保持时间但是与停止方向角度小于270,继续保持旋转 rotateTimer -= Time.deltaTime; if(speed<maxSpeed) speed += 1; transform.Rotate (new Vector3(0,0,speed)); }else{//减速旋转,知道停止在目标位置 moveState = 2; if (speed > minSpeed) speed -= 7*speed / 10; if (getAngle () > 10) transform.Rotate (new Vector3 (0, 0, speed)); else {//stop endMove(); } } } } #region 计算当前对象y方向与目标方向的夹角 float getAngle () { return calAngle (targetDir, transform.up);//计算y轴方向的旋转角度 } //计算从dir1旋转到dir2的角度 float calAngle (Vector3 dir1, Vector3 dir2) { float angle = Vector3.Angle (dir1, dir2); Vector3 normal = Vector3.Cross (dir1, dir2); // Debug.Log ("normal="+normal); // angle = normal.z > 0 ? angle : (180+(180-angle)); angle = normal.z > 0 ? angle : (360 - angle); return angle; } #endregion /// <summary> /// 计算目标位置的向量 /// Calculates the dir. /// </summary> /// <param name="endAngle">End angle.</param> Vector3 calculateDir(float endAngle){ float radiansX = Mathf.Cos( Mathf.PI *(endAngle + 90) / 180); float radiansY = Mathf.Sin( Mathf.PI *(endAngle + 90) / 180); return new Vector3 (radiansX, radiansY, 0); } void endMove(){ speed = 0; isMoving = false; moveState = 0; } void StartMove(){ if (isMoving) return; int index=Random.Range (0, 10) - 1; Debug.Log ("恭喜你获得"+rewards[index]); endAngle = index * 360/10;//获得目标位置相对y坐标方向的角度 targetDir = calculateDir (endAngle);//获得目标位置方向向量 rotateTimer = keepTime; isMoving = true; moveState = 1; } void OnGUI(){ if(GUILayout.Button("move")){ StartMove (); } // if(GUILayout.Button("rotate")){ // recTeansform.DORotate (new Vector3(0,0,recTeansform.position.z+endAngle),2f,RotateMode.Fast); // } if(GUILayout.Button("dir")){ Debug.Log("up angle:"+calAngle (targetDir,transform.up)); Debug.Log("right angle:"+calAngle (targetDir,transform.right)); Debug.Log("forward angle:"+calAngle (targetDir,transform.forward)); } } }
如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引