Skip to content

Commit 1ad8a3d

Browse files
committed
Rework connected tiles for better results and better performance
1 parent 9e096aa commit 1ad8a3d

10 files changed

Lines changed: 417 additions & 311 deletions

File tree

src/TSMapEditor/Config/Translations/en/Translation_en.ini

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,11 +1396,11 @@ DeleteTubeCursorAction.Text=Delete Tube
13961396
DeletionModeCursorAction.Name=Delete Object
13971397
DeletionModeCursorAction.Text=Delete
13981398

1399-
DrawCliffCursorAction.Name=Draw Connected Tiles
1400-
DrawCliffCursorAction.MainText=Click on a cell to place a new vertex.\r\n\r\nENTER to confirm\r\nBackspace to go back one step\r\n
1401-
DrawCliffCursorAction.TabText=TAB to toggle between front and back sides\r\n
1402-
DrawCliffCursorAction.PageUpDownText=PageUp to raise the tiles, PageDown to lower them\r\n
1403-
DrawCliffCursorAction.ExitText=Right-click or ESC to exit
1399+
DrawConnectedTilesCursorAction.Name=Draw Connected Tiles
1400+
DrawConnectedTilesCursorAction.MainText.V2=Click on a cell to place a new vertex.\r\n\r\nENTER to confirm\r\nBackspace to go back one step\r\n\r\nR to re-generate the pattern
1401+
DrawConnectedTilesCursorAction.TabText=TAB to toggle between front and back sides\r\n
1402+
DrawConnectedTilesCursorAction.PageUpDownText=PageUp to raise the tiles, PageDown to lower them\r\n
1403+
DrawConnectedTilesCursorAction.ExitText=Right-click or ESC to exit
14041404

14051405
GenerateTerrainCursorAction.Name=Generate Terrain
14061406

src/TSMapEditor/Config/Translations/zh-Hans/Translation_zh-Hans.ini

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,11 +1376,11 @@ DeleteTubeCursorAction.Text=删除隧道
13761376
DeletionModeCursorAction.Name=删除对象
13771377
DeletionModeCursorAction.Text=删除
13781378
1379-
DrawCliffCursorAction.Name=绘制连续地形
1380-
DrawCliffCursorAction.MainText=点击地图格放置一个顶点。@ENTER 确认@Backspace 回退一步@
1381-
DrawCliffCursorAction.TabText=TAB 切换前后方向@
1382-
DrawCliffCursorAction.PageUpDownText=PageUp 升高地块, PageDown 降低地块@
1383-
DrawCliffCursorAction.ExitText=右键或 ESC 退出
1379+
DrawConnectedTilesCursorAction.Name=绘制连续地形
1380+
DrawConnectedTilesCursorAction.MainText=点击地图格放置一个顶点。@ENTER 确认@Backspace 回退一步@
1381+
DrawConnectedTilesCursorAction.TabText=TAB 切换前后方向@
1382+
DrawConnectedTilesCursorAction.PageUpDownText=PageUp 升高地块, PageDown 降低地块@
1383+
DrawConnectedTilesCursorAction.ExitText=右键或 ESC 退出
13841384
13851385
GenerateTerrainCursorAction.Name=生成地形
13861386

src/TSMapEditor/GameMath/Point2D.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,20 @@ public int DistanceTo(Point2D other)
128128
return Math.Max(Math.Abs(X - other.X), Math.Abs(Y - other.Y));
129129
}
130130

131+
public bool IsInStraightLineWith(Point2D other)
132+
{
133+
if (X == other.X)
134+
return true;
135+
136+
if (Y == other.Y)
137+
return true;
138+
139+
if (Math.Abs(other.X - X) == Math.Abs(other.Y - Y))
140+
return true;
141+
142+
return false;
143+
}
144+
131145
public Point2D ScaleBy(double scale) => new Point2D((int)(X * scale), (int)(Y * scale));
132146

133147
public Point2D ScaleBy(float scale) => new Point2D((int)(X * scale), (int)(Y * scale));

src/TSMapEditor/Models/CliffType.cs renamed to src/TSMapEditor/Models/ConnectedTileType.cs

Lines changed: 61 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99

