Пример #1
0
        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);
            }
        }
Пример #2
0
        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));
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }
Пример #7
0
        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));
        }
Пример #8
0
        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);
        }
Пример #9
0
        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);
            }
        }
Пример #10
0
 public int GetHeuristic(Node node, Node goal, PathFindingAgent agent)
 {
     return(Mathf.Abs(node.X - goal.X) + Mathf.Abs(node.Y - goal.Y));
 }
Пример #11
0
        public PlatformerRules(PathFindingAgent agent)
        {
            int neighboursMaxSize = 2 + 2 * (agent.JumpStrength - 1);

            _neighbours = new Node[neighboursMaxSize];
        }
Пример #12
0
        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);
        }