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

Unity成就系统中C# Coroutine仅触发一次的问题求助

我正在做学校项目的Cookie Clicker类型游戏,现在完善成就系统。获得成就时往achievementlist列表加整数,系统每6秒检查列表项数,项数≥1就运行协程播放动画。但实际运行有两个问题:

  • 直接跳转到列表最新项,而非第一项
  • 打印显示列表还有项,但动画只播放一次;播放后用achievementlist.RemoveAt(0),之前列表有两个值,剩余一个后就被忽略了

问题代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Achievements : MonoBehaviour
{
    public int isrunning = 1;
    public bool checkcomplete = false;
    [SerializeField] GameObject achievementBanner;
    [SerializeField] GameObject achievementText;
    [SerializeField] GameObject achievementBannerAnimation;
    [SerializeField] GameObject achievementTextAnimation;


    [SerializeField] GameObject achiOne;
    [SerializeField] GameObject achiTwo;
    [SerializeField] GameObject achiThree;
    [SerializeField] GameObject achiFour;
    [SerializeField] GameObject achiFive;
    [SerializeField] GameObject achiSix;

    ///[SerializeField] GameObject[] AchievementList;

    public List<int> achievementlist = new List<int> ();
    ///public int[] achievementsunlock = new int[];


    [SerializeField] public static int achiementcount;
    bool achievementrec = false;
    ///bool achievementani = false;
    bool achidone = false;
    // Start is called before the first frame update
    void Start()
    {
        achiOne.SetActive(false);
        achiTwo.SetActive(false);
        achiThree.SetActive(false);
        achiFour.SetActive(false);
        achiFive.SetActive(false);
        achiSix.SetActive(false);
        achievementBanner.SetActive(false);
        achievementText.SetActive(false);
        achievementText.GetComponent<Text>().text = "Achievement: First cookie!";

    }

    // Update is called once per frame
    void Update()
    {
        print("|");
        print(achievementlist.Count);
        print("|");
        if (isrunning == 1)
        {
            StartCoroutine(Wait());
        }
        if (checkcomplete == true)
        {
            StartCoroutine(CheckAchievement());
        }
        ///print(achievementlist.Count);
        ///print(achidone);
        if (achiementcount == 1)
        {
            ///print("Test D");
            ///achiOne.SetActive(true);
            ///achievementBanner.SetActive(true);
            ///achievementText.SetActive(true);
            if (!achidone)
            {
                ///print("Test D");
                achiOne.SetActive(true);
                ///achievementBanner.SetActive(true);
                ///achievementText.SetActive(true);
                if (!achievementrec)
                {
                    achievementlist.Add(1);
                    achievementrec = true;
                }
            }
            
            ///print(achievementlist[1]);
            ///print(achievementlist[1]);
            ///StartCoroutine(AchievementGot());
            ///achidone = true;
            ///}
            ///}
        }
        if (achiementcount == 2)
        {
            achievementText.GetComponent<Text>().text = "Achievement: First Clicker!";
            ///achievementrec = false;
            if (achievementrec == true)
            {
                achievementlist.Add(2);
                achievementrec = false;
            }
            ///print(achievementlist[1]);
            ///print(achievementlist[2]);
            ///print("Test C");
            achiTwo.SetActive(true);
            ///achievementBanner.SetActive(true);
            ///achievementText.SetActive(true);
            ///StartCoroutine(AchievementGot());
        }
        
        ///print(achidone);

            ///achidone = false;
        if (achiementcount == 3)
        {
            achievementText.GetComponent<Text>().text = "Achievement: First Upgrade!";
            achievementlist.Add(3);
            ///achievementrec = false;
            ///print("Test A");
            achiThree.SetActive(true);
            ///achievementBanner.SetActive(true);
            ///achievementText.SetActive(true);
            ///StartCoroutine(AchievementGot());
            ///}
            ////}
        }
    }
    public IEnumerator Wait()
    {
        isrunning = 0;
        yield return new WaitForSeconds(7);
        if (achievementlist.Count >= 1)
        {
            achievementlist.RemoveAt(0);
            print("Test A");
            print(achievementlist.Count);
            checkcomplete = true;
        }
        else
        {
            print("Test B");
            checkcomplete = false;
        }
        isrunning = 1;
    }
    IEnumerator CheckAchievement()
    {
        ///achievementlist.RemoveAt(0);
        achievementBanner.SetActive(true);
        achievementText.SetActive(true);
        ///achievementText.GetComponent<Text>().text = (achievementlist[1]);
        achievementBannerAnimation.GetComponent<Animation>().Play("Achievement");
        achievementTextAnimation.GetComponent<Animation>().Play("AchiText");
        ///achievementlist.RemoveAt(0);
        yield return new WaitForSeconds(6);
        achievementBanner.SetActive(false);
        achievementText.SetActive(false);
        ///yield return new WaitForSeconds(6);
    }
    IEnumerator AchievementGot()
    {
        ///achievementrec = true;
        ///achievementlist.RemoveAt(1);
        ///if (achievementlist.Count == 1)
        ///{
            ///print("Test List");
            ///achievementBannerAnimation.GetComponent<Animation>().Play("Achievement");
            ///achievementTextAnimation.GetComponent<Animation>().Play("AchiText");
            ///achievementlist.RemoveAt(0);
            ///achidone = true;
        ///}
        ///achievementBannerAnimation.GetComponent<Animation>().Play("Achievement");
        ///achievementTextAnimation.GetComponent<Animation>().Play("AchiText");
        ///print(achievementlist[1]);
        ///print(achievementlist[2]);
        yield return new WaitForSeconds(6);
        achidone = true;
        ///print(achievementlist.Contains(1));
        ///print(achievementlist.Count);
        ///if(achievementlist.Length >= 1)
        ///{
            ///print("Test F");
        ///}
        ///print("Test B");
        achievementBanner.SetActive(false);
        achievementText.SetActive(false);
        ///achievementrec = true;
    }
}

