// PERF: If this ends up being slow, we can mark with a dirty bit /** * Returns a path from start to end, exclusive - that is, the start and end nodes are *not* listed in the path. Does a full * naive search every time. */ public static List <EncounterPosition> AStarWithNewGrid( EncounterPosition start, EncounterPosition end, EncounterState state, int maxAreaToExplore = 950 ) { SimplePriorityQueue <EncounterPosition> frontier = new SimplePriorityQueue <EncounterPosition>(); frontier.Enqueue(start, 0f); var cameFrom = new Dictionary <EncounterPosition, EncounterPosition>(); var costSoFar = new Dictionary <EncounterPosition, float>(); costSoFar[start] = 0f; while (frontier.Count > 0 && cameFrom.Count < maxAreaToExplore) { var currentPosition = frontier.Dequeue(); var adjacentPositions = state.AdjacentPositions(currentPosition); if (currentPosition == end || (state.IsPositionBlocked(end) && adjacentPositions.Contains(end))) { var path = new List <EncounterPosition>() { currentPosition }; EncounterPosition cameFromPos; while (cameFrom.TryGetValue(path[path.Count - 1], out cameFromPos) && (cameFromPos != start)) { path.Add(cameFromPos); } path.Reverse(); return(path); } var adjacentUnblocked = adjacentPositions.Where(adjacent => !state.IsPositionBlocked(adjacent)).ToList(); adjacentUnblocked.ForEach(adjacent => { var newNextPositionCost = costSoFar[currentPosition] + 1f; if (!costSoFar.ContainsKey(adjacent) || newNextPositionCost < costSoFar[adjacent]) { costSoFar[adjacent] = newNextPositionCost; // Uses straight-line distance as heuristic float priority = newNextPositionCost + adjacent.DistanceTo(end); frontier.Enqueue(adjacent, priority); cameFrom[adjacent] = currentPosition; } }); } return(null); }
private static bool ResolveMove(MoveAction action, EncounterState state) { Entity actor = state.GetEntityById(action.ActorId); var positionComponent = state.GetEntityById(action.ActorId).GetComponent <PositionComponent>(); if (positionComponent.EncounterPosition == action.TargetPosition) { GD.PrintErr(string.Format("Entity {0}:{1} tried to move to its current position {2}", actor.EntityName, actor.EntityId, action.TargetPosition)); return(false); } else if (state.IsPositionBlocked(action.TargetPosition)) { var blocker = state.BlockingEntityAtPosition(action.TargetPosition.X, action.TargetPosition.Y); var actorCollision = actor.GetComponent <CollisionComponent>(); if (actorCollision.OnCollisionAttack) { Attack(actor, blocker, state); } if (actorCollision.OnCollisionSelfDestruct) { state.TeleportEntity(actor, action.TargetPosition, ignoreCollision: true); if (state.FoVCache.IsVisible(action.TargetPosition)) { positionComponent.PlayExplosion(); } ResolveAction(new DestroyAction(action.ActorId), state); } return(true); } else { state.TeleportEntity(actor, action.TargetPosition, ignoreCollision: false); return(true); } }