Unity2D中Vector3.Lerp实现移动管道开合动画失效求助
问题分析与解决:Unity2D管道移动+开合动画异常
问题描述
在Flappy Bird类2D游戏中,尝试实现管道(Top和Bottom两个子物体)在向左移动的同时平滑开合的效果,通过W键触发。但实际运行时,管道会直接瞬移到开合后的位置,动画期间管道停止向左移动,完全不符合预期。
原因分析
- Lerp起点每帧重置:
TopStartPoint和BottomStartPoint在Update中每帧重新计算,导致Vector3.Lerp的起始位置不断变化,无法完成从初始位置到目标位置的平滑插值,最终表现为瞬移。 - 父物体移动与子物体位置修改冲突:父物体(管道整体)通过
transform.position向左移动,同时子物体(Top/Bottom)的世界位置被Lerp直接覆盖,两者的位置更新逻辑互相干扰,导致动画期间管道停止移动。 - 目标位置计算冗余:原本试图计算X轴偏移,但实际上管道的X轴移动由父物体统一控制,额外计算反而导致位置逻辑混乱。
修正后的代码
using UnityEngine; public class PipeMove : MonoBehaviour { public float deadZone = -15; public float MoveSpeed; public BorbPhysics borb; public float DeathMoveSpeed = 1; public GameObject Top; public GameObject Bottom; public float Offset = 5; // 改为存储局部位置的起始/目标点 private Vector3 TopStartLocalPos; private Vector3 BottomStartLocalPos; private Vector3 TopEndLocalPos; private Vector3 BottomEndLocalPos; public float desiredDuration = 3f; private float elapsedTime; public float TyStart; public float ByStart; public bool IsOpening = false; public bool hasSet = false; void Start() { borb = GameObject.FindGameObjectWithTag("borb").GetComponent<BorbPhysics>(); // 记录初始局部Y位置 TyStart = Top.transform.localPosition.y; ByStart = Bottom.transform.localPosition.y; } void Update() { // 管道整体移动逻辑,保持不变 if (borb.BorbIsAlive) { transform.position += Vector3.left * MoveSpeed * Time.deltaTime; } else { transform.position += Vector3.left * DeathMoveSpeed * Time.deltaTime; } if (transform.position.x < deadZone) { Destroy(gameObject); } // 触发开合逻辑 if (Input.GetKeyDown(KeyCode.W) && !IsOpening) { IsOpening = true; hasSet = false; elapsedTime = 0f; } if (IsOpening) { // 仅在触发时初始化一次起始和目标位置 if (!hasSet) { // 记录触发时的局部位置作为起点 TopStartLocalPos = Top.transform.localPosition; BottomStartLocalPos = Bottom.transform.localPosition; // 计算目标局部位置(只修改Y轴,X轴跟随父物体移动) TopEndLocalPos = new Vector3(TopStartLocalPos.x, TyStart + Offset, 0); BottomEndLocalPos = new Vector3(BottomStartLocalPos.x, ByStart - Offset, 0); hasSet = true; } elapsedTime += Time.deltaTime; float percentageComplete = Mathf.Clamp01(elapsedTime / desiredDuration); // 修改局部位置,父物体的移动会自动带动子物体X轴移动 Top.transform.localPosition = Vector3.Lerp(TopStartLocalPos, TopEndLocalPos, percentageComplete); Bottom.transform.localPosition = Vector3.Lerp(BottomStartLocalPos, BottomEndLocalPos, percentageComplete); if (percentageComplete >= 1f) { IsOpening = false; hasSet = false; } } } }
关键改动说明
- 固定Lerp起始位置:仅在触发开合时初始化
TopStartLocalPos和BottomStartLocalPos,避免每帧重置导致插值失效。 - 使用局部位置(localPosition):子物体的开合动画修改局部位置,父物体负责整体向左移动,两者逻辑分离,确保动画期间管道持续移动。
- 简化目标位置计算:开合仅修改Y轴位置,X轴跟随父物体自然移动,无需额外计算X坐标的偏移,逻辑更清晰。
- 优化状态控制:添加
Mathf.Clamp01确保插值进度不会超过1,同时调整触发逻辑避免重复初始化。
内容的提问来源于stack exchange,提问作者Noé Crespo García
相关产品推荐
相关产品推荐

