unity前端架构之定时器完整代码实现

目录

前言:

一、定义定时器

1、定义帧定时器类

2、定义普通定时器

 二、定时器管理类


前言:

Unity游戏开发中需要定时器的原因主要有以下几点:

  1. 延迟操作:游戏中有很多需要在一定的时间间隔之后才能执行的操作。例如在某个角色死亡后需要重新生成、在物品被拾取后需要消失、在陷阱触发后需要一段时间再释放等等。此时就可以使用定时器来实现延迟操作,达到需要的效果。

  2. 倒计时:游戏中有很多需要倒计时的情况,例如任务倒计时、炸弹倒计时等。在这种情况下,我们可以使用定时器来记录时间并显示倒计时。当时间到达指定时间后,就可以执行相应的操作。

  3. 动画控制:在游戏中,一些动画需要精确的时间控制,例如闪烁、振动等。在这种情况下,定时器可以很好的帮助我们控制动画的播放时间和速度,使得动画可以按照我们的预期进行。

总之,定时器在Unity游戏开发中非常重要,可以帮助我们实现延迟操作、倒计时、精确的动画控制等功能。通过使用定时器,我们能够更加方便地控制游戏对象的行为和状态,从而提高游戏的玩家体验。

定时器是unity前端架构中必须有的一个模块功能。定时器一定要满足几个需求

第一、需要能够添加和删除定时器

第二、实现延时触发一次

第三、实现循环调用

第四、实现隔一定帧数调用一次


一、定义定时器

1、定义帧定时器类

帧定时器在希望某个操作在下一帧或一定帧数后执行,定时器接口中包含两个参数,定时器ID和object类型参数

Action<int, object> _action;

 隔多少帧调用

_maxFrameCount 

完整的帧定时器代码如下: 

 public class FrameTimer
    {
        private Action<int, object> _action;
        private int _maxFrameCount;
        private int _currentFrame;
        private object _param;

        public FrameTimer(Action<int, object> action, object param = null, int maxFrame = 1)
        {
            _action = action;
            _maxFrameCount = maxFrame;
            _param = param;
        }

        public bool Execute()
        {
            try
            {
                if (_action != null)
                    _action(0, _param);

            }
            catch (Exception e)
            {
                ULog.Error(e);
            }

            return false;
        }

        public bool TryAction()
        {
            _currentFrame++;
            if (_currentFrame == _maxFrameCount)
                return true;

            return false;
        }

    }

2、定义普通定时器

如果是延时调用的一次定时器_intervalSeconds是延时时间

如果是循环(_isLoop)调用的定时器 _intervalSeconds,就是调用间隔时间

private float _intervalSeconds;
private bool _isLoop;

普通定时器类定义

 public class OneTimer
    {
        public Action<int,object> _action;
        private object _param;
        private float _intervalSeconds;
        private bool _isLoop;

        private float _beginTime;
        private int _id;


        public OneTimer(Action<int, object> action,float intervalSeconds,object param=null,bool isLoop=false)
        {
            _id = UId.I.NextId();
            _action = action;
            _param = param;
            _isLoop = isLoop;
            _beginTime = TimeUtils.RealtimeSinceStartup;
            _intervalSeconds = intervalSeconds;

        }

        public void Execute()
        {
            try
            {
                if (_action != null)
                    _action(_id, _param);

            }
            catch (Exception e)
            {
                ULog.Error(e);
            }
        }

        public int Id
        {
            get { return _id; }
        }

        public float GetEndTime()
        {
            return _beginTime + _intervalSeconds;
        }

        public bool IsLoop
        {
            get { return _isLoop; }
        }

        public void UpdateNextTime()
        {
            _beginTime = GetEndTime();
        }

        public override string ToString()
        {
            StringBuilder sb = UString.GetBuilder();
            sb.Append(" id:" + _id);
            sb.Append(" ");
            if (_action != null)
            {
                if (_action.Target != null)
                {
                    sb.Append(_action.Target.ToString());
                    sb.Append(":");
                }

                if (_action.Method != null)
                {
                    sb.Append(_action.Method.ToString());
                }
            }

            sb.Append(" param:");
            sb.Append(_param);

            sb.Append(" intervalSeconds:");
            sb.Append(_intervalSeconds);

            sb.Append(" _isLoop:");
            sb.Append(_isLoop);

            sb.Append(" beginTime:");
            sb.Append(_beginTime);

            sb.Append(" waitSeconds:");
            sb.Append(GetEndTime() - TimeUtils.RealtimeSinceStartup);
            return sb.ToString();
        }
    }

 二、定时器管理类

定时器定义每帧调用函数Update,_timers管理的是普通定时器,_frames管理的是帧定时器

UpdateFrameTimer循环遍历帧定时器是否符合触发条件,并进行触发

