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

Unity披萨餐厅游戏中WaitForPizza协程无法停止的问题求助

Fixing Your WaitForPizza Coroutine Stop Issue

Hey there! Let's break down why your WaitForPizza coroutine won't stop when you deliver the pizza, and fix it step by step.

The Core Problem

Your current code has two big issues with how you handle coroutine instances:

  1. Mismatched Coroutine References: You initialize WAIT = WaitForPizza() in Start(), but every time you call StartCoroutine(WaitForPizza()) in Update(), you're creating a new coroutine instance. The WAIT variable points to the original (unused) instance, so StopCoroutine(WAIT) does nothing to the actually running coroutines.
  2. Repeated Coroutine Starts: The Update() loop checks your condition every frame, so it's starting dozens of WaitForPizza coroutines over time—even if one's already running. Stopping a single reference won't kill all those duplicates.

Fixed Code Implementation

Here's the revised code with comments explaining the key changes:

// Use Coroutine type to track actively running coroutines (not just IEnumerator)
private Coroutine currentWaitCoroutine;
private Coroutine currentEatCoroutine;
private Coroutine currentPayCoroutine;

private void Start() {
    // No need to pre-initialize IEnumerators—we'll create coroutines when needed
}

private void OnTriggerEnter(Collider other) {
    if (other.gameObject.CompareTag("Pizza")) {
        canEat = true;
        // Stop the wait coroutine immediately when pizza is delivered
        StopWaitCoroutine();
    }
    if (other.gameObject.CompareTag("Out")) {
        Destroy(this.gameObject);
    }
}

void Update() {
    if (isEating) {
        if (Vector3.Distance(transform.position, agent.destination) <= 1f) {
            anim.SetTrigger("sit");
            isEating = false;
        }
    }

    // Only start WaitForPizza if it's not already running and conditions are met
    if (!isEating && !isPaying && !isOut && !canEat && currentWaitCoroutine == null) {
        currentWaitCoroutine = StartCoroutine(WaitForPizza());
    }

    // Start EatPizza when canEat is true, and ensure we don't start multiple instances
    if (!isEating && !isPaying && !isOut && canEat && currentEatCoroutine == null) {
        currentEatCoroutine = StartCoroutine(EatPizza());
    }

    if (isPaying) {
        isEating = false;
        anim.SetTrigger("walk");
        agent.destination = checkoutTarget.position;
        if (Vector3.Distance(transform.position, agent.destination) <= 1f) {
            anim.SetTrigger("wait");
            if (ifCashier) {
                // Throw money logic here
                isPaying = false;
                isOut = true;
            }
            if (!ifCashier && currentPayCoroutine == null) {
                currentPayCoroutine = StartCoroutine(WaitForTheCase());
            }
        }
    }

    if (isOut) {
        anim.SetTrigger("walk");
        isEating = false;
        isPaying = false;
        agent.destination = outTarget.position;
        // Clean up coroutines when leaving
        StopAllCoroutines();
        currentWaitCoroutine = null;
        currentEatCoroutine = null;
        currentPayCoroutine = null;
    }
}

// Helper method to safely stop the wait coroutine
private void StopWaitCoroutine() {
    if (currentWaitCoroutine != null) {
        StopCoroutine(currentWaitCoroutine);
        currentWaitCoroutine = null;
    }
}

IEnumerator WaitForTheCase() {
    anim.SetTrigger("wait");
    yield return new WaitForSeconds(randomFloatWait);
    angry.SetActive(true);
    isEating = false;
    isPaying = false;
    isOut = true;
    currentPayCoroutine = null;
}

IEnumerator EatPizza() {
    angry.SetActive(false);
    happy.SetActive(true);
    yield return new WaitForSeconds(randomFloatWait);
    happy.SetActive(false);
    isEating = false;
    isPaying = true;
    isOut = false;
    currentEatCoroutine = null;
}

IEnumerator WaitForPizza() {
    yield return new WaitForSeconds(randomFloatWait);
    // Only trigger angry state if we still haven't received pizza
    if (!canEat) {
        angry.SetActive(true);
        isEating = false;
        isPaying = false;
        isOut = true;
    }
    currentWaitCoroutine = null;
}

Key Changes Explained

  • Coroutine Tracking: We switched from IEnumerator variables to Coroutine variables. This lets us track the actual running instance of each coroutine, so we can stop it reliably.
  • Single Instance Checks: We add checks like currentWaitCoroutine == null before starting a new coroutine, preventing multiple duplicate coroutines from running at once.
  • Helper Stop Method: The StopWaitCoroutine() method ensures we only stop the coroutine if it's actually running, avoiding null reference errors.
  • Cleanup: We reset coroutine references to null once they finish, so we can start them again later if needed.
  • Simplified WaitForPizza: Removed the while loop (it was causing infinite waits if canEat never triggered) and added a check after the wait to only trigger anger if the pizza still hasn't been delivered.

This should fix your issue—when the pizza is delivered, the WaitForPizza coroutine will be stopped immediately, and EatPizza will take over as expected.

内容的提问来源于stack exchange,提问作者Dcnsll

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 15:58:13