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

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

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

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

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

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

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

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

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

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


  1. using UnityEngine; 
  2.  
  3. public abstract class GameControllor : MonoBehaviour 
  4.  
  5.  
  6.     //先写一个主框架,用来声明更新的函数 
  7.     public abstract void FixedUpdateGame();//一个按照FixedUpdate更新的函数,当然你可以自己定义或者添加,在子类中复写就行了,注意你的需求是基于哪个更新 
  8.     public abstract void UpdateGame();//一个按照Update更新的函数,同上 
  9.     public abstract void LateUpdateGame();//一个按照LateUpdate更新的函数,同上 
  10.  
  11.  
  12.  
  13.  

using UnityEngine;

public abstract class GameControllor : MonoBehaviour
{

    //先写一个主框架,用来声明更新的函数
    public abstract void FixedUpdateGame();//一个按照FixedUpdate更新的函数,当然你可以自己定义或者添加,在子类中复写就行了,注意你的需求是基于哪个更新
    public abstract void UpdateGame();//一个按照Update更新的函数,同上
    public abstract void LateUpdateGame();//一个按照LateUpdate更新的函数,同上

}


  1. using UnityEngine; 
  2. public abstract class MyGameControllor : GameControllor 
  3.     //为什么要写成抽象类的,因为这个控制器本身没有具体的意义,只是控制时间,而且直接控制属性就行了。 
  4.     private static bool isStopGame = false;//控制是否暂停 
  5.  
  6.     public static bool IsStopGame 
  7.     { 
  8.         get { return MyGameControllor.isStopGame; } 
  9.         set { MyGameControllor.isStopGame = value; } 
  10.     } 
  11.     private static float gameTime = 0;//脚本更新的时间,0为正常更新,1代表1秒更新一次 
  12.  
  13.     public static float GameTime 
  14.     { 
  15.         get { return MyGameControllor.gameTime; } 
  16.         set { MyGameControllor.gameTime = value; } 
  17.     } 
  18.     private static float runtime = 0;//计时器 
  19.     private bool IsOnTime = false; 
  20.  
  21.     void Update()//Update更新 
  22.     { 
  23.         if (IsOnTime) 
  24.         { 
  25.             UpdateGame(); 
  26.  
  27.         } 
  28.     } 
  29.     void FixedUpdate()//FixedUpdate更新 
  30.     { 
  31.         if (IsOnTime = (IsRun())) 
  32.         { 
  33.             FixedUpdateGame(); 
  34.         } 
  35.     } 
  36.  
  37.     void LateUpdate() 
  38.     { 
  39.         if (IsOnTime) 
  40.         { 
  41.             LateUpdateGame(); 
  42.         } 
  43.  
  44.  
  45.     } 
  46.     private bool LateTime()//这个判断是否到了更新的时间 
  47.     { 
  48.         if (GameTime <= 0) return true; 
  49.         runtime += Time.fixedDeltaTime; 
  50.         if (runtime >= GameTime) 
  51.         { 
  52.             runtime = 0; 
  53.             return true; 
  54.         } 
  55.         return false; 
  56.     } 
  57.     private bool IsRun()//判断是否暂停 
  58.     { 
  59.         if (!IsStopGame) 
  60.         { 
  61.             if (LateTime())//不是暂停时判断是否到了更新的时间 
  62.             { 
  63.                 return true; 
  64.             } 
  65.         } 
  66.         return false; 
  67.     } 
  68.     public override void FixedUpdateGame() { } 
  69.     public override void UpdateGame() { } 
  70.     public override void LateUpdateGame() { } 

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,然后复写你更新的方法就行了,好吧,测试一下(这是照顾一下小白):


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

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


  1. using UnityEngine; 
  2. using System.Collections; 
  3.  
  4. public class SystemTimeControl : MonoBehaviour 
  5.  
  6.      
  7.     void Update() 
  8.     { 
  9.         if (Input.GetKeyDown(KeyCode.Escape)) 
  10.         { 
  11.             MyGameControllor.IsStopGame = !MyGameControllor.IsStopGame; 
  12.         } 
  13.  
  14.     } 
  15.      

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

作者:决晴谷

来源:51CTO

时间: 2024-11-02 08:53:46

简单Unity时间架构设计(克洛诺斯之匙)的相关文章

简单描述关于CloudFoundry的架构设计

VMware发布了,业内第一个开源的PaaS--CloudFoundry.时至今日,笔者一直关注它的进程,当然也从它的架构设计中收获了很多东西,现在拿出来跟大家分享一下我的感想. 本文会分为两个部份进行描述:第一部份主要讲CloudFoundry的架构设计,从它所包含的模块介绍开始,到各部份的消息流向,各个模块的协调合作:第二部份会在第一部份的基础上,以如何在你的数据中心里面用到的CloudFoundry开始部署一个私有PaaS为目标,把两部分结合起来. 第一部份讲的很多内容,会引用Pat在10