普通定时器隔一定时间判定一次,CHECK_INTERVAL_SECONDS来确定

 const float CHECK_INTERVAL_SECONDS = 0.1f;
 public class TimersComponent
    {


        const float CHECK_INTERVAL_SECONDS = 0.1f;


        private List<OneTimer> _timers = new List<OneTimer>();
        private List<OneTimer> _timersTemp = new List<OneTimer>();
        private float _NextCheckTime = 0.0f;

        private List<FrameTimer> _frames = new List<FrameTimer>();


        public int  AddLoop(Action<int,object> action, float intervalSeconds,object param=null)
        {
            return Register(intervalSeconds, action, null, true);
        }

        public int AddOnce(Action<int, object> action, float beginSecond, object param)
        {
            return Register(beginSecond, action, param);
        }

        public void  AddOnceDelayFrame(Action<int, object> action, object param=null,int delayFrameCount=1)
        {
            _frames.Add(new FrameTimer(action,param, delayFrameCount));
        }

        private int Register(float intervalSeconds, Action<int, object> action, object param = null, bool isLoop  = false)
        {
            if (action == null)
            {
                LogError("Register: callback is null");
                return 0;
            }
            if (intervalSeconds <= 0.0f)
            {
                LogError("Register: intervalSeconds = " + intervalSeconds + " <= 0.0f");
                return 0;
            }

            OneTimer data = new OneTimer(action, intervalSeconds, param, isLoop);

            _timers.Add(data);
            if (intervalSeconds < CHECK_INTERVAL_SECONDS)
            {
                LogError("Register: Interval seconds: " + intervalSeconds + " < " + CHECK_INTERVAL_SECONDS);
            }
            if (_timers.Count >= 128)
            {
                LogError("Register: Too many timers: " + _timers.Count + " >= 128. Please redesign TimerSimple");
            }
            return data.Id;
        }

        public bool Remove(int id)
        {
            for (int i = 0; i < _timers.Count; ++i)
            {
                if (_timers[i].Id == id)
                {
                    _timers.RemoveAt(i);
                    return true;
                }
            }
            return false;
        }

        public bool Remove(Action<int, object> action)
        {
            if (action == null)
            {
                return false;
            }
            bool find = false;
            for (int i = 0; i < _timers.Count; ++i)
            {
                if (_timers[i]._action == action)
                {
                    find = true;
                    _timers.RemoveAt(i);
                    --i;
                }
            }
            return find;
        }

        public void Update()
        {
            UpdateFrameTimer();
            float curTime = TimeUtils.RealtimeSinceStartup;
            if (curTime < _NextCheckTime)
            {
                return;
            }
            if (_NextCheckTime <= 0.0f)
            {
                _NextCheckTime = TimeUtils.RealtimeSinceStartup + CHECK_INTERVAL_SECONDS;
                return;
            }
            _NextCheckTime = curTime + CHECK_INTERVAL_SECONDS;

            _timersTemp.Clear();
            for (int i = 0; i < _timers.Count; ++i)
            {
                OneTimer oneTimer = _timers[i];
                float endTime = oneTimer.GetEndTime();
                if (curTime >= endTime)
                {
                    _timersTemp.Add(oneTimer);
                    if (!oneTimer.IsLoop)
                    {
                        _timers.RemoveAt(i);
                        --i;
                    }
                }
            }
            for (int i = 0; i < _timersTemp.Count; ++i)
            {
                OneTimer oneTimer = _timersTemp[i];
                oneTimer.Execute();
                oneTimer.UpdateNextTime();
            }
            _timersTemp.Clear();
        }

        private void UpdateFrameTimer()
        {
            for (int i = 0; i < _frames.Count; i++)
            {
                FrameTimer timer = _frames[i];
                if (timer.TryAction())
                {
                    timer.Execute();
                    --i;
                    _frames.RemoveAt(i);
                    continue;
                }
            }
        }

        static void LogError(string str)
        {
            Debug.LogError(TimeUtils.RealtimeSinceStartup + " TimerSimple." + str);
        }


        public void Destroy()
        {
            base.Destroy();

            _timersTemp.Clear();
            _timers.Clear();
            _frames.Clear();
        }
    }

 当我们想要创建定时器时根据:循环定时器AddLoop、一次调用定时器AddOnce、一次调用帧定时器AddOnceDelayFrame接口创建我们想要的定时器。通过定时器id来Remove接口删除相应的定时器


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity实现 MVC 架构通常需要以下几步: 1. 创建 Model 类:Model 类用于存储数据和数据操作方法,例如: ``` public class PlayerModel { private int _health; public int Health { get { return _health; } set { _health = value; if (_health <= 0) { // 触发死亡事件 OnDeath(); } } } public event Action OnDeath; public void TakeDamage(int amount) { Health -= amount; } } ``` 2. 创建 View 类:View 类用于显示数据,例如: ``` public class PlayerView : MonoBehaviour { public TextMeshProUGUI healthText; public void UpdateHealth(int health) { healthText.text = "Health: " + health; } } ``` 3. 创建 Controller 类:Controller 类用于控制 Model 和 View,例如: ``` public class PlayerController { private PlayerModel _model; private PlayerView _view; public PlayerController(PlayerModel model, PlayerView view) { _model = model; _view = view; // 监听 Model 的数据变化并更新 View _model.OnHealthChanged += _view.UpdateHealth; // 监听 View 的用户操作并控制 Model _view.OnTakeDamage += _model.TakeDamage; } } ``` 4. 在场景中创建 View 对象,并在 Controller 中传入 Model 和 View: ``` public class GameController : MonoBehaviour { public PlayerView playerViewPrefab; private void Start() { // 创建 Model 对象 var playerModel = new PlayerModel(); // 创建 View 对象并绑定到场景中的 GameObject 上 var playerView = Instantiate(playerViewPrefab); playerView.transform.SetParent(transform, false); // 创建 Controller 对象并传入 Model 和 View var playerController = new PlayerController(playerModel, playerView); } } ``` 这样就完成了一个简单的 MVC 架构实现。在实际项目中,可能需要更复杂的 Model 和 View 类,以及更多的 Controller 类来控制不同的数据和视图。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值