官方的教程足够用了,为了方便,在这里记录一下
https://ludiq.io/chronos/tutorial
导入Chronos组件。
用Chronos控制各个物体的时间,本质上是通过控制物件参照
的时钟,再在脚本中用Chronos帮忙做好的时间计算代理代替原来的物理/运动控制。
第一步 设置参照时钟
有三种时钟,一是全局时钟,一是区域时钟,三是本地时钟
全局时钟只需要静态设置看向此类时钟,物件就能受到该时钟影响
区域时钟是需要挂载在一个有触发器碰撞体的物体上,进入碰撞体内部的发生触发事件
的物体就会被影响
本地时钟直接挂载在需要影响的物体上
时钟可以设置父时钟,产生链式叠加的时间控制。可以设置是相乘叠加
or相加叠加
全局时钟
在场景中放一个TimeKeeper
物体,在这个物体上挂在全局时钟才有效。
需要为各个不同的全局时钟起名字Key
接下来只需要在需要看向这个时钟的物体上挂载Timeline
组件,并设置它看向全局的某个时钟
区域时钟
在一个设定了触发型碰撞体的组件上挂载一个区域时钟
Mode为Instant 一碰撞就立即产生效果
Mode为Point To Edge、Distance From Entry都是渐进产生效果的
前者设置曲线如下图时,基本上表示越靠近碰撞体中心受到效果越大
本地时钟
自产自销属于是
第二步 影响物体行动
所有需要受时间控制的物体,都需要挂载一个Timeline
组件,可以看向全局的某个时钟,也可以看向本地时钟。自动处理受到区域时钟的影响。
主要是在代码中,物体的物理/运动控制需要参照由自己的TimeLine
组件代理计算出来的时间流速。
比如说在Update
里的Time.deltaTime
,需要改成GetComponent<Timeline>().deltaTime
为了写法方便,官方的做法是将本来的MonoBehaviour
简单封装一层,这样其它新建的C#脚本类继承BaseBohaviour
,就可以用time
简单快速地获取到自己的Timeline
组件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Chronos;
public class BaseBohaviour : MonoBehaviour
{
public Timeline time
{
get
{
return GetComponent<Timeline>();
}
}
}
案例0:脚本控制时钟时间流速
用TimeKeeper
的静态函数,附上全局时钟的名字就可以直接获取全局时钟
本地时钟和区域时钟用正常的物体-组件
获得
例子中使用了LerpTimeScale
函数,这会线性过渡时间速率的变化而不是瞬间变化(注释中的就是瞬间变化)
注意使用localTimeScale
设置此时钟的时间而非timeScale,因为链式叠加,只能改变自身。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Chronos;
public class TimeScaleChange : MonoBehaviour
{
public GlobalClock globalClock;
void Start()
{
globalClock = Timekeeper.instance.Clock("Enemies");
}
void Update()
{
if (Input.GetKeyDown(KeyCode.UpArrow)){
globalClock.LerpTimeScale(globalClock.localTimeScale + 0.5f, 0.5f);
//globalClock.localTimeScale += 0.5f;
}
if (Input.GetKeyDown(KeyCode.DownArrow)){
globalClock.LerpTimeScale(globalClock.localTimeScale - 0.5f, 0.5f);
//globalClock.localTimeScale -= 0.5f;
}
}
}
案例1:控制物体运动
TimeLine
组件可以很容易的代理刚体的速度控制,而需要注意的是组件只能代理设置速度
,不能用它获取速度
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Chronos;
public class PlayerMove : BaseBohaviour
{
public float moveSpeed = 300;
float moveDir;
Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
moveDir = Input.GetAxisRaw("Horizontal");
}
private void FixedUpdate() {
time.rigidbody2D.velocity = new Vector2(moveDir * moveSpeed, rb.velocity.y);
}
}
案例2:控制动画效果/控制音乐
配置好时钟和timeline
后,
正常使用AnimatorController
和Animator
控制动画、使用AudioSource
控制音乐就可以。
真方便捏。
案例3:控制事件
事件中的时间控制,自己写脚本使用time.deltaTime
进行时间计数产生事件(如怪物刷新),并不是难事,只要是正向流速就容易控制。
但是如果时间逆向控制,也就是事件发生后,时间会退到事件发生前,那么要将事件发生产生的所有效果全部撤销。
比如吃到金币事件发生后,回退时间,要将金币吐回去,收集到的金币数减回去。
这最好是需要重新设计项目结构,用一个队列记录场景中发生的事件。多数情况下游戏应该没有时间倒流的设计需求吧?