公司要做一个转盘的抽奖,因为想让转盘像现实生活中的,慢慢加速慢慢减速,但是最后的减速还要确定目标位置,所以呢,抱起了高中的数学书
匀加速直线运动
百度百科:https://baike.baidu.com/item/%E5%8C%80%E5%8A%A0%E9%80%9F%E7%9B%B4%E7%BA%BF%E8%BF%90%E5%8A%A8
好吧,下面直接上代码,代码放unity里,直接把脚本挂到物体上,把转盘拖到wheel上,就能转动了,如果想改什么参数,具体的参数我都列出来了,看看注释
启动的话仔细看屏幕左上角,有一个输入框,表示转到第几个格子,格子索引从1开始
using UnityEngine;
public class LuckyWheelDemo : MonoBehaviour {
public Transform wheel;//转盘
public bool isRun = false;//转盘是否在转动
public float speedUpTime = 2;//用多久时间来加速
public float highSpeedTime = 3;//在最高速运行多久
public float maxSpeed = 500;//最高速
public int areaCount = 8;//转盘一共多少个区域
private float runTime;//转盘转动多久了
private float curSpeed;//当前速度
private float stopZ;//停止的Z轴坐标
private float speedCutTime = 1;//减速时间
private float lastFrameSpeed;//上一帧的速度
private float acceleration;//加速度
private bool isSpeedCut;//是否开始减速
public string input;
public void OnGUI()
{
input = GUILayout.TextField(input);
if (GUILayout.Button("Rotate"))
{
RunWheel(int.Parse(input));
}
}
/// <summary>
/// 运行转盘
/// </summary>
/// <param name="idx">转到哪个格子</param>
public void RunWheel(int idx)
{
if (isRun) return;
Init(idx);
}
/// <summary>
/// 获取目标格子的随机角度
/// </summary>
/// <param name="idx">格子索引</param>
/// <returns></returns>
public float GetRandomEndZ(int idx)
{
float areaAngle = 360f / areaCount;
float endZ = areaAngle * idx;
float offZ = UnityEngine.Random.Range(0.1f, areaAngle - 0.1f)-(areaAngle/2);
return endZ + offZ;
}
/// <summary>
/// 设置减速时间和加速度
/// </summary>
/// <param name="curZ">当前转盘的Z角度</param>
public void SetSpeedCutTime(float curZ)
{
lastFrameSpeed = maxSpeed;
float angle;
if (curZ < stopZ)
angle = curZ + 360 - stopZ + 360;
else
angle = curZ - stopZ + 360;
speedCutTime = angle / (maxSpeed / 2);
Debug.Log("角度:"+angle+" 减速时间:"+speedCutTime);
acceleration = maxSpeed / speedCutTime;
}
/// <summary>
/// 初始化转盘数据
/// </summary>
/// <param name="idx">转到哪个格子</param>
private void Init(int idx)
{
runTime = 0;
speedCutTime = 1;
isSpeedCut = false;
stopZ = GetRandomEndZ(idx);
isRun = true;
}
private void Update()
{
if (isRun)
{
if (runTime <= speedUpTime)//加速阶段
{
wheel.Rotate(Vector3.back * curSpeed * Time.deltaTime);
runTime += Time.deltaTime;
curSpeed = runTime / speedUpTime * maxSpeed;
}
else if (runTime <= speedUpTime + highSpeedTime)//全速转动阶段
{
wheel.Rotate(Vector3.back * maxSpeed * Time.deltaTime);
runTime += Time.deltaTime;
}
else if (runTime <= speedUpTime + highSpeedTime + speedCutTime)//减速阶段
{
if (!isSpeedCut)//有没有初始化减速数据
{
SetSpeedCutTime(wheel.localRotation.eulerAngles.z);
isSpeedCut = true;
}
float nowSpeed = maxSpeed - (runTime - speedUpTime - highSpeedTime)*acceleration;
wheel.Rotate(Vector3.back*(nowSpeed+lastFrameSpeed)*0.5f*Time.deltaTime);
lastFrameSpeed = nowSpeed;
runTime += Time.deltaTime;
}
else//停止转动
{
isRun = false;
}
}
}
}