Example #1
0
    public static void TryAddTileToPathfinder(Tile Branch)
    {
        Tile TryGetPlatform(Vector3 Position, Vector3 RaycastOffset = new Vector3())
        {
            var Area = GridClass.CalculateArea(Position);

            foreach (IInGrid Entry in Grid.GetItems(Area))
            {
                if (Entry is Tile OtherTile && OtherTile.Type == Items.ID.PLATFORM)
                {
                    PhysicsDirectSpaceState State = Branch.GetWorld().DirectSpaceState;

                    var RayBranchPos = Branch.Point.Pos + RaycastOffset;
                    var RayOtherPos  = OtherTile.Point.Pos + RaycastOffset;
                    var Excluding    = new Godot.Collections.Array {
                    };

                    var Results = State.IntersectRay(RayBranchPos, RayOtherPos, Excluding, 4);
                    if (Results.Count > 0)                    //Hit something in between
                    {
                        return(null);
                    }
                    else
                    {
                        return(OtherTile);
                    }
                }
            }

            return(null);
        }

        Tile TryGetSlope(Vector3 Position, Vector3 RaycastOffset = new Vector3())
        {
            var Area = GridClass.CalculateArea(Position);

            foreach (IInGrid Entry in Grid.GetItems(Area))
            {
                if (Entry is Tile OtherTile && OtherTile.Type == Items.ID.SLOPE)
                {
                    PhysicsDirectSpaceState State = Branch.GetWorld().DirectSpaceState;

                    var RayBranchPos = Branch.Point.Pos + RaycastOffset;
                    var RayOtherPos  = OtherTile.Point.Pos + RaycastOffset;
                    var Excluding    = new Godot.Collections.Array {
                    };

                    var Results = State.IntersectRay(RayBranchPos, RayOtherPos, Excluding, 4);
                    if (Results.Count > 0)                    //Hit something in between
                    {
                        return(null);
                    }
                    else
                    {
                        return(OtherTile);
                    }
                }
            }

            return(null);
        }

        bool IsSlopePointingAt(Tile Slope, Vector3 At)
        {
            float Rot = SnapToGrid(LoopRotation(Slope.RotationDegrees.y), 360, 4);

            Rot = LoopRotation(Rot);             //Make 360 become 0

            Vector3 Addend   = new Vector3(0, 0, PlatformSize / 3).Rotated(new Vector3(0, 1, 0), Deg2Rad(Rot));
            Vector3 SlopePos = Slope.Translation + Addend;

            if (Rot == 0)
            {
                return(At.z >= SlopePos.z);
            }
            if (Rot == 90)
            {
                return(At.x >= SlopePos.x);
            }
            if (Rot == 180)
            {
                return(At.z <= SlopePos.z);
            }
            if (Rot == 270)
            {
                return(At.x <= SlopePos.x);
            }

            throw new Exception("This `if` chain should have 100% coverage");
        }

        bool IsSlopePointingAway(Tile Slope, Vector3 At)
        {
            float Rot = SnapToGrid(LoopRotation(Slope.RotationDegrees.y), 360, 4);

            Rot = LoopRotation(Rot);             //Make 360 become 0

            Vector3 Addend   = new Vector3(0, 0, -PlatformSize / 3).Rotated(new Vector3(0, 1, 0), Deg2Rad(Rot));
            Vector3 SlopePos = Slope.Translation + Addend;

            if (Rot == 0)
            {
                return(At.z <= SlopePos.z);
            }
            if (Rot == 90)
            {
                return(At.x <= SlopePos.x);
            }
            if (Rot == 180)
            {
                return(At.z >= SlopePos.z);
            }
            if (Rot == 270)
            {
                return(At.x >= SlopePos.x);
            }

            throw new Exception("This `if` chain should have 100% coverage");
        }

        switch (Branch.Type)
        {
        case (Items.ID.PLATFORM): {
            Branch.Point = Pathfinder.AddPoint(Branch.Translation + new Vector3(0, 2, 0));

            {                     //Connect to platforms in the eight spaces around us
                var AheadPos  = Branch.Translation + new Vector3(0, 1, PlatformSize);
                var BehindPos = Branch.Translation + new Vector3(0, 1, -PlatformSize);
                var RightPos  = Branch.Translation + new Vector3(-PlatformSize, 1, 0);
                var LeftPos   = Branch.Translation + new Vector3(PlatformSize, 1, 0);

                Tile Ahead  = TryGetPlatform(AheadPos);
                Tile Behind = TryGetPlatform(BehindPos);
                Tile Right  = TryGetPlatform(RightPos);
                Tile Left   = TryGetPlatform(LeftPos);

                if (Ahead != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, Ahead.Point);
                }
                if (Behind != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, Behind.Point);
                }
                if (Right != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, Right.Point);
                }
                if (Left != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, Left.Point);
                }

                var AheadRightPos  = Branch.Translation + new Vector3(-PlatformSize, 1, PlatformSize);
                var AheadLeftPos   = Branch.Translation + new Vector3(PlatformSize, 1, PlatformSize);
                var BehindRightPos = Branch.Translation + new Vector3(-PlatformSize, 1, -PlatformSize);
                var BehindLeftPos  = Branch.Translation + new Vector3(PlatformSize, 1, -PlatformSize);

                Tile AheadRight  = null;
                Tile AheadLeft   = null;
                Tile BehindRight = null;
                Tile BehindLeft  = null;

                if (Ahead != null && Right != null)
                {
                    AheadRight = TryGetPlatform(AheadRightPos);
                }
                if (Ahead != null && Left != null)
                {
                    AheadLeft = TryGetPlatform(AheadLeftPos);
                }
                if (Behind != null && Right != null)
                {
                    BehindRight = TryGetPlatform(BehindRightPos);
                }
                if (Behind != null && Left != null)
                {
                    BehindLeft = TryGetPlatform(BehindLeftPos);
                }

                if (AheadRight != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, AheadRight.Point);
                }
                if (AheadLeft != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, AheadLeft.Point);
                }
                if (BehindRight != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, BehindRight.Point);
                }
                if (BehindLeft != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, BehindLeft.Point);
                }
            }

            {                     //Connect to slopes in the four cardinal directions (same Y)
                var AheadPos  = Branch.Translation + new Vector3(0, 1, PlatformSize);
                var BehindPos = Branch.Translation + new Vector3(0, 1, -PlatformSize);
                var RightPos  = Branch.Translation + new Vector3(-PlatformSize, 1, 0);
                var LeftPos   = Branch.Translation + new Vector3(PlatformSize, 1, 0);

                Tile Ahead  = TryGetSlope(AheadPos);
                Tile Behind = TryGetSlope(BehindPos);
                Tile Right  = TryGetSlope(RightPos);
                Tile Left   = TryGetSlope(LeftPos);

                Vector3 Pos = Branch.Translation;
                if (Ahead != null && IsSlopePointingAway(Ahead, Pos))
                {
                    Pathfinder.ConnectPoints(Branch.Point, Ahead.Point);
                }
                if (Behind != null && IsSlopePointingAway(Behind, Pos))
                {
                    Pathfinder.ConnectPoints(Branch.Point, Behind.Point);
                }
                if (Right != null && IsSlopePointingAway(Right, Pos))
                {
                    Pathfinder.ConnectPoints(Branch.Point, Right.Point);
                }
                if (Left != null && IsSlopePointingAway(Left, Pos))
                {
                    Pathfinder.ConnectPoints(Branch.Point, Left.Point);
                }
            }

            {                     //Connect to slopes in the four cardinal directions (lower Y)
                var AheadPos  = Branch.Translation + new Vector3(0, -PlatformSize + 1, PlatformSize);
                var BehindPos = Branch.Translation + new Vector3(0, -PlatformSize + 1, -PlatformSize);
                var RightPos  = Branch.Translation + new Vector3(-PlatformSize, -PlatformSize + 1, 0);
                var LeftPos   = Branch.Translation + new Vector3(PlatformSize, -PlatformSize + 1, 0);

                var  RaycastOffset = new Vector3(0, PlatformSize / 4, 0);
                Tile Ahead         = TryGetSlope(AheadPos, RaycastOffset);
                Tile Behind        = TryGetSlope(BehindPos, RaycastOffset);
                Tile Right         = TryGetSlope(RightPos, RaycastOffset);
                Tile Left          = TryGetSlope(LeftPos, RaycastOffset);

                Vector3 Pos = Branch.Translation;
                if (Ahead != null && IsSlopePointingAt(Ahead, Pos))
                {
                    Pathfinder.ConnectPoints(Branch.Point, Ahead.Point);
                }
                if (Behind != null && IsSlopePointingAt(Behind, Pos))
                {
                    Pathfinder.ConnectPoints(Branch.Point, Behind.Point);
                }
                if (Right != null && IsSlopePointingAt(Right, Pos))
                {
                    Pathfinder.ConnectPoints(Branch.Point, Right.Point);
                }
                if (Left != null && IsSlopePointingAt(Left, Pos))
                {
                    Pathfinder.ConnectPoints(Branch.Point, Left.Point);
                }
            }

            break;
        }

        case (Items.ID.SLOPE): {
            Branch.Point = Pathfinder.AddPoint(Branch.Translation + new Vector3(0, 2, 0));

            var Axis = new Vector3(0, 1, 0);
            var Rad  = Branch.Rotation.y;

            {                     //Connect to other slopes in four cardinal directions
                var AheadPos  = Branch.Translation + new Vector3(0, PlatformSize, PlatformSize).Rotated(Axis, Rad);
                var BehindPos = Branch.Translation + new Vector3(0, -PlatformSize, -PlatformSize).Rotated(Axis, Rad);
                var RightPos  = Branch.Translation + new Vector3(-PlatformSize, 0, 0).Rotated(Axis, Rad);
                var LeftPos   = Branch.Translation + new Vector3(PlatformSize, 0, 0).Rotated(Axis, Rad);

                var  RaycastOffset = new Vector3(0, PlatformSize / 4, 0);
                Tile Ahead         = TryGetSlope(AheadPos, RaycastOffset);
                Tile Behind        = TryGetSlope(BehindPos, RaycastOffset);
                Tile Right         = TryGetSlope(RightPos);
                Tile Left          = TryGetSlope(LeftPos);

                if (Ahead != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, Ahead.Point);
                }
                if (Behind != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, Behind.Point);
                }
                if (Right != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, Right.Point);
                }
                if (Left != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, Left.Point);
                }
            }

            {                     //Connect to platforms forward and backwards
                var AheadPos  = Branch.Translation + new Vector3(0, PlatformSize / 2, PlatformSize).Rotated(Axis, Rad);
                var BehindPos = Branch.Translation + new Vector3(0, 0, -PlatformSize).Rotated(Axis, Rad);

                var  RaycastOffset = new Vector3(0, PlatformSize / 4, 0);
                Tile Ahead         = TryGetPlatform(AheadPos, RaycastOffset);
                Tile Behind        = TryGetPlatform(BehindPos);

                if (Ahead != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, Ahead.Point);
                }
                if (Behind != null)
                {
                    Pathfinder.ConnectPoints(Branch.Point, Behind.Point);
                }
            }

            break;
        }

        default:
            return;
        }
    }