需求
转盘速度开始速度较慢,然后逐渐加速,达到最大速度保持一段时间,然后减速,保证指针最终可以选择到制定角度。
核心内容
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));
}
}
}
代码下载:http://download.youkuaiyun.com/download/u011484013/9989267