Home > database >  How do I use an IEnumerator in a for loop?
How do I use an IEnumerator in a for loop?

Time:09-08

I'm trying to make a snake game where I want the user to move 1 square at a time at a regular pace. I want to calculate how far the edge of the screen is and then loop my IEnumerator as many times as it takes to get there. My square character's first movement works as intended, but then it just snaps to the side of the screen where it's going. How do I prevent this ?

    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));
                }
            }
        }
    }

CodePudding user response:

The problem is, everything that happens in your for loop takes place during single frame and you end up starting multiple co-routines at the same time. So if you are at y=0 and move up, you will start four co-routines. First will execute its code instantly, other three will fire their code at the same time half a second later, hence your snap to the edge behaviour.

To prevent this, you would have to put your loop inside your co-routine body, and use yield inside the loop. Maybe you should add a parameter for number of steps to your co-routine to parameterize it.

That should answer your question, but frankly speaking using co-routines for this problem seems unsuitable: you need to stop them, when user changes direction, and that can happen quite frequently. Starting co-routine to execute single move and then kill it seems like an overkill. Just use timer in an update, move player one space according to last inputed direction and check if he isn't at the edge already.

  • Related