int GetCost(PathFindingAgent agent, Node fromNode, Node toNode, TransitionType transitionType) { int dy; switch (transitionType) { case TransitionType.Walk: return(1); case TransitionType.Jump: dy = toNode.Y - fromNode.Y; int dx = toNode.X - fromNode.X; return(agent.JumpStrength + Mathf.Abs(dx) /*+ agent.JumpStrength - dy*/); case TransitionType.Fall: dy = fromNode.Y - toNode.Y; return(dy); case TransitionType.None: Debug.LogError("Transition type is None."); return(-1); default: throw new ArgumentOutOfRangeException(nameof(transitionType), transitionType, null); } }
public List <Node> FindPath(PathFindingAgent agent, Transform goalObject) { Node start = WorldPositionToNode(agent.transform.position); Node goal = WorldPositionToNode(goalObject.position); return(_search.Search(start, goal, _pathFindingRules, agent)); }
static bool CheckTrajectory(PathFindingGrid grid, PathFindingAgent agent, Node jumpStart, Node jumpLanding, int xDelta, int precision = 12) { float cellSize = grid.CellSize; Vector2 a = jumpStart.WorldPosition + new Vector2(-.5f, agent.Height - .5f) * cellSize; Vector2 b = a + Vector2.up * (agent.JumpStrength * cellSize); Vector2 c = b + Vector2.right * (xDelta * cellSize); Vector2 d = jumpLanding.WorldPosition + new Vector2(-.5f, agent.Height - .5f) * cellSize; var bezierCurve = new BezierCurve(a, b, c, d); bool isRight = xDelta > 0; Node lastNode = null; float offset = 1f / precision; float t = 0; for (int i = 0; i < precision - 1; i++) { t += offset; var curveValue = bezierCurve.GetValue(t); var node = grid.WorldPositionToNode(curveValue); if (node == lastNode) { continue; } if (!AllNodes(grid, node.Y, node.X, 1, agent.Width + 1, IsAir)) { return(false); } if (isRight) { if (!AllNodes(grid, node.Y - (agent.Height - 1), node.X + agent.Width, agent.Height + 1, 1, IsAir)) { return(false); } } else { if (!AllNodes(grid, node.Y - (agent.Height - 1), node.X - 1, agent.Height + 1, 1, IsAir)) { return(false); } } lastNode = node; } return(true); }
public int GetCost(Node fromNode, Node toNode, PathFindingAgent agent) { int deltaY = toNode.Y - fromNode.Y, deltaX = toNode.X - fromNode.X; if (Node.IsWalkTransition(fromNode, toNode) != TransitionType.Jump) { return(1); } return(agent.JumpStrength + Mathf.Abs(deltaX) + agent.JumpStrength - deltaY); }
public List <Node> Search(Node start, Node goal, IPathFindingRules rules, PathFindingAgent agent) { _openSet.Clear(); _closedSet.Clear(); _openSet.Add(start); var foundGoal = false; while (_openSet.Count > 0) { Node node = _openSet.RemoveFirst(); _closedSet.Add(node); if (node == goal) { foundGoal = true; break; } var transitions = rules.GetTransitions(_pathFindingGrid, agent, node); foreach (var transition in transitions) { Node neighbour = transition.Node; if (/*!neighbour.IsWalkable ||*/ _closedSet.Contains(neighbour)) { continue; } int newCost = node.GCost + transition.Cost; if (newCost < neighbour.GCost || !_openSet.Contains(neighbour)) { neighbour.GCost = newCost; neighbour.HCost = rules.GetHeuristic(neighbour, goal, agent); neighbour.Parent = node; neighbour.Transition = transition.Transition; if (_openSet.Contains(neighbour)) { _openSet.UpdateItem(neighbour); } else { _openSet.Add(neighbour); } } } } return(foundGoal ? RetracePath(start, goal) : null); }
public List <TransitionData> GetTransitions(PathFindingGrid grid, PathFindingAgent agent, Node node) { var neighbours = new List <TransitionData>(); bool isGrounded = AnyNode(grid, node.X, node.Y - 1, agent.Width, 1, IsGround); if (isGrounded) { if (AllInColumn(grid, node.X - 1, node.Y, agent.Height, IsAir)) { var neighbourNode = grid.GetNode(node.X - 1, node.Y); var neighbour = new TransitionData(neighbourNode, TransitionType.Walk, 1); neighbours.Add(neighbour); } if (AllInColumn(grid, node.X + agent.Width, node.Y, agent.Height, IsAir)) { var neighbourNode = grid.GetNode(node.X + 1, node.Y); var neighbour = new TransitionData(neighbourNode, TransitionType.Walk, 1); neighbours.Add(neighbour); } for (var dx = 2; dx <= agent.JumpStrength; dx++) { CheckJump(grid, agent, neighbours, node, dx); } for (var dx = -2; dx >= -agent.JumpStrength; --dx) { CheckJump(grid, agent, neighbours, node, dx); } } else { Node landing = GetFallOnGroundNode(grid, agent, node.X, node.Y); if (landing != null) { int fallHeight = node.Y - landing.Y; if (fallHeight <= agent.FallLimit) { const TransitionType fall = TransitionType.Fall; var neighbour = new TransitionData(landing, fall, GetCost(agent, node, landing, fall)); neighbours.Add(neighbour); } } } return(neighbours); }
static Node GetFallOnGroundNode(PathFindingGrid grid, PathFindingAgent agent, int x, int y) { if (!AllInRow(grid, x, y, agent.Width, node => node != null)) { return(null); } while (AllInRow(grid, x, y - 1, agent.Width, IsAir)) { --y; } return(grid.GetNode(x, y)); }
static bool CheckTrajectory(PathFindingGrid grid, PathFindingAgent agent, Node jumpStart, Node jumpEnd) { int dx = jumpEnd.X - jumpStart.X, dy = jumpEnd.Y - jumpStart.Y; var offsets = agent.GetCheckNodes(dx, dy); foreach (var offset in offsets) { Node toCheck = grid.GetNode(jumpStart.X + offset.x, jumpStart.Y + offset.y); if (!IsAir(toCheck)) { return(false); } } return(true); }
void CheckJump(PathFindingGrid grid, PathFindingAgent agent, List <TransitionData> neighbours, Node node, int dx) { Node landing = GetFallOnGroundNode(grid, agent, node.X + dx, node.Y + agent.JumpStrength); if (landing == null) { return; } int fallHeight = node.Y + agent.JumpStrength - landing.Y; if (fallHeight > agent.FallLimit) { return; } if (CheckTrajectory(grid, agent, node, landing)) { const TransitionType jump = TransitionType.Jump; var neighbour = new TransitionData(landing, jump, GetCost(agent, node, landing, jump)); neighbours.Add(neighbour); } }
public int GetHeuristic(Node node, Node goal, PathFindingAgent agent) { return(Mathf.Abs(node.X - goal.X) + Mathf.Abs(node.Y - goal.Y)); }
public PlatformerRules(PathFindingAgent agent) { int neighboursMaxSize = 2 + 2 * (agent.JumpStrength - 1); _neighbours = new Node[neighboursMaxSize]; }
public Node[] GetNeighbours(PathFindingGrid grid, Node node, PathFindingAgent agent, out int count) { count = 0; bool isGrounded = AnyNode(grid, node.Y - 1, node.X, 1, agent.Width, IsGround); if (isGrounded) { Node neighbour; if (AllNodes(grid, node.Y, node.X - 1, agent.Height, 1, IsAir)) { neighbour = grid.GetNode(node.Y, node.X - 1); _neighbours[count++] = neighbour; } if (AllNodes(grid, node.Y, node.X + agent.Width, agent.Height, 1, IsAir)) { neighbour = grid.GetNode(node.Y, node.X + 1); _neighbours[count++] = neighbour; } // Jump to the Right for (var x = 2; x <= agent.JumpStrength; ++x) { neighbour = GetFallOnGroundNode(grid, node.Y + agent.JumpStrength, node.X + x, agent.Width); if (neighbour == null) { continue; } if (CheckTrajectory(grid, agent, node, neighbour, x)) { _neighbours[count++] = neighbour; } } // Jump to the Left for (var x = -2; x >= -agent.JumpStrength; --x) { neighbour = GetFallOnGroundNode(grid, node.Y + agent.JumpStrength, node.X + x, agent.Width); if (neighbour == null) { continue; } if (CheckTrajectory(grid, agent, node, neighbour, x)) { _neighbours[count++] = neighbour; } } } // Falling Down. This should only happen if spawned above the ground. else { _neighbours[count++] = grid.GetNode(node.Y - 1, node.X); } return(_neighbours); }