Time Manipulate
|Word count:450|Reading time:2min|Post View:
前言
个人认为 SuperHot 的核心是时间控制和回放,一个一个实现。
试了一下发现时间控制实现起来挺简单的,因为 Unity 已经提供了时间尺度(时间流速)的接口,所以只需要包装一下就好了。
代码暂时先不传,等后面的回放做完再一起传吧。
TimeScaleManager
由于 UnityEngine.Time.timeScale 是 static 的,所以我这边用单例模式进行管理。
之后如果做成联机,让每个玩家都是独立的话,不知道难度怎么样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class TimeScaleManager { private static TimeScaleManager _instance;
private float _timeScale = 1f;
public static TimeScaleManager Instance { get { if (_instance == null) { _instance = new TimeScaleManager(); }
return _instance; } }
public void SetTimeScale(float scale) { if (scale < 0f) { throw new System.ArgumentOutOfRangeException(nameof(scale), "Time scale cannot be negative."); }
Instance._timeScale = scale; UnityEngine.Time.timeScale = scale; }
public float GetTimeScale() { return Instance._timeScale; }
public void ResetTimeScale() { Instance._timeScale = 1f; UnityEngine.Time.timeScale = 1f; } }
|
Controller2D
这里主要是加了个 PlayerState 来表示玩家的状态,这样的话就可以根据状态来决定具体如何操控时间。
我这里的话就是实现到只有静止的时候才会减慢时间流速,其他时候都保持正常速度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| public class Controller2D : MonoBehaviour { private enum PlayerState { Idle, Walking, Shooting, }
private PlayerState _playerState = PlayerState.Idle;
private float _moveSpeed = 5f;
private void Awake() { TimeScaleManager.Instance.SetTimeScale(1f); }
private void Update() { if (Input.GetKeyDown(KeyCode.Escape)) { Application.Quit(); }
OnMove(); OnAttack();
OnPlayerStateChange(); }
private void OnMove() { var movement = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"), 0f);
if (movement.magnitude > 0.1f) { _playerState = PlayerState.Walking; transform.Translate(movement * (_moveSpeed * Time.deltaTime)); } else { _playerState = PlayerState.Idle; } }
private void OnAttack() { if (Input.GetMouseButtonDown(0)) { _playerState = PlayerState.Shooting; Debug.Log("Player is shooting."); } }
private void OnPlayerStateChange() { if (_playerState == PlayerState.Idle) { TimeScaleManager.Instance.SetTimeScale(0.1f); } else { TimeScaleManager.Instance.ResetTimeScale(); } } }
|