Skip to content

Commit b061ae3

Browse files
committed
Produces a 3d gridmap but fails to be correct
1 parent cfca414 commit b061ae3

File tree

7 files changed

+244
-48
lines changed

7 files changed

+244
-48
lines changed

Documentation/README_ARCHITECTURE.md

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,45 @@ Godot Terrain Generator for 3D Tiled Maps
66

77
Requires a C++ compiler such as MSVC or MSY2
88

9-
Building :
9+
### Building :
1010

1111
1. `scons use_mingw=yes` or just `scons`
12+
13+
## Debugging:
14+
15+
1. https://youtu.be/8WSIMTJWCBk?t=3624
16+
1. `scons target=template_debug debug_symbols=yes`
17+
18+
Launch.json
19+
20+
```json
21+
{
22+
"version": "0.2.0",
23+
"configurations": [
24+
{
25+
"type": "lldb",
26+
"request": "launch",
27+
"preLaunchTask": "build",
28+
"name": "Debug",
29+
"program": "<path to godot>/Godot 4.4.1.exe",
30+
"args": ["--path", "<path to demo project>/GaiaGreen/demo"],
31+
"cwd": "${workspaceFolder}"
32+
}
33+
]
34+
}
35+
```
36+
37+
Tasks.json:
38+
39+
```json
40+
{
41+
"version": "2.0.0",
42+
"tasks": [
43+
{
44+
"label": "build",
45+
"type": "shell",
46+
"command": "scons -j12 target=template_debug debug_symbols=yes"
47+
}
48+
]
49+
}
50+
```

demo/Test.tscn

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
1-
[gd_scene load_steps=3 format=3 uid="uid://cs6xj3i70yh0f"]
1+
[gd_scene load_steps=5 format=3 uid="uid://cs6xj3i70yh0f"]
22

33
[ext_resource type="Script" uid="uid://ba0phkf16vg6l" path="res://terrain_gen_script.gd" id="1_myinc"]
4-
[ext_resource type="MeshLibrary" uid="uid://cwusqwtpjkoaa" path="res://TerrainTiles/3D_Terrain_Tiles.tres" id="2_njov2"]
4+
[ext_resource type="MeshLibrary" uid="uid://bubhdqje2s6rn" path="res://TerrainTiles/3D_Terrain_Tiles.tres" id="2_njov2"]
5+
[ext_resource type="Script" uid="uid://txvq7hrqtxyd" path="res://camera_3d.gd" id="3_2au82"]
6+
7+
[sub_resource type="Environment" id="Environment_njov2"]
58

69
[node name="Test" type="Node3D"]
710

11+
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
12+
13+
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
14+
environment = SubResource("Environment_njov2")
15+
816
[node name="TerrainGen" type="TerrainGen" parent="."]
917
script = ExtResource("1_myinc")
1018

1119
[node name="GridMap" type="GridMap" parent="."]
1220
mesh_library = ExtResource("2_njov2")
1321
cell_size = Vector3(1, 0.25, 1)
1422
data = {
15-
"cells": PackedInt32Array(65535, 2, 1, 65535, 3, 0, 0, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, 0, 3, 1048577, 2, 0, 1441796, 3, 1, 1441794, 3, 0, 1441794, 1, 0, 1441794, 3, 2, 655362, 65540, 2, 1, 65540, 3, 1, 65540, 65535, 1, 65541, 65535, 2, 65541, 0, 2, 65541, 1, 2, 65541, 2, 2, 65541, 3, 2, 65540, 1, 5, 65540, 0, 5, 3, 3, 2, 2, 3, 2, 1, 3, 2, 3, 65535, 2, 3, 4, 2, 65540, 4, 0, 65541, 4, 1048577, 65542, 4, 1048577, 65543, 4, 1048577, 65544, 4, 1048577, 2, 4, 1048578, 2, 5, 1048578, 3, 5, 1048578, 4, 5, 1048578, 5, 5, 1048578, 6, 5, 1048578, 7, 5, 1048578, 8, 5, 1048578, 9, 5, 1048578, 65542, 65535, 1048578, 65542, 0, 1048578, 65542, 1, 1048578, 65542, 2, 1048578, 65542, 3, 1048578, 65543, 3, 1048578, 65544, 3, 1048578, 65544, 2, 1048578, 65544, 1, 1048578, 65544, 0, 1048578, 65544, 65535, 1048578, 65543, 65535, 1048578, 65543, 0, 1048578, 65543, 1, 1048578, 65543, 2, 1048578)
23+
"cells": PackedInt32Array(65546, 2, 1048588, 65547, 1, 655372)
1624
}
17-
metadata/_editor_floor_ = Vector3(0, 1, 0)
25+
metadata/_editor_floor_ = Vector3(0, 0, 0)
26+
27+
[node name="Camera3D" type="Camera3D" parent="."]
28+
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 22.3218, 36.7455)
29+
script = ExtResource("3_2au82")

