~ruther/NosSmooth

ref: 7db0734be035f651f465d1115391a519a62853b5 NosSmooth/Extensions/NosSmooth.Extensions.Pathfinding/Path.cs -rw-r--r-- 4.6 KiB
7db0734b — Rutherther feat(combat): remove item selector from simple attack technique 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//
//  Path.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace NosSmooth.Extensions.Pathfinding;

/// <summary>
/// Represents a found walkable path.
/// </summary>
public class Path
{
    /// <summary>
    /// Initializes a new instance of the <see cref="Path"/> class.
    /// </summary>
    /// <param name="map">The map id.</param>
    /// <param name="x">The current x.</param>
    /// <param name="y">The current y.</param>
    /// <param name="targetX">The target x.</param>
    /// <param name="targetY">The target y.</param>
    /// <param name="parts">The parts that represent the path from the current to the target.</param>
    public Path
    (
        int map,
        short x,
        short y,
        short targetX,
        short targetY,
        IReadOnlyList<(short X, short Y)> parts
    )
    {
        MapId = map;
        CurrentX = x;
        CurrentY = y;
        TargetX = targetX;
        TargetY = targetY;
        Parts = parts;
        CurrentPartIndex = 0;
    }

    /// <summary>
    /// Gets the map id this path is for.
    /// </summary>
    public int MapId { get; }

    /// <summary>
    /// Gets whether the path has reached an end.
    /// </summary>
    public bool ReachedEnd => CurrentPartIndex >= Parts.Count - 1;

    /// <summary>
    /// Gets the current walk path index.
    /// </summary>
    public int CurrentPartIndex { get; private set; }

    /// <summary>
    /// Gets the list of the parts that have to be taken.
    /// </summary>
    public IReadOnlyList<(short X, short Y)> Parts { get; }

    /// <summary>
    /// Gets the target x coordinate.
    /// </summary>
    public short TargetX { get; }

    /// <summary>
    /// Gets the target y coordinate.
    /// </summary>
    public short TargetY { get; }

    /// <summary>
    /// Gets the current x coordinate.
    /// </summary>
    public short CurrentX { get; private set; }

    /// <summary>
    /// gets the current y coordinate.
    /// </summary>
    public short CurrentY { get; private set; }

    /// <summary>
    /// Take a path only in the same direction.
    /// </summary>
    /// <returns>A position to walk to.</returns>
    public (short X, short Y) TakeForwardPath()
    {
        if (ReachedEnd)
        {
            return (TargetX, TargetY);
        }
        if (CurrentPartIndex + 2 >= Parts.Count)
        {
            CurrentPartIndex++;
            return (TargetX, TargetY);
        }

        var zeroTile = (CurrentX, CurrentY);
        var firstTile = Parts[++CurrentPartIndex];
        var currentTile = firstTile;
        var nextTile = Parts[CurrentPartIndex + 1];

        while (!ReachedEnd && IsInLine(zeroTile, firstTile, nextTile))
        {
            currentTile = nextTile;
            CurrentPartIndex++;
            if (!ReachedEnd)
            {
                nextTile = Parts[CurrentPartIndex + 1];
            }
        }

        return currentTile;
    }

    private bool IsInLine((short X, short Y) start, (short X, short Y) first, (short X, short Y) current)
    {
        var xFirstDiff = first.X - start.X;
        var yFirstDiff = first.Y - start.Y;

        var xCurrentDiff = current.X - start.X;
        var yCurrentDiff = current.Y - start.Y;

        if (xFirstDiff == 0 && yFirstDiff == 0)
        {
            throw new ArgumentException("The path went back to the start.");
        }

        if (xCurrentDiff == 0 && yCurrentDiff == 0)
        {
            throw new ArgumentException("The path went back to the start.");
        }

        if (xFirstDiff != 0)
        {
            var xRatio = xCurrentDiff / (float)xFirstDiff;
            return Math.Abs((yFirstDiff * xRatio) - yCurrentDiff) < float.Epsilon;
        }

        var yRatio = yCurrentDiff / (float)yFirstDiff;
        return Math.Abs((xFirstDiff * yRatio) - xCurrentDiff) < float.Epsilon;
    }

    /// <summary>
    /// Take the given number of tiles and return the position we ended up at.
    /// </summary>
    /// <remarks>
    /// If the count is greater than what is remaining, the end will be taken.
    /// </remarks>
    /// <param name="partsCount">The count of parts to take.</param>
    /// <returns>A position to walk to.</returns>
    public (short X, short Y) TakePath(uint partsCount)
    {
        if (ReachedEnd)
        {
            return (TargetX, TargetY);
        }

        if (CurrentPartIndex + partsCount >= Parts.Count - 1)
        {
            CurrentPartIndex = Parts.Count - 1;
        }
        else
        {
            CurrentPartIndex += (int)partsCount;
        }

        return Parts[CurrentPartIndex];
    }
}
Do not follow this link