@@ -9,7 +9,7 @@ TerrainGen::TerrainGen() {
99TerrainGen::~TerrainGen () {
1010}
1111
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) {
1313 /* ****************************************************
1414
1515 Setup the Noise Function
@@ -18,11 +18,6 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
1818 noise->set_noise_type (static_cast <FastNoiseLite::NoiseType>(noiseType));
1919 noise->set_fractal_type (FastNoiseLite::FractalType::FRACTAL_NONE);
2020 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 );
2621 noise->set_frequency (noiseFreq);
2722
2823 /* ****************************************************
@@ -46,7 +41,7 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
4641
4742 /* ****************************************************
4843
49- Noise Map Generation & Smoothing
44+ Noise Elevation Generation & Modification
5045
5146 *****************************************************/
5247
@@ -55,181 +50,221 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
5550 for (int y = 0 ; y < height; y++) {
5651 float currentNoise = noise->get_noise_2d ((float )x, (float )y);
5752
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) ;
6156 }
6257 }
6358
64- // Downsample by sampling one pixel per block.
59+ // Reduce Resolution by sampling one pixel per block
6560 for (int x = 0 ; x < reducedX; x++) {
6661 for (int y = 0 ; y < reducedY; y++) {
6762 int sampleX = x * blockSize;
6863 int sampleY = y * blockSize;
6964
70- lowResMap[y][x ] = ( elevationMap[x][y] + 1 . 0f ) / 2 . 0f ;
65+ lowResMap[x][y ] = elevationMap[sampleX][sampleY] ;
7166 }
7267 }
7368
74- // Posterize
69+ // Posterize
7570 for (int x = 0 ; x < reducedX; x++) {
7671 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) );
7974 }
8075 }
8176
77+ // Upscale back to Original Size
8278 for (int x = 0 ; x < width; x++) {
8379 for (int y = 0 ; y < height; y++) {
8480 int srcX = x / blockSize;
8581 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+ }
8791 }
8892 }
93+ /* ****************************************************
94+
95+ Tile Placement
96+
97+ *****************************************************/
98+
99+ bool forceCliff = false ; // Track cliff sections
89100
90101 for (int x = 0 ; x < width; ++x) {
91102 for (int y = 0 ; y < height; ++y) {
92103 int elevation = elevationMap[x][y];
93- /* ****************************************************
94104
95- Edge & Water Setter
96- Encountering the edge of the Map, set the Tile to ground
105+ TileType tileType = GROUND;
97106
98- **************************************************** */
107+ bool needsRamp = false , needsCliff = false , adjacentToWater = false ;
99108
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 };
101115
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 ) {
107117 myGridMap->set_cell_item (Vector3i (x, elevation, y), WATER, 0 );
108118 continue ;
109- } else {
110- /* ****************************************************
111-
112- Elevation Change & Rotation Detection
119+ }
113120
114- **************************************************** */
121+ int neighborElevations[ 4 ] = { elevation, elevation, elevation, elevation };
115122
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];
117126
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+ }
121130
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 ;
124136 }
125137 }
138+ }
126139
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;
133142
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 ;
145158 }
146159 }
160+ }
147161
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
154173 }
174+ }
155175
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+ }
163181
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;
170194 }
195+ }
171196
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;
176202
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) {
179207 secondaryNeighborIndex = highestNeighborIndex;
208+ secondaryNeighborElevation = highestNeighborElevation;
180209 highestNeighborElevation = neighborElevations[d];
181210 highestNeighborIndex = d;
211+ } else if (diff > secondaryNeighborElevation - elevation) {
212+ secondaryNeighborElevation = neighborElevations[d];
213+ secondaryNeighborIndex = d;
182214 }
183215 }
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 );
184220
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 :
206226 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
217252 }
218253 }
219254 }
255+ }
220256
221- /* ****************************************************
257+ /* ****************************************************
222258
223- Grid Map Cell Setter
259+ Grid Map Cell Setter
224260
225- *****************************************************/
261+ *****************************************************/
226262
227- myGridMap->set_cell_item (Vector3i (x, elevation, y), tileType, rotationOrientation);
228- }
263+ myGridMap->set_cell_item (Vector3i (x, elevation, y), tileType, rotationOrientation);
229264 }
230265 }
231266}
232267
233268void 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);
235270}
0 commit comments