1010
namespace TSMapEditor.Models
1111
{
12-
public enum CliffSide
12+
public enum ConnectedTileSide
1313
{
1414
Front,
1515
Back
1616
}
1717

18-
public readonly struct CliffConnectionPoint
18+
public readonly struct TileConnectionPoint
1919
{
2020
/// <summary>
2121
/// Index of the connection point, 0 or 1
@@ -51,24 +51,28 @@ public readonly struct CliffConnectionPoint
5151
/// <summary>
5252
/// Whether the connection point faces "backwards" or "forwards"
5353
/// </summary>
54-
public CliffSide Side { get; init; }
54+
public ConnectedTileSide Side { get; init; }
5555
}
5656

57-
public class CliffAStarNode
57+
public class ConnectedTileAStarNode
5858
{
59-
private CliffAStarNode() {}
59+
private ConnectedTileAStarNode() {}
6060

61-
public CliffAStarNode(CliffAStarNode parent, CliffConnectionPoint exit, Point2D location, CliffTile tile)
61+
public ConnectedTileAStarNode(ConnectedTileAStarNode parent, TileConnectionPoint exit, Point2D location, ConnectedTile tile)
6262
{
6363
Location = location;
6464
Tile = tile;
6565

6666
Parent = parent;
6767
Exit = exit;
6868
Destination = Parent.Destination;
69+
GScore = Parent.GScore + Vector2.Distance(Parent.ExitCoords.ToXNAVector(), ExitCoords.ToXNAVector());
6970

7071
OccupiedCells = new HashSet<Point2D>(parent.OccupiedCells);
71-
OccupiedCells.UnionWith(tile.Foundation.Select(coordinate => coordinate + Location));
72+
foreach (var foundationCell in tile.Foundation)
73+
{
74+
OccupiedCells.Add(foundationCell + Location);
75+
}
7276
}
7377

7478
/// <summary>
@@ -84,7 +88,7 @@ public CliffAStarNode(CliffAStarNode parent, CliffConnectionPoint exit, Point2D
8488
/// <summary>
8589
/// Tile data
8690
/// </summary>
87-
public CliffTile Tile;
91+
public ConnectedTile Tile;
8892

8993
///// A* Stuff
9094

@@ -96,12 +100,12 @@ public CliffAStarNode(CliffAStarNode parent, CliffConnectionPoint exit, Point2D
96100
/// <summary>
97101
/// Where this node connects to the next node
98102
/// </summary>
99-
public CliffConnectionPoint Exit;
103+
public TileConnectionPoint Exit;
100104

101105
/// <summary>
102106
/// Distance from starting node
103107
/// </summary>
104-
public float GScore => Parent == null ? 0 : Parent.GScore + Vector2.Distance(Parent.ExitCoords.ToXNAVector(), ExitCoords.ToXNAVector());
108+
public float GScore { get; private set; }
105109

106110
/// <summary>
107111
/// Distance to end node
@@ -112,16 +116,16 @@ public CliffAStarNode(CliffAStarNode parent, CliffConnectionPoint exit, Point2D
112116
/// <summary>
113117
/// Previous node
114118
/// </summary>
115-
public CliffAStarNode Parent;
119+
public ConnectedTileAStarNode Parent;
116120

117121
/// <summary>
118122
/// Accumulated set of all cell coordinates occupied up to this node
119123
/// </summary>
120124
public HashSet<Point2D> OccupiedCells = new HashSet<Point2D>();
121125

122-
public static CliffAStarNode MakeStartNode(Point2D location, Point2D destination, CliffSide startingSide)
126+
public static ConnectedTileAStarNode MakeStartNode(Point2D location, Point2D destination, ConnectedTileSide startingSide)
123127
{
124-
CliffConnectionPoint connectionPoint = new CliffConnectionPoint
128+
TileConnectionPoint connectionPoint = new TileConnectionPoint
125129
{
126130
Index = 0,
127131
ConnectionMask = 0b11111111,
@@ -131,24 +135,25 @@ public static CliffAStarNode MakeStartNode(Point2D location, Point2D destination
131135
ForbiddenTiles = Array.Empty<int>()
132136
};
133137

134-
var startNode = new CliffAStarNode()
138+
var startNode = new ConnectedTileAStarNode()
135139
{
136140
Location = location,
137141
Tile = null,
138142

139143
Parent = null,
140144
Exit = connectionPoint,
141-
Destination = destination
145+
Destination = destination,
146+
GScore = 0
142147
};
143148

144149
return startNode;
145150
}
146151

147-
public List<CliffAStarNode> GetNextNodes(CliffTile tile)
152+
public List<ConnectedTileAStarNode> GetNextNodes(ConnectedTile tile)
148153
{
149-
List<(CliffConnectionPoint, List<Direction>)> possibleNeighbors = new();
154+
var neighbors = new List<ConnectedTileAStarNode>();
150155

151-
foreach (CliffConnectionPoint cp in tile.ConnectionPoints)
156+
foreach (TileConnectionPoint cp in tile.ConnectionPoints)
152157
{
153158
if (Tile != null)
154159
{
@@ -161,36 +166,38 @@ public List<CliffAStarNode> GetNextNodes(CliffTile tile)
161166
if (possibleDirections.Count == 0)
162167
continue;
163168

164-
possibleNeighbors.Add((cp, possibleDirections));
165-
}
166-
167-
var neighbors = new List<CliffAStarNode>();
168-
169-
foreach (var (connectionPoint, directions) in possibleNeighbors)
170-
{
171-
if (connectionPoint.Side != Exit.Side)
169+
if (cp.Side != Exit.Side)
172170
continue;
173171

174-
foreach (Direction dir in directions)
172+
foreach (Direction dir in possibleDirections)
175173
{
176-
Point2D placementOffset = Helpers.VisualDirectionToPoint(dir) - connectionPoint.CoordinateOffset;
174+
Point2D placementOffset = Helpers.VisualDirectionToPoint(dir) - cp.CoordinateOffset;
177175
Point2D placementCoords = ExitCoords + placementOffset;
178176

179-
var exit = tile.GetExit(connectionPoint.Index);
180-
var newNode = new CliffAStarNode(this, exit, placementCoords, tile);
177+
bool overlaps = false;
178+
foreach (var foundationCell in tile.Foundation)
179+
{
180+
if (OccupiedCells.Contains(foundationCell + placementCoords))
181+
{
182+
overlaps = true;
183+
break;
184+
}
185+
}
186+
187+
if (overlaps)
188+
continue;
181189

182-
// Make sure that the new node doesn't overlap anything
183-
if (newNode.OccupiedCells.Count - OccupiedCells.Count == newNode.Tile.Foundation.Count)
184-
neighbors.Add(newNode);
190+
var exit = tile.GetExit(cp.Index);
191+
neighbors.Add(new ConnectedTileAStarNode(this, exit, placementCoords, tile));
185192
}
186193
}
187194

188195
return neighbors;
189196
}
190197

191-
public List<CliffAStarNode> GetNextNodes(List<CliffTile> tiles, bool allowTurn)
198+
public List<ConnectedTileAStarNode> GetNextNodes(List<ConnectedTile> tiles, bool allowTurn)
192199
{
193-
List <CliffAStarNode > nextNodes = new List<CliffAStarNode>();
200+
List <ConnectedTileAStarNode > nextNodes = new List<ConnectedTileAStarNode>();
194201
foreach (var tile in tiles)
195202
{
196203
if (!allowTurn && tile.ConnectionPoints[0].Side != tile.ConnectionPoints[1].Side)
@@ -203,9 +210,9 @@ public List<CliffAStarNode> GetNextNodes(List<CliffTile> tiles, bool allowTurn)
203210
}
204211
}
205212

206-
public class CliffTile
213+
public class ConnectedTile
207214
{
208-
public CliffTile(IniSection iniSection, int index)
215+
public ConnectedTile(IniSection iniSection, int index)
209216
{
210217
Index = index;
211218

@@ -222,7 +229,7 @@ public CliffTile(IniSection iniSection, int index)
222229

223230
IndicesInTileSet = indicesString.Split(',').Select(s => int.Parse(s, CultureInfo.InvariantCulture)).ToList();
224231

225-
ConnectionPoints = new CliffConnectionPoint[2];
232+
ConnectionPoints = new TileConnectionPoint[2];
226233

227234
for (int i = 0; i < ConnectionPoints.Length; i++)
228235
{
@@ -257,11 +264,11 @@ public CliffTile(IniSection iniSection, int index)
257264
}
258265

259266
string sideString = iniSection.GetStringValue($"ConnectionPoint{i}.Side", string.Empty);
260-
CliffSide side = sideString.ToLower() switch
267+
ConnectedTileSide side = sideString.ToLower() switch
261268
{
262-
"front" => CliffSide.Front,
263-
"back" => CliffSide.Back,
264-
"" => CliffSide.Front,
269+
"front" => ConnectedTileSide.Front,
270+
"back" => ConnectedTileSide.Back,
271+
"" => ConnectedTileSide.Front,
265272
_ => throw new INIConfigException($"Connected Tile {iniSection.SectionName} has an invalid ConnectionPoint{i}.Side value: {sideString}!")
266273
};
267274

@@ -284,7 +291,7 @@ public CliffTile(IniSection iniSection, int index)
284291
requiredTiles = Array.Empty<int>();
285292
}
286293

287-
ConnectionPoints[i] = new CliffConnectionPoint
294+
ConnectionPoints[i] = new TileConnectionPoint
288295
{
289296
Index = i,
290297
ConnectionMask = directions,
@@ -326,7 +333,7 @@ public CliffTile(IniSection iniSection, int index)
326333
/// <summary>
327334
/// Places this tile connects to other tiles
328335
/// </summary>
329-
public CliffConnectionPoint[] ConnectionPoints { get; set; }
336+
public TileConnectionPoint[] ConnectionPoints { get; set; }
330337

331338
/// <summary>
332339
/// Set of all relative cell coordinates this tile occupies
@@ -343,18 +350,18 @@ public CliffTile(IniSection iniSection, int index)
343350
/// </summary>
344351
public int DistanceModifier { get; set; }
345352

346-
public CliffConnectionPoint GetExit(int entryIndex)
353+
public TileConnectionPoint GetExit(int entryIndex)
347354
{
348355
return ConnectionPoints[0].Index == entryIndex ? ConnectionPoints[1] : ConnectionPoints[0];
349356
}
350357

351-
private bool IsStraight(CliffConnectionPoint[] connectionPoints)
358+
private bool IsStraight(TileConnectionPoint[] connectionPoints)
352359
{
353360
int mask = connectionPoints[0].ConnectionMask & connectionPoints[1].ReversedConnectionMask;
354361
return mask > 0;
355362
}
356363

357-
private bool IsDiagonal(CliffConnectionPoint[] connectionPoints)
364+
private bool IsDiagonal(TileConnectionPoint[] connectionPoints)
358365
{
359366
var directions = Helpers.GetDirectionsInMask((byte)(connectionPoints[0].ConnectionMask &
360367
connectionPoints[1].ReversedConnectionMask));
@@ -406,9 +413,9 @@ private static byte DirectionFromString(string str)
406413
}
407414
}
408415

409-
public class CliffType
416+
public class ConnectedTileType
410417
{
411-
public static CliffType FromIniSection(IniFile iniFile, string sectionName)
418+
public static ConnectedTileType FromIniSection(IniFile iniFile, string sectionName)
412419
{
413420
IniSection cliffSection = iniFile.GetSection(sectionName);
414421
if (cliffSection == null)
@@ -427,18 +434,18 @@ public static CliffType FromIniSection(IniFile iniFile, string sectionName)
427434
if (cliffSection.KeyExists("Color"))
428435
color = cliffSection.GetColorValue("Color", Microsoft.Xna.Framework.Color.White);
429436

430-
return new CliffType(iniFile, sectionName, cliffName, frontOnly, allowedTheaters, color);
437+
return new ConnectedTileType(iniFile, sectionName, cliffName, frontOnly, allowedTheaters, color);
431438
}
432439

433-
private CliffType(IniFile iniFile, string iniName, string name, bool frontOnly, List<string> allowedTheaters, Color? color)
440+
private ConnectedTileType(IniFile iniFile, string iniName, string name, bool frontOnly, List<string> allowedTheaters, Color? color)
434441
{
435442
IniName = iniName;
436443
Name = Translate(this, iniName, name);
437444
AllowedTheaters = allowedTheaters;
438445
FrontOnly = frontOnly;
439446
Color = color;
440447

441-
Tiles = new List<CliffTile>();
448+
Tiles = new List<ConnectedTile>();
442449

443450
foreach (var sectionName in iniFile.GetSections())
444451
{
@@ -452,7 +459,7 @@ private CliffType(IniFile iniFile, string iniName, string name, bool frontOnly,
452459
$"Connected Tile {iniName} has multiple tiles with the same index {index}!");
453460
}
454461

455-
Tiles.Add(new CliffTile(iniFile.GetSection(sectionName), index));
462+
Tiles.Add(new ConnectedTile(iniFile.GetSection(sectionName), index));
456463
}
457464
}
458465

@@ -462,6 +469,6 @@ private CliffType(IniFile iniFile, string iniName, string name, bool frontOnly,
462469
public bool IsLegal { get; set; } = true;
463470
public Color? Color { get; set; }
464471
public List<string> AllowedTheaters { get; set; }
465-
public List<CliffTile> Tiles { get; }
472+
public List<ConnectedTile> Tiles { get; }
466473
}
467474
}

src/TSMapEditor/Models/EditorConfig.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public EditorConfig()
3030
public List<Theater> Theaters { get; } = new List<Theater>();
3131
public List<BridgeType> Bridges { get; } = new List<BridgeType>();
3232
public List<ConnectedOverlayType> ConnectedOverlays { get; } = new List<ConnectedOverlayType>();
33-
public List<CliffType> Cliffs { get; } = new List<CliffType>();
33+
public List<ConnectedTileType> Cliffs { get; } = new List<ConnectedTileType>();
3434
public List<TeamTypeFlag> TeamTypeFlags { get; } = new List<TeamTypeFlag>();
3535
public EvaSpeeches Speeches { get; private set; }
3636

@@ -449,7 +449,7 @@ private void ReadCliffs()
449449
{
450450
string cliffIniName = kvp.Value;
451451

452-
CliffType cliffType = CliffType.FromIniSection(iniFile, cliffIniName);
452+
ConnectedTileType cliffType = ConnectedTileType.FromIniSection(iniFile, cliffIniName);
453453
if (cliffType != null)
454454
Cliffs.Add(cliffType);
455455
}

0 commit comments

Comments
 (0)