Unity计时器设计 - 基础计时器

来源:互联网 发布:德国巧克力价格 知乎 编辑:程序博客网 时间:2024/06/09 03:39

Unity计时器设计 - 基础计时器

在Unity中,Time类的功能较少,例如Time.time在Awake等函数中无法获取,并且没有计时器概念等,大部分项目有计时器的需求,这篇文章将实现一个自己定义的计时器。


在开始写代码之前,先总结需求:

计时器应当具有以下操作:

  • 设置计时器
  • 开始和取消计时器
  • 暂停和继续计时器
  • 重置计时器
  • 一系列事件(OnStart,OnUpdate,OnCancel,OnEnd等)。

并且具有这些属性:

  • 计时器时间:开始、剩余、到时、总时长。
  • 计时器状态:未开始,运行中,暂停中。

设计完以上内容后,可以做这些事情:

  • 延时函数
  • 一切基于时间执行的概念,例如技能,类似cocos2d-x的动作系统等。
  • 很多情况下,计时器不希望随挂载对象被销毁时消失,所以Timer不继承于MonoBehaviour。

总结完可以开始写了。
首先,添加引用

using UnityEngine;using System;

可以运行的最基础的计时器:

//注意不继承于MonoBehaviorpublic class Timer{    //开始时间    public float StartTime { get; private set; }    //持续时间    public float Duration { get; private set; }    //结束时间    public float EndTime { get; private set; }    //当前时间    public float CurTime { get; private set; }    //运行标识    public bool IsStart { get; private set; }    //开始和结束事件,这里直接用System.Action(相当于空返回值无参数委托)    public Action OnStart { get; set; }    public Action OnEnd { get; set; }    public Action OnUpdate { get; set; }    //构造函数,设置计时器    public Timer(float duration)    {        Duration = duration;    }    //开始计时 Timer类不继承于MonoBehaviour,该方法不会在任何对象开始时被调用。    public void Start()    {        IsStart = true;        StartTime = Time.time;        CurTime = StartTime;        EndTime = StartTime + Duration;        if(OnStart != null) OnStart();    }    //更新时间,并检查状态。Timer类不继承于MonoBehaviour,该方法将在中心计时器每帧调用。    public void Update()    {        if (!IsStart) return;        CurTime += Time.deltaTime;        if(CurTime > EndTime)        {            End();        }        else if (OnUpdate != null) OnUpdate();    }    //计时器结束    void End()    {        IsStart = false;        if(OnEnd!= null) OnEnd();    }}
  • 新增取消
//取消事件public Action OnCancel { get; set; }//取消接口。public void Cancel(){    IsStart = false;    if(OnCancel != null) OnCancel();}
  • 新增暂停和继续
//事件public Action OnPause { get; set; }public Action OnContinue { get; set; }//属性public bool IsPause { get; private set; }//取消接口public void Pause(){    IsPause = false;    if(OnCancel != null) OnCancel();}//继续接口public void Continue(){    IsPause = true;    if(OnContinue!= null) OnContinue();}//Update逻辑需要更改public void Update(){    if (!IsStart) return;    CurTime += Time.deltaTime;    if(IsPause) EndTime += Time.deltaTime;    if(CurTime > EndTime)    {        End();    }    else if (OnUpdate != null) OnUpdate();}
  • 新增重置
//重置接口public void Reset(){    IsStart = false;    IsPause = false;}

一个简单的计时器就这样完成了。
但是我们往往需要获取计时器的各种属性,下面新增一些public属性:

  • 计时器已经完成的百分比,常用于
public float Ratio{    get    {        if(!IsStart)        {            return 0;        }        else        {            return 1 - (EndTime - CurTime) / Duration;        }    }}
  • 计时器次数,可用于循环计时、检测是否已经完成等。(常规循环计时推荐新定义循环计时器)
//开始次数public int StartCount { get; private set; }//完成次数public int FinishCount { get; private set; }//Start修改public void Start(){    IsStart = false;    StartTime = Time.time;    CurTime = StartTime;    EndTime = StartTime + Duration;    //新增这一行↓    StartCount++;    if(OnStart != null) OnStart();}//End修改void End(){    IsStart = true;    //新增这一行↓    FinishCount++;    if(OnEnd!= null) OnEnd();}

简单的计时器设计完成啦!
但是还不可以运行,毕竟Update还不会主动调用。

我们可以先简单写一个中心计时器来解决问题:
新建CenterTimer.cs:

using UnityEngine;using System.Collections.Generic;//因为中心计时器应该只有一个,所以所有新定义的成员都应该为静态成员。public Class CenterTimer : MonoBehaviour{    static List<Timer> timers = new List<Timer>();    //添加计时器    public static void AddTimer(Timer timer)        {        timers.Add(timer);    }    //移除计时器    public static void RemoveTimer(Timer timer)    {        timers.Remove(timer);    }    //每帧更新    void Update()    {        foreach(var timer in timers)        {            timer.Update();        }    }}

同时对Timer类做一点点修改:

public void Start(){    IsStart = true;    StartTime = Time.time;    CurTime = StartTime;    EndTime = StartTime + Duration;    //新增这一行↓    CenterTime.AddTimer(this);    StartCount++;    if(OnStart!= null) OnStart();}//计时器结束void End(){    IsStart = false;    if(OnEnd!= null) OnEnd();    //新增这一行↓    CenterTimer.RemoveTimer(this);}public void Reset(){    IsStart = false;    IsPause = false;    //新增这一行↓    CenterTimer.RemoveTimer(this);}

使用方法如下:
Test.cs 挂在一个GameObject上
CenterTimer.cs 挂在摄像头上。

using UnityEngine;public class Test : MonoBehaviour{    Timer timer;    void Update()    {        if(Input.GetKeyDown(KeyCode.T))        {            timer = new Timer(3f);            timer.OnUpdate += SetScale;            timer.OnEnd += Hide;            timer.Start();        }    }    //缩放动画    void SetScale()    {        float scale = 1 - timer.Ratio;        gameObject.transform.localScale = new Vector3(scale, scale, scale);    }    void Hide()    {        gameObject.SetActive(false);    }}

执行游戏并按下T键,我们可以看到该对象在3秒内从大变小到完全消失。

0 0
原创粉丝点击