Example #1
0
        /// <summary>
        /// Attach nodes which span from the given node to another ground node.</summary>
        /// <param name="origin">The point being searched from.</param>
        /// <param name="left">Indicates whether the path is to the left of origin; False indicates to right.</param>
        /// <param name="groundNodes">The set of path nodes along the ground.</param>
        private void AttachSpanNodes(LinkedPathNode origin, bool left, Dictionary<Point, LinkedPathNode> groundNodes)
        {
            // Attach span for a direct vertical 'pin drop' downwards
            this.AttachPinDropJump(origin, left, groundNodes);

            // Attach spans for parabolic jumps
            this.AttachParabolicJump(origin, left, groundNodes, 0.4f, 4);
            this.AttachParabolicJump(origin, left, groundNodes, 1, 2);
            this.AttachParabolicJump(origin, left, groundNodes, 1.5f, 1);
        }
Example #2
0
        /// <summary>
        /// Attach nodes which span from the given node as a vertical 'pin drop' downwards to another ground node.
        /// </summary>
        /// <param name="origin">The point being jumped down from.</param>
        /// <param name="left">Indicates whether the path is to the left of origin; False indicates to right.</param>
        /// <param name="groundNodes">The set of path nodes along the ground.</param>
        private void AttachPinDropJump(LinkedPathNode origin, bool left, Dictionary<Point, LinkedPathNode> groundNodes)
        {
            var spanNodes = new List<LinkedPathNode>();

            // Set the x coordinate of the pin drop
            int x = left ? origin.Node.X - 1 : origin.Node.X + 1;

            // Add the first 2 points as they have already been tested
            spanNodes.Add(new LinkedPathNode(x, origin.Node.Y, PathNodeType.Jump));
            spanNodes.Add(new LinkedPathNode(x, origin.Node.Y + 1, PathNodeType.Jump));
            spanNodes[0].AddLink(spanNodes[1], LinkCostFourDirection);
            spanNodes[1].AddLink(spanNodes[0], LinkCostFourDirection);

            // Test the remaining points until ground is hit or max span length is reached
            LinkedPathNode groundBelow = null;
            LinkedPathNode prevNode = spanNodes[1];
            for (int y = origin.Node.Y + 2; y <= origin.Node.Y + this.MaxSpanLength; y++)
            {
                var point = new Point(x, y);

                // Check that this point is passable
                if (!this.IsPassableTerrain(point))
                {
                    // This is a non-passable point so the path fails
                    break;
                }

                // If the point below this one is non-passable terrain then the ground has been hit
                if (!this.IsPassableTerrain(new Point(point.X, point.Y + 1)))
                {
                    // A ground node has been hit, so set this and break
                    groundBelow = groundNodes[point];
                    break;
                }

                // The point is mid-air, so create the node and connect it to the previous node
                var node = new LinkedPathNode(point, PathNodeType.Jump);
                prevNode.AddLink(node, LinkCostFourDirection);
                node.AddLink(prevNode, LinkCostFourDirection);

                // Add the node to the list
                spanNodes.Add(node);

                // Set the previous node
                prevNode = node;
            }

            // If the path is complete, join this span to the ground nodes
            if (groundBelow != null && spanNodes.Count > 0)
            {
                // If it is a small drop, don't treat this as a jump
                if (spanNodes.Count < this.MinJumpHeight)
                {
                    foreach (LinkedPathNode node in spanNodes)
                    {
                        node.Node = new PathNode(node.Node.X, node.Node.Y, PathNodeType.Normal);
                    }
                }

                // Connect the first jump node to the origin
                origin.AddLink(spanNodes[0], LinkCostFourDirection);
                spanNodes[0].AddLink(origin, LinkCostFourDirection);

                // Connect the last jump node to the ground
                groundBelow.AddLink(spanNodes[spanNodes.Count - 1], LinkCostFourDirection);
                spanNodes[spanNodes.Count - 1].AddLink(groundBelow, LinkCostFourDirection);
            }
        }
 /// <summary>
 /// Add a linked path node.
 /// </summary>
 /// <param name="node">The linked node.</param>
 /// <param name="cost">The movement cost of this link.</param>
 public void AddLink(LinkedPathNode node, int cost)
 {
     this.links.Add(new PathLink(node, cost));
 }
