Unity中如何实现门的平滑旋转?代码问题求助
问题分析与解决方案
你的代码存在三个核心问题导致平滑旋转失效:
- Lerp仅执行一次:
DoorOpen()和DoorClose()只在按下E时被调用一次,而Quaternion.Lerp需要每一帧持续执行才能产生平滑过渡效果,单次调用只会让门旋转极小的角度,看起来没变化。 - 目标旋转计算错误:
Start()里用transform.rotation.y(四元数的分量)来构建欧拉角,这完全不符合逻辑——四元数的x/y/z/w不是欧拉角的轴角度,应该用transform.eulerAngles来获取当前门的欧拉角参数。 - 全局开关状态混乱:
Interaction里的doorOpened是全局变量,当场景中有多个门时,这个变量会导致开关逻辑混乱。
修改后的Door脚本
using UnityEngine; public class Door : MonoBehaviour { [SerializeField] float speed = 2f; [SerializeField] float openAngle; [SerializeField] float closeAngle; private Quaternion _targetRotation; private bool _isOpening; void Start() { // 基于当前门的欧拉角设置目标旋转(仅修改Y轴) _targetRotation = Quaternion.Euler(transform.eulerAngles.x, closeAngle, transform.eulerAngles.z); _isOpening = false; } void Update() { // 每一帧执行Lerp,实现平滑旋转 transform.rotation = Quaternion.Lerp(transform.rotation, _targetRotation, Time.deltaTime * speed); } public void ToggleDoor() { _isOpening = !_isOpening; // 根据开关状态切换目标旋转 _targetRotation = _isOpening ? Quaternion.Euler(transform.eulerAngles.x, openAngle, transform.eulerAngles.z) : Quaternion.Euler(transform.eulerAngles.x, closeAngle, transform.eulerAngles.z); } // 保留原方法兼容旧逻辑(可选) public void DoorOpen() { _isOpening = true; _targetRotation = Quaternion.Euler(transform.eulerAngles.x, openAngle, transform.eulerAngles.z); } public void DoorClose() { _isOpening = false; _targetRotation = Quaternion.Euler(transform.eulerAngles.x, closeAngle, transform.eulerAngles.z); } // 对外暴露开关状态,供Interaction脚本判断 public bool IsOpening => _isOpening; }
修改后的Interaction脚本
using UnityEngine; public class Interaction : MonoBehaviour { void Update() { Vector3 rayStartPosition = new Vector3(Screen.width / 2, Screen.height / 2, 0); Ray cameraRay = Camera.main.ScreenPointToRay(rayStartPosition); float maxDistance = 3f; if (Physics.Raycast(cameraRay, out RaycastHit hit, maxDistance)) { if (hit.collider.CompareTag("Door") && Input.GetKeyDown(KeyCode.E)) { var door = hit.collider.GetComponent<Door>(); // 调用ToggleDoor直接切换状态,或者根据门自身状态判断 door.ToggleDoor(); // 或者用原逻辑: // if (door.IsOpening) door.DoorClose(); // else door.DoorOpen(); } } } }
关键修改说明
- 持续帧更新Lerp:把Lerp逻辑移到
Update()中,确保每一帧都计算旋转过渡,实现平滑动画。 - 修正目标旋转计算:使用
transform.eulerAngles获取门的当前欧拉角,仅修改Y轴角度来构建目标旋转四元数,避免四元数分量误用。 - 门自身维护状态:将开关状态
_isOpening移到Door脚本中,每个门独立管理自己的开关状态,解决多门场景的逻辑混乱问题。 - 简化交互逻辑:新增
ToggleDoor()方法,一键切换门的开关状态,减少重复代码。
内容的提问来源于stack exchange,提问作者dmitry rubanov
相关产品推荐
相关产品推荐

