您的位置:首页 > 移动开发 > Unity3D

Unity简单计时器,实现随时播放,暂停,继续,停止

2017-11-28 18:45 344 查看
最近的项目中要用到简单的计时功能,又因为函数的构造已经写好了,不想去改变,所以最后用了dotween模拟计时功能,闲下来时就自己实现了一个简易的计时器

首先是状态图



计时器由三个状态组成,停止状态,播放状态和暂停状态,其中的切换逻辑见图

因为是一个工具类,所有为了使用上尽可能的简单,我在调用方式上模仿了dotween的使用方式

大致是这样的

CountTimeModel model1;
void Start () {
//计时5秒
model1 = CountTime.Count(5)
.OnBegin(delegate
{
Debug.Log("开始");
})
.OnEnd(delegate {
Debug.Log("结束");
})
.OnStop(delegate {
Debug.Log("停止");
})
//更新,可以指定更新频率
.OnUpdate(onTimeUpdate);

model1.Begin();
model1.Pause();
model1.Continue();
model1.Stop();
}
// update对应的回调需要有一个float参数
void onTimeUpdate(float time)
{
Debug.Log(time);
}

首先定义一个CountTimeModel对象,局部和全局的都可以,如果想在任意地方去暂停播放最好用全局类型

pause函数可以暂停计时,continue可以从之前的进度重新开始,这两个函数特别好用

内部实现原理,我使用了unity的协程机制,但是因为工具类没有继承自monobehaviour,所有在启动协程上使用了取巧的方式

/// <summary>
/// 调用携程,需要借助这个类
/// </summary>
public class CountTimeGameObject : MonoBehaviour
{
public static void PrintT(string msg) {
Debug.Log(msg);
}
}
在第一次计时时会创建一个空的对象去挂载这个脚本,然后将这个实例的引用抓在手里,后面全部通过这个behaviour的子类去启动协程

最开始的方法是在begin时需要将调用者传入以执行协程,后面觉得不够方便,违反了工具类的实质,而且不是所有的调用者都继承了monobehaviour

/// <summary>
/// 更新频率,执行update的频率
/// </summary>
public enum UpdateLevel
{
S,//1秒
S0,//0.1秒
S00//0.01秒
}

/// <summary>
/// 计时器的三种状态
/// </summary>
public enum CountTimeStateType{
STOPED,
PLAYING,
PAUSED
}

/// <summary>
/// 操作类型
/// </summary>
public enum OperationType {
NORMAL,//正常类型
PAUSED,//暂停操作
STOP//停止操作
}
在创建计时实例时可以指定update刷新的类型,是通过UpdateLevel类型实现的,控制每多久执行一个update回调

其他两个类型用来控制状态的切换

最后是全部的代码,如果在使用过程中发现有什么问题或者需要改进,添加的功能都可以留言告诉我,我自己也在用这个脚本,慢慢优化

// ========================================================
// 描 述:计时工具类
// 作 者:xzf
// 创建时间:2017/11/14 15:36:35
// 版 本:v 1.0
// ========================================================
using System;
using System.Collections;
using UnityEngine;