Example #4
0
        /// <summary>
        /// Attach nodes which span from the given node as a parabolic jump to another ground node.
        /// </summary>
        /// <param name="origin">The point being jumped down from.</param>
        /// <param name="left">Indicates whether the path is to the left of origin; False indicates to right.</param>
        /// <param name="groundNodes">The set of path nodes along the ground.</param>
        /// <param name="coefficient">The parabolic coefficient.</param>
        /// <param name="peakOffset">The distance to peak upwards before spanning downwards.</param>
        private void AttachParabolicJump(
            LinkedPathNode origin,
            bool left,
            Dictionary<Point, LinkedPathNode> groundNodes,
            float coefficient,
            uint peakOffset)
        {
            var spanNodes = new List<LinkedPathNode>();

            // Iterate along x values calculating the y coordinate for each step
            LinkedPathNode groundBelow = null;
            LinkedPathNode prevNode = null;
            int deltaX = 0;
            int jumpNodeCount = 0;
            bool terrainHit = false;
            while (groundBelow == null && jumpNodeCount < this.MaxSpanLength && !terrainHit)
            {
                // Increment/decrement the x delta
                deltaX = left ? deltaX - 1 : deltaX + 1;

                // Calculate the x and y point for this step
                int x = origin.Node.X + deltaX;
                double square = (coefficient * (left ? -1 : 1) * deltaX) - Math.Sqrt(peakOffset);
                int y = (int)Math.Round(origin.Node.Y - (-(square * square) + peakOffset));

                // Calculate how many points of interpolation are required and the direction
                PathNode prevPoint = prevNode == null ? origin.Node : prevNode.Node;
                int interpolateLength = (int)Math.Abs(prevPoint.Y - y);
                bool up = prevPoint.Y > y;

                // Add the points (or just the one point if no interpolation is required)
                int deltaY = 0;
                while (interpolateLength == 0 || Math.Abs(deltaY) < interpolateLength)
                {
                    // If interpolation is required, increment/decrement the delta y value
                    if (interpolateLength > 0)
                    {
                        deltaY = up ? deltaY - 1 : deltaY + 1;
                    }

                    var point = new Point(x, prevPoint.Y + deltaY);

                    // Check that this point is passable
                    if (!this.IsPassableTerrain(point))
                    {
                        // This is a non-passable point so the path fails
                        terrainHit = true;
                        break;
                    }

                    // If the point below this one is non-passable terrain then the ground has been hit
                    if (!this.IsPassableTerrain(new Point(point.X, point.Y + 1)))
                    {
                        // A ground node has been hit, so set this and break
                        groundBelow = groundNodes[point];
                        break;
                    }

                    // The point is mid-air, so create the node and connect it to the previous node
                    var node = new LinkedPathNode(point, PathNodeType.Jump);
                    if (prevNode != null)
                    {
                        int cost = this.CalculatePathCost(node.Node.Y - prevNode.Node.Y, node.Node.X - prevNode.Node.X);
                        prevNode.AddLink(node, cost);
                        node.AddLink(prevNode, cost);
                    }

                    // Add the node to the list
                    spanNodes.Add(node);

                    // Increment the jump nodes count and check whether the limit has been reached
                    if (++jumpNodeCount >= this.MaxSpanLength)
                    {
                        break;
                    }

                    // Set the previous node
                    prevNode = node;

                    // If no interpolation is required do not perform any further iteration
                    if (interpolateLength == 0)
                    {
                        break;
                    }
                }
            }

            // If this path is complete, join this jump-segment to the dictionary nodes
            if (groundBelow != null && spanNodes.Count >= this.MinJumpHeight)
            {
                LinkedPathNode first = spanNodes[0];
                LinkedPathNode last = spanNodes[spanNodes.Count - 1];

                // Connect the first jump node to the origin
                int cost = this.CalculatePathCost(origin.Node.Y - first.Node.Y, origin.Node.X - first.Node.X);
                origin.AddLink(first, cost);
                first.AddLink(origin, cost);

                // Connect the last jump node to the ground
                cost = this.CalculatePathCost(groundBelow.Node.Y - last.Node.Y, groundBelow.Node.X - last.Node.X);
                groundBelow.AddLink(last, cost);
                last.AddLink(groundBelow, cost);
            }
        }
        /// <summary>
        /// Indicates whether this node contains a link to the given node. 
        /// </summary>
        /// <param name="node">The node.</param>
        /// <returns>True if the given node is linked to this node.</returns>
        public bool HasLinkedNode(LinkedPathNode node)
        {
            foreach (PathLink link in this.links)
            {
                if (link.Node.Equals(node))
                {
                    return true;
                }
            }

            return false;
        }