复刻Mario Party棋盘:如何用偏移量跟踪位置实现棋子正确移动
问题描述
我正在复刻Mario Party棋盘游戏,需要通过射线检测让棋子能移动到任意状态(开启/关闭)的地格上。目前用DOTween实现固定距离移动,棋子能从初始地格左右移动,但返回第一个地格时会直接跳到最外侧地格。后续还会添加更多地格,布局不固定。
我试过加偏移量变量newPos,初始设为Vector3(0,0,0),每次移动后把新位置赋值给它,但棋子会跑到完全偏离目标的位置。如果去掉newPos,移动能正常运行,但没法跟踪当前位置。怎么通过偏移量正确跟踪棋子位置?
附当前代码:
public class PlayerMovement : MonoBehaviour { Vector3 startPos; Vector3 newPos; private void Start() { print(transform.position); startPos = gameObject.transform.localPosition; newPos = new Vector3(0, 0, 0); } void Update() { if (Input.GetKey(KeyCode.LeftArrow)) { gameObject.transform.DOLocalMove(startPos + newPos + new Vector3Int(-5, 0 , 0), 1); print(gameObject.transform.localPosition); newPos = gameObject.transform.localPosition; } if (Input.GetKey(KeyCode.RightArrow)) { gameObject.transform.DOLocalMove(startPos + newPos + new Vector3Int(5, 0, 0), 1); print(gameObject.transform.localPosition); newPos = gameObject.transform.localPosition; } } }
解决方案
问题根源
- 动画触发过于频繁:
Update中每帧都会响应按键触发DOTween动画,导致多个动画叠加,位置计算混乱。 - 位置逻辑错误:
startPos + newPos是重复叠加——newPos已经是棋子当前的本地位置,再加初始位置startPos会让目标位置偏移到错误区域。 - 位置更新时机错误:DOTween动画是异步执行的,按键时立刻取
transform.localPosition拿到的是动画开始前的旧位置,不是最终目标位置。
修正方案
方案1:用地格索引跟踪位置(推荐,适配后续可变布局)
既然后续布局不固定,直接跟踪棋子所在的地格索引比偏移量更灵活,步骤如下:
- 把所有地格存入一个数组或列表,方便通过索引获取位置。
- 用整数变量记录当前所在地格的索引。
- 按键时根据索引计算下一个地格的位置,触发动画,同时更新索引。
示例代码:
public class PlayerMovement : MonoBehaviour { // 把场景中的所有地格拖到这个列表里,顺序要和实际布局一致 public List<Transform> tiles; private int currentTileIndex = 0; // 标记是否正在移动,防止重复触发动画 private bool isMoving = false; private void Start() { // 初始位置直接对齐第一个地格 transform.localPosition = tiles[currentTileIndex].localPosition; } void Update() { if (Input.GetKeyDown(KeyCode.LeftArrow) && !isMoving && currentTileIndex > 0) { currentTileIndex--; MoveToTarget(tiles[currentTileIndex].localPosition); } if (Input.GetKeyDown(KeyCode.RightArrow) && !isMoving && currentTileIndex < tiles.Count - 1) { currentTileIndex++; MoveToTarget(tiles[currentTileIndex].localPosition); } } private void MoveToTarget(Vector3 targetPos) { isMoving = true; // 执行移动动画,动画完成后解除移动标记 transform.DOLocalMove(targetPos, 1f).OnComplete(() => { isMoving = false; }); } }
方案2:修正偏移量跟踪逻辑(适合临时横向布局)
如果暂时用地格间距固定的横向布局,修改位置计算逻辑:
public class PlayerMovement : MonoBehaviour { // 每个地格的间距 public int tileSpacing = 5; // 记录当前的偏移步数(比如0是初始位置,-1是左移1格,+1是右移1格) private int currentOffsetStep = 0; private Vector3 startPos; private bool isMoving = false; private void Start() { startPos = transform.localPosition; } void Update() { if (Input.GetKeyDown(KeyCode.LeftArrow) && !isMoving) { currentOffsetStep--; Vector3 targetPos = startPos + new Vector3(currentOffsetStep * tileSpacing, 0, 0); MoveToTarget(targetPos); } if (Input.GetKeyDown(KeyCode.RightArrow) && !isMoving) { currentOffsetStep++; Vector3 targetPos = startPos + new Vector3(currentOffsetStep * tileSpacing, 0, 0); MoveToTarget(targetPos); } } private void MoveToTarget(Vector3 targetPos) { isMoving = true; transform.DOLocalMove(targetPos, 1f).OnComplete(() => { isMoving = false; }); } }
关键注意点
- 用
Input.GetKeyDown代替Input.GetKey,确保每次按键只触发一次移动,避免动画叠加。 - 加
isMoving标记,防止移动过程中重复触发动画。 - 用地格索引的方案更适配后续的可变布局(比如环形、分支形棋盘),推荐优先使用。
内容的提问来源于stack exchange,提问作者Jellyfish
相关产品推荐
相关产品推荐

