0

This is the part i'm trying to use the StartCoroutine:

//StartCoroutine(movement());
    }

    IEnumerator movement()
    {
        player.localPosition += selectedDirection;
        FindDirections();

        yield return new WaitForSeconds(0.5f);
    }

Now i'm not using it but when i do use it i'm getting this error and the program is close:

Close

Then i have to select or Debug or Close Program What i want is to make the player to change position each 0.5 seconds.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System.IO;

public class PathFinder : MonoBehaviour
{
    public Transform player;
    public float playerMoveSpeed = 1f;
    public float playerRotationSpeed = 0.5f;
    public float distanceToTravel = 1f;
    public bool randomPath = true;
    public List<Vector3> possibleDirections = new List<Vector3>();
    public Vector3 selectedDirection;

    private Transform start;
    private Transform end;
    private GridGenerator gridgenerator;
    private float m_distanceTraveled = 0f;
    private List<Vector3> visitedList = new List<Vector3>();
    private List<Vector3> toBeVisitedList = new List<Vector3>();
    private Vector3 playerPosition;
    private const float margin = 0.001f;

    public void FindPath()
    {
        gridgenerator = GetComponent<GridGenerator>();
        GenerateStartEnd();
        FindDirections();
        m_distanceTraveled = 0;
    }

    private void FindDirections()
    {
        possibleDirections = new List<Vector3>();
        playerPosition = player.localPosition;
        m_distanceTraveled = 0;

        if (playerPosition.x > 1)
        {
            // can go left
            possibleDirections.Add(Vector3.left);
        }

        if (playerPosition.x + gridgenerator.spaceBetweenBlocks < gridgenerator.gridWidth * gridgenerator.spaceBetweenBlocks)
        {
            // can go right
            possibleDirections.Add(Vector3.right);
        }

        if (playerPosition.z > 1)
        {
            // can go backward
            possibleDirections.Add(Vector3.back);
        }


        if (playerPosition.z + gridgenerator.spaceBetweenBlocks < gridgenerator.gridHeight * gridgenerator.spaceBetweenBlocks)
        {
            // can go forward
            possibleDirections.Add(Vector3.forward);
        }

        if (randomPath == true)
        {
            selectedDirection = possibleDirections[Random.Range(0, possibleDirections.Count)];
        }

        player.forward = selectedDirection;

        //StartCoroutine(movement());
    }

    IEnumerator movement()
    {
        player.localPosition += selectedDirection;
        FindDirections();

        yield return new WaitForSeconds(0.5f);
    }

    private void Update()
    {

        /*if (m_distanceTraveled < distanceToTravel)
        {
            Vector3 oldPosition = player.localPosition;
            player.localPosition += selectedDirection * Time.deltaTime * playerMoveSpeed;
            m_distanceTraveled += Vector3.Distance(oldPosition, player.localPosition);
        }

        if (m_distanceTraveled > distanceToTravel)
        {
            FindDirections();
        }*/
    }

    private List<Vector3> GenerateStartEnd()
    {
        GameObject walls = GameObject.Find("Walls");
        List<Transform> wallsParents = new List<Transform>();
        List<Vector3> startEndPos = new List<Vector3>();

        foreach (Transform child in walls.transform)
        {
            wallsParents.Add(child);
        }

        for (int i = 0; i < 2; i++)
        {
            wallsParents.Remove(wallsParents[Random.Range(0, wallsParents.Count)]);
        }

        var childsWall0 = wallsParents[0].GetComponentsInChildren<Transform>().ToList();
        var childsWall1 = wallsParents[1].GetComponentsInChildren<Transform>().ToList();
        childsWall0.RemoveAt(0);
        childsWall1.RemoveAt(0);

        start = childsWall0[Random.Range(0, childsWall0.Count)];
        player.position = start.position;
        end = childsWall1[Random.Range(0, childsWall1.Count)];
        end.tag = "End";
        startEndPos.Add(start.position);
        startEndPos.Add(end.position);

        start.GetComponent<Renderer>().material.color = Color.red;
        end.GetComponent<Renderer>().material.color = Color.blue;

        return startEndPos;
    }
}
jdoedoe doedoe
  • 343
  • 5
  • 16

2 Answers2

4

Inside the coroutine movement() you call FindDirections(). Inside FindDirections() you start movement(), now; Inside the coroutine movement() you call FindDirections()... and so on..

Also, you are invoking FindDirections() inside the Update() method. The method Update is called every frame (so if your game is running at 30FPS this Update will be executed 30 times every second), so, you are calling every frame a method A that will call another method B, that will call method A, etc.. I recommend you to be careful about what are you invoking inside Update().

So, probably you are getting a StackOverFlowException (yes, the same name that this website has). If for any reason Unity crash, a way to understand what happened is check the logs.

mayo
  • 3,845
  • 1
  • 32
  • 42
  • I understand. Then how can i call it using only Update ? I want for example every second or half of second to call FindDirections and move the player by 1.5 distance according to the directions he is facing. Calling FindDirections will give each time a new direction and the player will be facing that direction. – jdoedoe doedoe Dec 11 '17 at 06:28
  • Well, you have to define when are you going to call a.- FindDirections() and b.- Movement(). Now boths calls the other, and that is one problem. So, for example, you can call only on `Update()`; `FindDirections()` and `Movement()` and remove the reference to `FindDirections` inside `Movement` and the reference to `Movement` inside `FindDirections`. So part of your code (`movement`) will try to follow certain direction, and another part of your code (`FindDirections`) will try to set a direction that satisfy some rules. – mayo Dec 11 '17 at 06:37
  • I recommend also think first about how frequent do you want to a.- move the player to some direction, and b.- update the target-direction. In order to call some elements after x seconds, you can check this: https://answers.unity.com/questions/1220440/how-to-display-call-a-function-every-second.html – mayo Dec 11 '17 at 06:39
3

Mayo's answer explained your issue well. This shows you how to accomplish what you wanted to do.

I want is to make the player to change position each 0.5 seconds.

Instead of calling the movement function every time in the FindDirections function, call it once then execute your code in a while loop. This should fix your issue. Just move StartCoroutine(movement()); from the FindDirections function to the Start function or somewhere that calls it once. Below is your new movement code.

IEnumerator movement()
{
    while (true)
    {
        player.localPosition += selectedDirection;


        FindDirections();

        yield return new WaitForSeconds(0.5f);
    }
}

The while loop above will execute every 0.5f second.

Programmer
  • 121,791
  • 22
  • 236
  • 328