Unity实现《羞辱》时间弯曲机制:仅玩家不受时间暂停影响
Unity实现《羞辱》风格时间弯曲机制(仅暂停非玩家对象)
直接放弃修改Time.timeScale的方案——它会全局影响所有依赖时间的系统,包括玩家的物理和动画。我们用单独控制非玩家对象时间更新的方式来实现,步骤如下:
1. 给非玩家对象添加时间控制脚本
创建一个名为TimeControlledObject.cs的脚本,挂到所有需要被暂停的非玩家对象上(比如敌人、可交互物体、粒子特效等,玩家对象绝对不能挂这个脚本):
using UnityEngine; public class TimeControlledObject : MonoBehaviour { // 全局暂停状态,供控制器脚本修改 public static bool isTimePaused = false; private Rigidbody _rb; private Animator _anim; private ParticleSystem _ps; private Vector3 _savedVelocity; private Vector3 _savedAngularVelocity; private float _savedAnimSpeed; private float _savedParticleSpeed; void Awake() { // 获取组件,没有的话不处理 _rb = GetComponent<Rigidbody>(); _anim = GetComponent<Animator>(); _ps = GetComponent<ParticleSystem>(); if (_anim != null) _savedAnimSpeed = _anim.speed; if (_ps != null) _savedParticleSpeed = _ps.main.playbackSpeed; } void Update() { if (isTimePaused) { PauseObject(); } else { ResumeObject(); } } void PauseObject() { // 保存刚体当前速度,然后停止运动 if (_rb != null) { _savedVelocity = _rb.velocity; _savedAngularVelocity = _rb.angularVelocity; _rb.velocity = Vector3.zero; _rb.angularVelocity = Vector3.zero; // 可选:冻结位置/旋转,防止碰撞干扰 _rb.constraints = RigidbodyConstraints.FreezeAll; } // 暂停动画 if (_anim != null) _anim.speed = 0f; // 暂停粒子系统 if (_ps != null) { var mainModule = _ps.main; mainModule.playbackSpeed = 0f; _ps.Pause(); } } void ResumeObject() { // 恢复刚体速度 if (_rb != null) { _rb.constraints = RigidbodyConstraints.None; _rb.velocity = _savedVelocity; _rb.angularVelocity = _savedAngularVelocity; } // 恢复动画速度 if (_anim != null) _anim.speed = _savedAnimSpeed; // 恢复粒子系统 if (_ps != null) { var mainModule = _ps.main; mainModule.playbackSpeed = _savedParticleSpeed; _ps.Play(); } } }
2. 玩家输入控制器
创建TimeBendController.cs脚本,挂到玩家对象上,用来触发时间暂停/恢复:
using UnityEngine; public class TimeBendController : MonoBehaviour { // 设置触发按键,这里用左Shift,你可以改成自己需要的键 public KeyCode timeBendKey = KeyCode.LeftShift; void Update() { // 按下按键时切换暂停状态 if (Input.GetKeyDown(timeBendKey)) { TimeControlledObject.isTimePaused = !TimeControlledObject.isTimePaused; } } }
3. 新手注意事项
- 不要给玩家对象挂
TimeControlledObject:玩家的刚体、动画会完全不受影响,正常运行。 - 场景中遗漏的对象:如果有某些非玩家对象没挂脚本,它们不会被暂停,记得检查所有需要暂停的物体(比如场景中的门、掉落的道具)。
- 协程处理:如果非玩家对象用了协程,默认协程依赖
Time.timeScale,要把协程里的时间判断改成用Time.unscaledDeltaTime或者Time.realtimeSinceStartup,比如:// 错误写法(依赖timeScale) yield return new WaitForSeconds(2f); // 正确写法(不受timeScale影响,适用于需要在暂停时继续运行的协程) yield return new WaitForSecondsRealtime(2f); - 物理碰撞:暂停后如果玩家和被冻结的刚体碰撞,不会有物理反馈(因为刚体被冻结了),如果需要保留碰撞效果,可以去掉
_rb.constraints = RigidbodyConstraints.FreezeAll,只清空速度——但这样可能会有轻微的位置偏移,按需选择。
内容的提问来源于stack exchange,提问作者Alex Roth
相关产品推荐
相关产品推荐

