zoukankan      html  css  js  c++  java
  • 简单Unity时间架构设计(克洛诺斯之匙)

    简单Unity时间架构设计(克洛诺斯之匙)

    好吧,这次的题目有点标题党之嫌,提出这个设计,是因为最近玩了鬼泣,其中有一个关卡叫做“为了自己的主人”,任务中,需要利用克洛诺斯之匙将时间变慢,便于通过激光镇。

    使用克洛诺斯之匙之后,主角的行动是正常的,运走,攻击等等。而其他的如怪物,死亡特效等对象的更新都变慢了。当时我想,如何让不同的对象能够按不同频率更新呢?

    在unity中,脚本按时更新的是Time.FixedUpdate,改变其速率只需要修改Time.timeScale就行了。然而这么做非常“鲁莽”,因为这个值是全局的,所有以Time.FixedUpdate为更新的游戏对象都会受到影响。例如实现游戏的暂停功能,很多初学者会将对象的更新使用Time.FixedUpdate,然后动态修改timeScale。这样可以将所有以FixedUpdate为更新的游戏对象都停了。

    貌似没有什么问题,然而却会影响所有以FixedUpdate更新的脚本,例如DFGUI,NGUI等。我曾经使用上面的方法,结果出了问题,就是把timeScale设为0之后,UI的监听事件竟然没反应了,当时调试很久才反应过来。

    后来为了解决这个问题,以及局部对象的暂停,定义了很多变量来控制,感觉太麻烦。后来玩到鬼泣的时候,突然有了灵感,为何不自己写一个时间控制器呢?

    首先要清楚需求是什么:在unity自带更新脚本的基础上设计一个时间控制器,用来控制所有对象的更新频率。

    我的设计方案是这样的,写一个父类,实现Update,LateUpdate,FixedUpdate的正常更新与计时,暂停控制。然后所有需要控制更新的对象脚本继承这个控制类,复写相应的方法。

    使用的时候,直接控制几个全局的静态变量就可以控制所有继承此类的游戏对象,用来实现暂停,或者局部对象的延时。这个可以很好的扩展,你复写不同的方法就可以实现不同对象的更新频率。这个你自己发挥即可。就像鬼泣中那样,主角的行动不收时间钥匙的影响,而其他对象都会延时。

    说起来挺高大上,但是实现的代码却是很简单(我喜欢用最精简的代码来实现功能),就是使用静态变量全局控制,简单计时器,以及继承和复写。好不多说上代码:

     

    
    
    using UnityEngine;
    
    public abstract class GameControllor : MonoBehaviour
    {
    
    
        //先写一个主框架,用来声明更新的函数
        public abstract void FixedUpdateGame();//一个按照FixedUpdate更新的函数,当然你可以自己定义或者添加,在子类中复写就行了,注意你的需求是基于哪个更新
        public abstract void UpdateGame();//一个按照Update更新的函数,同上
        public abstract void LateUpdateGame();//一个按照LateUpdate更新的函数,同上
    
    
    
    
    }
    
    
    using UnityEngine;
    public abstract class MyGameControllor : GameControllor
    {
        //为什么要写成抽象类的,因为这个控制器本身没有具体的意义,只是控制时间,而且直接控制属性就行了。
        private static bool isStopGame = false;//控制是否暂停
    
        public static bool IsStopGame
        {
            get { return MyGameControllor.isStopGame; }
            set { MyGameControllor.isStopGame = value; }
        }
        private static float gameTime = 0;//脚本更新的时间,0为正常更新,1代表1秒更新一次
    
        public static float GameTime
        {
            get { return MyGameControllor.gameTime; }
            set { MyGameControllor.gameTime = value; }
        }
        private static float runtime = 0;//计时器
        private bool IsOnTime = false;
    
        void Update()//Update更新
        {
            if (IsOnTime)
            {
                UpdateGame();
    
            }
        }
        void FixedUpdate()//FixedUpdate更新
        {
            if (IsOnTime = (IsRun()))
            {
                FixedUpdateGame();
            }
        }
    
        void LateUpdate()
        {
            if (IsOnTime)
            {
                LateUpdateGame();
            }
    
    
        }
        private bool LateTime()//这个判断是否到了更新的时间
        {
            if (GameTime <= 0) return true;
            runtime += Time.fixedDeltaTime;
            if (runtime >= GameTime)
            {
                runtime = 0;
                return true;
            }
            return false;
        }
        private bool IsRun()//判断是否暂停
        {
            if (!IsStopGame)
            {
                if (LateTime())//不是暂停时判断是否到了更新的时间
                {
                    return true;
                }
            }
            return false;
        }
        public override void FixedUpdateGame() { }
        public override void UpdateGame() { }
        public override void LateUpdateGame() { }
    }
     

     

    代码很简单,关键是方案和思路。怎么使用呢?所有逻辑更新的脚本继承这个MyGameControllor,然后复写你更新的方法就行了,好吧,测试一下(这是照顾一下小白):

    using UnityEngine;
    using System.Collections;
    
    public class PlayerMove : MyGameControllor {
        //继承MyGameControllor,并复写UpdateGame方法
        public void Move() {
            //一个简单移动的方法,用来观察测试
            transform.Translate(new Vector3(Random.Range(-1, 1), Random.Range(-1, 1), Random.Range(-1, 1))*Time.deltaTime);
        }
        public override void UpdateGame()
        {
            //复写UpdateGame
            Move();
        }
    }

    最后是一个时间控制器代码,就是按下esc暂停的,代码很简单,好再给小白看一下:

    using UnityEngine;
    using System.Collections;
    
    public class SystemTimeControl : MonoBehaviour
    {
    
        
        void Update()
        {
            if (Input.GetKeyDown(KeyCode.Escape))
            {
                MyGameControllor.IsStopGame = !MyGameControllor.IsStopGame;
            }
    
        }
        
    }

    好了,关于时间的架构设计就介绍到这了,方案简单实用,也许有更好的方法,欢迎交流。打个广告:大三软件工程专业(java方向),擅长面向对象设计,常用算法。自学js,C#,以及unity3D引擎,擅长前端开发以及系统架构优化。

     原文地址:http://www.cnblogs.com/jqg-aliang/p/4719429.html。转载请申明出处,谢谢

     

    后记:此种方案已经被我淘汰,我会在合适的时间再分享最新的方案,谢谢关注!另:楼主现在已经工作了!

     

  • 相关阅读:
    IOS 修改UISearchBar 输入框的颜色 placeholder字体的颜色
    iOS-集成微信支付和支付宝支付
    iOS-集成极光推送
    常用iOS开发网站资源
    iOS -媒体播放器 AVPlayer 与 AVPlayerViewController
    使用终端统计代码行数
    swift 与 OC中的需要注意知识点
    去掉tableview顶部留白
    解决UIScrollView把uitableviewcell的点击事件屏蔽
    按钮点击发光效果
  • 原文地址:https://www.cnblogs.com/jqg-aliang/p/4719429.html
Copyright © 2011-2022 走看看