《企业迁云实战》——3.3 应用架构设计

3.3 应用架构设计 上面已经介绍了用户业务上云时如何进行网络设计.运维管理环境规划,本章将重点介绍如何基于阿里云产品和服务设计应用系统架构.3.3.1 负载均衡 阿里云负载均衡(Server Load Balancer,SLB)是将访问流量根据转发策略分发到后端多台ECS的流量分发控制服务.用户可以通过负载均衡的流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性. 阿里云负载均衡主要功能: 负载均衡服务通过设置虚拟服务地址(IP),将多台云服务器ECS实例虚拟成一个高性能

【架构篇】Android移动app架构设计浅谈

前言 架构,又名软件架构,是有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计. 软件架构设计目标: 1.可靠性(Reliable).软件架构的可靠是产品设计的前提. 2.安全性(Secure).软件架构的安全性是产品可持续发展的条件. 3.可扩展性(Scalable).软件架构必须能够不同的功能需求情况下,支持可扩散性. 4.可定制化(Customizable).同样的一套软件,可以根据客户群的不同和市场需求的变化进行调整. 5.可伸缩 (Extensible).在新技术出现

[精华]web架构设计经验分享!

经验|经验分享|精华|设计|web架构 本人作为一位web工程师,着眼最多之处莫过于 性能与架构,本次幸得参与sd2.0大会,得以与同行广泛交流,于此二方面,有些心得,不敢独享,与众博友分享,本文是这次参会与众同撩交流的心得,有兴趣者可以查看视频 架构设计的几个心得: 一,不要过设计:never over design 这是一个常常被提及的话题,但是只要想想你的架构里有多少功能是根本没有用到,或者最后废弃的,就能明白其重要性了,初涉架构设计,往往倾向于设计大而化 一的架构,希望设计出具有无比扩展

基于Ajax的应用程序架构设计汇总

ajax|程序|架构|设计 1 浏览器端框架被划分成两大类: •应用程序框架:提供浏览器的功能,但是常以包括窗口小部件抽象和另外的部件而出名,其功能主要围绕桌面GUI框架. •基本结构框架:提供基本的管道和可移植的浏览器抽象,让开发者去创建内容.典型的功能: * 针对XMLHttpRequest的包装器以封装浏览器-服务器的交互.(所有的框架都提供这一功能). * XML操作和查询. * 根据来自XMLHttpRequest的应答执行DOM操作. * 在一些情况中,与另外的浏览器端技术如Flas

iOS开发之浅谈MVVM的架构设计与团队协作

今天写这篇博客是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇博客的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦~). 由于本人项目经验有限,关于架构设计方面的东西理解有限,我个人对MVVM的理解主要是借鉴于之前的用过的MVC的Web框架~在学校的时候用过ThinkPHP框架,和SSH框架,都是MVC的架构模式,今天MVVM与传统的MVC可谓是极为相似,也可以说是兄弟关系,也就是一家人了. 说道架构设计和团队

从不同的角度来认识和理解Impala的架构设计

我们知道,在实时性要求不是很高的应用场景中,比如,月度统计报表生成等,我们基于传统的Hadoop MapReduce来处理海量大数据(包括使用Hive),在各方面表现都还不错,只需要离线处理数据,然后存储结果即可.但是如果在一些实时性要求相对较高的应用场景中,哪怕处理时间能够在原有的基础有大幅度地减少,也能很好地提升用户体验.对于大数据的实时性要求,其实是相对的,比如,传统使用MapReduce计算框架处理PB级别的查询分析请求,可能耗时30分钟甚至更多,但是如果能够使这个延迟大大降低,如3分钟

Cloudera Impala架构设计要点

我们知道,在实时性要求不是很高的应用场景中,比如,月度统计报表生成等,我们基于传统的Hadoop MapReduce来处理海量大数据(包括使用Hive),在各方面表现都还不错,只需要离线处理数据,然后存储结果即可.但是如果在一些实时性要求相对较高的应用场景中,哪怕处理时间能够在原有的基础有大幅度地减少,也能很好地提升用户体验.对于大数据的实时性要求,其实是相对的,比如,传统使用MapReduce计算框架处理PB级别的查询分析请求,可能耗时30分钟甚至更多,但是如果能够使这个延迟大大降低,如3分钟

基于微服务和Docker容器技术的PaaS云平台架构设计

本文讲的是基于微服务和Docker容器技术的PaaS云平台架构设计[编者的话]在系统架构上,PaaS云平台主要分为微服务架构.Docker容器技术.DveOps三部分,这篇文章重点介绍微服务架构的实施. [3 天烧脑式容器存储网络训练营 | 深圳站]本次培训以容器存储和网络为主题,包括:Docker Plugin.Docker storage driver.Docker Volume Pulgin.Kubernetes Storage机制.容器网络实现原理和模型.Docker网络实现.网络插件.