2D项目传送门如何让玩家传送后保持动量?
2D传送门保留动量的实现方案
完全可行,你当前直接修改transform.position的思路本身没问题,但只改位置会丢失玩家的动量数据,这是你需要补充的核心逻辑,不是思路错误。
要实现保留动量且方向适配出口角度,核心是完成「动量记录→方向转换→重新赋值」这三步:
第一步:记录玩家进入传送门瞬间的动量
如果你用的是Rigidbody2D,直接获取rigidbody2D.velocity即可;如果是自定义的移动逻辑,就记录当前的移动速度向量。第二步:转换动量方向以匹配出口角度
你需要计算入口传送门与出口传送门的朝向差值,把原速度向量旋转这个差值角度。比如假设传送门用transform.up作为朝向:- 计算两个传送门的Z轴旋转差:
float rotationDiff = exitPortal.transform.eulerAngles.z - transform.eulerAngles.z - 用四元数旋转原速度向量:
Vector2 rotatedVelocity = Quaternion.Euler(0, 0, rotationDiff) * originalVelocity
- 计算两个传送门的Z轴旋转差:
第三步:传送后重新赋值动量
把玩家位置移到出口(建议稍微偏移一点,比如exitPortal.transform.position + exitPortal.transform.up * 0.1f,避免立刻再次触发传送门),然后将转换后的速度赋值给玩家的Rigidbody2D.velocity或自定义移动变量。
示例代码(Unity C#)
public class Portal : MonoBehaviour { public Portal exitPortal; [SerializeField] private float teleportOffset = 0.1f; [SerializeField] private float cooldown = 0.2f; private bool isOnCooldown; private void OnTriggerEnter2D(Collider2D other) { if (isOnCooldown || !other.CompareTag("Player")) return; Rigidbody2D playerRb = other.GetComponent<Rigidbody2D>(); if (playerRb == null) return; // 记录原速度 Vector2 originalVelocity = playerRb.velocity; // 计算旋转角度差 float rotationDelta = exitPortal.transform.eulerAngles.z - transform.eulerAngles.z; // 转换速度方向 Vector2 adjustedVelocity = Quaternion.Euler(0, 0, rotationDelta) * originalVelocity; // 传送位置(偏移避免重复触发) other.transform.position = exitPortal.transform.position + exitPortal.transform.up * teleportOffset; // 赋值新速度 playerRb.velocity = adjustedVelocity; // 启动冷却 isOnCooldown = true; exitPortal.isOnCooldown = true; Invoke(nameof(ResetCooldown), cooldown); exitPortal.Invoke(nameof(ResetCooldown), cooldown); } private void ResetCooldown() { isOnCooldown = false; } }
额外注意事项
- 确保传送门的碰撞器设置为触发器,否则会触发物理碰撞导致异常
- 添加冷却时间是为了防止玩家在两个传送门之间反复触发传送逻辑
- 如果你的玩家用的是
CharacterController2D而非Rigidbody2D,只需把速度赋值逻辑替换为对应组件的移动参数即可
内容的提问来源于stack exchange,提问作者Harsh Kumar
相关产品推荐
相关产品推荐