问题根源与修复方案

1. 列表项被提前移除导致数据丢失

Wait协程里在触发动画前就执行了achievementlist.RemoveAt(0),直接删掉第一个成就,后续动画拿不到对应数据,多成就场景下还会跳过剩余项。

修复:把移除操作移到动画播放完成后,放在CheckAchievement协程末尾,同时根据当前成就ID设置对应文本:

IEnumerator CheckAchievement()
{
    // 获取当前要显示的成就ID
    int currentAchievementId = achievementlist[0];
    // 根据ID匹配对应文本
    switch(currentAchievementId)
    {
        case 1:
            achievementText.GetComponent<Text>().text = "Achievement: First cookie!";
            break;
        case 2:
            achievementText.GetComponent<Text>().text = "Achievement: First Clicker!";
            break;
        case 3:
            achievementText.GetComponent<Text>().text = "Achievement: First Upgrade!";
            break;
    }

    achievementBanner.SetActive(true);
    achievementText.SetActive(true);
    achievementBannerAnimation.GetComponent<Animation>().Play("Achievement");
    achievementTextAnimation.GetComponent<Animation>().Play("AchiText");
    
    yield return new WaitForSeconds(6);
    
    achievementBanner.SetActive(false);
    achievementText.SetActive(false);
    // 动画播放完成后再移除第一项
    achievementlist.RemoveAt(0);
    // 重置标记,等待下一轮检查
    checkcomplete = false;
}

2. 协程重复触发导致逻辑混乱

Update每帧检查isrunning == 1就启动Wait协程,会生成多个并行协程,互相干扰状态值。

修复:用布尔值标记协程运行状态,避免重复启动:

// 替换原int类型的isrunning为布尔值
private bool isWaitCoroutineRunning = false;

void Update()
{
    // ...其他代码...
    if (!isWaitCoroutineRunning)
    {
        StartCoroutine(Wait());
    }
    // ...其他代码...
}

public IEnumerator Wait()
{
    isWaitCoroutineRunning = true;
    yield return new WaitForSeconds(6); // 改为需求的6秒检查间隔
    if (achievementlist.Count >= 1 && !checkcomplete)
    {
        checkcomplete = true;
    }
    isWaitCoroutineRunning = false;
}

3. 成就添加逻辑冗余且错误

原代码用achievementrec全局标记导致部分成就无法正确添加,改为给每个成就加独立标记,确保只添加一次:

// 给每个成就添加独立的已获取标记
private bool hasGotAchievement1 = false;
private bool hasGotAchievement2 = false;
private bool hasGotAchievement3 = false;

void Update()
{
    // ...其他代码...
    if (achiementcount == 1 && !hasGotAchievement1)
    {
        achiOne.SetActive(true);
        achievementlist.Add(1);
        hasGotAchievement1 = true;
    }
    if (achiementcount == 2 && !hasGotAchievement2)
    {
        achiTwo.SetActive(true);
        achievementlist.Add(2);
        hasGotAchievement2 = true;
    }
    if (achiementcount == 3 && !hasGotAchievement3)
    {
        achiThree.SetActive(true);
        achievementlist.Add(3);
        hasGotAchievement3 = true;
    }
    // ...其他代码...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 13:55:24