@@ -309,9 +309,8 @@ Dictionary TerrainGen::generate(
309
309
(Cardinal Neighbors Only)
310
310
311
311
*****************************************************/
312
- int neighborRadius = 1 ; // 3x3 neighborhood (cardinal only)
313
312
int threshold = 2 ; // Minimum matching neighbors to preserve center
314
- int iterations = 1 ; // Number of CA generations to apply
313
+ int iterations = 2 ; // Number of CA generations to apply
315
314
316
315
vector<vector<int >> curr = heightMap;
317
316
vector<vector<int >> next = heightMap;
@@ -321,6 +320,24 @@ Dictionary TerrainGen::generate(
321
320
{ 0 , -1 }, { 0 , 1 }, { -1 , 0 }, { 1 , 0 }
322
321
};
323
322
323
+ // Height Map is a double grid
324
+ // +----+----+----+----+
325
+ // | z1 | z2 | y1 | y2 |
326
+ // +----+----+----+----+
327
+ // | z3 | z4 | y3 | y5 |
328
+ // +----+----+----+----+
329
+ // | x1 | x2 | w1 | w2 |
330
+ // +----+----+----+----+
331
+ // | x3 | x4 | w3 | w4 |
332
+ // +----+----+----+----+
333
+ //
334
+ // Eventually the map will be reduced to :
335
+ // +----+----+
336
+ // | z | y |
337
+ // +----+----+
338
+ // | x | w |
339
+ // +----+----+
340
+
324
341
for (int it = 0 ; it < iterations; ++it) {
325
342
bool anyChanged = false ;
326
343
@@ -395,80 +412,84 @@ Dictionary TerrainGen::generate(
395
412
396
413
*****************************************************/
397
414
415
+ int caCcount = 2 ;
416
+
398
417
if (waterRemoval >= 10 .0f ) {
399
418
// Clamp percentage
400
419
if (waterRemoval > 100 .0f )
401
420
waterRemoval = 100 .0f ;
402
421
if (waterRemoval < 0 .0f )
403
422
waterRemoval = 0 .0f ;
404
423
405
- vector<vector<bool >> visited (heightx2, vector<bool >(widthx2, false ));
424
+ for (int iter = 0 ; iter < caCcount; iter++) {
425
+ vector<vector<bool >> visited (heightx2, vector<bool >(widthx2, false ));
406
426
407
- for (int y = 0 ; y < heightx2; y++) {
408
- for (int x = 0 ; x < widthx2; x++) {
409
- if (heightMap[y][x] != 0 || visited[y][x])
410
- continue ;
427
+ for (int y = 0 ; y < heightx2; y++) {
428
+ for (int x = 0 ; x < widthx2; x++) {
429
+ if (heightMap[y][x] != 0 || visited[y][x])
430
+ continue ;
411
431
412
- // Manual stack flood fill
413
- vector<pair<int , int >> stack;
414
- vector<pair<int , int >> region;
415
- stack.push_back (make_pair (x, y));
416
- visited[y][x] = true ;
417
-
418
- while (!stack.empty ()) {
419
- pair<int , int > current = stack.back ();
420
- stack.pop_back ();
421
- int cx = current.first ;
422
- int cy = current.second ;
423
- region.push_back (current);
424
-
425
- for (int d = 0 ; d < 4 ; d++) {
426
- int nx = cx + dx[d];
427
- int ny = cy + dy[d];
428
- if (nx < 0 || ny < 0 || nx >= widthx2 || ny >= heightx2)
429
- continue ;
430
- if (visited[ny][nx])
431
- continue ;
432
- if (heightMap[ny][nx] != 0 )
433
- continue ;
434
- visited[ny][nx] = true ;
435
- stack.push_back (make_pair (nx, ny));
432
+ // Manual stack flood fill
433
+ vector<pair<int , int >> stack;
434
+ vector<pair<int , int >> region;
435
+ stack.push_back (make_pair (x, y));
436
+ visited[y][x] = true ;
437
+
438
+ while (!stack.empty ()) {
439
+ pair<int , int > current = stack.back ();
440
+ stack.pop_back ();
441
+ int cx = current.first ;
442
+ int cy = current.second ;
443
+ region.push_back (current);
444
+
445
+ for (int d = 0 ; d < 4 ; d++) {
446
+ int nx = cx + dx[d];
447
+ int ny = cy + dy[d];
448
+ if (nx < 0 || ny < 0 || nx >= widthx2 || ny >= heightx2)
449
+ continue ;
450
+ if (visited[ny][nx])
451
+ continue ;
452
+ if (heightMap[ny][nx] != 0 )
453
+ continue ;
454
+ visited[ny][nx] = true ;
455
+ stack.push_back (make_pair (nx, ny));
456
+ }
436
457
}
437
- }
438
458
439
- // Determine how many cells to flip
440
- int regionSize = region.size ();
441
- int toFlip = (int )(regionSize * (waterRemoval / 100 .0f ));
442
- if (toFlip <= 0 )
443
- continue ;
459
+ // Determine how many cells to flip
460
+ int regionSize = region.size ();
461
+ int toFlip = (int )(regionSize * (waterRemoval / 100 .0f ));
462
+ if (toFlip <= 0 )
463
+ continue ;
444
464
445
- // Rank by proximity to edge
446
- vector<pair<int , pair<int , int >>> candidates;
447
- for (int i = 0 ; i < regionSize; i++) {
448
- int rx = region[i].first ;
449
- int ry = region[i].second ;
450
- int distX = min (rx, widthx2 - 1 - rx);
451
- int distY = min (ry, heightx2 - 1 - ry);
452
- int edgeDist = min (distX, distY);
453
- candidates.push_back (make_pair (edgeDist, region[i]));
454
- }
465
+ // Rank by proximity to edge
466
+ vector<pair<int , pair<int , int >>> candidates;
467
+ for (int i = 0 ; i < regionSize; i++) {
468
+ int rx = region[i].first ;
469
+ int ry = region[i].second ;
470
+ int distX = min (rx, widthx2 - 1 - rx);
471
+ int distY = min (ry, heightx2 - 1 - ry);
472
+ int edgeDist = min (distX, distY);
473
+ candidates.push_back (make_pair (edgeDist, region[i]));
474
+ }
455
475
456
- // Bubble sort
457
- for (int i = 0 ; i < (int )candidates.size (); i++) {
458
- for (int j = i + 1 ; j < (int )candidates.size (); j++) {
459
- if (candidates[j].first < candidates[i].first ) {
460
- pair<int , pair<int , int >> temp = candidates[i];
461
- candidates[i] = candidates[j];
462
- candidates[j] = temp;
476
+ // Bubble sort
477
+ for (int i = 0 ; i < (int )candidates.size (); i++) {
478
+ for (int j = i + 1 ; j < (int )candidates.size (); j++) {
479
+ if (candidates[j].first < candidates[i].first ) {
480
+ pair<int , pair<int , int >> temp = candidates[i];
481
+ candidates[i] = candidates[j];
482
+ candidates[j] = temp;
483
+ }
463
484
}
464
485
}
465
- }
466
486
467
- // Flip top N water cells to land
468
- for (int i = 0 ; i < toFlip && i < (int )candidates.size (); i++) {
469
- int fx = candidates[i].second .first ;
470
- int fy = candidates[i].second .second ;
471
- heightMap[fy][fx] = 1 ;
487
+ // Flip top N water cells to land
488
+ for (int i = 0 ; i < toFlip && i < (int )candidates.size (); i++) {
489
+ int fx = candidates[i].second .first ;
490
+ int fy = candidates[i].second .second ;
491
+ heightMap[fy][fx] = 1 ;
492
+ }
472
493
}
473
494
}
474
495
}
@@ -798,7 +819,7 @@ Dictionary TerrainGen::generate(
798
819
// | n3 | n4 | | 1 | 1 | | 2 | 2 |
799
820
// +----+----+ +---+---+ +---+---+
800
821
//
801
- if (n1 == n2 && n2 == n3 && n3 == n4 && n1 > 0 && n2 > 0 && n3 > 0 && n4 > 0 ) {
822
+ if (n1 == n2 && n2 == n3 && n3 == n4 && n1 == n4 && n1 > 0 && n2 > 0 && n3 > 0 && n4 > 0 ) {
802
823
tileMap[x][y] = GROUND;
803
824
}
804
825
@@ -1072,7 +1093,9 @@ Dictionary TerrainGen::generate(
1072
1093
//
1073
1094
//
1074
1095
//
1075
- // Phase 2 : Determine the Tile's Rotation
1096
+ // Phase 2 : Corrections & Rotations
1097
+ //
1098
+ // Description: Determine the Tile's Rotation and correct tiles
1076
1099
//
1077
1100
// Models: Ramp Corner's/ Cliff Corner's / Water Corner's start with HIGH at (−Z, +X)
1078
1101
// i.e., NE corner.
@@ -1087,11 +1110,12 @@ Dictionary TerrainGen::generate(
1087
1110
// | m6 | m7 | m8 |
1088
1111
// +----+----+----+
1089
1112
//
1113
+
1090
1114
for (int x = 0 ; x < width; x++) {
1091
1115
for (int y = 0 ; y < height; y++) {
1092
1116
int c_height = elevationMap[x][y];
1093
1117
int tile_id = myGridMap->get_cell_item (Vector3i (x, c_height, y));
1094
- if (tile_id == -1 || tile_id == WATER || tile_id == GROUND)
1118
+ if (tile_id == -1 || tile_id == GROUND)
1095
1119
continue ;
1096
1120
1097
1121
auto in_bounds = [&](int gx, int gy) {
@@ -1107,6 +1131,10 @@ Dictionary TerrainGen::generate(
1107
1131
return myGridMap->get_cell_item (Vector3i (gx, h, gy));
1108
1132
};
1109
1133
1134
+ auto isWaterLike = [&](TileType t) {
1135
+ return t == WATER || t == WATER_EDGE || t == WATER_CORNER || t == WATER_CORNER_INNER;
1136
+ };
1137
+
1110
1138
int rotation_val = NORTH; // default face −Z
1111
1139
1112
1140
//
@@ -1151,6 +1179,31 @@ Dictionary TerrainGen::generate(
1151
1179
int nwHeight = safe_height (x - 1 , y + 1 , c_height);
1152
1180
int nwTile = safe_tile_at (x - 1 , y + 1 ); // m1
1153
1181
1182
+ //
1183
+ // Water Tiles
1184
+ //
1185
+
1186
+ bool nWater = isWaterLike (static_cast <TileType>(nTile));
1187
+ bool sWater = isWaterLike (static_cast <TileType>(sTile ));
1188
+ bool eWater = isWaterLike (static_cast <TileType>(eTile));
1189
+ bool wWater = isWaterLike (static_cast <TileType>(wTile));
1190
+ bool neWater = isWaterLike (static_cast <TileType>(neTile));
1191
+ bool nwWater = isWaterLike (static_cast <TileType>(nwTile));
1192
+ bool seWater = isWaterLike (static_cast <TileType>(seTile));
1193
+ bool swWater = isWaterLike (static_cast <TileType>(swTile));
1194
+
1195
+ if (isWaterLike (static_cast <TileType>(tile_id))) {
1196
+ int waterNeighbors =
1197
+ nWater + sWater + eWater + wWater +
1198
+ neWater + nwWater + seWater + swWater;
1199
+
1200
+ // Fully surrounded by water
1201
+ if (waterNeighbors == 8 ) {
1202
+ tile_id = WATER;
1203
+ rotation_val = 0 ;
1204
+ }
1205
+ }
1206
+
1154
1207
if (tile_id == RAMP || tile_id == CLIFF || tile_id == WATER_EDGE) {
1155
1208
// +----+----+----+
1156
1209
// | m1 | m2 | m3 |
0 commit comments