close Warning: Can't synchronize with repository "(default)" (No changeset 184 in the repository). Look in the Trac log for more information.

source: trunk/UMap.pas

Last change on this file was 177, checked in by chronos, 6 years ago
  • Modified: Propagate build mode settings to used packages.
File size: 10.5 KB
Line 
1unit UMap;
2
3{$mode delphi}
4
5interface
6
7uses
8 Classes, SysUtils, UGame, XMLRead, XMLWrite, DOM, UGeometry, fgl;
9
10type
11 TCellsDistance = class
12 Cell1: TCell;
13 Cell2: TCell;
14 Distance: Double;
15 end;
16
17 { THexMap }
18
19 THexMap = class(TMap)
20 private
21 function IsCellsPosNeighbor(CellPos1, CellPos2: TPoint): Boolean;
22 procedure GetCellPosNeighbors(CellPos: TPoint; Neighbours: TCells);
23 function GetHexagonPolygon(Pos: TPoint; Size: TPoint): TPolygon;
24 public
25 procedure LoadFromFile(FileName: string); override;
26 procedure SaveToFile(FileName: string); override;
27 function IsValidIndex(Index: TPoint): Boolean; override;
28 procedure Generate; override;
29 end;
30
31 { TSquareMap }
32
33 TSquareMap = class(TMap)
34 private
35 function GetSquarePolygon(Pos: TPoint; Size: TPoint): TPolygon;
36 public
37 function IsValidIndex(Index: TPoint): Boolean; override;
38 procedure Generate; override;
39 end;
40
41 { TTriangleMap }
42
43 TTriangleMap = class(TMap)
44 private
45 function GetTrianglePolygon(Pos: TPoint; Size: TPoint; Reverse: Boolean): TPolygon;
46 public
47 function IsValidIndex(Index: TPoint): Boolean; override;
48 procedure Generate; override;
49 end;
50
51 { TVoronoiMap }
52
53 TVoronoiMap = class(TMap)
54 private
55 public
56 procedure Generate; override;
57 end;
58
59implementation
60
61{ THexMap }
62
63function THexMap.GetHexagonPolygon(Pos: TPoint; Size: TPoint): TPolygon;
64var
65 Shift: TPointF;
66begin
67 Shift := TPointF.Create(0.5 * cos(30 / 180 * Pi), 0.5 * sin(30 / 180 * Pi));
68 SetLength(Result.Points, 6);
69 Result.Points[0] := TPoint.Create(Trunc(Pos.X + 0 * Size.X), Trunc(Pos.Y - 0.5 * Size.Y));
70 Result.Points[1] := TPoint.Create(Trunc(Pos.X + Shift.X * Size.X), Trunc(Pos.Y - Shift.Y * Size.Y));
71 Result.Points[2] := TPoint.Create(Trunc(Pos.X + Shift.X * Size.X), Trunc(Pos.Y + Shift.Y * Size.Y));
72 Result.Points[3] := TPoint.Create(Trunc(Pos.X + 0 * Size.X), Trunc(Pos.Y + 0.5 * Size.Y));
73 Result.Points[4] := TPoint.Create(Trunc(Pos.X - Shift.X * Size.X), Trunc(Pos.Y + Shift.Y * Size.Y));
74 Result.Points[5] := TPoint.Create(Trunc(Pos.X - Shift.X * Size.X), Trunc(Pos.Y - Shift.Y * Size.Y));
75end;
76
77function THexMap.IsCellsPosNeighbor(CellPos1, CellPos2: TPoint): Boolean;
78var
79 DX: Integer;
80 DY: Integer;
81 MinY: Integer;
82begin
83 if CellPos1.Y < CellPos2.Y then MinY:= CellPos1.Y
84 else MinY := CellPos2.Y;
85 DX := CellPos2.X - CellPos1.X;
86 DY := CellPos2.Y - CellPos1.Y;
87 Result := (Abs(DX) <= 1) and (Abs(DY) <= 1) and
88 ((((MinY mod 2) = 1) and
89 not ((DX = 1) and (DY = -1)) and
90 not ((DX = -1) and (DY = 1))) or
91 (((MinY mod 2) = 0) and
92 not ((DX = -1) and (DY = -1)) and
93 not ((DX = 1) and (DY = 1))));
94 Result := Result and not ((CellPos1.X = CellPos2.X) and (CellPos1.Y = CellPos2.Y));
95end;
96
97procedure THexMap.LoadFromFile(FileName: string);
98var
99 Doc: TXMLDocument;
100begin
101 try
102 ReadXMLFile(Doc, FileName);
103 if Doc.DocumentElement.TagName <> 'Map' then
104 raise Exception.Create('Invalid map format');
105 finally
106 Doc.Free;
107 end;
108 inherited LoadFromFile(FileName);
109end;
110
111procedure THexMap.SaveToFile(FileName: string);
112var
113 Doc: TXMLDocument;
114 RootNode: TDOMNode;
115begin
116 try
117 Doc := TXMLDocument.Create;
118 RootNode := Doc.CreateElement('Map');
119 Doc.Appendchild(RootNode);
120 WriteXMLFile(Doc, FileName);
121 finally
122 Doc.Free;
123 end;
124 inherited SaveToFile(FileName);
125end;
126
127function THexMap.IsValidIndex(Index: TPoint): Boolean;
128begin
129 Result := (Index.X >= 0) and (Index.X < Size.X) and
130 (Index.Y >= 0) and (Index.Y < Size.Y);
131end;
132
133procedure THexMap.GetCellPosNeighbors(CellPos: TPoint; Neighbours: TCells);
134var
135 X, Y: Integer;
136begin
137 Neighbours.Count := 0;
138 for Y := -1 to 1 do
139 for X := -1 to 1 do
140 if IsValidIndex(TPoint.Create(CellPos.X + X, CellPos.Y + Y)) and
141 IsCellsPosNeighbor(CellPos, TPoint.Create((CellPos.X + X), (CellPos.Y + Y))) then begin
142 Neighbours.Add(TCell(Cells[(CellPos.Y + Y) * Size.X + (CellPos.X + X)]));
143 end;
144end;
145
146procedure THexMap.Generate;
147var
148 X, Y: Integer;
149 NewCell: TCell;
150 PX, PY: Double;
151begin
152 Clear;
153
154 // Allocate and init new
155 Cells.Count := Size.Y * Size.X;
156 for Y := 0 to Size.Y - 1 do
157 for X := 0 to Size.X - 1 do begin
158 NewCell := TCell.Create;
159 NewCell.Map := Self;
160 PX := X;
161 PY := Y;
162 if (Y and 1) = 1 then begin
163 PX := PX + 0.5;
164 //Y := Y + 0.5;
165 end;
166 NewCell.PosPx := TPoint.Create(Trunc(PX * DefaultCellSize.X / HexCellMulX),
167 Trunc(PY * DefaultCellSize.Y / HexCellMulY));
168 NewCell.Polygon := GetHexagonPolygon(NewCell.PosPx, DefaultCellSize);
169 NewCell.Id := GetNewCellId;
170 Cells[Y * Size.X + X] := NewCell;
171 end;
172
173 // Generate neightbours
174 for Y := 0 to Size.Y - 1 do
175 for X := 0 to Size.X - 1 do
176 with TCell(Cells[Y * Size.X + X]) do begin
177 GetCellPosNeighbors(TPoint.Create(X, Y), Neighbors);
178 end;
179
180 FPixelRect := CalculatePixelRect;
181end;
182
183
184{ TSquareMap }
185
186procedure TSquareMap.Generate;
187var
188 X, Y: Integer;
189 NewCell: TCell;
190begin
191 Clear;
192
193 // Allocate and init new
194 Cells.Count := Size.Y * Size.X;
195 for Y := 0 to Size.Y - 1 do
196 for X := 0 to Size.X - 1 do begin
197 NewCell := TCell.Create;
198 NewCell.Map := Self;
199 NewCell.PosPx := TPoint.Create(Trunc(X * DefaultCellSize.X * SquareCellMulX),
200 Trunc(Y * DefaultCellSize.Y * SquareCellMulY));
201 NewCell.Polygon := GetSquarePolygon(NewCell.PosPx, DefaultCellSize);
202 NewCell.Id := GetNewCellId;
203 Cells[Y * Size.X + X] := NewCell;
204 end;
205
206 // Generate neighbours
207 for Y := 0 to Size.Y - 1 do
208 for X := 0 to Size.X - 1 do
209 with TCell(Cells[Y * Size.X + X]) do begin
210 if IsValidIndex(TPoint.Create(X + 1, Y + 0)) then
211 Neighbors.Add(TCell(Cells[(Y + 0) * Size.X + (X + 1)]));
212 if IsValidIndex(TPoint.Create(X + 0, Y + 1)) then
213 Neighbors.Add(TCell(Cells[(Y + 1) * Size.X + (X + 0)]));
214 if IsValidIndex(TPoint.Create(X - 1, Y + 0)) then
215 Neighbors.Add(TCell(Cells[(Y + 0) * Size.X + (X - 1)]));
216 if IsValidIndex(TPoint.Create(X + 0, Y - 1)) then
217 Neighbors.Add(TCell(Cells[(Y - 1) * Size.X + (X + 0)]));
218 end;
219
220 FPixelRect := CalculatePixelRect;
221end;
222
223function TSquareMap.IsValidIndex(Index: TPoint): Boolean;
224begin
225 Result := (Index.X >= 0) and (Index.X < Size.X) and
226 (Index.Y >= 0) and (Index.Y < Size.Y);
227end;
228
229function TSquareMap.GetSquarePolygon(Pos: TPoint; Size: TPoint): TPolygon;
230begin
231 SetLength(Result.Points, 4);
232 Result.Points[0] := TPoint.Create(Trunc(Pos.X - Size.X / 2), Trunc(Pos.Y - Size.Y / 2));
233 Result.Points[1] := TPoint.Create(Trunc(Pos.X + Size.X / 2), Trunc(Pos.Y - Size.Y / 2));
234 Result.Points[2] := TPoint.Create(Trunc(Pos.X + Size.X / 2), Trunc(Pos.Y + Size.Y / 2));
235 Result.Points[3] := TPoint.Create(Trunc(Pos.X - Size.X / 2), Trunc(Pos.Y + Size.Y / 2));
236end;
237
238{ TVoronoiMap }
239
240function CompareDistance(const C1, C2: TCellsDistance): Integer;
241begin
242 if C1.Distance > C2.Distance then Result := 1
243 else if C1.Distance < C2.Distance then Result := -1
244 else Result := 0;
245end;
246
247procedure TVoronoiMap.Generate;
248var
249 X, Y: Integer;
250 NewCell: TCell;
251 I, J: Integer;
252 Cell: TCell;
253 Cell2: TCell;
254 L1: TLine;
255 MP: TPoint;
256 LinkLine: TLine;
257const
258 CellGapWidth = 4;
259begin
260 Clear;
261 //RandSeed := 1234;
262
263 // Allocate and init new cells
264 Cells.Count := Size.Y * Size.X;
265 for Y := 0 to Size.Y - 1 do
266 for X := 0 to Size.X - 1 do begin
267 NewCell := TCell.Create;
268 NewCell.Map := Self;
269 NewCell.PosPx := TPoint.Create(Trunc(Random * Size.X * DefaultCellSize.X),
270 Trunc(Random * Size.Y * DefaultCellSize.Y));
271 SetLength(NewCell.Polygon.Points, 1);
272 NewCell.Polygon.Points[0] := NewCell.PosPx;
273 NewCell.Id := GetNewCellId;
274 Cells[Y * Size.X + X] := NewCell;
275 end;
276
277 // Compute polygon cat out by all other cells
278 for Cell in Cells do begin
279 Cell.Polygon := TPolygon.Create(TRect.Create(TPoint.Create(0, 0),
280 TPoint.Create(Size.X * DefaultCellSize.X, Size.Y * DefaultCellSize.Y)));
281 for Cell2 in Cells do
282 if Cell2 <> Cell then begin
283 LinkLine := TLine.Create(Cell.PosPx, Cell2.PosPx);
284 LinkLine.Distance := LinkLine.Distance - CellGapWidth;
285 MP := LinkLine.GetMiddle;
286 // Create half plane vector
287 L1 := TLine.Create(MP, TPoint.Create(MP.X + LinkLine.GetSize.X,
288 MP.Y + LinkLine.GetSize.Y));
289
290 Cell.Polygon.CutLine(L1, Cell.PosPx);
291 end;
292 end;
293
294 // Link all cells with neighboring polygon edges
295 for I := 0 to Cells.Count - 1 do begin
296 for J := I + 1 to Cells.Count - 1 do begin
297 if Cells[I].Polygon.EdgeDistance(Cells[J].Polygon) < 2 * CellGapWidth then
298 Cells[I].ConnectTo(Cells[J]);
299 end;
300 end;
301
302 FPixelRect := CalculatePixelRect;
303end;
304
305{ TTriangleMap }
306
307function TTriangleMap.GetTrianglePolygon(Pos: TPoint; Size: TPoint;
308 Reverse: Boolean): TPolygon;
309var
310 Rev: Integer;
311begin
312 if Reverse then Rev := -1
313 else Rev := 1;
314 SetLength(Result.Points, 3);
315 Result.Points[0] := TPoint.Create(Trunc(Pos.X - Size.X / 2), Trunc(Pos.Y - (Size.Y * 0.8) / 2 * Rev));
316 Result.Points[1] := TPoint.Create(Trunc(Pos.X + Size.X / 2), Trunc(Pos.Y - (Size.Y * 0.8) / 2 * Rev));
317 Result.Points[2] := TPoint.Create(Trunc(Pos.X), Trunc(Pos.Y + (Size.Y * 1.2) / 2 * Rev));
318end;
319
320function TTriangleMap.IsValidIndex(Index: TPoint): Boolean;
321begin
322 Result := (Index.X >= 0) and (Index.X < Size.X) and
323 (Index.Y >= 0) and (Index.Y < Size.Y);
324end;
325
326procedure TTriangleMap.Generate;
327var
328 X, Y: Integer;
329 Rev: Integer;
330 Reverse: Boolean;
331 NewCell: TCell;
332begin
333 Clear;
334
335 // Allocate and init new
336 Cells.Count := Size.Y * Size.X;
337 for Y := 0 to Size.Y - 1 do
338 for X := 0 to Size.X - 1 do begin
339 NewCell := TCell.Create;
340 NewCell.Map := Self;
341 Reverse := Boolean(X mod 2) xor Boolean(Y mod 2);
342 if Reverse then Rev := -1
343 else Rev := 1;
344 NewCell.PosPx := TPoint.Create(Trunc(X * DefaultCellSize.X * TriangleCellMulX),
345 Trunc((Y * DefaultCellSize.Y * TriangleCellMulY) - (0.1 * Rev * DefaultCellSize.Y)));
346 NewCell.Polygon := GetTrianglePolygon(NewCell.PosPx, DefaultCellSize, Reverse);
347 NewCell.Id := GetNewCellId;
348 Cells[Y * Size.X + X] := NewCell;
349 end;
350
351 // Generate neighbours
352 for Y := 0 to Self.Size.Y - 1 do
353 for X := 0 to Size.X - 1 do
354 with TCell(Cells[Y * Size.X + X]) do begin
355 if Boolean(X mod 2) xor Boolean(Y mod 2) then Rev := -1
356 else Rev := 1;
357 if IsValidIndex(TPoint.Create(X + 1, Y + 0)) then
358 Neighbors.Add(TCell(Cells[(Y + 0) * Size.X + (X + 1)]));
359 if IsValidIndex(TPoint.Create(X + 0, Y - 1 * Rev)) then
360 Neighbors.Add(TCell(Cells[(Y - 1 * Rev) * Size.X + (X + 0)]));
361 if IsValidIndex(TPoint.Create(X - 1, Y + 0)) then
362 Neighbors.Add(TCell(Cells[(Y + 0) * Size.X + (X - 1)]));
363 end;
364
365 FPixelRect := CalculatePixelRect;
366end;
367
368
369end.
370
Note: See TracBrowser for help on using the repository browser.