Home > database >  C# Coroutine repeating a specific part?
C# Coroutine repeating a specific part?

Time:10-27

I am making a cookie clicker game for a school project and for my achievement system I want to have a simple animation pop up, and text in a separate menu script that already works perfectly fine.

The issue I am having is that the first two achievements work fine, but after the second one pops up, it just repeats with "Test B" and "Test C" repeating infinitely in the console.

I've tried to have values try to make an 'if' statement void but nothing seems to work.

I feel like I am just eating my own tail with all of the Boolean values I created to get this far.

This is my code below, from only a single script in my Unity file. Hopefully this has enough information needed for guidance.

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

public class Achievements : MonoBehaviour
{
    [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] 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(achiementcount);
        print(achidone);
        if (achiementcount == 1)
        {
            if (!achievementani)
            {
                if (!achievementrec)
                {
                    print("Test D");
                    achiOne.SetActive(true);
                    achievementBanner.SetActive(true);
                    achievementText.SetActive(true);
                    StartCoroutine(AchievementGot());
                    ///achidone = true;
                }
            }
        }
        if (achidone == true)
        {
            ///print("Test");
            ///achidone = false;
            if (achiementcount == 2)
                    {
                        achievementText.GetComponent<Text>().text = "Achievement: First Clicker!";
                        achievementani = false;
                        achievementrec = false;
                        if (!achievementani)
                        {
                            if (!achievementrec)
                            {
                                print("Test C");
                                achiTwo.SetActive(true);
                                achievementBanner.SetActive(true);
                                achievementText.SetActive(true);
                                ///achidone = true;
                                StartCoroutine(AchievementGot());
                            }
                        }
                    }
        }
        
        ///print(achidone);
        if (achidone == true)
        {
            ///achidone = false;
            if (achiementcount == 3)
                    {
                        achievementText.GetComponent<Text>().text = "Achievement: First Upgrade!";
                        achievementani = false;
                        achievementrec = false;
                        if (!achievementani)
                        {
                            if (!achievementrec)
                            {
                                print("Test A");
                                achiThree.SetActive(true);
                                achievementBanner.SetActive(true);
                                achievementText.SetActive(true);
                                StartCoroutine(AchievementGot());
                            }
                        }
                    }
        }   
    }
    IEnumerator AchievementGot()
    {
        ///achievementrec = true;
        achievementBannerAnimation.GetComponent<Animation>().Play("Achievement");
        achievementTextAnimation.GetComponent<Animation>().Play("AchiText");
        yield return new WaitForSeconds(6);
        achidone = true;
        print("Test B");
        ///print(achidone);
        achievementBanner.SetActive(false);
        achievementText.SetActive(false);
        achievementani = true;
        achievementrec = true;
        ///achidone = false;
    }
}

CodePudding user response:

First of all you should use a List/Array.

Then you probably also want to show the banner only ONCE when the achievement is unlocked the first time so you should also keep track of which one you already showed.

E.g. something like

[Serializable]
public class Achievement
{
    // text to display in the banner
    public string Label; 
    // the object to enable
    public GameObject GameObject;
    // has this been achieved
    public bool Unlocked;
    // has this achievement been displayed
    public bool Displayed;
}

public class Achievements : MonoBehaviour
{
    // in general instead of many GetComponent calls use the correct type right away in the Inspector
    [SerializeField] private GameObject achievementBanner;
    [SerializeField] private Text achievementText;
    [SerializeField] private Animation achievementBannerAnimation;
    [SerializeField] private Animation achievementTextAnimation;
    [SerializeField] private Achievement[] achievements;

    // is currently a display routine running already?
    private bool currentlyDisplaying;

    private void Start()
    {
        // initially hide all objects
        foreach (var achievement in achievements)
        {
            achievement.GameObject.SetActive(false);
        }

        achievementBanner.SetActive(false);
        achievementText.gameObject.SetActive(false);
    }

    private void Update()
    {
        // if currently a display routine is running do nothing
        if (currentlyDisplaying) return;

        // otherwise go through all achievements
        foreach (var achievement in achievements)
        {
            // check if one is unlocked but hasn't been displayed yet
            if (achievement.Unlocked && !achievement.Displayed)
            {
                // set to displayed and display it
                StartCoroutine(DisplayAchievement(achievement));
                // break to only handle one at a time
                break;
            }
        }
    }

    private IEnumerator DisplayAchievement(Achievement achievement)
    {
        // just in case if other routine is already running do nothing
        if (currentlyDisplaying) yield break;

        // block other routines from being started
        currentlyDisplaying = true;

        // set displayed so it is not displayed again
        achievement.Displayed = true;

        // Enable your objects and set the text accordingly
        achievementText.text = achievement.Label;
        achievementText.gameObject.SetActive(true);
        achievementBanner.SetActive(true);
        achievement.GameObject.SetActive(true);

        achievementBannerAnimation.Play("Achievement");
        achievementTextAnimation.Play("AchiText");

        yield return new WaitForSeconds(6);

        achievementBanner.SetActive(false);
        achievementText.gameObject.SetActive(false);

        // allow the next routine to start
        currentlyDisplaying = false;
    }
}
  • Related