Skip to content

Commit 050fda3

Browse files
committed
Add a Voxel demo project
1 parent ac5013f commit 050fda3

40 files changed

+1745
-0
lines changed

3d/voxel/README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Voxel Game
2+
3+
This demo is a minimal first-person voxel game,
4+
inspired by others such as Minecraft.
5+
6+
Language: GDScript
7+
8+
Renderer: GLES 2
9+
10+
## How does it work?
11+
12+
Each chunk is a
13+
[`StaticBody`](https://docs.godotengine.org/en/latest/classes/class_staticbody.html)
14+
with each block having its own
15+
[`CollisionShape`](https://docs.godotengine.org/en/latest/classes/class_collisionshape.html)
16+
for collisions. The meshes are created using
17+
[`SurfaceTool`](https://docs.godotengine.org/en/latest/classes/class_surfacetool.html)
18+
which allows specifying vertices, triangles, and UV coordinates
19+
for constructing a mesh.
20+
21+
The chunks and chunk data are stored in
22+
[`Dictionary`](https://docs.godotengine.org/en/latest/classes/class_dictionary.html)
23+
objects. New chunks have their meshes drawn in separate
24+
[`Thread`](https://docs.godotengine.org/en/latest/classes/class_thread.html)s,
25+
but generating the collisions is done in the main thread, since Godot does
26+
not support changing physics objects in a separate thread. There
27+
are two terrain types, random blocks and flat grass. A more
28+
complex terrain generator is out-of-scope for this demo project.
29+
30+
The player can place and break blocks using the
31+
[`RayCast`](https://docs.godotengine.org/en/latest/classes/class_raycast.html)
32+
node attached to the camera. It uses the collision information to
33+
figure out the block position and change the block data. You can
34+
switch the active block using the brackets or with the middle mouse button.
35+
36+
There is a settings menu for render distance and toggling the fog.
37+
Settings are stored inside of an
38+
[AutoLoad singleton](https://docs.godotengine.org/en/latest/getting_started/step_by_step/singletons_autoload.html)
39+
called "Settings". This class will automatically save
40+
settings, and load them when the game opens, by using the
41+
[`File`](https://docs.godotengine.org/en/latest/classes/class_file.html) class.
42+
43+
Sticking to GDScript and the built-in Godot tools, as this demo does, is
44+
quite limiting. If you are making your own voxel game, you should probably
45+
use Zylann's voxel module instead: https://github.com/Zylann/godot_voxel
46+
47+
## Screenshots
48+
49+
![Screenshot](screenshots/blocks.png)
50+
51+
![Screenshot](screenshots/title.png)
52+
53+
## Licenses
54+
55+
Textures are from [Minetest](https://www.minetest.net/). Copyright © 2010-2018 Minetest contributors, CC BY-SA 3.0 Unported (Attribution-ShareAlike)
56+
http://creativecommons.org/licenses/by-sa/3.0/
57+
58+
Font is "TinyUnicode" by DuffsDevice. Copyright © DuffsDevice, CC-BY (Attribution) http://www.pentacom.jp/pentacom/bitfontmaker2/gallery/?id=468

3d/voxel/default_bus_layout.tres

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[gd_resource type="AudioBusLayout" load_steps=2 format=2]
2+
3+
[sub_resource type="AudioEffectPitchShift" id=1]
4+
resource_name = "PitchShift"
5+
6+
[resource]
7+
bus/0/effect/0/effect = SubResource( 1 )
8+
bus/0/effect/0/enabled = true

3d/voxel/default_env.tres

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[gd_resource type="Environment" load_steps=2 format=2]
2+
3+
[sub_resource type="ProceduralSky" id=1]
4+
sun_longitude = 100.0
5+
sun_angle_min = 2.0
6+
sun_angle_max = 20.0
7+
8+
[resource]
9+
background_mode = 2
10+
background_sky = SubResource( 1 )
11+
fog_enabled = true
12+
fog_color = Color( 0.501961, 0.6, 0.701961, 1 )
13+
fog_depth_begin = 32.0
14+
fog_depth_end = 64.0
15+
fog_transmit_enabled = true
16+
dof_blur_far_enabled = true
17+
dof_blur_far_transition = 32.0
18+
dof_blur_far_amount = 0.05

3d/voxel/icon.png

25 KB
Loading

3d/voxel/icon.png.import

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[remap]
2+
3+
importer="texture"
4+
type="StreamTexture"
5+
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
6+
metadata={
7+
"vram_texture": false
8+
}
9+
10+
[deps]
11+
12+
source_file="res://icon.png"
13+
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
14+
15+
[params]
16+
17+
compress/mode=0
18+
compress/lossy_quality=0.7
19+
compress/hdr_mode=0
20+
compress/bptc_ldr=0
21+
compress/normal_map=0
22+
flags/repeat=0
23+
flags/filter=true
24+
flags/mipmaps=false
25+
flags/anisotropic=false
26+
flags/srgb=2
27+
process/fix_alpha_border=true
28+
process/premult_alpha=false
29+
process/HDR_as_SRGB=false
30+
process/invert_color=false
31+
stream=false
32+
size_limit=0
33+
detect_3d=true
34+
svg/scale=1.0

3d/voxel/menu/button.png

840 Bytes
Loading

3d/voxel/menu/button.png.import

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[remap]
2+
3+
importer="texture"
4+
type="StreamTexture"
5+
path="res://.import/button.png-e6ddd405c0968c9fb68dca7b600a69a3.stex"
6+
metadata={
7+
"vram_texture": false
8+
}
9+
10+
[deps]
11+
12+
source_file="res://menu/button.png"
13+
dest_files=[ "res://.import/button.png-e6ddd405c0968c9fb68dca7b600a69a3.stex" ]
14+
15+
[params]
16+
17+
compress/mode=0
18+
compress/lossy_quality=0.7
19+
compress/hdr_mode=0
20+
compress/bptc_ldr=0
21+
compress/normal_map=0
22+
flags/repeat=0
23+
flags/filter=true
24+
flags/mipmaps=false
25+
flags/anisotropic=false
26+
flags/srgb=2
27+
process/fix_alpha_border=true
28+
process/premult_alpha=false
29+
process/HDR_as_SRGB=false
30+
process/invert_color=false
31+
stream=false
32+
size_limit=0
33+
detect_3d=true
34+
svg/scale=1.0

3d/voxel/menu/debug.gd

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
extends Label
2+
# Displays some useful debug information in a Label.
3+
4+
onready var player = $"../Player"
5+
onready var voxel_world = $"../VoxelWorld"
6+
7+
8+
func _process(_delta):
9+
if Input.is_action_just_pressed("debug"):
10+
visible = !visible
11+
12+
text = "Position: " + _vector_to_string_appropriate_digits(player.transform.origin)
13+
text += "\nEffective render distance: " + str(voxel_world.effective_render_distance)
14+
text += "\nLooking: " + _cardinal_string_from_radians(player.transform.basis.get_euler().y)
15+
text += "\nFPS: " + str(Engine.get_frames_per_second())
16+
17+
18+
# Avoids the problem of showing more digits than needed or available.
19+
func _vector_to_string_appropriate_digits(vector):
20+
var factors = [1000, 1000, 1000]
21+
for i in range(3):
22+
if abs(vector[i]) > 4096:
23+
factors[i] = factors[i] / 10
24+
if abs(vector[i]) > 65536:
25+
factors[i] = factors[i] / 10
26+
if abs(vector[i]) > 524288:
27+
factors[i] = factors[i] / 10
28+
29+
return "(" + \
30+
str(round(vector.x * factors[0]) / factors[0]) + ", " + \
31+
str(round(vector.y * factors[1]) / factors[1]) + ", " + \
32+
str(round(vector.z * factors[2]) / factors[2]) + ")"
33+
34+
35+
# Expects a rotation where 0 is North, on the range -PI to PI.
36+
func _cardinal_string_from_radians(angle):
37+
if angle > TAU * 3 / 8:
38+
return "South"
39+
if angle < -TAU * 3 / 8:
40+
return "South"
41+
if angle > TAU * 1 / 8:
42+
return "West"
43+
if angle < -TAU * 1 / 8:
44+
return "East"
45+
return "North"

3d/voxel/menu/ingame/pause_menu.gd

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
extends Control
2+
3+
onready var tree = get_tree()
4+
5+
onready var crosshair = $Crosshair
6+
onready var pause = $Pause
7+
onready var options = $Options
8+
onready var voxel_world = $"../VoxelWorld"
9+
10+
11+
func _process(_delta):
12+
if Input.is_action_just_pressed("pause"):
13+
pause.visible = crosshair.visible
14+
crosshair.visible = !crosshair.visible
15+
options.visible = false
16+
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED if crosshair.visible else Input.MOUSE_MODE_VISIBLE)
17+
18+
19+
func _on_Resume_pressed():
20+
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
21+
crosshair.visible = true
22+
pause.visible = false
23+
24+
25+
func _on_Options_pressed():
26+
options.prev_menu = pause
27+
options.visible = true
28+
pause.visible = false
29+
30+
31+
func _on_MainMenu_pressed():
32+
voxel_world.clean_up()
33+
tree.change_scene("res://menu/main/main_menu.tscn")
34+
35+
36+
func _on_Exit_pressed():
37+
voxel_world.clean_up()
38+
tree.quit()
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
[gd_scene load_steps=6 format=2]
2+
3+
[ext_resource path="res://player/crosshair.svg" type="Texture" id=1]
4+
[ext_resource path="res://menu/theme/theme.tres" type="Theme" id=2]
5+
[ext_resource path="res://menu/options/options.tscn" type="PackedScene" id=3]
6+
[ext_resource path="res://menu/ingame/pause_menu.gd" type="Script" id=4]
7+
[ext_resource path="res://menu/button.png" type="Texture" id=5]
8+
9+
[node name="PauseMenu" type="Control"]
10+
anchor_right = 1.0
11+
anchor_bottom = 1.0
12+
theme = ExtResource( 2 )
13+
script = ExtResource( 4 )
14+
__meta__ = {
15+
"_edit_use_anchors_": false
16+
}
17+
18+
[node name="Crosshair" type="CenterContainer" parent="."]
19+
anchor_right = 1.0
20+
anchor_bottom = 1.0
21+
__meta__ = {
22+
"_edit_use_anchors_": false
23+
}
24+
25+
[node name="TextureRect" type="TextureRect" parent="Crosshair"]
26+
margin_left = 784.0
27+
margin_top = 434.0
28+
margin_right = 816.0
29+
margin_bottom = 466.0
30+
texture = ExtResource( 1 )
31+
32+
[node name="Pause" type="VBoxContainer" parent="."]
33+
visible = false
34+
anchor_right = 1.0
35+
anchor_bottom = 1.0
36+
__meta__ = {
37+
"_edit_use_anchors_": false
38+
}
39+
40+
[node name="ButtonHolder" type="HBoxContainer" parent="Pause"]
41+
margin_right = 1600.0
42+
margin_bottom = 900.0
43+
size_flags_vertical = 3
44+
alignment = 1
45+
46+
[node name="MainButtons" type="VBoxContainer" parent="Pause/ButtonHolder"]
47+
margin_left = 608.0
48+
margin_right = 992.0
49+
margin_bottom = 900.0
50+
custom_constants/separation = 20
51+
alignment = 1
52+
53+
[node name="Resume" type="TextureButton" parent="Pause/ButtonHolder/MainButtons"]
54+
margin_top = 292.0
55+
margin_right = 384.0
56+
margin_bottom = 356.0
57+
rect_min_size = Vector2( 384, 64 )
58+
texture_normal = ExtResource( 5 )
59+
60+
[node name="Label" type="Label" parent="Pause/ButtonHolder/MainButtons/Resume"]
61+
anchor_right = 1.0
62+
anchor_bottom = 1.0
63+
margin_top = -1.0
64+
margin_bottom = -18.0
65+
text = "Resume Game"
66+
align = 1
67+
valign = 1
68+
__meta__ = {
69+
"_edit_use_anchors_": false
70+
}
71+
72+
[node name="Options" type="TextureButton" parent="Pause/ButtonHolder/MainButtons"]
73+
margin_top = 376.0
74+
margin_right = 384.0
75+
margin_bottom = 440.0
76+
rect_min_size = Vector2( 384, 64 )
77+
texture_normal = ExtResource( 5 )
78+
79+
[node name="Label" type="Label" parent="Pause/ButtonHolder/MainButtons/Options"]
80+
anchor_right = 1.0
81+
anchor_bottom = 1.0
82+
margin_top = -1.0
83+
margin_bottom = -18.0
84+
text = "Options"
85+
align = 1
86+
valign = 1
87+
__meta__ = {
88+
"_edit_use_anchors_": false
89+
}
90+
91+
[node name="MainMenu" type="TextureButton" parent="Pause/ButtonHolder/MainButtons"]
92+
margin_top = 460.0
93+
margin_right = 384.0
94+
margin_bottom = 524.0
95+
rect_min_size = Vector2( 384, 64 )
96+
texture_normal = ExtResource( 5 )
97+
98+
[node name="Label" type="Label" parent="Pause/ButtonHolder/MainButtons/MainMenu"]
99+
anchor_right = 1.0
100+
anchor_bottom = 1.0
101+
margin_top = -1.0
102+
margin_bottom = -18.0
103+
text = "Main Menu"
104+
align = 1
105+
valign = 1
106+
__meta__ = {
107+
"_edit_use_anchors_": false
108+
}
109+
110+
[node name="Exit" type="TextureButton" parent="Pause/ButtonHolder/MainButtons"]
111+
margin_top = 544.0
112+
margin_right = 384.0
113+
margin_bottom = 608.0
114+
rect_min_size = Vector2( 384, 64 )
115+
texture_normal = ExtResource( 5 )
116+
117+
[node name="Label" type="Label" parent="Pause/ButtonHolder/MainButtons/Exit"]
118+
anchor_right = 1.0
119+
anchor_bottom = 1.0
120+
margin_top = -1.0
121+
margin_bottom = -18.0
122+
text = "Exit Game"
123+
align = 1
124+
valign = 1
125+
__meta__ = {
126+
"_edit_use_anchors_": false
127+
}
128+
129+
[node name="Options" parent="." instance=ExtResource( 3 )]
130+
[connection signal="pressed" from="Pause/ButtonHolder/MainButtons/Resume" to="." method="_on_Resume_pressed"]
131+
[connection signal="pressed" from="Pause/ButtonHolder/MainButtons/Options" to="." method="_on_Options_pressed"]
132+
[connection signal="pressed" from="Pause/ButtonHolder/MainButtons/MainMenu" to="." method="_on_MainMenu_pressed"]
133+
[connection signal="pressed" from="Pause/ButtonHolder/MainButtons/Exit" to="." method="_on_Exit_pressed"]

0 commit comments

Comments
 (0)