Skip to content

Commit eda28f7

Browse files
committed
Clean up Water, Not perfect but better
The code half works, in that it generates a somewhat desirable terrain but there are inconsistencies in the output. Sometimes random cliff tiles are created in the center of a body of water. The bigger issue is that is only places cliffs or edges due to the raw noise value which is equal in areas. So some form of intervention is needed to have cliffs and ramps mixed for instances of elevation layers. The rotation of the tiles is also incorrect and needs work to rotate correctly, which is assumed to be an easy fix to do later.
1 parent 3644dc1 commit eda28f7

File tree

2 files changed

+88
-39
lines changed

2 files changed

+88
-39
lines changed

src/TerrainGen/Terrain_Gen.cpp

Lines changed: 83 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
2929
vector<vector<vector<int>>> gridMap(
3030
depth, vector<vector<int>>(width, vector<int>(height, 0)));
3131

32+
vector<vector<float>> rawNoise(width, vector<float>(height, 0));
3233
vector<vector<int>> elevationMap(width, vector<int>(height, 0));
34+
vector<vector<TileType>> tileMap(width, vector<TileType>(height, GROUND));
3335

3436
int blockSize = 4;
3537
int reducedX = floor(width / blockSize);
@@ -50,6 +52,7 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
5052
for (int y = 0; y < height; y++) {
5153
float currentNoise = noise->get_noise_2d((float)x, (float)y);
5254

55+
rawNoise[x][y] = currentNoise;
5356
// Normalize and scale noise to [0, depth]
5457
float normalizedNoise = (currentNoise + 1.0f) / 2.0f;
5558
elevationMap[x][y] = round(normalizedNoise * depth);
@@ -90,20 +93,50 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
9093
}
9194
}
9295
}
96+
97+
//Smoothing
98+
// Ensure elevation change's aren't in succession
99+
//TODO...
100+
101+
// Water Clean Up
102+
for (int x = 1; x < width - 1; x++) {
103+
for (int y = 1; y < height - 1; y++) {
104+
if (elevationMap[x][y] > 0) { // Check if it's an elevated tile
105+
int waterCount = 0;
106+
107+
// Check surrounding 3x3 neighbors
108+
for (int dx = -1; dx <= 1; dx++) {
109+
for (int dy = -1; dy <= 1; dy++) {
110+
if (elevationMap[x + dx][y + dy] == 0) {
111+
waterCount++;
112+
}
113+
}
114+
}
115+
116+
// If it's surrounded by water, set elevation to 0
117+
if (waterCount >= 5) {
118+
elevationMap[x][y] = 0;
119+
}
120+
}
121+
}
122+
}
123+
93124
/*****************************************************
94125
95126
Tile Placement
96127
97128
*****************************************************/
98129

