如何在for循环中使用IEnumerator?蛇游戏移动瞬移问题解决
问题
制作蛇类游戏时,希望角色以固定节奏每次移动1格。计算角色到屏幕边缘的距离后,通过循环调用IEnumerator实现移动到边缘,但首次移动正常后,角色直接瞬移到目标边缘,该如何解决?
原代码
bool firstgo = true; void Start() { transform.position = new Vector3(0, 0, 0); } void Update() { CalculateMovement(); } private IEnumerator Delay(int x,int y,int z) { if (firstgo == true) { transform.position += new Vector3(x, y, z); firstgo = false; } else { yield return new WaitForSeconds(0.5f); transform.position += new Vector3(x, y, z); } } void CalculateMovement() { if (Input.GetKeyDown(KeyCode.UpArrow)) { if (transform.position.y != 4) { float updistance = 4f - transform.position.y; for (int i = 0; i < updistance; i++) { StartCoroutine(Delay(0, 1, 0)); } } } if (Input.GetKeyDown(KeyCode.DownArrow)) { if (transform.position.y != -4) { float downdistance = 4f + transform.position.y; for (int i = 0; i < downdistance; i++) { StartCoroutine(Delay(0, -1, 0)); } } } if (Input.GetKeyDown(KeyCode.RightArrow)) { if (transform.position.x != 4) { float rightdistance = 4f - transform.position.x; for (int i = 0; i < rightdistance; i++) { StartCoroutine(Delay(1, 0, 0)); } } } if (Input.GetKeyDown(KeyCode.LeftArrow)) { if (transform.position.x != -4) { float leftdistance = 4f + transform.position.x; for (int i = 0; i < leftdistance; i++) { StartCoroutine(Delay(-1, 0, 0)); } } } }
问题原因
- 协程批量启动导致同步执行:循环里一次性启动了所有移动协程,每个协程都会等待0.5秒后执行移动操作。由于所有协程的等待时间完全一致,到时间后会同时完成移动,角色瞬间跑完所有步数,看起来像瞬移。
firstgo逻辑仅生效一次:firstgo只在第一次调用协程时跳过等待,之后所有协程都进入等待分支,但它们是同时启动的,等待结束后会同步执行移动,无法形成分步移动的节奏。
解决方法
改为在单个协程内循环执行移动操作,每次移动后等待固定间隔,同时添加移动状态标记避免重复触发输入:
bool isMoving = false; float moveInterval = 0.5f; void Start() { transform.position = new Vector3(0, 0, 0); } void Update() { CalculateMovement(); } private IEnumerator MoveToEdge(int xDir, int yDir, float targetPos) { isMoving = true; // 根据移动方向判断当前是否到达目标边缘 while ((xDir != 0 && Mathf.Abs(transform.position.x) < Mathf.Abs(targetPos)) || (yDir != 0 && Mathf.Abs(transform.position.y) < Mathf.Abs(targetPos))) { transform.position += new Vector3(xDir, yDir, 0); yield return new WaitForSeconds(moveInterval); } isMoving = false; } void CalculateMovement() { // 移动过程中不响应新的输入指令 if (isMoving) return; if (Input.GetKeyDown(KeyCode.UpArrow) && transform.position.y != 4) { StartCoroutine(MoveToEdge(0, 1, 4f)); } else if (Input.GetKeyDown(KeyCode.DownArrow) && transform.position.y != -4) { StartCoroutine(MoveToEdge(0, -1, -4f)); } else if (Input.GetKeyDown(KeyCode.RightArrow) && transform.position.x != 4) { StartCoroutine(MoveToEdge(1, 0, 4f)); } else if (Input.GetKeyDown(KeyCode.LeftArrow) && transform.position.x != -4) { StartCoroutine(MoveToEdge(-1, 0, -4f)); } }
关键改进点
- 用单个协程处理连续移动,每次移动后等待固定间隔,确保角色按节奏分步移动。
- 添加
isMoving状态标记,避免移动过程中触发新的移动指令,防止逻辑冲突。 - 直接在协程内循环判断是否到达边缘,无需提前计算移动次数,逻辑更简洁可靠。
内容的提问来源于stack exchange,提问作者Mohamed Nasser
相关产品推荐
相关产品推荐

