If it isn’t one ‘gotcha’, it’s another.
If you can’t tell, i’m new to the job system.
I’m working on an astar path finding script with jobs.
I need to generate a grid of nodes to path find through but I’m having trouble setting values for nodes.
I have nodes, and in the job I have a NativeArray of nodes.
I make a couple for loops and set each nodes values to some default values.
The issue I have is all the values return zero after setting them, god knows why. For example, as you’ll see below, ‘isWalkable’ for all nodes are explicitly set to 1 during the loops. Later. If I Debug.Log any node from the array when the job is complete, it prints 0.
So what am I missing now? Why aren’t these values being set?
PathNode Script:
public struct PathNode {
public int x;
public int y;
public int index;
public int gCost;
public int hCost;
public int fCost;
public int isWalkable;
public int cameFromNodeIndex;
public void CalculateFCost() {
fCost = gCost + hCost;
}
public void SetIsWalkable(int isWalkable) {
this.isWalkable = isWalkable;
}
}
Pathfinding Script:
using UnityEngine;
using Unity.Mathematics;
using Unity.Collections;
using Unity.Jobs;
using Unity.Burst;
using System.Collections;
public class Pathfinding : MonoBehaviour {
const int MOVE_STRAIGHT_COST = 10;
const int MOVE_DIAGONAL_COST = 14;
public float pathTimeInterval = 1f;
public int2 startPosition = new int2(0, 0),
endPosition = new int2(5, 5);
float intervalTimer;
public int pathsToTest = 5;
Coroutine gridCoroutine, pathfindingCoroutine;
JobHandle generateGridHandle;
public NativeArray<PathNode> grid;
public int2 gridSize = new int2(10, 10);
void Awake() {
grid = new NativeArray<PathNode>(gridSize.x * gridSize.y, Allocator.Persistent);
}
void OnDestroy() {
grid.Dispose();
}
void Update() {
intervalTimer += Time.deltaTime;
if (intervalTimer >= pathTimeInterval) {
intervalTimer = 0;
if (gridCoroutine != null) {
StopCoroutine(gridCoroutine);
}
gridCoroutine = StartCoroutine(GenerateGrid());
}
}
IEnumerator GenerateGrid() {
GenerateGridJob gridJob = new GenerateGridJob {
_gridSize = gridSize,
pathNodeArray = grid
};
generateGridHandle = gridJob.Schedule();
while (!generateGridHandle.IsCompleted) {
}
generateGridHandle.Complete();
//Why do these return 0?
Debug.Log(grid[73].isWalkable);
Debug.Log(gridJob.pathNodeArray[73].isWalkable);
yield return null;
}
[BurstCompile]
struct GenerateGridJob : IJob {
public int2 _gridSize;
public NativeArray<PathNode> pathNodeArray;
public void Execute() {
pathNodeArray = new NativeArray<PathNode>(_gridSize.x * _gridSize.y, Allocator.Temp);
Debug.Log("Generating Grid...");
for (int x = 0; x < _gridSize.x; x++) {
for (int y = 0; y < _gridSize.y; y++) {
PathNode pathNode = new PathNode();
pathNode.x = x;
pathNode.y = y;
pathNode.index = CalculateIndex(x, y, _gridSize.x);
pathNode.gCost = int.MaxValue;
//pathNode.hCost = CalculateDistanceCost(new int2(x, y), _endPosition);
pathNode.CalculateFCost();
pathNode.isWalkable = 1;
pathNode.cameFromNodeIndex = -1;
pathNodeArray[pathNode.index] = pathNode;
}
}
}
int CalculateIndex(int x, int y, int gridWidth) {
return x + y * gridWidth;
}
int CalculateDistanceCost(int2 aPosition, int2 bPosition) {
int xDistance = math.abs(aPosition.x - bPosition.x);
int yDistance = math.abs(aPosition.y - bPosition.y);
int remaining = math.abs(xDistance - yDistance);
return MOVE_DIAGONAL_COST * math.min(xDistance, yDistance) + MOVE_STRAIGHT_COST * remaining;
}
}
}
On row 59 you immediately override pathNodeArray struct, and your grid not using anymore as expected, and as expected it’s values never changes.
1 Like
Line 41-43: You did not set _startPosition, _endPosition and _gridSize of GenerateGridJob and may be default value 0. So its loop do nothing.
Whoops. I forgot to remove these variables before posting. _startPosition and _endPosition shouldnt be there. I did forget to set grid size too.
However, my problem still persists after these changes. I edited my post to reflect these changes though.
As @eizenhorn said, you must not create new instance of pathNodeArray in the job. Remove line 62.
1 Like
TY! This was it. Now I understand the weirdness I was experiencing.
It helps to be consistent with naming. If the caller has a collection named “grid” and it gets assigned to a job whose field calls it “pathNodeArray” it’s only a matter of time where you get bitten by the fact that, even though they are named quite differently, they’re actually the same collection.
I “Refactor => Rename” all the time. Like hundreds of times a day! 
1 Like