99-
bool forceCliff = false; // Track cliff sections
100-
130+
// Loop over all the grid cells
101131
for (int x = 0; x < width; ++x) {
102132
for (int y = 0; y < height; ++y) {
133+
//Get the elevation for the current grid cell
103134
int elevation = elevationMap[x][y];
104135

105-
TileType tileType = GROUND;
136+
//Init the current grid cell to ground
137+
tileMap[x][y] = GROUND;
106138

139+
// Setup booleans & Ints
107140
bool needsRamp = false, needsCliff = false, adjacentToWater = false;
108141

109142
int rotationOrientation = 0;
@@ -113,88 +146,76 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
113146
int waterEdgeNeighbors = 0;
114147
int waterNeighbors[4] = { 0, 0, 0, 0 };
115148

149+
// If Elevation is 0, we get water tiles
116150
if (elevation == 0) {
117151
myGridMap->set_cell_item(Vector3i(x, elevation, y), WATER, 0);
118152
continue;
119153
}
120154

155+
// Get the cardinal neighbors
121156
int neighborElevations[4] = { elevation, elevation, elevation, elevation };
122157

158+
// Loop through and assign value to the cardinal neighbors
123159
for (int d = 0; d < 4; ++d) {
124160
int nx = x + dx[d];
125161
int ny = y + dy[d];
126162

127163
if (nx >= 0 && ny >= 0 && nx < width && ny < height) {
128-
neighborElevations[d] = elevationMap[nx][ny];
129-
}
130-
131-
if (nx >= 0 && ny >= 0 && nx < width && ny < height) {
164+
// Get Neighbors Elevation
132165
neighborElevations[d] = elevationMap[nx][ny];
133166
if (neighborElevations[d] == 0) {
167+
// If neighbor is water, store that info
134168
adjacentToWater = true;
135169
waterNeighbors[d] = 1;
136170
}
137171
}
138172
}
139173

174+
// Loop through the grid cells cardinal neighbors again
140175
for (int d = 0; d < 4; ++d) {
176+
// Find the Elevation diff between neighbors
141177
int diff = neighborElevations[d] - elevation;
142178

179+
// If not 0, then there is a change
143180
if (diff != 0)
144181
numDirectionChanges++;
145182

183+
// If an elevation diff of 1
146184
if (diff == 1 || diff == -1) {
185+
//We have elevation change
186+
147187
numElevationChanges++;
148188
maxElevationChange = max(maxElevationChange, abs(diff));
149189

150190
float randomFactor = (float)rand() / RAND_MAX;
151191

152-
if (forceCliff || randomFactor < 0.2) {
153-
tileType = CLIFF;
154-
forceCliff = true;
192+
// Set Cliffs or Ramps since Elevation has changed
193+
if (rawNoise[x][y] < 0.4) {
194+
tileMap[x][y] = CLIFF;
155195
} else {
156-
tileType = RAMP;
157-
forceCliff = false;
196+
tileMap[x][y] = RAMP;
158197
}
159198
}
160199
}
161200

201+
// If grid cell is adjacent to water
162202
if (adjacentToWater) {
203+
// Get the cardinal neighbors
163204
waterEdgeNeighbors = waterNeighbors[0] + waterNeighbors[1] + waterNeighbors[2] + waterNeighbors[3];
164205

206+
// Decide if it needs to be a water edge or a water corner
165207
if (waterEdgeNeighbors == 1) {
166-
tileType = WATER_EDGE;
208+
tileMap[x][y] = WATER_EDGE;
167209
} else if (
168210
(waterNeighbors[0] && waterNeighbors[1]) ||
169211
(waterNeighbors[1] && waterNeighbors[2]) ||
170212
(waterNeighbors[2] && waterNeighbors[3]) ||
171213
(waterNeighbors[3] && waterNeighbors[0])) {
172-
tileType = WATER_CORNER; // Two adjacent water edges form a corner
214+
tileMap[x][y] = WATER_CORNER; // Two adjacent water edges form a corner
173215
}
174216
}
175217

176-
if (tileType == CLIFF && forceCliff) {
177-
forceCliff = true;
178-
} else if (tileType == RAMP) {
179-
forceCliff = false;
180-
}
181-
182-
if (numElevationChanges >= 2) {
183-
if (tileType == RAMP)
184-
tileType = RAMP_CORNER;
185-
if (tileType == CLIFF)
186-
tileType = CLIFF_CORNER;
187-
}
188-
189-
if (tileType == WATER) {
190-
if (numDirectionChanges == 1) {
191-
tileType = WATER_EDGE;
192-
} else if (numDirectionChanges >= 2) {
193-
tileType = WATER_CORNER;
194-
}
195-
}
196-
197-
if (tileType == RAMP || tileType == CLIFF || tileType == RAMP_CORNER || tileType == CLIFF_CORNER) {
218+
if (tileMap[x][y] == RAMP || tileMap[x][y] == CLIFF || tileMap[x][y] == RAMP_CORNER || tileMap[x][y] == CLIFF_CORNER) {
198219
int highestNeighborIndex = -1;
199220
int secondaryNeighborIndex = -1;
200221
int highestNeighborElevation = elevation;
@@ -260,11 +281,36 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
260281
261282
*****************************************************/
262283

263-
myGridMap->set_cell_item(Vector3i(x, elevation, y), tileType, rotationOrientation);
284+
myGridMap->set_cell_item(Vector3i(x, elevation, y), tileMap[x][y], rotationOrientation);
264285
}
265286
}
266287
}
267288

289+
TerrainGen::TileType TerrainGen::isCornerTile(int x, int y, vector<vector<TileType>> &tileMap) {
290+
if (x < 1 || y < 1 || x >= tileMap.size() - 1 || y >= tileMap[0].size() - 1)
291+
return GROUND; // Bounds check
292+
293+
TileType TL = tileMap[x - 1][y - 1];
294+
TileType TR = tileMap[x + 1][y - 1];
295+
TileType BL = tileMap[x - 1][y + 1];
296+
TileType BR = tileMap[x + 1][y + 1];
297+
298+
// Check diagonal patterns for L-shapes
299+
if ((TL == WATER && BR == WATER) || (TR == WATER && BL == WATER)) {
300+
return WATER_CORNER; // Water Corner
301+
}
302+
303+
if ((TL == CLIFF && BR == CLIFF) || (TR == CLIFF && BL == CLIFF)) {
304+
return CLIFF_CORNER; // Cliff Corner
305+
}
306+
307+
if ((TL == RAMP && BR == RAMP) || (TR == RAMP && BL == RAMP)) {
308+
return RAMP_CORNER; // Ramp Corner
309+
}
310+
311+
return GROUND;
312+
}
313+
268314
void TerrainGen::_bind_methods() {
269315
ClassDB::bind_method(D_METHOD("generate", "GridMap", "height", "width", "depth", "seed", "noiseType", "waterRemoval", "noiseFreq"), &TerrainGen::generate);
270316
}

src/TerrainGen/Terrain_Gen.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#ifndef HELLOWORLD_H
2-
#define HELLOWORLD_H
1+
#ifndef TERRAIN_GEN_H
2+
#define TERRAIN_GEN_H
33

44
#include <godot_cpp/classes/fast_noise_lite.hpp>
55
#include <godot_cpp/classes/grid_map.hpp>
@@ -36,6 +36,9 @@ class TerrainGen : public Node {
3636

3737
static void _bind_methods();
3838

39+
private:
40+
TileType isCornerTile(int x, int y, vector<vector<TileType>> &tileMap);
41+
3942
public:
4043
TerrainGen();
4144
~TerrainGen();

0 commit comments

Comments
 (0)