Then I'd make a data structure to represent a state of a shipan A* node - with a few convenience methods to make it easier to compute neighbouring nodes I want frequently:
public struct MoveState {
public readonly ShipTransform transform;
public readonly int moveBudget;gCost;
public float hCost;
public MoveState(ShipTransform transform, int moveBudgetcost) {
this.transform = transform;
this.moveBudgetgCost = moveBudget;cost;
hCost = 0; // Our parent will fill this in later.
}
public MoveState SpendMove() {
return new MoveState(transform, moveBudget - 1gCost+1);
}
public MoveState MoveForward() {
return new MoveState(
new ShipTransform(transform.position + ToOffset(transform.heading), transform.heading),
moveBudgetgCost);
}
public MoveState Turn(Direction direction) {
return new MoveState(
new ShipTransform(transform.position, direction),
moveBudgetgCost);
}
}
public static void FindMoves(MoveState start, List<MoveState> outcomes, Map map, int moveBudget) {
outcomes.Clear();
// If we have no moves left, return with an empty list.
if (start.moveBudgetgCost <>= 1moveBudget)
return;
// Add "wait" move (or move that cannot be completed).
var here = start.SpendMove();
outcomes.Add(here);
// First, we'll try moving in our current heading.
var forward = here.MoveForward();
if (map.IsBlocked(forward.transform.position, forward.transform.heading)) {
// If we're facing a barrier, we can only turn in-place.
outcomes.Add(here.Turn(TurnLeft(here.transform.heading)));
outcomes.Add(here.Turn(TurnRight(here.transform.heading)));
} else {
// Otherwise, we can move forward into the tile in front of us.
outcomes.Add(forward);
// And we can turn into the tiles left or right of it...
var turned = forward.Turn(TurnLeft(here.transform.heading));
var advanced = turned.MoveForward();
if (map.IsBlocked(advanced.transform.position, advanced.transform.heading)) {
// If that tile is blocked, we just turn our facing direction.
outcomes.Add(turned);
} else {
// Otherwise, we move into the tile diagonal to our original.
outcomes.Add(advanced);
}
// Repeat for a right turn.
turned = forward.Turn(TurnRight(here.transform.heading));
advanced = turned.MoveForward();
if (map.IsBlocked(advanced.transform.position, advanced.transform.heading)) {
outcomes.Add(advanced);
} else {
outcomes.Add(turned);
}
}
// After we've moved, then the map takes a turn and can move us.
for (int i = 0; i < outcomes.Count; i++) {
// If we're on a tile that moves us, replace the outcome with that move.
if (map.ProcessTileEffect(outcomes[i].transform, out ShipTransform result)) {
outcomes[i] = new MoveState(result, outcomes[i].moveBudget);
}
}
// Done!
}
YourAlso notice here that the costToReachgCost variable in this case should always beonly ever increments by 1 - because every move exhausts exactly one movement action slot, whether it's orthogonal or diagonal or a "wait".