After a lot of debugging here are my problems that I’ve found thus far.
note: my script is based on A* Pathfinding (E03: algorithm implementation) - YouTube
-
The neighbour nodes seem to be around the empty pathfinding object with my grid and pathfinding script instead of the object’s i’ve assigned to be the player/enemy node
-
pathfinding’s starting point is way off from the seeker and target ![alt text][1]
3.The math for finding the distance between the player’s position and the enemy position is most likely wrong(Or could stem from problem 1)
here are my 3 scripts for path finding(Look below scripts for areas I think are problems)
PathfindingScript
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Pathfinding : MonoBehaviour
{
public Transform seeker, target;
Grid grid;
void Awake()
{
grid = GetComponent<Grid>();
}
void Update()
{
FindPath(seeker.position, target.position);
}
void FindPath(Vector3 StartPos, Vector3 TargetPos)
{
Node StartNode = grid.NodeFromWorldPoint(StartPos);
Node TargetNode = grid.NodeFromWorldPoint(TargetPos);
List<Node> openSet = new List<Node>();
HashSet<Node> closedSet = new HashSet<Node>();
openSet.Add(StartNode);
while(openSet.Count > 0)
{
Node currentNode = openSet[0];
for(int i = 1; i < openSet.Count; i++)
{
if(openSet<em>.fCost < currentNode.fCost || openSet_.fCost == currentNode.fCost && openSet*.hCost < currentNode.hCost)*_</em>
{
currentNode = openSet*;*
}
}
openSet.Remove(currentNode);
closedSet.Add(currentNode);
if(currentNode == TargetNode)
{
//Debug.Log(“this is getting called”);
RetracePath(StartNode, TargetNode);
return;
}
foreach(Node neighbour in grid.GetNeighbours(currentNode))
{
if(!neighbour.walkable || closedSet.Contains(neighbour))
{
continue;
}
int newMovementCostToNeighbour = currentNode.gCost + GetDistance(currentNode, neighbour);
if(newMovementCostToNeighbour < neighbour.gCost || !openSet.Contains(neighbour))
{
neighbour.gCost = newMovementCostToNeighbour;
neighbour.hCost = GetDistance(neighbour, TargetNode);
neighbour.parent = currentNode;
if (!openSet.Contains(neighbour))
{
openSet.Add(neighbour);
}
}
}
}
}
void RetracePath(Node StartNode, Node EndNode)
{
List path = new List();
Node currentNode = EndNode;
while(currentNode != StartNode)
{
path.Add(currentNode);
currentNode = currentNode.parent;
}
path.Reverse();
grid.path = path;
}
int GetDistance(Node nodeA, Node nodeB)
{
int distX = Mathf.Abs(nodeA.GridX - nodeB.GridX);
int distY = Mathf.Abs(nodeA.GridY - nodeB.GridY);
int distZ = Mathf.Abs(nodeA.GridZ - nodeB.GridZ);
if(distX > distY && distX > distZ)
{
// Debug.Log(“1”);
return 14 * distY + 10 * (distX - distY);
}
else if(distY > distX && distY > distZ)
{
// Debug.Log(“2”);
return 14 * distX + 10 * (distY - distX);
}
else if(distZ > distX && distZ < distY)
{
// Debug.Log(“3”);
return 17 * distZ + 10 * (distZ - distX);
}
// Debug.Log(distX);
//Debug.Log(distY);
//Debug.Log(distZ);
return 17 * distZ + 10 * (distZ - distY);
}
}
Grid Script(creats the nodes that pathfinding uses)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Grid : MonoBehaviour
{
public GameObject enemy;
public LayerMask unwalkableMask;
public Vector3 gridWorldSize;
public float nodeRadius;
Node[,] grid;
public List temp;
float nodeDiameter;
int gridSizeX, gridSizeY, gridSizeZ;
void Start()
{
temp = new List();
nodeDiameter = nodeRadius * 2;
gridSizeX = Mathf.RoundToInt(gridWorldSize.x / nodeDiameter);
gridSizeY = Mathf.RoundToInt(gridWorldSize.y / nodeDiameter);
gridSizeZ = Mathf.RoundToInt(gridWorldSize.z / nodeDiameter);
CreateGrid();
}
void Update()
{
CreateGrid();
}
void CreateGrid()
{
grid = new Node[gridSizeX, gridSizeY, gridSizeZ];
Vector3 worldBottomLeft = transform.position - Vector3.right * gridWorldSize.x / 2 - Vector3.forward * gridWorldSize.y / 2 - Vector3.up * gridWorldSize.z / 2;
for (int x = 0; x < gridSizeX; x++)
{
for (int y = 0; y < gridSizeY; y++)
{
for (int z = 0; z < gridSizeZ; z++)
{
Vector3 worldPoint = worldBottomLeft + Vector3.right * (x * nodeDiameter + nodeRadius) + Vector3.forward * (y * nodeDiameter + nodeRadius) + Vector3.up * (z * nodeDiameter + nodeRadius);
bool walkable = !(Physics.CheckSphere(worldPoint, nodeRadius - .1f, unwalkableMask));
grid[x, y, z] = new Node(walkable, worldPoint, x, y, z);
}
}
}
}
public List GetNeighbours(Node node)
{
List neighbours = new List();
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
for (int z = -1; z <= 1; z++)
{
if (x == 0 && y == 0 && z == 0)
{
continue;
}
int checkX = node.GridX + x;
int checkY = node.GridY + y;
int checkZ = node.GridZ + z;
if (checkX >= 0 && checkX < gridSizeX && checkY >= 0 && checkY < gridSizeY && checkZ >= 0 && checkZ < gridSizeZ)
{
neighbours.Add(grid[checkX, checkY, checkZ]);
}
}
}
}
return neighbours;
}
public Node NodeFromWorldPoint(Vector3 worldPosition)
{
float percentX = (worldPosition.x + gridWorldSize.x / 2) / gridWorldSize.x;
float percentY = (worldPosition.z + gridWorldSize.z / 2) / gridWorldSize.z;
float percentZ = (worldPosition.y + gridWorldSize.y / 2) / gridWorldSize.y;
percentX = Mathf.Clamp01(percentX);
percentY = Mathf.Clamp01(percentY);
percentZ = Mathf.Clamp01(percentZ);
//Debug.Log(percentX + " " + percentY + " " + percentZ);
int x = Mathf.RoundToInt((gridSizeX - 1) * percentX);
int y = Mathf.RoundToInt((gridSizeY - 1) * percentY);
int z = Mathf.RoundToInt((gridSizeZ - 1) * percentZ);
// Debug.Log(x + " " + y + " " + z);
return grid[x, y, z];
}
public List path;
public Node currentNode;
void OnDrawGizmos()
{
Gizmos.DrawWireCube(transform.position, new Vector3(gridWorldSize.x, gridWorldSize.z, gridWorldSize.y));
//Node Startnode = NodeFromWorldPoint(enemy.transform.position);
// Debug.Log(Startnode.worldPosition);
// temp = GetNeighbours(Startnode);
if (grid != null)
{
foreach (Node n in grid)
{
//Gizmos.color = (n.walkable) ? Color.white : Color.red;
if (path != null)
{
if (path.Contains(n))
{
Gizmos.color = Color.black;
Gizmos.DrawCube(n.worldPosition, Vector3.one * (nodeDiameter - .1f));
}
}
/* foreach(Node neighbour in temp)
{
Gizmos.color = Color.black;
Gizmos.DrawCube(neighbour.worldPosition, Vector3.one * (nodeDiameter - .1f));
}*/
//}
}
}
}
}
Node(Basis for nodes)
using UnityEngine;
using System.Collections;
public class Node
{
public bool walkable;
public Vector3 worldPosition;
public int GridX;
public int GridY;
public int GridZ;
public int gCost;
public int hCost;
public Node parent;
public Node(bool _walkable, Vector3 _worldPos, int _GridX, int _GridY, int _GridZ)
{
walkable = _walkable;
worldPosition = _worldPos;
GridX = _GridX;
GridY = _GridY;
GridZ = _GridZ;
}
public int fCost
{
get
{
return gCost + hCost;
}
}
}
Areas that I think are problems
-
for problem 1. , I keep getting worldposition to be the same as the empty gameobject with the pathfinding and grid script’s position and not the player/enemy thats supposed to be pathfinding
my modified function(THIS IS THE PROBLEM AREA)
-
public Node NodeFromWorldPoint(Vector3 worldPosition)
{
float percentX = (worldPosition.x + gridWorldSize.x / 2) / gridWorldSize.x;
float percentY = (worldPosition.z + gridWorldSize.z / 2) / gridWorldSize.z;
float percentZ = (worldPosition.y + gridWorldSize.y / 2) / gridWorldSize.y;
percentX = Mathf.Clamp01(percentX);
percentY = Mathf.Clamp01(percentY);
percentZ = Mathf.Clamp01(percentZ);
//Debug.Log(percentX + " " + percentY + " " + percentZ);
int x = Mathf.RoundToInt((gridSizeX - 1) * percentX);
int y = Mathf.RoundToInt((gridSizeY - 1) * percentY);
int z = Mathf.RoundToInt((gridSizeZ - 1) * percentZ);
// Debug.Log(x + " " + y + " " + z);
return grid[x, y, z];
}
the unmodified function
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];
}*_