How can a Player select the start and end waypoints in the game?

Hello!
I need help to make a function where the player can choose the start waypoint and the end waypoint and draw the path between the two waypoints right after I release the left mouse button from on the end waypoint.

I wrote the BFS algorithm and it works, in another hand, I wrote a function to get player click on a Cube “Waypoint” and drag the mouse, then release, it reads the waypoints as a start and end waypoint,
the error is in connecting between CalculatePath() and GetFirstAndEndwaypoints()
anyone can help

Hi Malek,

In the Realm Rush section, we have a method that creates a path. I assume this is also the case in your solution.

You could make the waypoints clickable with OnMouseDown() or whatever makes sense. If a waypoint was clicked, you assign it to a variable named startWaypoint. When you click the next waypoint, you could assign it to a variable named endWaypoint. In your method, you check whether variables are not null. If they are not null, you pass the waypoints on to the pathfinding method.

1 Like

Thank you for your reply, so this should be in the waypoint.cs?

Wherever it makes sense to you. It’s your idea. :slight_smile:

1 Like

Hello again Nina!

Thank you for your help.
I have done what i was aiming to, but there is still an error shows up when i click again to create another path, the same error shows if the start and end waypoints are the same.
the previous waypoint gets to be null in the second time i try to draw a new path.

here is the code:

public class PathFinder : MonoBehaviour
{
[SerializeField] Waypoint startWaypoint, endWaypoint;

public Dictionary<Vector2Int, Waypoint> grid = new Dictionary<Vector2Int, Waypoint>();
public Queue<Waypoint> queue = new Queue<Waypoint>();
bool isRunning = true;
public Waypoint searchCenter;
public Waypoint previous;


public List<List<Waypoint>> paths = new List<List<Waypoint>>();

Vector2Int[] directions = {
    Vector2Int.up,
    Vector2Int.right,
    Vector2Int.down,
    Vector2Int.left
};


private void Start()
{
    LoadBlocks();
    //CalculatePath();
    //ColorThePath(path);
}

private void Update()
{
    ClickToSelectStartPoint();
    ClickToSelectEndPoint();
    
   // CalculatePath();
    // ColorThePath(path);
    
}

void ColorThePath(List<Waypoint> path)
{
    foreach (Waypoint wp in path)
    {
        wp.SetTopColor(Color.cyan);
    }
}

// Start is called before the first frame update



public void CalculatePath()
{
    
    BreadthFirstSearch();
    paths.Add(CreatePath());
    
}

private List<Waypoint> CreatePath()
{
    
    List<Waypoint> path = new List<Waypoint>();
    
    path.Add(endWaypoint);

     previous = endWaypoint.exploredFrom;
 
    while (previous != startWaypoint)
    {
        path.Add(previous);

        previous = previous.exploredFrom;
    }

    
    path.Add(startWaypoint);
    
    path.Reverse();
    ColorThePath(path);
    

    return path;
}



private void BreadthFirstSearch()
{
    
    queue.Enqueue(startWaypoint);
    searchCenter = startWaypoint;

    while (queue.Count > 0 && isRunning)
    {
        searchCenter = queue.Dequeue();
        HaltIfEndFound();
        ExploreNeighbours();
        searchCenter.isExplored = true;
    }
}

private void HaltIfEndFound()
{
    if (searchCenter == endWaypoint)
    {
        isRunning = false;
    }
}

private void ExploreNeighbours()
{
    if (!isRunning) { return; }

    foreach (Vector2Int direction in directions)
    {
        Vector2Int neighbourCoordinates = searchCenter.GetGridPos() + direction;
        if (grid.ContainsKey(neighbourCoordinates))
        {
            QueueNewNeighbours(neighbourCoordinates);
        }
    }
}

private void QueueNewNeighbours(Vector2Int neighbourCoordinates)
{
    Waypoint neighbour = grid[neighbourCoordinates];
    if (neighbour.isExplored || queue.Contains(neighbour))
    {
        // do nothing
    }
    else
    {
        queue.Enqueue(neighbour);
        neighbour.exploredFrom = searchCenter;
    }
}

public void ClickToSelectStartPoint()
{
    
    if (Input.GetMouseButtonDown(0))
    {
        
        startWaypoint = null;

        RaycastHit hit;
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out hit, 100.0f))
        {
            if (hit.transform.tag == "WayPoint")
            {
                GameObject block = hit.transform.gameObject;
                print(block.name + "  Is Clicked");
                Waypoint startPoint = block.GetComponentInParent<Waypoint>();
                print(startPoint.name + "This is startpoint");
                startWaypoint = startPoint;
                startWaypoint.SetTopColor(Color.green);
                searchCenter = startWaypoint;
                searchCenter.exploredFrom = null;


            }

            else
            {
                //DoNothing
            }





        }

        
    }
    
}

