@@ -9,19 +9,20 @@ TerrainGen::TerrainGen() {
99TerrainGen::~TerrainGen () {
1010}
1111
12- void TerrainGen::generate (GridMap *myGridMap, int height, int width, int depth, int seed, bool useFractal , int noiseOctaves, float noiseFreq) {
12+ void TerrainGen::generate (GridMap *myGridMap, int height, int width, int depth, int seed, int noiseType , int noiseOctaves, float jitter , float noiseFreq) {
1313 UtilityFunctions::print (" Begin Terrain Generation!" );
1414
1515 /* ****************************************************
1616
1717 Setup the Noise Function
1818
1919 *****************************************************/
20-
21- noise->set_noise_type (FastNoiseLite::NoiseType::TYPE_SIMPLEX);
22- noise->set_fractal_type (useFractal ? FastNoiseLite::FractalType::FRACTAL_FBM : FastNoiseLite::FractalType::FRACTAL_NONE);
20+ noise->set_noise_type (static_cast <FastNoiseLite::NoiseType>(noiseType));
21+ noise->set_fractal_type (FastNoiseLite::FractalType::FRACTAL_NONE);
2322 noise->set_seed (seed);
2423 noise->set_fractal_octaves (noiseOctaves);
24+ noise->set_cellular_distance_function (FastNoiseLite::CellularDistanceFunction::DISTANCE_MANHATTAN);
25+ noise->set_cellular_jitter (jitter);
2526 noise->set_fractal_lacunarity (2.0 );
2627 noise->set_fractal_gain (0.5 );
2728 noise->set_frequency (noiseFreq);
@@ -33,33 +34,64 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
3334 *****************************************************/
3435
3536 vector<vector<vector<int >>> gridMap (
36- depth, vector<vector<int >>(height, vector<int >(width, 0 )));
37+ depth, vector<vector<int >>(width, vector<int >(height, 0 )));
38+
39+ // Noise Map may be used later, not sure yet
40+ // vector<vector<float>> noiseMap(width, vector<float>(height, 0.0f));
3741
38- vector<vector<float >> heightMap (height, vector<float >(width, 0 .0f ));
42+ vector<vector<int >> elevationMap (width, vector<int >(height, 0 ));
43+ vector<vector<int >> elevationMapSmooth (width, vector<int >(height, 0 ));
3944
4045 /* ****************************************************
4146
42- Height Map Generation
47+ Noise Map Generation & Smoothing
4348
4449 *****************************************************/
4550
46- for (int y = 0 ; y < height; y++) {
47- for (int x = 0 ; x < width; x++) {
48- heightMap[y][x] = noise->get_noise_2d ((float )x, (float )y) / 2 .0f * 0 .5f ;
51+ for (int x = 0 ; x < width; x++) {
52+ for (int y = 0 ; y < height; y++) {
53+ float currentNoise = noise->get_noise_2d ((float )x, (float )y);
54+ // noiseMap[x][y] = currentNoise;
55+ elevationMap[x][y] = round (((currentNoise + 1 .0f ) / 2 .0f ) * depth);
4956 }
5057 }
5158
59+ // Apply a Median Filter
60+ for (int x = 0 ; x < width; x++) {
61+ for (int y = 0 ; y < height; y++) {
62+ vector<int > neighbors;
63+
64+ for (int dx = -1 ; dx <= 1 ; dx++) {
65+ for (int dy = -1 ; dy <= 1 ; dy++) {
66+ int nx = x + dx;
67+ int ny = y + dy;
68+
69+ // Ensure indices are valid before adding to the list
70+ if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
71+ neighbors.push_back (elevationMap[nx][ny]);
72+ }
73+ }
74+ }
75+
76+ if (!neighbors.empty ()) {
77+ sort (neighbors.begin (), neighbors.end ());
78+ elevationMapSmooth[x][y] = max (0 , static_cast <int >(neighbors[neighbors.size () / 2 ]));
79+ }
80+ }
81+ }
82+
83+ // Apply the smoothed elevation map
84+ elevationMap = elevationMapSmooth;
85+
5286 /* ****************************************************
5387
5488 Tile Placement
5589
5690 *****************************************************/
5791
58- for (int y = 0 ; y < height; ++y) {
59- for (int x = 0 ; x < width; ++x) {
60- float noiseValue = heightMap[x][y];
61- int elevation = round (((noiseValue + 1 .0f ) / 2 .0f ) * depth); // Normalize to depth
62-
92+ for (int x = 0 ; x < width; ++x) {
93+ for (int y = 0 ; y < height; ++y) {
94+ int elevation = elevationMap[x][y];
6395 /* ****************************************************
6496
6597 Edge & Water Setter
@@ -73,134 +105,121 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
73105 isEdge = true ;
74106 }
75107 // Water assignment
76- if (elevation == 1 && !isEdge) {
108+ if (elevation == 0 && !isEdge) {
77109 myGridMap->set_cell_item (Vector3i (x, elevation, y), WATER, 0 );
78110 continue ;
79- }
111+ } else {
112+ /* ****************************************************
80113
81- /* ****************************************************
114+ Elevation Change & Rotation Detection
82115
83- Elevation Change & Rotation Detection
116+ **************************************************** */
84117
85- *****************************************************/
118+ int neighborElevations[4 ] = { elevation, elevation, elevation, elevation };
119+ int dx[4 ] = { 1 , -1 , 0 , 0 };
120+ int dy[4 ] = { 0 , 0 , 1 , -1 };
86121
87- int neighborElevations[ 4 ] = { elevation, elevation, elevation, elevation };
88- int dx[ 4 ] = { 1 , - 1 , 0 , 0 } ;
89- int dy[ 4 ] = { 0 , 0 , 1 , - 1 } ;
122+ for ( int d = 0 ; d < 4 ; ++d) {
123+ int nx = x + dx[d] ;
124+ int ny = y + dy[d] ;
90125
91- for (int d = 0 ; d < 4 ; ++d) {
92- int nx = x + dx[d];
93- int ny = y + dy[d];
94-
95- if (nx >= 0 && ny >= 0 && nx < width && ny < height) {
96- neighborElevations[d] = heightMap[ny][nx];
126+ if (nx >= 0 && ny >= 0 && nx < width && ny < height) {
127+ neighborElevations[d] = elevationMap[nx][ny];
128+ }
97129 }
98- }
99130
100- // Elevation analysis
101- TileType tileType = GROUND;
102- int rotationOrientation = 0 ;
103- bool needsRamp = false , needsCliff = false , needsCorner = false ;
104- int numDirectionChanges = 0 ;
105- int dominantDirection = -1 ;
106- int maxElevationChange = 0 ;
107-
108- for (int d = 0 ; d < 4 ; ++d) {
109- int diff = neighborElevations[d] - elevation;
110- if (diff != 0 )
111- numDirectionChanges++;
112- if (diff == 1 || diff == -1 )
113- needsRamp = true ;
114- if (abs (diff) > 1 )
115- needsCliff = true ;
116- if (abs (diff) > maxElevationChange) {
117- maxElevationChange = abs (diff);
118- dominantDirection = d;
131+ // Elevation analysis
132+ TileType tileType = GROUND;
133+ int rotationOrientation = 0 ;
134+ bool needsRamp = false , needsCliff = false , needsCorner = false ;
135+ int numDirectionChanges = 0 ;
136+ int dominantDirection = -1 ;
137+ int maxElevationChange = 0 ;
138+
139+ for (int d = 0 ; d < 4 ; ++d) {
140+ int diff = neighborElevations[d] - elevation;
141+ if (diff != 0 )
142+ numDirectionChanges++;
143+ if (diff == 1 || diff == -1 )
144+ needsRamp = true ;
145+ if (abs (diff) > 1 )
146+ needsCliff = true ;
147+ if (abs (diff) > maxElevationChange) {
148+ maxElevationChange = abs (diff);
149+ dominantDirection = d;
150+ }
119151 }
120- }
121-
122- // Assign terrain type
123- if (numDirectionChanges == 0 ) {
124- tileType = GROUND;
125- } else if (needsCliff) {
126- tileType = CLIFF;
127- } else if (needsRamp) {
128- tileType = RAMP;
129- }
130152
131- // Corner detection: Two direction elevation change
132- if (numDirectionChanges >= 2 ) {
133- needsCorner = true ;
134- if (tileType == RAMP)
135- tileType = RAMP_CORNER ;
136- if (tileType == CLIFF)
137- tileType = CLIFF_CORNER ;
138- }
153+ // Assign terrain type
154+ if (numDirectionChanges == 0 ) {
155+ tileType = GROUND ;
156+ } else if (needsCliff) {
157+ tileType = CLIFF ;
158+ } else if (needsRamp) {
159+ tileType = RAMP ;
160+ }
139161
140- // Water Edge & Corner detection
141- if (tileType == WATER) {
142- if (numDirectionChanges == 1 ) {
143- tileType = WATER_EDGE;
144- } else if (numDirectionChanges >= 2 ) {
145- tileType = WATER_CORNER;
162+ // Corner detection: Two direction elevation change
163+ if (numDirectionChanges >= 2 ) {
164+ needsCorner = true ;
165+ if (tileType == RAMP)
166+ tileType = RAMP_CORNER;
167+ if (tileType == CLIFF)
168+ tileType = CLIFF_CORNER;
146169 }
147- }
148170
149- /*
150- The key rotations (Orientation) in Godot's Grid Map around the Y-axis are:
151- - 0 → No rotation
152- - 1 → 90° clockwise around Y
153- - 2 → 180° around Y
154- - 3 → 90° counterclockwise around Y
155- - 10 → 180° around Y (alternative basis)
156- - 11 → 90° counterclockwise around Y (alternative basis)
157- - 9 → 90° clockwise around Y (alternative basis)
158-
159- Which can be set with : `myGridMap->set_cell_item(Vector3i(x, y, z), meshID, orientation);`
160- */
161-
162- // Assign rotation using **0, 90, 180, 270** only
163- if (tileType == RAMP || tileType == CLIFF || tileType == RAMP_CORNER || tileType == CLIFF_CORNER) {
164- if (!needsCorner) {
165- switch (dominantDirection) {
166- case 0 :
167- rotationOrientation = 0 ; // No Rotation
168- break ; // North
169- case 1 :
170- rotationOrientation = 1 ; // 90 Degrees Clockwise
171- break ; // East
172- case 2 :
173- rotationOrientation = 2 ; // 180 Degrees Clockwise
174- break ; // South
175- case 3 :
176- rotationOrientation = 3 ; // 270 Degrees Clockwise
177- break ; // West
171+ // Water Edge & Corner detection
172+ if (tileType == WATER) {
173+ if (numDirectionChanges == 1 ) {
174+ tileType = WATER_EDGE;
175+ } else if (numDirectionChanges >= 2 ) {
176+ tileType = WATER_CORNER;
178177 }
179- } else {
180- // Corner cases use the same **0, 90, 180, 270** logic.
181- if (neighborElevations[0 ] != elevation && neighborElevations[2 ] != elevation) {
182- rotationOrientation = 1 ; // Vertical corner (North-South elevation change)
183- } else if (neighborElevations[1 ] != elevation && neighborElevations[3 ] != elevation) {
184- rotationOrientation = 2 ; // Horizontal corner (East-West elevation change)
185- } else if (neighborElevations[0 ] != elevation && neighborElevations[1 ] != elevation) {
186- rotationOrientation = 0 ; // Corner facing North-East
187- } else if (neighborElevations[2 ] != elevation && neighborElevations[3 ] != elevation) {
188- rotationOrientation = 3 ; // Corner facing South-West
178+ }
179+
180+ // Assign rotation using **0, 90, 180, 270** only
181+ if (tileType == RAMP || tileType == CLIFF || tileType == RAMP_CORNER || tileType == CLIFF_CORNER) {
182+ if (!needsCorner) {
183+ switch (dominantDirection) {
184+ case 0 :
185+ rotationOrientation = 0 ; // No Rotation
186+ break ; // North
187+ case 1 :
188+ rotationOrientation = 1 ; // 90 Degrees Clockwise
189+ break ; // East
190+ case 2 :
191+ rotationOrientation = 2 ; // 180 Degrees Clockwise
192+ break ; // South
193+ case 3 :
194+ rotationOrientation = 3 ; // 270 Degrees Clockwise
195+ break ; // West
196+ }
197+ } else {
198+ // Corner cases use the same **0, 90, 180, 270** logic.
199+ if (neighborElevations[0 ] != elevation && neighborElevations[2 ] != elevation) {
200+ rotationOrientation = 1 ; // Vertical corner (North-South elevation change)
201+ } else if (neighborElevations[1 ] != elevation && neighborElevations[3 ] != elevation) {
202+ rotationOrientation = 2 ; // Horizontal corner (East-West elevation change)
203+ } else if (neighborElevations[0 ] != elevation && neighborElevations[1 ] != elevation) {
204+ rotationOrientation = 0 ; // Corner facing North-East
205+ } else if (neighborElevations[2 ] != elevation && neighborElevations[3 ] != elevation) {
206+ rotationOrientation = 3 ; // Corner facing South-West
207+ }
189208 }
190209 }
191- }
192210
193- /* ****************************************************
211+ /* ****************************************************
194212
195- Grid Cell Setter
213+ Grid Cell Setter
196214
197- *****************************************************/
215+ *****************************************************/
198216
199- myGridMap->set_cell_item (Vector3i (x, elevation, y), tileType, rotationOrientation);
217+ myGridMap->set_cell_item (Vector3i (x, elevation, y), tileType, rotationOrientation);
218+ }
200219 }
201220 }
202221}
203222
204223void TerrainGen::_bind_methods () {
205- ClassDB::bind_method (D_METHOD (" generate" , " GridMap" , " height" , " width" , " depth" , " seed" , " useFBM " , " noiseOctaves" , " noiseFreq" ), &TerrainGen::generate);
224+ ClassDB::bind_method (D_METHOD (" generate" , " GridMap" , " height" , " width" , " depth" , " seed" , " noiseType " , " noiseOctaves" , " jitter " , " noiseFreq" ), &TerrainGen::generate);
206225}
0 commit comments