Unity如何自定义物体移动起始位置并保证移动时位置正确更新
问题根源
- 原代码在
Start()方法中就固定记录了游戏启动瞬间的物体位置作为移动起点,若你是游戏启动后才触发移动(比如运行后手动勾选go参数、其他逻辑延迟触发移动),此时如果物体位置已经发生变化,移动时就会跳回游戏启动时的位置;即使你运行前就勾选了go,出现位置重置也大概率是编辑模式下测试时originPosition被异常序列化导致。 - 注释掉
originPosition赋值语句后,该私有变量默认值为Vector3.zero,因此物体会从世界坐标原点开始插值,位置自然不符合预期。 - 将赋值语句移到
Update()中会导致每帧都用当前位置覆盖移动起点,Lerp插值的起始点不断变化,移动逻辑完全失效。
修复方案
将移动初始化逻辑(记录起始位置、重置计时器、重置状态)调整到移动指令真正触发的时刻,也就是go参数从false切换为true的瞬间,修改后代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MoveToTarget : MonoBehaviour { public enum TransitionState { None, MovingTowards, Transferring } public Transform destinationTransform; public Transform navi; public Transform player; public bool isChild = false; public AnimationCurve curve = AnimationCurve.EaseInOut(0.0f, 0.0f, 1.0f, 1.0f); public float duration = 10.0f; public bool go = false; private float t; private Transform originTransform; private float timer; private TransitionState state = TransitionState.MovingTowards; private Vector3 originPosition; // 新增标记:记录移动是否已经初始化 private bool _moveStarted = false; void Start() { curve.postWrapMode = WrapMode.Once; } void Update() { // 检测到移动指令触发,且未初始化过移动时执行初始化 if (go && !_moveStarted) { originPosition = transform.position; t = 0f; state = TransitionState.MovingTowards; _moveStarted = true; } // 检测到移动指令取消,重置初始化标记,支持下次重新触发移动 else if (!go && _moveStarted) { _moveStarted = false; } if (go) { switch (state) { case TransitionState.MovingTowards: var v = destinationTransform.position - transform.position; if (v.magnitude < 0.001f) { state = TransitionState.Transferring; originTransform = destinationTransform; timer = 0; return; } t += Time.deltaTime; float s = t / duration; transform.position = Vector3.Lerp(originPosition, destinationTransform.position, curve.Evaluate(s)); break; case TransitionState.Transferring: timer += Time.deltaTime; this.transform.position = Vector3.Lerp(originTransform.position, destinationTransform.position, timer); if (timer >= 1.0f) { this.transform.parent = destinationTransform; transform.localPosition = new Vector3(0, 0, 0); isChild = true; state = TransitionState.None; this.enabled = false; return; } break; default: this.enabled = false; return; } } } }
修改说明
- 现在你可以在编辑器运行游戏前,任意拖拽调整物体的位置,只要运行后触发
go = true(运行前就勾选go也可以),物体就会从你设置的位置开始向目标点移动。 - 额外支持中途停止再重新移动的需求:如果移动过程中取消
go的勾选,下次再勾选时物体会从当前所在位置重新开始向目标点移动。
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

