0
\$\begingroup\$

I'm trying to implement pathfinding in my platformer and I'm having trouble coming up with a way to find the nearest node to a world point.


I tried this:

public Node GetNodeFromPoint(Vector2 point)
    {
        int xGridPoint = Mathf.RoundToInt(point.x / gridWorldSize.x);
        int yGridPoint = Mathf.RoundToInt(point.y / gridWorldSize.y);

        Debug.Log(xGridPoint + " " + yGridPoint);

        return grid[xGridPoint, yGridPoint];
    }

But it always gave me [0,0].

This is my "NavGrid" class it creates the grid and is going to set up the links between nodes:

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

public class NavGrid : MonoBehaviour {

    public LayerMask unWalkableMask;
    public Vector2 gridWorldSize;
    public float nodeSize;

    public float maxFallLinkLimit = 100f;

    Node[,] grid;

    int gridSizeX;
    int gridSizeY;

    float nodeDiameter;

    // Use this for initialization
    void Start () {
        nodeDiameter = nodeSize * 2;
        gridSizeX = Mathf.RoundToInt(gridWorldSize.x / nodeDiameter);
        gridSizeY = Mathf.RoundToInt(gridWorldSize.y / nodeDiameter);
        CreateGrid();
        CreateFallLinks();
    }

    private void CreateGrid()
    {
        grid = new Node[gridSizeX, gridSizeY];
        Vector2 worldBottomLeft = transform.position - (Vector3)Vector2.left * gridWorldSize.x / 2 - (Vector3)Vector2.down * gridWorldSize.y / 2;

        for(int x = 0; x < gridSizeX; x++)
        {
            for(int y = 0; y < gridSizeY; y++)
            {
                Vector2 worldPoint = worldBottomLeft + Vector2.left * (x * nodeDiameter + nodeSize) + Vector2.down * (y * nodeDiameter + nodeSize);

                bool iswalkable = false;

                if (!Physics2D.CircleCast(worldPoint, nodeSize, Vector2.down, nodeSize/2, unWalkableMask))
                {
                    if (Physics2D.Raycast(new Vector2(worldPoint.x, worldPoint.y - nodeSize), Vector2.down, nodeDiameter, unWalkableMask))
                    {
                        iswalkable = true;
                    }
                }

                Node node = new Node(iswalkable, worldPoint);

                grid[x, y] = node;
            }
        }
    }

    private void CreateFallLinks()
    {
        for(int x = 0; x < gridSizeX; x++)
        {
            for(int y = 0; y < gridSizeY; y++)
            {
                Node node = grid[x, y];
                if (!node.isWalkable) continue;

                if(!grid[x+1,y].isWalkable && !grid[x+1,y-1].isWalkable)
                {
                    Vector2 fallPoint = grid[x + 1, y].worldPosition;

                    RaycastHit2D hit = Physics2D.Raycast(fallPoint, Vector2.down, maxFallLinkLimit, unWalkableMask);
                    if(hit.collider != null)
                    {
                        node.fallLink = GetNodeFromPoint(hit.point);
                        continue;
                    }
                }

                if (!grid[x - 1, y].isWalkable && !grid[x - 1, y - 1].isWalkable)
                {
                    Vector2 fallPoint = grid[x - 1, y].worldPosition;

                    RaycastHit2D hit = Physics2D.Raycast(fallPoint, Vector2.down, maxFallLinkLimit, unWalkableMask);
                    if (hit.collider != null)
                    {
                        node.fallLink = GetNodeFromPoint(hit.point);
                        continue;
                    }
                }
            }
        }
    }

    public Node GetNodeFromPoint(Vector2 point)
    {
        int xGridPoint = Mathf.RoundToInt(point.x / nodeSize);
        int yGridPoint = Mathf.RoundToInt(point.y / nodeSize);

        Debug.Log(xGridPoint + " " + yGridPoint);

        return grid[xGridPoint, yGridPoint];
    }

    public void OnDrawGizmos()
    {
        Gizmos.DrawWireCube(transform.position, new Vector3(gridWorldSize.x, gridWorldSize.y, 1));

        if (grid != null)
        {
            foreach (Node n in grid)
            {
                if (n.isWalkable)
                {
                    Gizmos.color = Color.red;
                    Gizmos.DrawRay(new Vector2(n.worldPosition.x, n.worldPosition.y - nodeSize), new Vector2(0, -nodeDiameter));
                    Gizmos.color = Color.cyan;
                    Gizmos.DrawCube(n.worldPosition, Vector3.one * (nodeDiameter * 0.9f));
                    Gizmos.color = Color.yellow;
                    Gizmos.DrawWireSphere(n.worldPosition, nodeSize / 2);
                }

                if(n.fallLink != null)
                {
                    Gizmos.color = Color.blue;
                    Gizmos.DrawLine(n.worldPosition, n.fallLink.worldPosition);
                }
            }
        }
    }
}

I tried coldSteel's answer but it gave me a array index out of range error because it world return a negative number.

This is the node class:

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

public class Node {

    public bool isWalkable = false;
    public Vector2 worldPosition;
    public Node fallLink = null;

    public Node(bool isWalkable, Vector2 worldPosition)
    {
        this.isWalkable = isWalkable;
        this.worldPosition = worldPosition;
    }
}
\$\endgroup\$
  • \$\begingroup\$ To help you with this, we'll need to know the range of your point argument and the value of gridWorldSize - it sounds like they're not in compatible units, causing their quotient to always be so small it rounds to zero. \$\endgroup\$ – DMGregory May 15 at 22:45
  • \$\begingroup\$ gridWorldSize is the "area" the grid covers in world space. \$\endgroup\$ – ThePumkinMelon May 15 at 23:10
  • \$\begingroup\$ Wait, the size of the entire grid, not the size of one cell? That sounds like your problem. \$\endgroup\$ – DMGregory May 15 at 23:13
  • \$\begingroup\$ I tried it with the node size and that didn't work either. \$\endgroup\$ – ThePumkinMelon May 16 at 0:56
  • 1
    \$\begingroup\$ "Didn't work" isn't enough for us to diagnose the problem. Can you update your question to include a minimal, complete, verifiable example of the issue that we can reproduce in a new project? \$\endgroup\$ – DMGregory May 16 at 1:37
1
\$\begingroup\$

You are dividing a point by a grid size - thus you get a 0,0 because I assume that grid size is much larger than a point.

What you want to do is: To take your point in World coordinates and divide it by a GridCellSize.

For example your CellSize is [3,3] And your point is [6,0]

XCoord = 6/3 = 2

YCoord = 0/3 = 0

\$\endgroup\$
0
\$\begingroup\$

In This tutorial there is a good way of doing it.

public Node NodeFromWorldPoint(Vector3 worldPosition) {
        float percentX = (worldPosition.x + gridWorldSize.x/2) / gridWorldSize.x;
        float percentY = (worldPosition.z + gridWorldSize.y/2) / gridWorldSize.y;
        percentX = Mathf.Clamp01(percentX);
        percentY = Mathf.Clamp01(percentY);

        int x = Mathf.RoundToInt((gridSizeX-1) * percentX);
        int y = Mathf.RoundToInt((gridSizeY-1) * percentY);
        return grid[x,y];
    }

It's explained here nicely.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.