You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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));
            }
        }
    }
}
问题原因
  1. 协程批量启动导致同步执行:循环里一次性启动了所有移动协程,每个协程都会等待0.5秒后执行移动操作。由于所有协程的等待时间完全一致,到时间后会同时完成移动,角色瞬间跑完所有步数,看起来像瞬移。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 23:45:42