Unity开发Portal类2D游戏:Quaternion旋转速度向量遇问题
问题分析与解决方案
核心问题拆解
2D环境下轴方向误用
Unity 2D中transform.forward指向Z轴(垂直屏幕),完全不在XY游戏平面内。你用它计算传送门朝向的旋转,等于基于错误的轴做转换,自然得不到正确的速度方向。传送激活逻辑混乱
Portal脚本里的activated变量触发逻辑颠倒,且Movement中每帧都会检查该状态,会导致速度被重复修改;同时硬编码指定Green/Blue传送门,无法适配动态配对的场景。2D速度旋转方式错误
2D平面的向量旋转无需用3D的Quaternion复杂处理,直接基于平面角度计算更准确,强行用Quaternion会因轴空间不匹配导致结果异常。
修正后代码实现
Portal脚本(优化触发逻辑)
using UnityEngine; public class Portal : MonoBehaviour { public Portal linkedPortal; // 直接在Inspector指定配对传送门 private bool isTeleporting; // 防止连续触发传送 void OnTriggerEnter2D(Collider2D col) { if (isTeleporting || linkedPortal == null) return; var playerMovement = col.GetComponent<Movement>(); if (playerMovement == null) return; // 标记传送中状态 isTeleporting = true; linkedPortal.isTeleporting = true; // 传送位置(偏移一点避免立刻再次触发触发器) col.transform.position = linkedPortal.transform.position + linkedPortal.transform.up * 0.1f; // 应用旋转后的速度 playerMovement.ApplyPortalVelocity(this, linkedPortal); // 延迟重置状态,防止连续触发 Invoke(nameof(ResetTeleportFlag), 0.2f); linkedPortal.Invoke(nameof(ResetTeleportFlag), 0.2f); } void ResetTeleportFlag() { isTeleporting = false; } }
Movement脚本(优化速度旋转与移动逻辑)
using UnityEngine; public class Movement : MonoBehaviour { private float horizontal; private float speed = 8f; private float jumpingPower = 8f; public Rigidbody2D rb; void Update() { horizontal = Input.GetAxisRaw("Horizontal"); if (Input.GetButtonDown("Jump")) { rb.velocity = new Vector2(rb.velocity.x, jumpingPower); } } private void FixedUpdate() { // 只有非传送状态下处理常规移动,避免覆盖传送后的速度 if (!IsInTeleport()) { rb.velocity = new Vector2(horizontal * speed, rb.velocity.y); } } // 检查是否处于传送状态 private bool IsInTeleport() { foreach (var portal in FindObjectsOfType<Portal>()) { if (portal.isTeleporting) return true; } return false; } // 处理传送门速度转换 public void ApplyPortalVelocity(Portal inPortal, Portal outPortal) { // 计算两个传送门的朝向角度(基于up轴,假设传送门up为正对方向) float inAngle = Mathf.Atan2(inPortal.transform.up.y, inPortal.transform.up.x) * Mathf.Rad2Deg; float outAngle = Mathf.Atan2(outPortal.transform.up.y, outPortal.transform.up.x) * Mathf.Rad2Deg; // 旋转差值:从进入方向转为穿出方向,额外加180度修正方向 float rotationDelta = outAngle - inAngle + 180f; // 旋转速度向量 rb.velocity = Rotate2DVector(rb.velocity, rotationDelta); } // 2D向量旋转工具方法 private Vector2 Rotate2DVector(Vector2 vec, float angleDeg) { float angleRad = angleDeg * Mathf.Deg2Rad; float cos = Mathf.Cos(angleRad); float sin = Mathf.Sin(angleRad); return new Vector2( vec.x * cos - vec.y * sin, vec.x * sin + vec.y * cos ); } }
关键修正说明
- 轴方向修正:改用
transform.up作为传送门的朝向参考(需确保传送门Sprite的up方向与视觉朝向一致),完全基于XY平面计算角度。 - 触发逻辑优化:用
isTeleporting标记防止连续触发,传送后延迟重置状态,避免反复触发触发器。 - 动态配对:每个传送门直接指定
linkedPortal,无需硬编码固定传送门名称,适配更多场景。 - 2D向量旋转:用三角函数直接计算平面旋转,避免3D Quaternion的轴空间混淆,结果更准确。
内容的提问来源于stack exchange,提问作者Harmonical
相关产品推荐
相关产品推荐

