@@ -9,19 +9,20 @@ TerrainGen::TerrainGen() {
9
9
TerrainGen::~TerrainGen () {
10
10
}
11
11
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) {
13
13
UtilityFunctions::print (" Begin Terrain Generation!" );
14
14
15
15
/* ****************************************************
16
16
17
17
Setup the Noise Function
18
18
19
19
*****************************************************/
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);
23
22
noise->set_seed (seed);
24
23
noise->set_fractal_octaves (noiseOctaves);
24
+ noise->set_cellular_distance_function (FastNoiseLite::CellularDistanceFunction::DISTANCE_MANHATTAN);
25
+ noise->set_cellular_jitter (jitter);
25
26
noise->set_fractal_lacunarity (2.0 );
26
27
noise->set_fractal_gain (0.5 );
27
28
noise->set_frequency (noiseFreq);
@@ -33,33 +34,64 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
33
34
*****************************************************/
34
35
35
36
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));
37
41
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 ));
39
44
40
45
/* ****************************************************
41
46
42
- Height Map Generation
47
+ Noise Map Generation & Smoothing
43
48
44
49
*****************************************************/
45
50
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);
49
56
}
50
57
}
51
58
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
+
52
86
/* ****************************************************
53
87
54
88
Tile Placement
55
89
56
90
*****************************************************/
57
91
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];
63
95
/* ****************************************************
64
96
65
97
Edge & Water Setter
@@ -73,134 +105,121 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
73
105
isEdge = true ;
74
106
}
75
107
// Water assignment
76
- if (elevation == 1 && !isEdge) {
108
+ if (elevation == 0 && !isEdge) {
77
109
myGridMap->set_cell_item (Vector3i (x, elevation, y), WATER, 0 );
78
110
continue ;
79
- }
111
+ } else {
112
+ /* ****************************************************
80
113
81
- /* ****************************************************
114
+ Elevation Change & Rotation Detection
82
115
83
- Elevation Change & Rotation Detection
116
+ **************************************************** */
84
117
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 };
86
121
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] ;
90
125
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
+ }
97
129
}
98
- }
99
130
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
+ }
119
151
}
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
- }
130
152
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
+ }
139
161
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;
146
169
}
147
- }
148
170
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;
178
177
}
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
+ }
189
208
}
190
209
}
191
- }
192
210
193
- /* ****************************************************
211
+ /* ****************************************************
194
212
195
- Grid Cell Setter
213
+ Grid Cell Setter
196
214
197
- *****************************************************/
215
+ *****************************************************/
198
216
199
- myGridMap->set_cell_item (Vector3i (x, elevation, y), tileType, rotationOrientation);
217
+ myGridMap->set_cell_item (Vector3i (x, elevation, y), tileType, rotationOrientation);
218
+ }
200
219
}
201
220
}
202
221
}
203
222
204
223
void 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);
206
225
}
0 commit comments