namespace StoneTools
{
/// <summary>
/// 对CountTimeModel的调用做一层封装,添加了一些处理
/// </summary>
public class CountTime
{
public static CountTimeGameObject CountTimeObject;

/// <summary>
/// 计时
/// </summary>
/// <param name="time">时间</param>
/// <returns></returns>
public static CountTimeModel Count(float time)
{
if (!checkTimeAvailable(time)) {
return null;
}
checkCountTimeObject();
CountTimeModel timeModel = new CountTimeModel(time);
return timeModel;
}

/// <summary>
/// 计时
/// </summary>
/// <param name="time">时间</param>
/// <param name="level">刷新频率(调用update),默认为0.1s</param>
/// <returns></returns>
public static CountTimeModel Count(float time, UpdateLevel level)
{
if (!checkTimeAvailable(time))
{
return null;
}
checkCountTimeObject();
CountTimeModel timeModel = new CountTimeModel(time, level);
return timeModel;
}

/// <summary>
/// 计时
/// </summary>
/// <param name="time">时间</param>
/// <param name="isRealTime">是否真实时间,默认为游戏中时间</param>
/// <returns></returns>
public static CountTimeModel Count(float time, bool isRealTime)
{
if (!checkTimeAvailable(time))
{
return null;
}
checkCountTimeObject();
CountTimeModel timeModel = new CountTimeModel(time, isRealTime);
return timeModel;
}

/// <summary>
/// 计时
/// </summary>
/// <param name="time">时间</param>
/// <param name="level">刷新频率(调用update),默认为0.1s</param>
/// <param name="isRealTime">是否真实时间,默认为游戏中时间</param>
/// <returns></returns>
public static CountTimeModel Count(float time, UpdateLevel level, bool isRealTime)
{
if (!checkTimeAvailable(time))
{
return null;
}
checkCountTimeObject();
CountTimeModel timeModel = new CountTimeModel(time, isRealTime);
return timeModel;
}

static void checkCountTimeObject()
{
if (CountTimeObject == null)
{
GameObject tGO = new GameObject("【CountTimeObject】");
CountTimeObject = tGO.AddComponent<CountTimeGameObject>();
}
}

static bool checkTimeAvailable(float time) {
if (time <= 0)
return false;
return true;
}
}

/// <summary> /// 调用携程,需要借助这个类 /// </summary> public class CountTimeGameObject : MonoBehaviour { public static void PrintT(string msg) { Debug.Log(msg); } }

/// <summary> /// 更新频率,执行update的频率 /// </summary> public enum UpdateLevel { S,//1秒 S0,//0.1秒 S00//0.01秒 } /// <summary> /// 计时器的三种状态 /// </summary> public enum CountTimeStateType{ STOPED, PLAYING, PAUSED } /// <summary> /// 操作类型 /// </summary> public enum OperationType { NORMAL,//正常类型 PAUSED,//暂停操作 STOP//停止操作 }

public class CountTimeModel
{
private float _aimTime;
private float _currentTime = 0;
private float _updateValue = 0.1f;
private bool _isRealTime = false;

Action _beginAction; //开始
Action<float> _updateAction;//更新
Action _endAction; //正常结束
Action _stopAction; //中途停止

//记录当前状态
private CountTimeStateType _state = CountTimeStateType.STOPED;
//记录上一步执行的操作
private OperationType _operation = OperationType.NORMAL;

public CountTimeModel(float cTime)
{
_aimTime = cTime;
}

public CountTimeModel(float cTime, bool isRealTime)
{
_aimTime = cTime;
_isRealTime = isRealTime;
}

public CountTimeModel(float cTime, UpdateLevel level)
{
_aimTime = cTime;
setUpdateLevel(level);
}

public CountTimeModel(float cTime, UpdateLevel level, bool isRealTime) {
_aimTime = cTime;
setUpdateLevel(level);
_isRealTime = isRealTime;
}

void setUpdateLevel(UpdateLevel level) {
switch (level)
{
case UpdateLevel.S:
_updateValue = 1f;
break;
case UpdateLevel.S0:
_updateValue = 0.1f;
break;
case UpdateLevel.S00:
_updateValue = 0.01f;
break;
default:
break;
}
}

/// <summary>
/// 开始
/// </summary>
public void Begin()
{
if (_state != CountTimeStateType.STOPED)
return;
if (_beginAction != null)
{
_beginAction();
}
_currentTime = 0;
CountTime.CountTimeObject.StartCoroutine(updateTime());
}

/// <summary>
/// 暂停
/// </summary>
public void Pause() {
if (_state != CountTimeStateType.PLAYING)
return;
_operation = OperationType.PAUSED;
}

/// <summary>
/// 继续
/// </summary>
public void Continue() {
if (_state != CountTimeStateType.PAUSED)
return;
_operation = OperationType.NORMAL;
CountTime.CountTimeObject.StartCoroutine(updateTime());
}

/// <summary>
/// 停止
/// </summary>
public void Stop() {
if (_state == CountTimeStateType.STOPED)
return;
_operation = OperationType.STOP;
}

IEnumerator updateTime()
{
_state = CountTimeStateType.PLAYING;
if (_isRealTime)
{
while (_currentTime < _aimTime)
{
//停止计时
if (_operation != OperationType.NORMAL)
break;
yield return new WaitForSecondsRealtime(_updateValue);
_currentTime += _updateValue;
if(_updateAction != null)
_updateAction(_currentTime);
}
}
else
{
while (_currentTime < _aimTime)
{
//停止计时
if (_operation != OperationType.NORMAL)
break;
yield return new WaitForSeconds(_updateValue);
_currentTime += _updateValue;
if (_updateAction != null)
_updateAction(_currentTime);
}
}
if (_operation == OperationType.STOP)
{
if (_stopAction != null)
_stopAction();
_state = CountTimeStateType.STOPED;
}
else if (_operation == OperationType.NORMAL)
{
if (_endAction != null)
_endAction();
_state = CountTimeStateType.STOPED;
}
else if (_operation == OperationType.PAUSED) {
_state = CountTimeStateType.PAUSED;
}
_operation = OperationType.NORMAL;
yield return 0;
}

public CountTimeModel OnBegin(Action ac)
{
_beginAction = ac;
return this;
}

public CountTimeModel OnUpdate(Action<float> ac)
{
_updateAction = ac;
return this;
}

public CountTimeModel OnEnd(Action ac)
{
_endAction = ac;
return this;
}

public CountTimeModel OnStop(Action ac) {
_stopAction = ac;
return this;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: