复刻经典Snake游戏:MoveTowards与OnTriggerEnter2D异常问题
经典Snake游戏复刻的两个技术问题排查与解决
问题1:Vector3.MoveTowards函数未正常工作(蛇身无法正确跟随玩家)
核心原因
蛇身跟随逻辑存在设计错误:所有蛇身都直接追逐玩家的当前位置,而非经典Snake游戏中“链式跟随”(每个蛇身追逐前一个身体部位位置)的标准逻辑。此外还有两个细节问题放大了异常:
- 蛇身移动速度(
Speed = 4)低于玩家速度(snakeSpeed = 5),导致蛇身永远无法追上玩家,看起来像是MoveTowards失效。 - 虽然
snakePosition的赋值时机(先移动玩家再更新位置)逻辑正确,但由于整体跟随逻辑错误,导致最终效果异常。
解决方法
实现正确的链式跟随逻辑,维护蛇身部位队列,让每个蛇身追踪前一个部位的位置:
- 在
SnakeMovement中添加列表存储所有蛇身对象:
public List<Transform> snakeBodyParts = new List<Transform>();
- 修改生成蛇身的代码,将新蛇身加入列表:
// 替换原Instantiate代码段 GameObject newBody = Instantiate(snakeBody, spawnPosition, transform.rotation); snakeBodyParts.Add(newBody.transform);
- 重写
ChaseSnake脚本,让蛇身追踪指定目标(而非固定追踪玩家):
using UnityEngine; public class ChaseSnake : MonoBehaviour { private Transform target; [SerializeField] private float speed = 5f; // 设为与玩家速度一致或略高 public void SetTarget(Transform newTarget) { target = newTarget; } void Update() { if (target != null) { transform.position = Vector3.MoveTowards(transform.position, target.position, speed * Time.deltaTime); } } }
- 在
SnakeMovement中,为新生成的蛇身设置追踪目标:
// 生成新蛇身后添加 ChaseSnake chaseScript = newBody.GetComponent<ChaseSnake>(); if (snakeBodyParts.Count == 1) { // 第一个蛇身追踪玩家 chaseScript.SetTarget(transform); } else { // 后续蛇身追踪前一个蛇身部位 chaseScript.SetTarget(snakeBodyParts[snakeBodyParts.Count - 2]); }
问题2:生成snakeBody时,蛇与蛇身未靠近却触发碰撞
核心原因
- 蛇身生成位置逻辑错误:初始
Distance = 10被直接用作世界坐标偏移量,且每次吃食物都累加Distance,导致生成的蛇身距离玩家越来越远,蛇身向玩家移动时极易触发碰撞;同时生成位置的方向计算未贴合蛇身链式排列的需求。 - 未销毁食物对象:玩家碰撞食物后未销毁食物,若食物的Collider为Trigger,可能与新生成的蛇身触发碰撞,被误判为蛇身碰撞。
- 碰撞检测无初始化过滤:蛇身生成时若因位置误差与玩家Collider重叠,会直接触发死亡逻辑。
解决方法
- 修正蛇身生成位置逻辑:改为基于移动方向的链式排列,使用固定间距生成蛇身:
// 替换原生成蛇身的多分支代码 // 先获取当前移动方向 Vector3 moveDirection = Vector3.zero; if (up) moveDirection = Vector3.up; else if (down) moveDirection = Vector3.down; else if (right) moveDirection = Vector3.right; else if (left) moveDirection = Vector3.left; // 固定蛇身间距(根据Sprite大小调整,示例为1单位) float bodySpacing = 1f; // 生成在玩家后方,与最后一个部位保持固定间距 Vector3 spawnPosition = transform.position - moveDirection * bodySpacing * (snakeBodyParts.Count + 1); GameObject newBody = Instantiate(snakeBody, spawnPosition, transform.rotation); snakeBodyParts.Add(newBody.transform);
- 碰撞食物后销毁食物:在每个食物碰撞分支中添加销毁代码:
if (up == true && collision.gameObject.tag == "Food") { // ... 原生成蛇身代码 Destroy(collision.gameObject); // 添加此行 } // 其他方向的食物碰撞逻辑同理添加
- 过滤初始化阶段的碰撞:生成蛇身时暂时禁用其Collider,延迟一帧后启用:
// 生成新蛇身后添加 Collider2D bodyCollider = newBody.GetComponent<Collider2D>(); bodyCollider.enabled = false; StartCoroutine(EnableColliderAfterFrame(bodyCollider)); // 在SnakeMovement中新增协程函数 private IEnumerator EnableColliderAfterFrame(Collider2D collider) { yield return null; collider.enabled = true; }
内容的提问来源于stack exchange,提问作者raphael
相关产品推荐
相关产品推荐