demo/camera_3d.gd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
extends Camera3D
2+
3+
func _ready():
4+
5+
size = 10
6+
position = Vector3(0, 20, 0) # Adjust position to view the GridMap
7+
look_at(Vector3(50, 1, 50))

demo/camera_3d.gd.uid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://txvq7hrqtxyd

demo/terrain_gen_script.gd

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@ extends TerrainGen
22

33

44
func _ready():
5+
var grid_map = $"../GridMap"
56
var seed_value = int(Time.get_unix_time_from_system()) % 1000000;
6-
generate(get_node("GridMap"), 5, 5, 3, seed_value, 2, 0.005);
7+
grid_map.cell_size = Vector3(1, 0.25, 1);
8+
generate(grid_map, 100, 100, 3, seed_value, false, 2, 0.03);

src/TerrainGen/Terrain_Gen.cpp

Lines changed: 165 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,39 @@ TerrainGen::TerrainGen() {
99
TerrainGen::~TerrainGen() {
1010
}
1111

12-
void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth, int seed, int noiseOctaves, float noiseFreq) {
12+
void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth, int seed, bool useFractal, int noiseOctaves, float noiseFreq) {
1313
UtilityFunctions::print("Begin Terrain Generation!");
1414

15-
/*
15+
/*****************************************************
16+
1617
Setup the Noise Function
17-
*/
18+
19+
*****************************************************/
1820

1921
noise->set_noise_type(FastNoiseLite::NoiseType::TYPE_SIMPLEX);
20-
noise->set_fractal_type(FastNoiseLite::FractalType::FRACTAL_FBM);
22+
noise->set_fractal_type(useFractal ? FastNoiseLite::FractalType::FRACTAL_FBM : FastNoiseLite::FractalType::FRACTAL_NONE);
2123
noise->set_seed(seed);
2224
noise->set_fractal_octaves(noiseOctaves);
2325
noise->set_fractal_lacunarity(2.0);
2426
noise->set_fractal_gain(0.5);
2527
noise->set_frequency(noiseFreq);
2628

27-
/*
29+
/*****************************************************
30+
2831
Function dependent Variables
29-
*/
32+
33+
*****************************************************/
3034

3135
vector<vector<vector<int>>> gridMap(
3236
depth, vector<vector<int>>(height, vector<int>(width, 0)));
3337

3438
vector<vector<float>> heightMap(height, vector<float>(width, 0.0f));
3539

36-
/*
40+
/*****************************************************
41+
3742
Height Map Generation
38-
*/
43+
44+
*****************************************************/
3945

4046
for (int y = 0; y < height; y++) {
4147
for (int x = 0; x < width; x++) {
@@ -44,40 +50,158 @@ void TerrainGen::generate(GridMap *myGridMap, int height, int width, int depth,
4450
}
4551
}
4652

47-
/*
48-
The key rotations (Orientation) in Godot's Grid Map around the Y-axis are:
49-
- 0 → No rotation
50-
- 1 → 90° clockwise around Y
51-
- 2 → 180° around Y
52-
- 3 → 90° counterclockwise around Y
53-
- 10 → 180° around Y (alternative basis)
54-
- 11 → 90° counterclockwise around Y (alternative basis)
55-
- 9 → 90° clockwise around Y (alternative basis)
56-
57-
Which can be set with : `myGridMap->set_cell_item(Vector3i(x, y, z), meshID, orientation);`
58-
*/
59-
60-
/*
61-
Return the Grid Map to Godot in a GDScript consumable manner
62-
*/
63-
64-
// Array terrainMap;
65-
// for (size_t z = 0; z < depth; z++) { // Iterate over depth (Z-axis)
66-
// Array grid_layer;
67-
// for (size_t y = 0; y < height; y++) { // Iterate over height (Y-axis)
68-
// TypedArray<int> grid_row;
69-
// for (size_t x = 0; x < width; x++) { // Iterate over width (X-axis)
70-
// grid_row.append(gridMap[z][y][x]); // Append voxel values
71-
// }
72-
// grid_layer.append(grid_row);
73-
// }
74-
// terrainMap.append(grid_layer);
75-
// }
53+
/*****************************************************
54+
55+
Tile Placement
56+
57+
*****************************************************/
58+
59+
for (int y = 0; y < height; ++y) {
60+
for (int x = 0; x < width; ++x) {
61+
float noiseValue = heightMap[x][y];
62+
int elevation = round(((noiseValue + 1.0f) / 2.0f) * depth); // Normalize to depth
63+
64+
/*****************************************************
65+
66+
Edge & Water Setter
67+
Encountering the edge of the Map, set the Tile to ground
68+
69+
*****************************************************/
70+
71+
bool isEdge = false;
72+
73+
if (x == 0 || x == width - 1 || y == 0 || y == height - 1) {
74+
isEdge = true;
75+
}
76+
// Water assignment
77+
if (elevation == 1 && !isEdge) {
78+
myGridMap->set_cell_item(Vector3i(x, y, elevation), WATER, 0);
79+
continue;
80+
}
81+
82+
/*****************************************************
83+
84+
Elevation Change & Rotation Detection
85+
86+
*****************************************************/
87+
88+
int neighborElevations[4] = { elevation, elevation, elevation, elevation };
89+
int dx[4] = { 1, -1, 0, 0 };
90+
int dy[4] = { 0, 0, 1, -1 };
91+
92+
for (int d = 0; d < 4; ++d) {
93+
int nx = x + dx[d];
94+
int ny = y + dy[d];
95+
96+
if (nx >= 0 && ny >= 0 && nx < width && ny < height) {
97+
neighborElevations[d] = heightMap[ny][nx];
98+
}
99+
}
100+
101+
// Elevation analysis
102+
TileType tileType = GROUND;
103+
int rotationOrientation = 0;
104+
bool needsRamp = false, needsCliff = false, needsCorner = false;
105+
int numDirectionChanges = 0;
106+
int dominantDirection = -1;
107+
int maxElevationChange = 0;
108+
109+
for (int d = 0; d < 4; ++d) {
110+
int diff = neighborElevations[d] - elevation;
111+
if (diff != 0)
112+
numDirectionChanges++;
113+
if (diff == 1 || diff == -1)
114+
needsRamp = true;
115+
if (abs(diff) > 1)
116+
needsCliff = true;
117+
if (abs(diff) > maxElevationChange) {
118+
maxElevationChange = abs(diff);
119+
dominantDirection = d;
120+
}
121+
}
122+
123+
// Assign terrain type
124+
if (numDirectionChanges == 0) {
125+
tileType = GROUND;
126+
} else if (needsCliff) {
127+
tileType = CLIFF;
128+
} else if (needsRamp) {
129+
tileType = RAMP;
130+
}
131+
132+
// Corner detection: Two direction elevation change
133+
if (numDirectionChanges >= 2) {
134+
needsCorner = true;
135+
if (tileType == RAMP)
136+
tileType = RAMP_CORNER;
137+
if (tileType == CLIFF)
138+
tileType = CLIFF_CORNER;
139+
}
140+
141+
// Water Edge & Corner detection
142+
if (tileType == WATER) {
143+
if (numDirectionChanges == 1) {
144+
tileType = WATER_EDGE;
145+
} else if (numDirectionChanges >= 2) {
146+
tileType = WATER_CORNER;
147+
}
148+
}
149+
150+
/*
151+
The key rotations (Orientation) in Godot's Grid Map around the Y-axis are:
152+
- 0 → No rotation
153+
- 1 → 90° clockwise around Y
154+
- 2 → 180° around Y
155+
- 3 → 90° counterclockwise around Y
156+
- 10 → 180° around Y (alternative basis)
157+
- 11 → 90° counterclockwise around Y (alternative basis)
158+
- 9 → 90° clockwise around Y (alternative basis)
159+
160+
Which can be set with : `myGridMap->set_cell_item(Vector3i(x, y, z), meshID, orientation);`
161+
*/
162+
163+
// Assign rotation using **0, 90, 180, 270** only
164+
if (tileType == RAMP || tileType == CLIFF || tileType == RAMP_CORNER || tileType == CLIFF_CORNER) {
165+
if (!needsCorner) {
166+
switch (dominantDirection) {
167+
case 0:
168+
rotationOrientation = 0; // No Rotation
169+
break; // North
170+
case 1:
171+
rotationOrientation = 1; // 90 Degrees Clockwise
172+
break; // East
173+
case 2:
174+
rotationOrientation = 2; // 180 Degrees Clockwise
175+
break; // South
176+
case 3:
177+
rotationOrientation = 3; // 270 Degrees Clockwise
178+
break; // West
179+
}
180+
} else {
181+
// Corner cases use the same **0, 90, 180, 270** logic.
182+
if (neighborElevations[0] != elevation && neighborElevations[2] != elevation) {
183+
rotationOrientation = 1; // Vertical corner (North-South elevation change)
184+
} else if (neighborElevations[1] != elevation && neighborElevations[3] != elevation) {
185+
rotationOrientation = 2; // Horizontal corner (East-West elevation change)
186+
} else if (neighborElevations[0] != elevation && neighborElevations[1] != elevation) {
187+
rotationOrientation = 0; // Corner facing North-East
188+
} else if (neighborElevations[2] != elevation && neighborElevations[3] != elevation) {
189+
rotationOrientation = 3; // Corner facing South-West
190+
}
191+
}
192+
}
193+
194+
/*****************************************************
195+
196+
Grid Cell Setter
197+
198+
*****************************************************/
199+
200+
myGridMap->set_cell_item(Vector3i(x, elevation, y), tileType, rotationOrientation);
201+
}
202+
}
76203
}
77204

78205
void TerrainGen::_bind_methods() {
79-
ClassDB::bind_method(D_METHOD("generate", "Grid Map"
80-
"height",
81-
"width", "depth", "seed", "noiseOctaves", "noiseFreq"),
82-
&TerrainGen::generate);
206+
ClassDB::bind_method(D_METHOD("generate", "GridMap", "height", "width", "depth", "seed", "useFBM", "noiseOctaves", "noiseFreq"), &TerrainGen::generate);
83207
}

src/TerrainGen/Terrain_Gen.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ class TerrainGen : public Node {
1515
GDCLASS(TerrainGen, Node);
1616

1717
protected:
18+
enum TileType {
19+
WATER, // Pure water tile, Connects to bottom of Water Edge tiles and other Water tiles
20+
WATER_CORNER, // Water corner with a section of ground at the top height, Connects to corners of water on one side and ground on the other
21+
WATER_EDGE, // Water with a section of ground at the top height, Connects to water and ground on opposite sides
22+
GROUND, // Pure ground tile, Simple tile that connects to ground, top of ramp, and top of cliffs
23+
RAMP, // Ground to Ground tile of 45 degree angle, Connects ground tiles for elevation changes
24+
RAMP_CORNER, // Connector of ramps and cliffs on its corners, Connects to Ground tiles and can be next to cliffs
25+
CLIFF, // Cliffs separate elevation and on its sides can connect to cliffs & ramps, Connects to ground tiles & Water Edge for elevation changes
26+
CLIFF_CORNER // Connector of ramps and cliffs on its corners, Connects to Ground & Water edge tiles, can also be next to Ramps
27+
};
28+
1829
Ref<FastNoiseLite> noise;
1930

2031
static void _bind_methods();
@@ -25,7 +36,7 @@ class TerrainGen : public Node {
2536

2637
//Generate Terrain
2738
//Takes in a height & width for size of map on the X & Z axis
28-
void generate(GridMap *myGridMap, int height, int width, int depth, int seed, int noiseOctaves = 2, float noiseFreq = 0.005);
39+
void generate(GridMap *myGridMap, int height, int width, int depth, int seed, bool useFractal = false, int noiseOctaves = 2, float noiseFreq = 0.005);
2940
};
3041

3142
#endif

0 commit comments

Comments
 (0)