最近的项目中要用到简单的计时功能,又因为函数的构造已经写好了,不想去改变,所以最后用了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,所有在启动协程上使用了取巧的方式
///
/// 调用携程,需要借助这个类
///
public class CountTimeGameObject : MonoBehaviour
{
public static void PrintT(string msg) {
Debug.Log(msg);
}
}
在第一次计时时会创建一个空的对象去挂载这个脚本,然后将这个实例的引用抓在手里,后面全部通过这个behaviour的子类去启动协程
最开始的方法是在begin时需要将调用者传入以执行协程,后面觉得不够方便,违反了工具类的实质,而且不是所有的调用者都继承了monobehaviour
///
/// 更新频率,执行update的频率
///
public enum UpdateLevel
{
S,//1秒
S0,//0.1秒
S00//0.01秒
}
///
/// 计时器的三种状态
///
public enum CountTimeStateType{
STOPED,
PLAYING,
PAUSED
}
///
/// 操作类型
///
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
{
///
/// 对CountTimeModel的调用做一层封装,添加了一些处理
///
public class CountTime
{
public static CountTimeGameObject CountTimeObject;
///
/// 计时
///
/// 时间
///
public static CountTimeModel Count(float time)
{
if (!checkTimeAvailable(time)) {
return null;
}
checkCountTimeObject();
CountTimeModel timeModel = new CountTimeModel(time);
return timeModel;
}
///
/// 计时
///
/// 时间
/// 刷新频率(调用update),默认为0.1s
///
public static CountTimeModel Count(float time, UpdateLevel level)
{
if (!checkTimeAvailable(time))
{
return null;
}
checkCountTimeObject();
CountTimeModel timeModel = new CountTimeModel(time, level);
return timeModel;
}
///
/// 计时
///
/// 时间
/// 是否真实时间,默认为游戏中时间
///
public static CountTimeModel Count(float time, bool isRealTime)
{
if (!checkTimeAvailable(time))
{
return null;
}
checkCountTimeObject();
CountTimeModel timeModel = new CountTimeModel(time, isRealTime);
return timeModel;
}
///
/// 计时
///
/// 时间
/// 刷新频率(调用update),默认为0.1s
/// 是否真实时间,默认为游戏中时间
///
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();
}
}
static bool checkTimeAvailable(float time) {
if (time <= 0)
return false;
return true;
}
}
///
/// 调用携程,需要借助这个类
///
public class CountTimeGameObject : MonoBehaviour
{
public static void PrintT(string msg) {
Debug.Log(msg);
}
}
///
/// 更新频率,执行update的频率
///
public enum UpdateLevel
{
S,//1秒
S0,//0.1秒
S00//0.01秒
}
///
/// 计时器的三种状态
///
public enum CountTimeStateType{
STOPED,
PLAYING,
PAUSED
}
///
/// 操作类型
///
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 _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;
}
}
///
/// 开始
///
public void Begin()
{
if (_state != CountTimeStateType.STOPED)
return;
if (_beginAction != null)
{
_beginAction();
}
_currentTime = 0;
CountTime.CountTimeObject.StartCoroutine(updateTime());
}
///
/// 暂停
///
public void Pause() {
if (_state != CountTimeStateType.PLAYING)
return;
_operation = OperationType.PAUSED;
}
///
/// 继续
///
public void Continue() {
if (_state != CountTimeStateType.PAUSED)
return;
_operation = OperationType.NORMAL;
CountTime.CountTimeObject.StartCoroutine(updateTime());
}
///
/// 停止
///
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 ac)
{
_updateAction = ac;
return this;
}
public CountTimeModel OnEnd(Action ac)
{
_endAction = ac;
return this;
}
public CountTimeModel OnStop(Action ac) {
_stopAction = ac;
return this;
}
}
}