Unity幸运转盘实战项目
幸运转盘主要是由两部分组成——转盘、指针,实现的方式也分两种,转盘动或者指针动,不过两者的原理都是一样的,这里就以指针动做了一个项目级的demo(由于后面的圆盘中间的那条竖线有点往左偏,所以导致那些圣诞老人的显示有些偏移)。< Demo 下载 >
在项目开发中,一般这个功能的实现过程是:
1、当点击开始的时候,转盘开始动, 同时向服务端发送协议;
2、服务端返回数据(前端计算好对应的角度),当转盘旋转一定时间后开始减速直至对应角度
当然也可以等服务端返回数据后再开始模拟旋转过程,但是由于受网络的影响,这一过程可能会较长,表现效果不是很好。
关于Unity的旋转,主要有下面几类接口:Transform.Rotate(), Transform.RotateAround(),Transform.rotation, Transform.eulerAngles。 其中 Rotate() 和 RotateAround() 都是同一类接口(里面的具体重载这里就不细说了),都是指从当前位置做指定角度的偏移,而 rotation 和 eulerAngles 都是直接赋值的字段,rotation 是一个四元数类型, eulerAngles 则是一个欧拉角。很显然,我们在做旋转的时候不需要关心具体角度,使用 Rotate() 类型做定帧偏移是最合适的,通过设置偏移的角度就能实现变速转动,比较适合转盘开始阶段的加速过程和中间的匀速过程,而当我们知道停止的具体角度时,则可已利用差值运算能精准地实现减速过程并最终停到我们需要的位置。但是有一点需要注意,Unity里面角度是逆时针计算的,而我们日常生活中一般习惯于顺时针,所以,最终的角度还需要取反一下。废话不多说,见代码:
using UnityEngine; using UnityEngine.UI; public class LuckyTurntable : MonoBehaviour { public enum State { None, //待机状态 Start, //加速阶段 Prepared, //等待数据阶段 End, //减速阶段 } public delegate void OnFinishCallback(); private event OnFinishCallback OnFinish; /// <summary> /// 设置完成时的回调 /// </summary> /// <param name="onFinish"></param> public void SetOnFinishCallback(OnFinishCallback onFinish) { OnFinish += onFinish; } /// <summary> /// 最大速度 /// </summary> public int velocity = 3000; public Transform node; public Button btnStart; public Button btnStop; public Button btnRandom; public InputField input; private State _state; /// <summary> /// 转盘的状态 /// </summary> public State CurState { get { return _state; } private set { _state = value; switch (value) { //不同阶段限制各按钮的点击状态 case State.None: btnStart.enabled = true; btnStop.enabled = false; btnRandom.enabled = false; break; case State.Start: btnStart.enabled = false; btnStop.enabled = true; btnRandom.enabled = true; break; case State.Prepared: case State.End: btnStart.enabled = false; btnStop.enabled = false; btnRandom.enabled = false; break; } } } private float _endAngle = 0f; /// <summary> /// 最终停止的角度[0, 360] /// </summary> public float EndAngle { get { return _endAngle; } set { _endAngle = Mathf.Abs(value); print("End Angle: " + value); _endAngle = _endAngle % 360; //将角度限定在[0, 360]这个区间 _endAngle = -_endAngle - 360 * 2; //多N圈并取反,圈数能使减速阶段变得更长,显示更自然,逼真 } } /// <summary> /// 加速持续时间 /// </summary> private readonly float AcceleateTime = 1f; /// <summary> /// 减速前的最短持续时间 /// </summary> private float _minTime = 3.0f; /// <summary> /// 角度缓存 /// </summary> private float _tmpAngle = 0f; /// <summary> /// 时间统计 /// </summary> private float _time; /// <summary> /// 速度变化因子 /// </summary> private float _factor; private void Start() { CurState = State.None; btnStart.onClick.AddListener(OnStartClick); btnStop.onClick.AddListener(OnStopClick); btnRandom.onClick.AddListener(OnRandomClick); } private void Update() { if (CurState == State.None) return; _time += Time.deltaTime; if (CurState == State.End) { //通过差值运算实现精准地旋转到指定角度(球型插值无法实现大于360°的计算) float k = 2f; //如果嫌减速太慢,可以加个系数修正一下 _tmpAngle = Mathf.Lerp(_tmpAngle, EndAngle, Time.deltaTime * k); //这里只存在一个方向的旋转,所以不存在欧拉角万向节的问题,所以使用欧拉角和四元数直接赋值都是可以的 node.rotation = Quaternion.Euler(0, 0, _tmpAngle); //node.eulerAngles = new Vector3(0, 0, _tmpAngle); if (1 >= Mathf.Abs(_tmpAngle - EndAngle)) { CurState = State.None; if (null != OnFinish) { OnFinish(); OnFinish = null; } } } else { //利用一个速度因子实现变加速的过程 _factor = _time / AcceleateTime; _factor = _factor > 1 ? 1 : _factor; node.Rotate(Vector3.back, _factor * velocity * Time.deltaTime, Space.Self); } //当收到数据之后并且旋转了一定时间后开始减速 if (CurState == State.Prepared && _time > _minTime) { CurState = State.End; _tmpAngle = GetCurClockwiseAngle(); } } /// <summary> /// 将当前指针的欧拉角转换成顺时针统计角度 /// </summary> /// <returns></returns> private float GetCurClockwiseAngle() { //由于读取到的值是[0, 180] U [-180, 0],左边由0至180递增,右边由180转变成-180,然后递增至0,所以需要转相应的转换 return (-1) * (360 - node.eulerAngles.z) % 360; } private void OnStartClick() { CurState = State.Start; _time = 0; } /// <summary> /// 读取输入框中的角度并停止 /// </summary> private void OnStopClick() { try { EndAngle = float.Parse(input.text); } catch { EndAngle = 0f; } CurState = State.Prepared; } /// <summary> /// 随机一个角度并停止 /// </summary> private void OnRandomClick() { EndAngle = UnityEngine.Random.Range(0f, 360f); CurState = State.Prepared; } }
功能代码基本都在上面了,如果想要Demo的话可 前往下载 。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
上一篇:详解C#设置Excel数据自适应行高、列宽的2种情况
栏 目:C#教程
下一篇:Unity3D实现物体闪烁效果
本文标题:Unity幸运转盘实战项目
本文地址:https://www.xiuzhanwang.com/a1/C_jiaocheng/4781.html
您可能感兴趣的文章
- 01-10Unity3d获取系统时间
- 01-10Unity3D获取当前键盘按键及Unity3D鼠标、键盘的基本操作
- 01-10Unity UGUI教程之实现滑页效果
- 01-10C#使用Protocol Buffer(ProtoBuf)进行Unity中的Socket通信
- 01-10C#在Unity游戏开发中进行多线程编程的方法
- 01-10C#中Socket与Unity相结合示例代码
- 01-10C#实现JSON解析器MojoUnityJson功能(简单且高效)
- 01-10Unity中C#和Java的相互调用实例代码
- 01-10利用unity代码C#封装为dll的步骤分享
- 01-10Unity3D实现批量下载图片功能
阅读排行
本栏相关
- 01-10C#通过反射获取当前工程中所有窗体并
- 01-10关于ASP网页无法打开的解决方案
- 01-10WinForm限制窗体不能移到屏幕外的方法
- 01-10WinForm绘制圆角的方法
- 01-10C#实现txt定位指定行完整实例
- 01-10WinForm实现仿视频播放器左下角滚动新
- 01-10C#停止线程的方法
- 01-10C#实现清空回收站的方法
- 01-10C#通过重写Panel改变边框颜色与宽度的
- 01-10C#实现读取注册表监控当前操作系统已
随机阅读
- 01-10SublimeText编译C开发环境设置
- 08-05DEDE织梦data目录下的sessions文件夹有什
- 08-05dedecms(织梦)副栏目数量限制代码修改
- 04-02jquery与jsp,用jquery
- 01-10delphi制作wav文件的方法
- 01-11ajax实现页面的局部加载
- 01-10C#中split用法实例总结
- 01-10使用C语言求解扑克牌的顺子及n个骰子
- 08-05织梦dedecms什么时候用栏目交叉功能?
- 01-11Mac OSX 打开原生自带读写NTFS功能(图文