@@ -9,7 +9,7 @@ TerrainGen::TerrainGen() {
9
9
TerrainGen::~TerrainGen () {
10
10
}
11
11
12
- void TerrainGen::generate (GridMap *myGridMap, int height, int width, int depth, int seed, int noiseType, int noiseOctaves, float jitter , float noiseFreq) {
12
+ void TerrainGen::generate (GridMap *myGridMap, int height, int width, int depth, int seed, int noiseType, double waterRemoval , float noiseFreq) {
13
13
/* ****************************************************
14
14
15
15
Setup the Noise Function
@@ -18,11 +18,6 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
18
18
noise->set_noise_type (static_cast <FastNoiseLite::NoiseType>(noiseType));
19
19
noise->set_fractal_type (FastNoiseLite::FractalType::FRACTAL_NONE);
20
20
noise->set_seed (seed);
21
- noise->set_fractal_octaves (noiseOctaves);
22
- noise->set_cellular_distance_function (FastNoiseLite::CellularDistanceFunction::DISTANCE_MANHATTAN);
23
- noise->set_cellular_jitter (jitter);
24
- noise->set_fractal_lacunarity (2.0 );
25
- noise->set_fractal_gain (0.5 );
26
21
noise->set_frequency (noiseFreq);
27
22
28
23
/* ****************************************************
@@ -46,7 +41,7 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
46
41
47
42
/* ****************************************************
48
43
49
- Noise Map Generation & Smoothing
44
+ Noise Elevation Generation & Modification
50
45
51
46
*****************************************************/
52
47
@@ -55,181 +50,221 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
55
50
for (int y = 0 ; y < height; y++) {
56
51
float currentNoise = noise->get_noise_2d ((float )x, (float )y);
57
52
58
- float bias = 0.1 , stepSize = 4 ;
59
- int rawNoise = round ( pow ((( currentNoise + 1 .0f ) / 2 .0f ) + bias, 1.5 ) * depth) ;
60
- elevationMap[x][y] = round (rawNoise / stepSize) * stepSize ;
53
+ // Normalize and scale noise to [0, depth]
54
+ float normalizedNoise = ( currentNoise + 1 .0f ) / 2 .0f ;
55
+ elevationMap[x][y] = round (normalizedNoise * depth) ;
61
56
}
62
57
}
63
58
64
- // Downsample by sampling one pixel per block.
59
+ // Reduce Resolution by sampling one pixel per block
65
60
for (int x = 0 ; x < reducedX; x++) {
66
61
for (int y = 0 ; y < reducedY; y++) {
67
62
int sampleX = x * blockSize;
68
63
int sampleY = y * blockSize;
69
64
70
- lowResMap[y][x ] = ( elevationMap[x][y] + 1 . 0f ) / 2 . 0f ;
65
+ lowResMap[x][y ] = elevationMap[sampleX][sampleY] ;
71
66
}
72
67
}
73
68
74
- // Posterize
69
+ // Posterize
75
70
for (int x = 0 ; x < reducedX; x++) {
76
71
for (int y = 0 ; y < reducedY; y++) {
77
- int quantizedLevel = min (depth - 1 , static_cast < int >( lowResMap[x][y] * depth) );
78
- lowResMap[x][x ] = quantizedLevel / static_cast < float > (depth - 1 );
72
+ int quantizedLevel = round ( lowResMap[x][y]);
73
+ lowResMap[x][y ] = max ( 0 , min (depth, quantizedLevel) );
79
74
}
80
75
}
81
76
77
+ // Upscale back to Original Size
82
78
for (int x = 0 ; x < width; x++) {
83
79
for (int y = 0 ; y < height; y++) {
84
80
int srcX = x / blockSize;
85
81
int srcY = y / blockSize;
86
- elevationMap[x][y] = lowResMap[srcX][srcY];
82
+
83
+ int elevationValue = lowResMap[srcX][srcY];
84
+
85
+ float randomFactor = (float )rand () / RAND_MAX;
86
+ if (elevationValue == 0 && randomFactor < waterRemoval) { // Chance to turn Water to Ground
87
+ elevationMap[x][y] = 1 ;
88
+ } else {
89
+ elevationMap[x][y] = elevationValue;
90
+ }
87
91
}
88
92
}
93
+ /* ****************************************************
94
+
95
+ Tile Placement
96
+
97
+ *****************************************************/
98
+
99
+ bool forceCliff = false ; // Track cliff sections
89
100
90
101
for (int x = 0 ; x < width; ++x) {
91
102
for (int y = 0 ; y < height; ++y) {
92
103
int elevation = elevationMap[x][y];
93
- /* ****************************************************
94
104
95
- Edge & Water Setter
96
- Encountering the edge of the Map, set the Tile to ground
105
+ TileType tileType = GROUND;
97
106
98
- **************************************************** */
107
+ bool needsRamp = false , needsCliff = false , adjacentToWater = false ;
99
108
100
- bool isEdge = false ;
109
+ int rotationOrientation = 0 ;
110
+ int numElevationChanges = 0 ;
111
+ int numDirectionChanges = 0 ;
112
+ int maxElevationChange = 0 ;
113
+ int waterEdgeNeighbors = 0 ;
114
+ int waterNeighbors[4 ] = { 0 , 0 , 0 , 0 };
101
115
102
- if (x == 0 || x == width - 1 || y == 0 || y == height - 1 ) {
103
- isEdge = true ;
104
- }
105
- // Water assignment
106
- if (elevation == 0 && !isEdge) {
116
+ if (elevation == 0 ) {
107
117
myGridMap->set_cell_item (Vector3i (x, elevation, y), WATER, 0 );
108
118
continue ;
109
- } else {
110
- /* ****************************************************
111
-
112
- Elevation Change & Rotation Detection
119
+ }
113
120
114
- **************************************************** */
121
+ int neighborElevations[ 4 ] = { elevation, elevation, elevation, elevation };
115
122
116
- int neighborElevations[4 ] = { elevation, elevation, elevation, elevation };
123
+ for (int d = 0 ; d < 4 ; ++d) {
124
+ int nx = x + dx[d];
125
+ int ny = y + dy[d];
117
126
118
- for ( int d = 0 ; d < 4 ; ++d ) {
119
- int nx = x + dx[d ];
120
- int ny = y + dy[d];
127
+ if (nx >= 0 && ny > = 0 && nx < width && ny < height ) {
128
+ neighborElevations[d] = elevationMap[nx][ny ];
129
+ }
121
130
122
- if (nx >= 0 && ny >= 0 && nx < width && ny < height) {
123
- neighborElevations[d] = elevationMap[nx][ny];
131
+ if (nx >= 0 && ny >= 0 && nx < width && ny < height) {
132
+ neighborElevations[d] = elevationMap[nx][ny];
133
+ if (neighborElevations[d] == 0 ) {
134
+ adjacentToWater = true ;
135
+ waterNeighbors[d] = 1 ;
124
136
}
125
137
}
138
+ }
126
139
127
- TileType tileType = GROUND;
128
- int rotationOrientation = 0 ;
129
- bool needsRamp = false , needsCliff = false , needsCorner = false ;
130
- int numDirectionChanges = 0 ;
131
- int dominantDirection = -1 ;
132
- int maxElevationChange = 0 ;
140
+ for (int d = 0 ; d < 4 ; ++d) {
141
+ int diff = neighborElevations[d] - elevation;
133
142
134
- for (int d = 0 ; d < 4 ; ++d) {
135
- int diff = neighborElevations[d] - elevation;
136
- if (diff != 0 )
137
- numDirectionChanges++;
138
- if (diff == 1 || diff == -1 )
139
- needsRamp = true ;
140
- if (abs (diff) > 1 )
141
- needsCliff = true ;
142
- if (abs (diff) > maxElevationChange) {
143
- maxElevationChange = abs (diff);
144
- dominantDirection = d;
143
+ if (diff != 0 )
144
+ numDirectionChanges++;
145
+
146
+ if (diff == 1 || diff == -1 ) {
147
+ numElevationChanges++;
148
+ maxElevationChange = max (maxElevationChange, abs (diff));
149
+
150
+ float randomFactor = (float )rand () / RAND_MAX;
151
+
152
+ if (forceCliff || randomFactor < 0.2 ) {
153
+ tileType = CLIFF;
154
+ forceCliff = true ;
155
+ } else {
156
+ tileType = RAMP;
157
+ forceCliff = false ;
145
158
}
146
159
}
160
+ }
147
161
148
- if (numDirectionChanges == 0 ) {
149
- tileType = GROUND;
150
- } else if (needsCliff) {
151
- tileType = CLIFF;
152
- } else if (needsRamp) {
153
- tileType = RAMP;
162
+ if (adjacentToWater) {
163
+ waterEdgeNeighbors = waterNeighbors[0 ] + waterNeighbors[1 ] + waterNeighbors[2 ] + waterNeighbors[3 ];
164
+
165
+ if (waterEdgeNeighbors == 1 ) {
166
+ tileType = WATER_EDGE;
167
+ } else if (
168
+ (waterNeighbors[0 ] && waterNeighbors[1 ]) ||
169
+ (waterNeighbors[1 ] && waterNeighbors[2 ]) ||
170
+ (waterNeighbors[2 ] && waterNeighbors[3 ]) ||
171
+ (waterNeighbors[3 ] && waterNeighbors[0 ])) {
172
+ tileType = WATER_CORNER; // Two adjacent water edges form a corner
154
173
}
174
+ }
155
175
156
- if (numDirectionChanges >= 2 ) {
157
- needsCorner = true ;
158
- if (tileType == RAMP)
159
- tileType = RAMP_CORNER;
160
- if (tileType == CLIFF)
161
- tileType = CLIFF_CORNER;
162
- }
176
+ if (tileType == CLIFF && forceCliff) {
177
+ forceCliff = true ;
178
+ } else if (tileType == RAMP) {
179
+ forceCliff = false ;
180
+ }
163
181
164
- if (tileType == WATER) {
165
- if (numDirectionChanges == 1 ) {
166
- tileType = WATER_EDGE;
167
- } else if (numDirectionChanges >= 2 ) {
168
- tileType = WATER_CORNER;
169
- }
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;
170
194
}
195
+ }
171
196
172
- if (tileType == RAMP || tileType == CLIFF || tileType == RAMP_CORNER || tileType == CLIFF_CORNER) {
173
- int highestNeighborIndex = -1 ;
174
- int highestNeighborElevation = elevation;
175
- int secondaryNeighborIndex = -1 ;
197
+ if (tileType == RAMP || tileType == CLIFF || tileType == RAMP_CORNER || tileType == CLIFF_CORNER) {
198
+ int highestNeighborIndex = -1 ;
199
+ int secondaryNeighborIndex = -1 ;
200
+ int highestNeighborElevation = elevation;
201
+ int secondaryNeighborElevation = elevation;
176
202
177
- for (int d = 0 ; d < 4 ; ++d) {
178
- if (neighborElevations[d] > highestNeighborElevation) {
203
+ for (int d = 0 ; d < 4 ; ++d) {
204
+ int diff = neighborElevations[d] - elevation;
205
+ if (diff > 0 ) {
206
+ if (diff > highestNeighborElevation - elevation) {
179
207
secondaryNeighborIndex = highestNeighborIndex;
208
+ secondaryNeighborElevation = highestNeighborElevation;
180
209
highestNeighborElevation = neighborElevations[d];
181
210
highestNeighborIndex = d;
211
+ } else if (diff > secondaryNeighborElevation - elevation) {
212
+ secondaryNeighborElevation = neighborElevations[d];
213
+ secondaryNeighborIndex = d;
182
214
}
183
215
}
216
+ }
217
+
218
+ // Determine if we have a corner case (two adjacent neighbors at higher elevation)
219
+ bool isCorner = (secondaryNeighborIndex != -1 && abs (neighborElevations[secondaryNeighborIndex] - elevation) > 0 );
184
220
185
- bool isCorner = (secondaryNeighborIndex != -1 && abs (neighborElevations[secondaryNeighborIndex] - elevation) > 0 );
186
-
187
- if (highestNeighborIndex != -1 ) {
188
- if (!isCorner) {
189
- switch (highestNeighborIndex) {
190
- case 0 :
191
- rotationOrientation = 2 ;
192
- break ; // North
193
- case 1 :
194
- rotationOrientation = 3 ;
195
- break ; // East
196
- case 2 :
197
- rotationOrientation = 0 ;
198
- break ; // South
199
- case 3 :
200
- rotationOrientation = 1 ;
201
- break ; // West
202
- }
203
- } else {
204
- if ((highestNeighborIndex == 0 && secondaryNeighborIndex == 1 ) ||
205
- (highestNeighborIndex == 1 && secondaryNeighborIndex == 0 )) {
221
+ // Apply rotation based on elevation direction
222
+ if (highestNeighborIndex != -1 ) {
223
+ if (!isCorner) {
224
+ switch (highestNeighborIndex) {
225
+ case 0 :
206
226
rotationOrientation = 0 ;
207
- } else if ((highestNeighborIndex == 2 && secondaryNeighborIndex == 3 ) ||
208
- (highestNeighborIndex == 3 && secondaryNeighborIndex == 2 )) {
209
- rotationOrientation = 3 ;
210
- } else if ((highestNeighborIndex == 0 && secondaryNeighborIndex == 3 ) ||
211
- (highestNeighborIndex == 3 && secondaryNeighborIndex == 0 )) {
212
- rotationOrientation = 1 ;
213
- } else if ((highestNeighborIndex == 1 && secondaryNeighborIndex == 2 ) ||
214
- (highestNeighborIndex == 2 && secondaryNeighborIndex == 1 )) {
215
- rotationOrientation = 2 ;
216
- }
227
+ break ; // North
228
+ case 1 :
229
+ rotationOrientation = 10 ;
230
+ break ; // East
231
+ case 2 :
232
+ rotationOrientation = 16 ;
233
+ break ; // South
234
+ case 3 :
235
+ rotationOrientation = 22 ;
236
+ break ; // West
237
+ }
238
+ } else {
239
+ // Handle corner rotation logic
240
+ if ((highestNeighborIndex == 0 && secondaryNeighborIndex == 1 ) ||
241
+ (highestNeighborIndex == 1 && secondaryNeighborIndex == 0 )) {
242
+ rotationOrientation = 0 ; // Top-right corner
243
+ } else if ((highestNeighborIndex == 2 && secondaryNeighborIndex == 3 ) ||
244
+ (highestNeighborIndex == 3 && secondaryNeighborIndex == 2 )) {
245
+ rotationOrientation = 10 ; // Bottom-left corner
246
+ } else if ((highestNeighborIndex == 0 && secondaryNeighborIndex == 3 ) ||
247
+ (highestNeighborIndex == 3 && secondaryNeighborIndex == 0 )) {
248
+ rotationOrientation = 16 ; // Top-left corner
249
+ } else if ((highestNeighborIndex == 1 && secondaryNeighborIndex == 2 ) ||
250
+ (highestNeighborIndex == 2 && secondaryNeighborIndex == 1 )) {
251
+ rotationOrientation = 22 ; // Bottom-right corner
217
252
}
218
253
}
219
254
}
255
+ }
220
256
221
- /* ****************************************************
257
+ /* ****************************************************
222
258
223
- Grid Map Cell Setter
259
+ Grid Map Cell Setter
224
260
225
- *****************************************************/
261
+ *****************************************************/
226
262
227
- myGridMap->set_cell_item (Vector3i (x, elevation, y), tileType, rotationOrientation);
228
- }
263
+ myGridMap->set_cell_item (Vector3i (x, elevation, y), tileType, rotationOrientation);
229
264
}
230
265
}
231
266
}
232
267
233
268
void TerrainGen::_bind_methods () {
234
- ClassDB::bind_method (D_METHOD (" generate" , " GridMap" , " height" , " width" , " depth" , " seed" , " noiseType" , " noiseOctaves " , " jitter " , " noiseFreq" ), &TerrainGen::generate);
269
+ ClassDB::bind_method (D_METHOD (" generate" , " GridMap" , " height" , " width" , " depth" , " seed" , " noiseType" , " waterRemoval " , " noiseFreq" ), &TerrainGen::generate);
235
270
}
0 commit comments