public void ClickToSelectEndPoint()
{
    

    if (Input.GetMouseButtonUp(0))
    {
        RaycastHit hit;
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out hit, 100.0f))
        {
            if (hit.transform.tag == "WayPoint")
            {
                GameObject block = hit.transform.gameObject;
                print(block.name + "  Is Clicked");
                Waypoint endPoint = block.GetComponentInParent<Waypoint>();
                print(endPoint.name + "This is End point");
                endWaypoint = endPoint;
                endWaypoint.SetTopColor(Color.green);


            }

            else
            {
                //DoNothing
            }


        }
        CalculatePath();
        
        
        

        
    }


   

}






public void LoadBlocks()
{

    var waypoints = FindObjectsOfType<Waypoint>();
    foreach (Waypoint waypoint in waypoints)
    {
        var gridPos = waypoint.GetGridPos();
        if (grid.ContainsKey(gridPos))
        {
            Debug.LogWarning("Skipping overlapping block " + waypoint);
        }
        else
        {
            grid.Add(gridPos, waypoint);
        }
    }
}

}

NullReferenceException: Object reference not set to an instance of an object
PathFinder.CreatePath () (at Assets/Scripts/PathFinder.cs:77)
PathFinder.CalculatePath () (at Assets/Scripts/PathFinder.cs:60)
PathFinder.ClickToSelectEndPoint () (at Assets/Scripts/PathFinder.cs:214)
PathFinder.Update () (at Assets/Scripts/PathFinder.cs:37)

I’m afraid that approach won’t work. Unity is “stupid”. It does not know what a start or an end waypoint is. When you call those two methods in Update(), it simply assigns “the waypoint” to a variable.

Waypoint startPoint = block.GetComponentInParent<Waypoint>();
Waypoint endPoint = block.GetComponentInParent<Waypoint>();

The block variable contains a reference to the same game object in both cases: The game object that was hit this frame.

An approach could be this. It’s probably not a solution, and I didn’t test it.

Waypoint startPoint, endPoint;

public void SetStartOrEndPoint()
{ 
    if (Input.GetMouseButtonDown(0))
    {
        RaycastHit hit;
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray, out hit, 100.0f))
        {
            Waypoint wp = hit.transform.GetComponentInParent<Waypoint>();

            // Terminate method if no Waypoint
            if (wp == null) { return; }

            if (startPoint == null)
            {
                print(startPoint.name + "This is startpoint");
                startPoint = wp;
                startPoint.SetTopColor(Color.green);
                return;
            }
          
           print(endPoint.name + "This is endpoint");
           endPoint = wp;
           endPoint.SetTopColor(Color.red);

           CalculatePath();
           startPoint = endPoint = null;
       }
}
1 Like

I guess that the problem is not in selecting start and end way points, because in the inspector i tested it and it works fine, it gets the new start way point when i click down the left mouse button and the ens way point when i release it.
the problem is in previous way point when i create the path.

This is the first path

and here is the second attempt to create a new path, as you can see the previous waypoint in the inspector is null.

Just by staring at your code, I’m afraid I won’t be able to help you with this. I’d suggest to debug this step by step to see where the problem is. At some point, something must be null, so “nothing” gets assigned to previous.

The following video might help:

The connection between Unity and VS sometimes breaks when you debug. If that happens, just restart Unity and VS.

Here is a more in depth but longer video I can recommend to learn how to debug algorithms.

1 Like

Thank you so much for help!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms