Add building contruction, and various other changes.

This commit is contained in:
Nekojimi 2025-05-01 10:37:11 +01:00
parent db4d405464
commit a176f50a14
49 changed files with 794 additions and 1387 deletions

14
.gitattributes vendored
View File

@ -9,3 +9,17 @@
*.so filter=lfs diff=lfs merge=lfs -text *.so filter=lfs diff=lfs merge=lfs -text
*.dylib filter=lfs diff=lfs merge=lfs -text *.dylib filter=lfs diff=lfs merge=lfs -text
*.wasm filter=lfs diff=lfs merge=lfs -text *.wasm filter=lfs diff=lfs merge=lfs -text
*.dmg filter=lfs diff=lfs merge=lfs -text
*.apk filter=lfs diff=lfs merge=lfs -text
*.ipa filter=lfs diff=lfs merge=lfs -text
*.exe filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
*.dylib filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text
*.sketch filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text
*.xcf filter=lfs diff=lfs merge=lfs -text

View File

@ -10,10 +10,22 @@
"resource_name": { "resource_name": {
"visibility": 0.0 "visibility": 0.0
} }
},
"res://objects/buildings/": {
"metadata/_custom_type_script": {
"visibility": 0.0
},
"resource_local_to_scene": {
"visibility": 0.0
},
"resource_name": {
"visibility": 0.0
}
} }
}, },
"recent_paths": [ "recent_paths": [
"res://items/" "res://items/",
"res://objects/buildings/"
], ],
"table_functions": { "table_functions": {
"filter": [ "filter": [

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/models/Block Nav.obj (Stored with Git LFS)

Binary file not shown.

BIN
assets/models/Block.obj (Stored with Git LFS)

Binary file not shown.

BIN
assets/models/Bullets.obj (Stored with Git LFS)

Binary file not shown.

BIN
assets/models/Conveyor.obj (Stored with Git LFS)

Binary file not shown.

BIN
assets/models/Ingot.obj (Stored with Git LFS)

Binary file not shown.

BIN
assets/models/Miner.obj (Stored with Git LFS)

Binary file not shown.

BIN
assets/models/Ore.obj (Stored with Git LFS)

Binary file not shown.

BIN
assets/models/Ramp Corner Inner Nav.obj (Stored with Git LFS)

Binary file not shown.

BIN
assets/models/Ramp Corner Inner.obj (Stored with Git LFS)

Binary file not shown.

BIN
assets/models/Ramp Corner Outer Nav.obj (Stored with Git LFS)

Binary file not shown.

BIN
assets/models/Ramp Corner Outer.obj (Stored with Git LFS)

Binary file not shown.

BIN
assets/models/Ramp Nav.obj (Stored with Git LFS)

Binary file not shown.

BIN
assets/models/Ramp.obj (Stored with Git LFS)

Binary file not shown.

View File

@ -1,4 +1,5 @@
extends GridMap @tool
extends CustomGridMap
var postprocess_done: bool = false var postprocess_done: bool = false

File diff suppressed because one or more lines are too long

View File

@ -30,11 +30,10 @@ mesh = SubResource("BoxMesh_cee1v")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."] [node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
shape = SubResource("BoxShape3D_k07no") shape = SubResource("BoxShape3D_k07no")
disabled = true
[node name="NavObstacle" type="Node3D" parent="."] [node name="NavObstacle" type="Node3D" parent="."]
script = ExtResource("2_0gk2u") script = ExtResource("2_0gk2u")
make_solid = false enabled = true
[node name="NavigationObstacle3D" type="NavigationObstacle3D" parent="."] [node name="NavigationObstacle3D" type="NavigationObstacle3D" parent="."]
radius = 2.0 radius = 2.0
@ -47,3 +46,9 @@ navigation_mesh = SubResource("NavigationMesh_0gk2u")
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
visible = false visible = false
mesh = SubResource("QuadMesh_oywkk") mesh = SubResource("QuadMesh_oywkk")
[node name="Label3D" type="Label3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3.00872, 0)
billboard = 1
text = "Input: 1
Output: 2"

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=8 format=3 uid="uid://dhfqv26h4i0i3"] [gd_scene load_steps=10 format=3 uid="uid://dhfqv26h4i0i3"]
[ext_resource type="Script" uid="uid://cnoyykkcidp1d" path="res://scripts/buildings/conveyor.gd" id="1_m8ga5"] [ext_resource type="Script" uid="uid://cnoyykkcidp1d" path="res://scripts/buildings/conveyor.gd" id="1_m8ga5"]
[ext_resource type="ArrayMesh" uid="uid://bv225xw8xssl4" path="res://assets/models/Conveyor.obj" id="2_dyib0"] [ext_resource type="ArrayMesh" uid="uid://bv225xw8xssl4" path="res://assets/models/Conveyor.obj" id="2_dyib0"]
@ -6,25 +6,36 @@
[ext_resource type="Script" uid="uid://c4fquatkjmsgu" path="res://scripts/building_components/producer.gd" id="4_d3uke"] [ext_resource type="Script" uid="uid://c4fquatkjmsgu" path="res://scripts/building_components/producer.gd" id="4_d3uke"]
[ext_resource type="ArrayMesh" uid="uid://c6yj8uwsgqxv0" path="res://assets/models/Ingot.obj" id="5_w2262"] [ext_resource type="ArrayMesh" uid="uid://c6yj8uwsgqxv0" path="res://assets/models/Ingot.obj" id="5_w2262"]
[sub_resource type="Curve3D" id="Curve3D_r3fl7"] [sub_resource type="Curve3D" id="Curve3D_m8ga5"]
_data = { _data = {
"points": PackedVector3Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2), "points": PackedVector3Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2),
"tilts": PackedFloat32Array(0, 0) "tilts": PackedFloat32Array(0, 0)
} }
point_count = 2 point_count = 2
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m8ga5"]
albedo_color = Color(0.0703125, 0.0703125, 0.0703125, 1)
[sub_resource type="BoxMesh" id="BoxMesh_dyib0"]
material = SubResource("StandardMaterial3D_m8ga5")
size = Vector3(0.5, 0.3, 1)
[sub_resource type="MultiMesh" id="MultiMesh_6iypd"] [sub_resource type="MultiMesh" id="MultiMesh_6iypd"]
transform_format = 1 transform_format = 1
instance_count = 1 instance_count = 1
mesh = ExtResource("5_w2262") mesh = ExtResource("5_w2262")
buffer = PackedFloat32Array(1, 8.40779e-44, 8.54792e-44, 9.10844e-44, 8.54792e-44, 1, 9.10844e-44, 0.325, 8.82818e-44, 9.10844e-44, 1, 8.96831e-44) buffer = PackedFloat32Array(1, 8.40779e-44, 8.54792e-44, 9.10844e-44, 8.54792e-44, 1, 9.10844e-44, 0.325, 8.82818e-44, 9.10844e-44, 1, 8.96831e-44)
[node name="Conveyor" type="Path3D"] [node name="Conveyor" type="Node3D"]
curve = SubResource("Curve3D_r3fl7")
script = ExtResource("1_m8ga5") script = ExtResource("1_m8ga5")
item_offset = Vector3(0, 0.325, 0) item_offset = Vector3(0, 0.325, 0)
spacing = 0.5
[node name="PathMesh3D" type="PathMesh3D" parent="." node_paths=PackedStringArray("path_3d")] [node name="Path3D" type="Path3D" parent="."]
curve = SubResource("Curve3D_m8ga5")
[node name="PathMesh3D" type="PathMesh3D" parent="Path3D" node_paths=PackedStringArray("path_3d")]
mesh_transform = 1
mesh = ExtResource("2_dyib0") mesh = ExtResource("2_dyib0")
path_3d = NodePath("..") path_3d = NodePath("..")
surface_0/tile_rotation = Vector3(0, 0, 0) surface_0/tile_rotation = Vector3(0, 0, 0)
@ -43,19 +54,37 @@ surface_1/warp_along_curve = true
surface_1/sample_cubic = false surface_1/sample_cubic = false
surface_1/tilt = true surface_1/tilt = true
surface_1/offset = Vector2(0, 0) surface_1/offset = Vector2(0, 0)
visibility_range_end = 100.0
[node name="PathMesh3D2" type="PathMesh3D" parent="Path3D" node_paths=PackedStringArray("path_3d")]
mesh_transform = 1
mesh = SubResource("BoxMesh_dyib0")
path_3d = NodePath("..")
surface_0/tile_rotation = Vector3(0, 0, 0)
surface_0/tile_rotation_order = 2
surface_0/distribution = 0
surface_0/alignment = 0
surface_0/warp_along_curve = true
surface_0/sample_cubic = false
surface_0/tilt = true
surface_0/offset = Vector2(0, 0)
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0)
visibility_range_begin = 100.0
[node name="Consumer" type="Node" parent="."] [node name="Consumer" type="Node" parent="."]
script = ExtResource("3_vjqud") script = ExtResource("3_vjqud")
storage_size = 1 storage_size = 1
metadata/_custom_type_script = "uid://bshiyw2k3op02" metadata/_custom_type_script = "uid://bshiyw2k3op02"
[node name="Producer" type="Node" parent="." node_paths=PackedStringArray("consumers")] [node name="Producer" type="Node" parent="."]
script = ExtResource("4_d3uke") script = ExtResource("4_d3uke")
consumers = [null]
metadata/_custom_type_script = "uid://c4fquatkjmsgu" metadata/_custom_type_script = "uid://c4fquatkjmsgu"
[node name="MultiMeshInstance3D" type="MultiMeshInstance3D" parent="."] [node name="MultiMeshInstance3D" type="MultiMeshInstance3D" parent="."]
physics_interpolation_mode = 2 physics_interpolation_mode = 2
visibility_range_end = 50.0
visibility_range_end_margin = 50.0
visibility_range_fade_mode = 1
multimesh = SubResource("MultiMesh_6iypd") multimesh = SubResource("MultiMesh_6iypd")
[connection signal="item_added" from="Consumer" to="." method="consumer_has_item"] [connection signal="item_added" from="Consumer" to="." method="consumer_has_item"]

View File

@ -2,14 +2,14 @@
[ext_resource type="PackedScene" uid="uid://b1fnsl3k1mo5c" path="res://objects/buildings/building.tscn" id="1_8r86l"] [ext_resource type="PackedScene" uid="uid://b1fnsl3k1mo5c" path="res://objects/buildings/building.tscn" id="1_8r86l"]
[ext_resource type="Script" uid="uid://6dy54s70qf0x" path="res://scripts/buildings/miner.gd" id="2_k13eg"] [ext_resource type="Script" uid="uid://6dy54s70qf0x" path="res://scripts/buildings/miner.gd" id="2_k13eg"]
[ext_resource type="PackedScene" uid="uid://cjg7f5ktk20yq" path="res://assets/blends/Miner.blend" id="2_la0h1"] [ext_resource type="PackedScene" uid="uid://dx13fyjv0d8st" path="res://assets/blends/Miner.blend" id="2_la0h1"]
[ext_resource type="Resource" uid="uid://dbkxys3mr5u80" path="res://items/metal.tres" id="3_8y6s2"] [ext_resource type="Resource" uid="uid://dxlb2ixt3fx7l" path="res://items/ore.tres" id="3_k13eg"]
[ext_resource type="Script" uid="uid://c4fquatkjmsgu" path="res://scripts/building_components/producer.gd" id="5_65oni"] [ext_resource type="Script" uid="uid://c4fquatkjmsgu" path="res://scripts/building_components/producer.gd" id="5_65oni"]
[node name="Miner" instance=ExtResource("1_8r86l")] [node name="Miner" instance=ExtResource("1_8r86l")]
script = ExtResource("2_k13eg") script = ExtResource("2_k13eg")
mined_item = ExtResource("3_8y6s2")
mine_period = 1.0 mine_period = 1.0
can_stack = false
[node name="MeshInstance3D" parent="." index="0"] [node name="MeshInstance3D" parent="." index="0"]
visible = false visible = false
@ -18,4 +18,5 @@ visible = false
[node name="Producer" type="Node" parent="." index="6"] [node name="Producer" type="Node" parent="." index="6"]
script = ExtResource("5_65oni") script = ExtResource("5_65oni")
produced_item = ExtResource("3_k13eg")
metadata/_custom_type_script = "uid://c4fquatkjmsgu" metadata/_custom_type_script = "uid://c4fquatkjmsgu"

View File

@ -5,8 +5,8 @@
[ext_resource type="Script" uid="uid://kcdpck5ufgcc" path="res://scripts/item.gd" id="3_3h7kv"] [ext_resource type="Script" uid="uid://kcdpck5ufgcc" path="res://scripts/item.gd" id="3_3h7kv"]
[ext_resource type="Resource" uid="uid://ed64yksg1y6m" path="res://items/bullets.tres" id="4_3h7kv"] [ext_resource type="Resource" uid="uid://ed64yksg1y6m" path="res://items/bullets.tres" id="4_3h7kv"]
[ext_resource type="Script" uid="uid://bshiyw2k3op02" path="res://scripts/building_components/consumer.gd" id="4_dx8de"] [ext_resource type="Script" uid="uid://bshiyw2k3op02" path="res://scripts/building_components/consumer.gd" id="4_dx8de"]
[ext_resource type="Resource" uid="uid://dbkxys3mr5u80" path="res://items/metal.tres" id="4_miqab"]
[ext_resource type="Script" uid="uid://c4fquatkjmsgu" path="res://scripts/building_components/producer.gd" id="5_p3dou"] [ext_resource type="Script" uid="uid://c4fquatkjmsgu" path="res://scripts/building_components/producer.gd" id="5_p3dou"]
[ext_resource type="Resource" uid="uid://dxlb2ixt3fx7l" path="res://items/ore.tres" id="7_dx8de"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_evfwj"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_evfwj"]
albedo_color = Color(0.023159, 1, 0, 1) albedo_color = Color(0.023159, 1, 0, 1)
@ -18,18 +18,19 @@ size = Vector3(2, 2, 2)
[node name="Processor" instance=ExtResource("1_hxugg")] [node name="Processor" instance=ExtResource("1_hxugg")]
script = ExtResource("2_evfwj") script = ExtResource("2_evfwj")
ingredients = Dictionary[ExtResource("3_3h7kv"), int]({ ingredients = Dictionary[ExtResource("3_3h7kv"), int]({
ExtResource("4_miqab"): 2 ExtResource("7_dx8de"): 2
}) })
process_time = 1.0 process_time = 1.0
created_item = ExtResource("4_3h7kv")
[node name="MeshInstance3D" parent="." index="0"] [node name="MeshInstance3D" parent="." index="0"]
mesh = SubResource("BoxMesh_3h7kv") mesh = SubResource("BoxMesh_3h7kv")
[node name="Consumer" type="Node" parent="." index="2"] [node name="Consumer" type="Node" parent="." index="2"]
script = ExtResource("4_dx8de") script = ExtResource("4_dx8de")
accepted_items = Array[ExtResource("3_3h7kv")]([ExtResource("7_dx8de")])
metadata/_custom_type_script = "uid://bshiyw2k3op02" metadata/_custom_type_script = "uid://bshiyw2k3op02"
[node name="Producer" type="Node" parent="." index="3"] [node name="Producer" type="Node" parent="." index="3"]
script = ExtResource("5_p3dou") script = ExtResource("5_p3dou")
produced_item = ExtResource("4_3h7kv")
metadata/_custom_type_script = "uid://c4fquatkjmsgu" metadata/_custom_type_script = "uid://c4fquatkjmsgu"

View File

@ -1,9 +1,10 @@
[gd_scene load_steps=17 format=3 uid="uid://cav22qho14o47"] [gd_scene load_steps=25 format=3 uid="uid://cav22qho14o47"]
[ext_resource type="Script" uid="uid://ca8i18spgok4i" path="res://scripts/bullet.gd" id="1_rsjgb"] [ext_resource type="Script" uid="uid://ca8i18spgok4i" path="res://scripts/bullet.gd" id="1_rsjgb"]
[ext_resource type="Shader" uid="uid://jtlad4viky6j" path="res://addons/GPUTrail/shaders/trail.gdshader" id="1_ucnj8"] [ext_resource type="Shader" uid="uid://jtlad4viky6j" path="res://addons/GPUTrail/shaders/trail.gdshader" id="1_ucnj8"]
[ext_resource type="Shader" uid="uid://cxd8wfunwre2a" path="res://addons/GPUTrail/shaders/trail_draw_pass.gdshader" id="2_rsjgb"] [ext_resource type="Shader" uid="uid://cxd8wfunwre2a" path="res://addons/GPUTrail/shaders/trail_draw_pass.gdshader" id="2_rsjgb"]
[ext_resource type="Script" uid="uid://cdubip3a6325r" path="res://addons/GPUTrail/GPUTrail3D.gd" id="4_pt3a8"] [ext_resource type="Script" uid="uid://cdubip3a6325r" path="res://addons/GPUTrail/GPUTrail3D.gd" id="4_pt3a8"]
[ext_resource type="Texture2D" uid="uid://ct31fhxvcragr" path="res://addons/GPUTrail/defaults/curve.tres" id="4_rsjgb"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_3ndsa"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_3ndsa"]
radius = 0.1 radius = 0.1
@ -13,21 +14,12 @@ height = 0.3
shader = ExtResource("1_ucnj8") shader = ExtResource("1_ucnj8")
[sub_resource type="Gradient" id="Gradient_6sxjd"] [sub_resource type="Gradient" id="Gradient_6sxjd"]
offsets = PackedFloat32Array(0, 0.150862, 0.642241, 1) offsets = PackedFloat32Array(0, 0.0818966, 0.965517, 1)
colors = PackedColorArray(1, 1, 1, 1, 1, 0.920817, 0, 0.849138, 0.695312, 0.044384, 0, 0.357759, 1, 1, 1, 0) colors = PackedColorArray(0.983734, 1, 0.952478, 0, 0.996515, 0.887301, 0.259986, 1, 1, 0.0352941, 0.0352941, 1, 1, 0, 0.0265193, 0)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_od3fb"] [sub_resource type="GradientTexture1D" id="GradientTexture1D_od3fb"]
gradient = SubResource("Gradient_6sxjd") gradient = SubResource("Gradient_6sxjd")
[sub_resource type="Curve" id="Curve_tmmim"]
_limits = [0.0, 0.1, 0.0, 1.0]
bake_resolution = 16
_data = [Vector2(0, 0.1), 0.0, -0.167493, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
point_count = 2
[sub_resource type="CurveTexture" id="CurveTexture_7thed"]
curve = SubResource("Curve_tmmim")
[sub_resource type="Curve" id="Curve_ucnj8"] [sub_resource type="Curve" id="Curve_ucnj8"]
_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.511628, 1), -1.30273, -1.30273, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] _data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.511628, 1), -1.30273, -1.30273, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
point_count = 3 point_count = 3
@ -41,9 +33,9 @@ shader = ExtResource("2_rsjgb")
shader_parameter/tex = SubResource("CurveTexture_rsjgb") shader_parameter/tex = SubResource("CurveTexture_rsjgb")
shader_parameter/uv_offset = Vector2(0, 0) shader_parameter/uv_offset = Vector2(0, 0)
shader_parameter/color_ramp = SubResource("GradientTexture1D_od3fb") shader_parameter/color_ramp = SubResource("GradientTexture1D_od3fb")
shader_parameter/curve = SubResource("CurveTexture_7thed") shader_parameter/curve = ExtResource("4_rsjgb")
shader_parameter/emmission_transform = Projection(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) shader_parameter/emmission_transform = Projection(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
shader_parameter/flags = 45 shader_parameter/flags = 47
[sub_resource type="QuadMesh" id="QuadMesh_ucnj8"] [sub_resource type="QuadMesh" id="QuadMesh_ucnj8"]
material = SubResource("ShaderMaterial_xbcx7") material = SubResource("ShaderMaterial_xbcx7")
@ -63,6 +55,54 @@ height = 0.3
radial_segments = 6 radial_segments = 6
rings = 0 rings = 0
[sub_resource type="Curve" id="Curve_rsjgb"]
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), -2.95938, 0.0, 0, 0]
point_count = 2
[sub_resource type="CurveTexture" id="CurveTexture_4agyf"]
curve = SubResource("Curve_rsjgb")
[sub_resource type="Gradient" id="Gradient_pt3a8"]
colors = PackedColorArray(1, 0.952478, 0.959973, 1, 1, 0, 0.00575256, 1)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_fsn5s"]
gradient = SubResource("Gradient_pt3a8")
[sub_resource type="Gradient" id="Gradient_od3fb"]
colors = PackedColorArray(1, 1, 1, 1, 0.995088, 1, 0, 1)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_tmmim"]
gradient = SubResource("Gradient_od3fb")
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_7thed"]
particle_flag_align_y = true
direction = Vector3(1, 0.2, 0)
spread = 5.164
initial_velocity_max = 67.46
scale_max = 3.0
color = Color(0.946782, 1, 0.245254, 1)
color_ramp = SubResource("GradientTexture1D_tmmim")
color_initial_ramp = SubResource("GradientTexture1D_fsn5s")
alpha_curve = SubResource("CurveTexture_4agyf")
turbulence_enabled = true
turbulence_influence_min = 0.0
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1r0jv"]
transparency = 1
vertex_color_use_as_albedo = true
albedo_color = Color(0.978998, 1, 0.633145, 1)
emission_enabled = true
emission = Color(1, 1, 1, 1)
emission_energy_multiplier = 4.1
billboard_mode = 3
particles_anim_h_frames = 1
particles_anim_v_frames = 1
particles_anim_loop = false
[sub_resource type="QuadMesh" id="QuadMesh_oabvv"]
material = SubResource("StandardMaterial3D_1r0jv")
size = Vector2(0.1, 0.1)
[node name="Bullet" type="RigidBody3D"] [node name="Bullet" type="RigidBody3D"]
collision_layer = 16 collision_layer = 16
collision_mask = 5 collision_mask = 5
@ -79,7 +119,7 @@ shape = SubResource("CapsuleShape3D_3ndsa")
[node name="GPUTrail3D" type="GPUParticles3D" parent="."] [node name="GPUTrail3D" type="GPUParticles3D" parent="."]
physics_interpolation_mode = 2 physics_interpolation_mode = 2
transform = Transform3D(0.233971, -0.972243, 0, 0.972243, 0.233971, 0, 0, 0, 1, 0, 0, 0) transform = Transform3D(0.0233971, -0.0972244, 0, 0.0972244, 0.0233971, 0, 0, 0, 0.1, 0, 0, 0)
amount = 19 amount = 19
lifetime = 19.0 lifetime = 19.0
explosiveness = 1.0 explosiveness = 1.0
@ -91,8 +131,8 @@ length = 19
length_seconds = 0.322034 length_seconds = 0.322034
texture = SubResource("CurveTexture_rsjgb") texture = SubResource("CurveTexture_rsjgb")
color_ramp = SubResource("GradientTexture1D_od3fb") color_ramp = SubResource("GradientTexture1D_od3fb")
curve = SubResource("CurveTexture_7thed")
vertical_texture = true vertical_texture = true
use_red_as_alpha = true
billboard = true billboard = true
_defaults_have_been_set = true _defaults_have_been_set = true
metadata/_custom_type_script = "uid://cdubip3a6325r" metadata/_custom_type_script = "uid://cdubip3a6325r"
@ -105,4 +145,12 @@ mesh = SubResource("CylinderMesh_xbcx7")
[node name="AudioStreamPlayer3D" type="AudioStreamPlayer3D" parent="."] [node name="AudioStreamPlayer3D" type="AudioStreamPlayer3D" parent="."]
max_polyphony = 2 max_polyphony = 2
[node name="GPUParticles3D" type="GPUParticles3D" parent="."]
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0, 0, 0)
visible = false
emitting = false
amount = 40
process_material = SubResource("ParticleProcessMaterial_7thed")
draw_pass_1 = SubResource("QuadMesh_oabvv")
[connection signal="body_entered" from="." to="." method="_on_body_entered"] [connection signal="body_entered" from="." to="." method="_on_body_entered"]

View File

@ -27,7 +27,7 @@ config/name="TowerGame3D"
run/main_scene="uid://bwftban1ppo17" run/main_scene="uid://bwftban1ppo17"
config/features=PackedStringArray("4.4") config/features=PackedStringArray("4.4")
config/icon="uid://u1hpdb62rxlc" config/icon="uid://u1hpdb62rxlc"
addons/icon_finder/preview_size=24 addons/icon_finder/preview_size=25
[autoload] [autoload]
@ -36,6 +36,20 @@ IconsFonts="*res://addons/icons-fonts/icons_fonts/IconsFonts.gd"
[debug] [debug]
settings/stdout/print_fps=true settings/stdout/print_fps=true
gdscript/warnings/unassigned_variable=2
gdscript/warnings/unassigned_variable_op_assign=2
gdscript/warnings/shadowed_variable=2
gdscript/warnings/shadowed_variable_base_class=2
gdscript/warnings/shadowed_global_identifier=2
gdscript/warnings/incompatible_ternary=2
gdscript/warnings/untyped_declaration=1
gdscript/warnings/unsafe_property_access=1
gdscript/warnings/unsafe_method_access=1
gdscript/warnings/unsafe_cast=1
gdscript/warnings/unsafe_call_argument=2
gdscript/warnings/static_called_on_instance=2
gdscript/warnings/missing_tool=2
gdscript/warnings/assert_always_false=2
shapes/navigation/enable_edge_connections=false shapes/navigation/enable_edge_connections=false
shapes/navigation/enable_edge_connections_xray=false shapes/navigation/enable_edge_connections_xray=false
shapes/navigation/enable_edge_lines_xray=false shapes/navigation/enable_edge_lines_xray=false
@ -90,6 +104,23 @@ camera_set_target={
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":3,"canceled":false,"pressed":false,"double_click":false,"script":null) "events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":3,"canceled":false,"pressed":false,"double_click":false,"script":null)
] ]
} }
camera_zoom_in={
"deadzone": 0.2,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":4,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
camera_zoom_out={
"deadzone": 0.2,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
building_place={
"deadzone": 0.2,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194309,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
]
}
[layer_names] [layer_names]
@ -109,6 +140,7 @@ camera_set_target={
3d/default_edge_connection_margin=0.6 3d/default_edge_connection_margin=0.6
3d/default_link_connection_radius=0.5 3d/default_link_connection_radius=0.5
pathfinding/max_threads=-1
[physics] [physics]
@ -118,6 +150,3 @@ common/physics_interpolation=true
lights_and_shadows/directional_shadow/soft_shadow_filter_quality=0 lights_and_shadows/directional_shadow/soft_shadow_filter_quality=0
lights_and_shadows/positional_shadow/soft_shadow_filter_quality=0 lights_and_shadows/positional_shadow/soft_shadow_filter_quality=0
anti_aliasing/quality/msaa_2d=1
anti_aliasing/quality/msaa_3d=1
anti_aliasing/quality/screen_space_aa=1

View File

@ -1,8 +1,23 @@
extends Node3D extends Node3D
class_name Building class_name Building
@export_category("Defence")
@export var max_hp: int = 100 @export var max_hp: int = 100
@export_category("Stacking")
@export var can_stack: bool = true
@export var can_be_stacked_on: bool = true
@export var stack_position: Vector3 = Vector3(0,2,0)
@onready var build_position: Vector3 = global_position
@onready var nav_obstacle: NavObstable = $NavObstacle
@onready var consumer: Consumer = $Consumer
@onready var producer: Producer = $Producer
@onready var collision_shape: CollisionShape3D = $CollisionShape3D
signal functional_changed(functional: bool)
enum BuildState { enum BuildState {
UNPLACED, UNPLACED,
BUILDING, BUILDING,
@ -10,11 +25,88 @@ enum BuildState {
DESTROYED DESTROYED
} }
const PLACEMENT_POSITION_OK: int = 0b0001
const PLACEMENT_FOUNDATION_REQUIRED: int = 0b0010
const PLACEMENT_PART_ADDED: int = 0b0100
const PLACEMENT_COMPLETED: int = 0b1000
var hp: int = max_hp var hp: int = max_hp
var stacked_buildings: Array[Building] = []
var build_state: BuildState = BuildState.READY: var build_state: BuildState = BuildState.READY:
set(state): set(state):
build_state = state build_state = state
functional_changed.emit(is_functional())
func _ready() -> void:
if nav_obstacle != null:
functional_changed.connect(func(enable:bool): nav_obstacle.enabled = enable)
if consumer != null:
functional_changed.connect(func(enable:bool): consumer.enabled = enable)
if producer != null:
functional_changed.connect(func(enable:bool): producer.enabled = enable)
if collision_shape != null:
functional_changed.connect(func(enable:bool): collision_shape.disabled = !enable)
func _process(delta: float) -> void:
if build_state == BuildState.UNPLACED:
global_position = global_position.lerp(build_position, 0.4)
var debug_text: String = ""
debug_text += "State: %s\n" % build_state
if consumer != null:
var consumer_state: String
if consumer.enabled:
consumer_state = "OK"
else:
consumer_state = "Off"
debug_text += "Input: %s \nStorage: %d\n" % [consumer_state, consumer.storage_total]
if producer != null:
var producer_state = "OK"
if !producer.enabled:
producer_state = "Off"
elif !producer.can_produce():
producer_state = "Blocked"
debug_text += "Output: %s\n" % producer_state
$Label3D.text = debug_text
func is_functional() -> bool: func is_functional() -> bool:
return build_state == BuildState.READY return build_state == BuildState.READY
func _start_placement() -> void:
build_state = BuildState.UNPLACED
func _end_placement() -> void:
build_state = BuildState.READY
func _placement_select_building(building: Building, confirmed: bool) -> int:
while !building.stacked_buildings.is_empty():
building = building.stacked_buildings[0]
var stack_ok: bool = can_stack and building.can_be_stacked_on
var ret: int = 0
if stack_ok:
build_position = building.global_position + building.stack_position
ret |= PLACEMENT_POSITION_OK
if confirmed and stack_ok:
global_position = build_position
building.stacked_buildings.append(self)
ret |= PLACEMENT_COMPLETED
return ret
func _placement_select_position(pos: Vector3, confirmed: bool) -> int:
var ret: int = 0
ret |= PLACEMENT_POSITION_OK
build_position = Vector3(roundf(pos.x), ceilf(pos.y-0.01), roundf(pos.z))
if confirmed:
build_state = BuildState.BUILDING
ret |= PLACEMENT_COMPLETED
return ret

View File

@ -0,0 +1,4 @@
extends Node
class_name BuildingPart
@export var enabled: bool = true

View File

@ -0,0 +1 @@
uid://cfx1esms1e7py

View File

@ -1,4 +1,4 @@
extends Node extends BuildingPart
class_name Consumer class_name Consumer
signal item_added(item: Item) signal item_added(item: Item)
@ -12,7 +12,8 @@ var storage: Dictionary[Item, int] = {}
func can_accept_item(item: Item) -> bool: func can_accept_item(item: Item) -> bool:
return ((storage_total < storage_size) or void_excess_items) \ return ((storage_total < storage_size) or void_excess_items) \
and (accepted_items.has(item) or accepted_items.is_empty()) and (accepted_items.has(item) or accepted_items.is_empty()) \
and enabled
func offer_item(item: Item) -> bool: func offer_item(item: Item) -> bool:
if !can_accept_item(item): if !can_accept_item(item):
@ -30,13 +31,13 @@ func check_storage_for_item(item: Item) -> bool:
return check_storage_for_items({item:1}) return check_storage_for_items({item:1})
func check_storage_for_items(items: Dictionary[Item, int]) -> bool: func check_storage_for_items(items: Dictionary[Item, int]) -> bool:
for item in items.keys(): for item: Item in items.keys():
if storage.get(item, 0) < items[item]: if storage.get(item, 0) < items[item]:
return false return false
return true return true
func take_any_item_from_storage() -> Item: func take_any_item_from_storage() -> Item:
for item in storage.keys(): for item: Item in storage.keys():
if storage[item] >= 1: if storage[item] >= 1:
storage[item] -= 1 storage[item] -= 1
storage_total -= 1 storage_total -= 1
@ -49,7 +50,7 @@ func take_item_from_storage(item: Item) -> bool:
func take_items_from_storage(items: Dictionary[Item, int]) -> bool: func take_items_from_storage(items: Dictionary[Item, int]) -> bool:
if !check_storage_for_items(items): if !check_storage_for_items(items):
return false return false
for item in items.keys(): for item: Item in items.keys():
var old_count: int = storage.get(item, 0) var old_count: int = storage.get(item, 0)
storage.set(item, old_count - items[item]) storage.set(item, old_count - items[item])
storage_total -= items[item] storage_total -= items[item]

View File

@ -1,11 +1,12 @@
extends Node extends BuildingPart
class_name Producer class_name Producer
@export var produced_item: Item
@export var output_period: float = 0.1 @export var output_period: float = 0.1
@export var max_outputs: int = 1 @export var max_outputs: int = 1
@export var consumers: Array[Consumer] @export var consumers: Array[Consumer]
var next_consumer_idx: int = 0 var last_consumer_idx: int = 0
#var output_timer: float = 0.0 #var output_timer: float = 0.0
#var output_item: Item #var output_item: Item
@ -14,16 +15,39 @@ var next_consumer_idx: int = 0
#if output_timer >= output_period: #if output_timer >= output_period:
#output_timer -= output_period #output_timer -= output_period
#output() #output()
func can_produce() -> bool:
return can_send_item(produced_item)
func produce() -> bool:
return send_item(produced_item)
func can_send_item(item: Item) -> bool:
if !enabled:
return false
for consumer in consumers:
if consumer.can_accept_item(item):
return true
return false
func send_item(item: Item) -> bool: func send_item(item: Item) -> bool:
if !enabled:
return false
if consumers.is_empty(): if consumers.is_empty():
return false return false
next_consumer_idx += 1 var start_idx: int = last_consumer_idx
if next_consumer_idx >= consumers.size(): var first_try: bool = true
next_consumer_idx = 0 var idx: int = start_idx
while idx != start_idx or first_try:
idx += 1
if idx >= consumers.size():
idx = 0
first_try = false
var consumer: Consumer = consumers[next_consumer_idx] var consumer: Consumer = consumers[idx]
var accepted: bool = consumer.offer_item(item) var accepted: bool = consumer.offer_item(item)
return accepted if accepted:
last_consumer_idx = idx
return true
return false

View File

@ -0,0 +1,43 @@
extends Node3D
class_name BuildingManager
@export_flags_3d_physics var buildings_layer_mask: int = 0b10
var placing_building: Building = null
func start_placement(scene: PackedScene) -> void:
var object: Node = scene.instantiate()
add_child(object)
if object is Building:
placing_building = object
placing_building._start_placement()
func _input(event: InputEvent) -> void:
if placing_building == null:
return
if event is InputEventMouseButton and event.is_action("building_place"):
placement_mouse_input((event as InputEventMouseButton).global_position, true)
get_viewport().set_input_as_handled()
elif event is InputEventMouseMotion:
placement_mouse_input((event as InputEventMouseMotion).global_position, false)
get_viewport().set_input_as_handled()
func placement_mouse_input(screen_position: Vector2, confirmed: bool) -> void:
# try to raycast to see what we clicked on/are hovering
var camera: Camera3D = get_viewport().get_camera_3d()
var ray_origin: Vector3 = camera.project_ray_origin(screen_position)
var ray_normal: Vector3 = ray_origin + camera.project_ray_normal(screen_position) * 200
var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(ray_origin, ray_normal)
if placing_building.collision_shape != null:
params.exclude = [placing_building.get_rid()]
var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params)
var placment_feedback: int = 0
if result.has("collider") and result["collider"] is Building:
placment_feedback = placing_building._placement_select_building(result["collider"] as Building, confirmed)
elif result.has("position"):
DebugDraw3D.draw_sphere(result["position"] as Vector3)
placment_feedback = placing_building._placement_select_position(result["position"] as Vector3, confirmed)
if placment_feedback & Building.PLACEMENT_COMPLETED:
placing_building._end_placement()
placing_building = null

View File

@ -0,0 +1 @@
uid://bxd8ftp1hcf7e

View File

@ -0,0 +1,11 @@
@tool
extends Button
signal place_requested(scene: PackedScene)
@export var place_scene: PackedScene:
set(value):
place_scene = value
text = place_scene.get_state().get_node_name(0)
func _pressed() -> void:
place_requested.emit(place_scene)

View File

@ -0,0 +1 @@
uid://tmyvv1p7co51

View File

@ -1,35 +1,111 @@
extends Path3D extends Building
@export var speed: float = 1.0 @export var speed: float = 1.0
@export var item_offset: Vector3 = Vector3(0,2.0,0) @export var item_offset: Vector3 = Vector3(0,2.0,0)
@export var extra_distance_start: float = 1.0 @export var extra_distance_start: float = 1.0
@export var extra_distance_end: float = 1.0 @export var extra_distance_end: float = 1.0
@export var spacing: float = 1.0
var transported_items: Dictionary[Item, PackedFloat64Array] = {} var transported_items: Dictionary[Item, PackedFloat64Array] = {}
var belt_moving: bool = true
var closest_item: float = 0.0
@onready var consumer: Consumer = $Consumer @onready var path: Path3D = $Path3D
@onready var producer: Producer = $Producer
@onready var multimesh: MultiMeshInstance3D = $MultiMeshInstance3D @onready var multimesh: MultiMeshInstance3D = $MultiMeshInstance3D
var test_timer: float = 0 var test_timer: float = 0
@onready var test_item: Item = load("res://items/metal.tres") @onready var test_item: Item = load("res://items/metal.tres")
var input_building: Building = null:
set(value):
if value.producer != null:
input_building = value
input_building.producer.consumers.append(consumer)
var output_building: Building = null:
set(value):
if value.consumer != null:
output_building = value
producer.consumers.append(output_building.consumer)
var waypoints: Array[Vector3] = []
var editing_waypoint: int = 0
func _placement_select_building(building: Building, confirmed: bool) -> int:
var ret: int = 0
if input_building == null:
if building.producer != null:
ret |= PLACEMENT_POSITION_OK
if confirmed:
input_building = building
ret |= PLACEMENT_PART_ADDED
set_path_waypoint(building.global_position + Vector3(0,1,0), confirmed)
elif output_building == null and building != input_building:
if building.consumer != null:
ret |= PLACEMENT_POSITION_OK
if confirmed:
output_building = building
ret |= PLACEMENT_COMPLETED
set_path_waypoint(building.global_position + Vector3(0,1,0), confirmed)
return ret
#return super(building, confirmed)
func _placement_select_position(pos: Vector3, confirmed: bool) -> int:
var ret: int = PLACEMENT_POSITION_OK
set_path_waypoint(pos.round() + Vector3(0,1,0), confirmed)
if confirmed:
ret |= PLACEMENT_PART_ADDED
return confirmed
func set_path_waypoint(global_pos: Vector3, add: bool) -> void:
var local_pos: Vector3
if editing_waypoint == 0:
global_position = global_pos
local_pos = Vector3()
else:
local_pos = to_local(global_pos)
while waypoints.size() <= editing_waypoint:
waypoints.append(Vector3())
waypoints[editing_waypoint] = local_pos
if add:
editing_waypoint += 1
update_path_from_waypoints()
func update_path_from_waypoints() -> void:
path.curve.clear_points()
for waypoint in waypoints:
path.curve.add_point(waypoint)
# find paths between the defined points
#for i in range(1, waypoints.size()):
#var a: Vector3 = to_global(waypoints[i-1])
#var b: Vector3 = to_global(waypoints[i])
#var route: PackedVector3Array = NavigationServer3D.map_get_path(NavigationServer3D.get_maps()[0], a, b, false, 1)
#
#for point in route:
#path.curve.add_point(to_local(point + Vector3(0,1,0)))
# set the path3d's points to the path points
# adjust the control points to some uniform amount
pass
func _ready() -> void: func _ready() -> void:
multimesh.multimesh = multimesh.multimesh.duplicate() multimesh.multimesh = multimesh.multimesh.duplicate()
path.curve = path.curve.duplicate()
func _process(delta: float) -> void: func _process(delta: float) -> void:
#test_timer += delta belt_moving = check_items_at_end()
#if test_timer >= 2.0: consumer.enabled = belt_moving and (closest_item >= spacing)
#test_timer -= 2.0
#add_item(test_item)
var belt_moving: bool = check_items_at_end() var movement: float = (delta * speed)
closest_item += movement
if belt_moving: if belt_moving:
for transported_item_type in transported_items.keys(): for transported_item_type: Item in transported_items.keys():
var offsets: PackedFloat64Array = transported_items[transported_item_type] var offsets: PackedFloat64Array = transported_items[transported_item_type]
multimesh.multimesh.instance_count = offsets.size() multimesh.multimesh.instance_count = offsets.size()
for i in range(offsets.size()): for i in range(offsets.size()):
offsets[i] += (delta * speed) offsets[i] += movement
position_item(i, transported_item_type, offsets[i]) position_item(i, transported_item_type, offsets[i])
func consumer_has_item(item: Item) -> void: func consumer_has_item(item: Item) -> void:
@ -47,45 +123,47 @@ func add_item(item: Item) -> void:
offsets = [] offsets = []
offsets.append(get_start_offset()) offsets.append(get_start_offset())
transported_items[item] = offsets transported_items[item] = offsets
closest_item = 0.0
func check_items_at_end() -> bool: func check_items_at_end() -> bool:
var length: float = get_end_offset() var length: float = get_end_offset()
var belt_moving: bool = true var ret: bool = true
for transported_item_type in transported_items.keys(): for transported_item_type: Item in transported_items.keys():
var offsets: PackedFloat64Array = transported_items[transported_item_type] var offsets: PackedFloat64Array = transported_items[transported_item_type]
var to_delete: Array[int] = [] var to_delete: Array[int] = []
for i in range(offsets.size()): for i in range(offsets.size()):
if offsets[i] >= length: if offsets[i] >= length:
var sent: bool = producer.send_item(transported_item_type) var sent: bool = producer.send_item(transported_item_type)
if !sent: if !sent:
belt_moving = false ret = false
else: else:
to_delete.append(i) to_delete.append(i)
for d in to_delete: for d in to_delete:
offsets.remove_at(d) offsets.remove_at(d)
return belt_moving return ret
func get_start_offset() -> float: func get_start_offset() -> float:
return -extra_distance_start return -extra_distance_start
func get_end_offset() -> float: func get_end_offset() -> float:
return curve.get_baked_length() + extra_distance_end return path.curve.get_baked_length() + extra_distance_end
func position_item(instance: int, item: Item, offset: float) -> void: func position_item(instance: int, _item: Item, offset: float) -> void:
var trans: Transform3D var trans: Transform3D
trans = sample_curve_with_extrapolation(offset).translated_local(item_offset) trans = sample_curve_with_extrapolation(offset).translated_local(item_offset)
multimesh.multimesh.set_instance_transform(instance, trans) multimesh.multimesh.set_instance_transform(instance, trans)
func sample_curve_with_extrapolation(offset: float) -> Transform3D: func sample_curve_with_extrapolation(offset: float) -> Transform3D:
var end_offset: float = curve.get_baked_length() var end_offset: float = path.curve.get_baked_length()
if offset <= 0: if offset <= 0:
var zero: Transform3D = curve.sample_baked_with_rotation(0) var zero: Transform3D = path.curve.sample_baked_with_rotation(0)
var almost_zero: Transform3D = curve.sample_baked_with_rotation(0.1) var almost_zero: Transform3D = path.curve.sample_baked_with_rotation(0.1)
return almost_zero.interpolate_with(zero, (0.1-offset) * 10) return almost_zero.interpolate_with(zero, (0.1-offset) * 10)
elif offset > end_offset: elif offset > end_offset:
var end: Transform3D = curve.sample_baked_with_rotation(end_offset) var end: Transform3D = path.curve.sample_baked_with_rotation(end_offset)
var almost_end: Transform3D = curve.sample_baked_with_rotation(end_offset-0.1) var almost_end: Transform3D = path.curve.sample_baked_with_rotation(end_offset-0.1)
return almost_end.interpolate_with(end, (offset - (end_offset - 0.1)) * 10) return almost_end.interpolate_with(end, (offset - (end_offset - 0.1)) * 10)
else: else:
return curve.sample_baked_with_rotation(offset) return path.curve.sample_baked_with_rotation(offset)

View File

@ -1,16 +1,16 @@
extends Building extends Building
@export var mined_item: Item = preload("res://items/metal.tres") #@export var mined_item: Item = preload("res://items/metal.tres")
@export var mine_period: float = 1.0 @export var mine_period: float = 1.0
@onready var producer: Producer = $Producer
var mine_timer: float = 0.0 var mine_timer: float = 0.0
func _process(delta: float) -> void: func _process(delta: float) -> void:
super(delta)
mine_timer += delta mine_timer += delta
if mine_timer >= mine_period: if mine_timer >= mine_period:
mine_timer -= mine_period mine_timer -= mine_period
mine() mine()
func mine() -> void: func mine() -> void:
producer.send_item(mined_item) producer.produce()

View File

@ -2,15 +2,14 @@ extends Building
@export var ingredients: Dictionary[Item, int] = {} @export var ingredients: Dictionary[Item, int] = {}
@export var process_time: float = 1.0 @export var process_time: float = 1.0
@export var created_item: Item #@export var created_item: Item
var process_timer: float = 0.0 var process_timer: float = 0.0
var processing: bool = false var processing: bool = false
@onready var consumer: Consumer = $Consumer
@onready var producer: Producer = $Producer
func _process(delta: float) -> void: func _process(delta: float) -> void:
if is_functional(): super(delta)
if is_functional() and producer.can_produce():
if !processing: if !processing:
processing = consume_ingredients() processing = consume_ingredients()
if processing: if processing:
@ -24,4 +23,4 @@ func consume_ingredients() -> bool:
return consumer.take_items_from_storage(ingredients) return consumer.take_items_from_storage(ingredients)
func produce_item() -> void: func produce_item() -> void:
producer.send_item(created_item) producer.produce()

View File

@ -8,7 +8,6 @@ extends Building
@export var shot_impulse: float = 100 @export var shot_impulse: float = 100
@export var lead_shot_factor: float = 0.01 @export var lead_shot_factor: float = 0.01
@onready var consumer: Consumer = $Consumer
enum LoadState {UNLOADED, RELOADING, LOADED} enum LoadState {UNLOADED, RELOADING, LOADED}
@onready var ammo: int = 0 @onready var ammo: int = 0
@ -17,10 +16,11 @@ var cooldown_timer: float = 0.0
var reload_timer: float = 0.0 var reload_timer: float = 0.0
var current_target: Enemy = null var current_target: Enemy = null
func _on_consumer_item_added(item: Item) -> void: func _on_consumer_item_added(_item: Item) -> void:
pass pass
func _process(delta: float) -> void: func _process(delta: float) -> void:
super(delta)
if loaded == LoadState.UNLOADED: if loaded == LoadState.UNLOADED:
if consumer.take_any_item_from_storage(): if consumer.take_any_item_from_storage():
#Engine.time_scale = 1.0 #Engine.time_scale = 1.0
@ -47,25 +47,24 @@ func check_target_status() -> void:
func search_for_enemy() -> void: func search_for_enemy() -> void:
var enemies: Array[Node] = get_tree().get_nodes_in_group("Enemies") var enemies: Array[Node] = get_tree().get_nodes_in_group("Enemies")
var closest: float = 9999999999 var closest: float = 9999999999
for enemy in enemies: for enemy: Enemy in enemies:
if enemy is Enemy: if !enemy.sighted:
if !enemy.sighted: continue
continue var distance_sqr = global_position.distance_squared_to(enemy.global_position)
var distance_sqr = global_position.distance_squared_to(enemy.global_position) if distance_sqr <= closest:
if distance_sqr <= closest: var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new()
var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new() params.collision_mask = 0b00101
params.collision_mask = 0b00101 params.from = to_global(fire_position)
params.from = to_global(fire_position) params.to = enemy.global_position
params.to = enemy.global_position var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params)
var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params) #DebugDraw3D.draw_line_hit(params.from, params.to, result["position"] if result.has("position") else Vector3(), result.has("position"), 0.25, Color.YELLOW, Color.BLACK, 1.0)
#DebugDraw3D.draw_line_hit(params.from, params.to, result["position"] if result.has("position") else Vector3(), result.has("position"), 0.25, Color.YELLOW, Color.BLACK, 1.0) if result.has("collider"):
if result.has("collider"): if !result["collider"] is PhysicsBody3D:
if !result["collider"] is PhysicsBody3D: continue
continue var body: PhysicsBody3D = result["collider"]
var body: PhysicsBody3D = result["collider"] if body is Enemy:
if body is Enemy: current_target = body
current_target = body closest = body.global_position.distance_squared_to(global_position)
closest = body.global_position.distance_squared_to(global_position)
func fire_at_target() -> void: func fire_at_target() -> void:
#Engine.time_scale = 0.1 #Engine.time_scale = 0.1
@ -74,8 +73,8 @@ func fire_at_target() -> void:
bullet.global_position = to_global(fire_position) bullet.global_position = to_global(fire_position)
var aim_target: Vector3 = current_target.global_position var aim_target: Vector3 = current_target.global_position
var range: float = global_position.distance_to(current_target.global_position) var target_range: float = global_position.distance_to(current_target.global_position)
aim_target += current_target.linear_velocity * lead_shot_factor * range aim_target += current_target.linear_velocity * lead_shot_factor * target_range
DebugDraw3D.draw_sphere(aim_target, 0.25, Color.RED, 0.1) DebugDraw3D.draw_sphere(aim_target, 0.25, Color.RED, 0.1)
bullet.look_at(aim_target) bullet.look_at(aim_target)

View File

@ -10,7 +10,7 @@ func _on_body_entered(body: Node) -> void:
var speed: float = linear_velocity.length() var speed: float = linear_velocity.length()
var damage: float = speed * damage_per_speed var damage: float = speed * damage_per_speed
if damage >= min_damage: if damage >= min_damage:
body.hurt(damage) (body as Unit).hurt(damage)
func _process(delta: float) -> void: func _process(delta: float) -> void:
lifetime -= delta lifetime -= delta

View File

@ -1,40 +1,50 @@
extends Camera3D extends Camera3D
class_name GameCamera
@export var keyboard_movement_speed: float = 10
@export var maximum_movement_speed: float = 30
@export var mouse_orbit_sensitivity: float = 0.003
@export var zoom_sensitivity: float = 0.1
@export var focus_follows_terrain: bool = true
@export var pan_speed: float = 10
var focus_offset: Vector3 = Vector3(10, 10, 10) var focus_offset: Vector3 = Vector3(10, 10, 10)
var focus_object: Node3D = null var focus_object: Node3D = null
var focus_position: Vector3 var focus_position: Vector3
var mouse_movement: Vector2
var last_mouse_position: Vector2 var mouse_wheel_delta: int = 0
@onready var focus_marker: Node3D = $"Camera Focus" @onready var focus_marker: Node3D = $"Camera Focus"
@onready var viewport: Viewport = get_viewport()
func _physics_process(delta: float) -> void: func _process(delta: float) -> void:
var mouse_position: Vector2 = get_viewport().get_mouse_position() if Input.is_action_just_released("camera_set_target"):
var ray_origin: Vector3 = project_ray_origin(mouse_position) var mouse_position: Vector2 = get_viewport().get_mouse_position()
var ray_normal: Vector3 = ray_origin + project_ray_normal(mouse_position) * 200 var ray_origin: Vector3 = project_ray_origin(mouse_position)
var params = PhysicsRayQueryParameters3D.create(ray_origin, ray_normal) var ray_normal: Vector3 = ray_origin + project_ray_normal(mouse_position) * 200
var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params) var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(ray_origin, ray_normal)
if result.has("position"): var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params)
DebugDraw3D.draw_sphere(result["position"], 0.5, Color.REBECCA_PURPLE) if result.has("position"):
if Input.is_action_just_released("camera_set_target"): #DebugDraw3D.draw_sphere(result["position"], 0.5, Color.REBECCA_PURPLE)
if result.has("collider") and !(result["collider"] is GridMap): if result.has("collider") and !(result["collider"] is GridMap):
focus_object = result["collider"] focus_object = result["collider"]
else: else:
focus_object = null focus_object = null
focus_position = result["position"] focus_position = result["position"]
if focus_object != null: if focus_object != null:
focus_position = focus_object.global_position focus_position = focus_object.global_position
process_focus_movement(delta) process_focus_movement(delta)
process_camera_rotation(delta) process_camera_rotation(delta)
process_camera_zoom(delta)
var target_position: Vector3 = focus_position + focus_offset var target_position: Vector3 = focus_position + focus_offset
if target_position.distance_squared_to(global_position) > 0: if target_position.distance_squared_to(global_position) > 0:
global_position = global_position.move_toward(target_position, 30*(1/60.0)) global_position = global_position.move_toward(target_position, maximum_movement_speed*delta)
else: #else:
look_at(focus_position)
basis = basis.slerp(Basis.looking_at(focus_position - target_position), 0.05)
#global_position = global_position.lerp(target_position, 0.05) #global_position = global_position.lerp(target_position, 0.05)
#basis = basis.slerp(Basis.looking_at(focus_position - global_position), 0.05) #basis = basis.slerp(Basis.looking_at(focus_position - global_position), 0.05)
@ -58,29 +68,46 @@ func process_focus_movement(delta: float) -> void:
focus_object = null focus_object = null
input = input_basis * input input = input_basis * input
var movement: Vector3 = input * pan_speed * delta var movement: Vector3 = input * keyboard_movement_speed * delta
global_position += movement global_position += movement
focus_position += movement focus_position += movement
# handle moving on/off ramps # handle moving on/off ramps
var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new() if focus_follows_terrain:
params.from = focus_position + Vector3(0,2,0) var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new()
params.to = focus_position - Vector3(0,2,0) params.from = focus_position + Vector3(0,2,0)
var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params) params.to = focus_position - Vector3(0,2,0)
if result.has("position"): params.collision_mask = 1
focus_position = result["position"] var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params)
if result.has("position"):
focus_position = result["position"]
DebugDraw3D.draw_gizmo(Transform3D(input_basis, focus_position))
func process_camera_rotation(delta: float) -> void: func process_camera_rotation(delta: float) -> void:
var mouse_position: Vector2 = get_viewport().get_mouse_position() #var mouse_position: Vector2 = viewport.get_mouse_position()
var mouse_movement: Vector2 = mouse_position - last_mouse_position #var mouse_position: Vector2 = Vector2()
last_mouse_position = mouse_position #var mouse_movement: Vector2 = (mouse_position - last_mouse_position) * delta
#last_mouse_position = mouse_position
if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT): if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT):
focus_offset = focus_offset.rotated(Vector3.UP, -mouse_movement.x * mouse_orbit_sensitivity)
focus_offset = focus_offset.rotated(Vector3.UP, -mouse_movement.x * 0.006)
var vertical_axis: Vector3 = focus_offset.cross(Vector3.UP).normalized() var vertical_axis: Vector3 = focus_offset.cross(Vector3.UP).normalized()
focus_offset = focus_offset.rotated(vertical_axis, mouse_movement.y * 0.006) focus_offset = focus_offset.rotated(vertical_axis, mouse_movement.y * mouse_orbit_sensitivity)
global_position = focus_position + focus_offset global_position = focus_position + focus_offset
look_at(focus_position) look_at(focus_position)
mouse_movement = Vector2()
func process_camera_zoom(_delta: float) -> void:
#var wheel_input: float = Input.get_axis("camera_zoom_in", "camera_zoom_out")
var change: float = 1.0 + (-mouse_wheel_delta * zoom_sensitivity)
focus_offset *= change
mouse_wheel_delta = 0
func _input(event: InputEvent) -> void:
if event is InputEventMouseButton:
var button_event: InputEventMouseButton = event
if button_event.button_index == MOUSE_BUTTON_WHEEL_UP:
mouse_wheel_delta += 1
elif button_event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
mouse_wheel_delta -= 1
elif event is InputEventMouseMotion:
var motion_event: InputEventMouseMotion = event
mouse_movement += motion_event.relative

View File

@ -0,0 +1,12 @@
@tool
extends GridMap
class_name CustomGridMap
@export var travel_costs: Dictionary[String, float]
func _enter_tree() -> void:
mesh_library.changed.connect(update_dicts)
func update_dicts() -> void:
var keys: Array[String] = []
mesh_library.get_item_list()

View File

@ -0,0 +1 @@
uid://b61ea0hhhekmp

4
scripts/fps_label.gd Normal file
View File

@ -0,0 +1,4 @@
extends Label
func _process(_delta: float) -> void:
text = "FPS: %d" % [Engine.get_frames_per_second()]

1
scripts/fps_label.gd.uid Normal file
View File

@ -0,0 +1 @@
uid://vcf7wcmyewl8

View File

@ -1,20 +1,23 @@
extends Node3D extends Node3D
class_name NavObstable
@export var enabled: bool = false:
set(val):
if val != enabled:
enabled = val
update(enabled)
@export var aabb: AABB = AABB(Vector3(-1,0,-1),Vector3(2,2,2)) @export var aabb: AABB = AABB(Vector3(-1,0,-1),Vector3(2,2,2))
@export var weight: float = 10.0 @export var weight: float = 10.0
@export var make_solid: bool = true @export var make_solid: bool = false
var enable_timer: float = 1.0 var updated_regions: Array[RID] = []
var enabled: bool = false
func _process(delta: float) -> void: func _exit_tree() -> void:
if enable_timer > 0: update(false)
enable_timer -= delta
if !enabled and enable_timer <= 0:
enabled = true
update()
func update() -> void: func update(enable: bool) -> void:
if !is_node_ready():
await ready
var global_aabb: AABB = global_transform * aabb var global_aabb: AABB = global_transform * aabb
#DebugDraw3D.draw_aabb(global_aabb, Color.DARK_CYAN, 5) #DebugDraw3D.draw_aabb(global_aabb, Color.DARK_CYAN, 5)
for map_rid in NavigationServer3D.get_maps(): for map_rid in NavigationServer3D.get_maps():
@ -22,6 +25,9 @@ func update() -> void:
var region_aabb: AABB = NavigationServer3D.region_get_bounds(region_rid).grow(0.1) var region_aabb: AABB = NavigationServer3D.region_get_bounds(region_rid).grow(0.1)
#DebugDraw3D.draw_aabb(region_aabb, Color.YELLOW, 5) #DebugDraw3D.draw_aabb(region_aabb, Color.YELLOW, 5)
if global_aabb.intersects(region_aabb): if global_aabb.intersects(region_aabb):
NavigationServer3D.region_set_travel_cost(region_rid, weight) var old_weight: float = NavigationServer3D.region_get_travel_cost(region_rid)
#NavigationServer3D.region_set_enabled(region_rid, false) var new_weight: float = (old_weight * weight) if enable else (old_weight / weight)
DebugDraw3D.draw_aabb(region_aabb, Color.RED, 5) NavigationServer3D.region_set_travel_cost(region_rid, new_weight)
if make_solid:
NavigationServer3D.region_set_enabled(region_rid, enable)
DebugDraw3D.draw_aabb(region_aabb, Color.RED if enable else Color.GREEN, 5)

View File

@ -12,4 +12,4 @@ func _process(delta: float) -> void:
var node: Node = spawn_scene.instantiate() var node: Node = spawn_scene.instantiate()
add_child(node) add_child(node)
if node is Node3D: if node is Node3D:
node.global_position = global_position (node as Node3D).global_position = global_position

View File

@ -16,8 +16,12 @@ var stuck_timer: float = 0.0
var move_target: Vector3 = Vector3(16, 1, 13) var move_target: Vector3 = Vector3(16, 1, 13)
var move_radius: float = 5.0 var move_radius: float = 5.0
@onready var shapecast_3d: ShapeCast3D = $ShapeCast3D
@onready var nav_agent_3d: NavigationAgent3D = $NavigationAgent3D
@onready var label_3d: Label3D = $Label3D
func _ready() -> void: func _ready() -> void:
$NavigationAgent3D.connect("velocity_computed", avoidance_velocity_computed) nav_agent_3d.connect("velocity_computed", avoidance_velocity_computed)
pass pass
func avoidance_velocity_computed(velocity: Vector3) -> void: func avoidance_velocity_computed(velocity: Vector3) -> void:
@ -26,17 +30,17 @@ func avoidance_velocity_computed(velocity: Vector3) -> void:
avoidance_timeout = 0.5 avoidance_timeout = 0.5
func _process(delta: float) -> void: func _process(delta: float) -> void:
$Label3D.text = "HP: %d" % hp label_3d.text = "HP: %d" % hp
if $NavigationAgent3D.is_target_reached() \ if nav_agent_3d.is_target_reached() \
or $NavigationAgent3D.target_position.is_zero_approx() \ or nav_agent_3d.target_position.is_zero_approx() \
or !$NavigationAgent3D.is_target_reachable(): or !nav_agent_3d.is_target_reachable():
$NavigationAgent3D.target_position = move_target + Vector3(randfn(0, move_radius), 0, randfn(0, move_radius)) nav_agent_3d.target_position = move_target + Vector3(randfn(0, move_radius), 0, randfn(0, move_radius))
#$NavigationAgent3D.target_position = NavigationServer3D.map_get_random_point(NavigationServer3D.get_maps()[0], 1, true) #nav_agent_3d.target_position = NavigationServer3D.map_get_random_point(NavigationServer3D.get_maps()[0], 1, true)
last_distance_to_target = $NavigationAgent3D.distance_to_target() last_distance_to_target = nav_agent_3d.distance_to_target()
else: else:
if $ShapeCast3D.is_colliding(): if shapecast_3d.is_colliding():
var distance_to_target: float = $NavigationAgent3D.distance_to_target() var distance_to_target: float = nav_agent_3d.distance_to_target()
var progress_rate: float = (last_distance_to_target - distance_to_target) / delta var progress_rate: float = (last_distance_to_target - distance_to_target) / delta
last_distance_to_target = distance_to_target last_distance_to_target = distance_to_target
if progress_rate < minimum_progress_rate: if progress_rate < minimum_progress_rate:
@ -44,24 +48,24 @@ func _process(delta: float) -> void:
if stuck_timer >= stuck_time: if stuck_timer >= stuck_time:
unstuck() unstuck()
else: else:
$Label3D.modulate = Color.WHITE label_3d.modulate = Color.WHITE
stuck_timer = 0 stuck_timer = 0
if global_position.y <= -10: if global_position.y <= -10:
unstuck() unstuck()
#DebugDraw3D.draw_sphere($NavigationAgent3D.target_position, 0.5, Color.RED) #DebugDraw3D.draw_sphere(nav_agent_3d.target_position, 0.5, Color.RED)
var next_point: Vector3 = $NavigationAgent3D.get_next_path_position() var next_point: Vector3 = nav_agent_3d.get_next_path_position()
#DebugDraw3D.draw_sphere(next_point, 0.1, Color.YELLOW) #DebugDraw3D.draw_sphere(next_point, 0.1, Color.YELLOW)
var direction: Vector3 = (next_point - global_position).normalized() var direction: Vector3 = (next_point - global_position).normalized()
#DebugDraw3D.draw_line(global_position, global_position + linear_velocity, Color.BLUE) #DebugDraw3D.draw_line(global_position, global_position + linear_velocity, Color.BLUE)
target_velocity = direction * max_speed target_velocity = direction * max_speed
$NavigationAgent3D.velocity = target_velocity nav_agent_3d.velocity = target_velocity
#DebugDraw3D.draw_line(global_position, global_position + target_velocity, Color.MAGENTA) #DebugDraw3D.draw_line(global_position, global_position + target_velocity, Color.MAGENTA)
#DebugDraw3D.draw_text(global_position + Vector3(0,1,0), "%f" % $NavigationAgent3D.distance_to_target()) #DebugDraw3D.draw_text(global_position + Vector3(0,1,0), "%f" % nav_agent_3d.distance_to_target())
func unstuck() -> void: func unstuck() -> void:
# teleport to next path point # teleport to next path point
linear_velocity = Vector3() linear_velocity = Vector3()
global_position = $NavigationAgent3D.get_next_path_position() global_position = nav_agent_3d.get_next_path_position()
stuck_timer = 0 stuck_timer = 0
func hurt(damage: float) -> void: func hurt(damage: float) -> void:
@ -74,14 +78,14 @@ func die() -> void:
queue_free() queue_free()
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
if $ShapeCast3D.is_colliding(): if shapecast_3d.is_colliding():
var actual_target_velocity: Vector3 = target_velocity var actual_target_velocity: Vector3 = target_velocity
if avoidance_timeout > 0: if avoidance_timeout > 0:
avoidance_timeout -= delta avoidance_timeout -= delta
actual_target_velocity = actual_target_velocity.slerp(avoidance_velocity, 0.25) actual_target_velocity = actual_target_velocity.slerp(avoidance_velocity, 0.25)
#DebugDraw3D.draw_line(global_position, global_position + actual_target_velocity, Color.ORANGE) #DebugDraw3D.draw_line(global_position, global_position + actual_target_velocity, Color.ORANGE)
var force_direction: Vector3 = (actual_target_velocity-linear_velocity) var force_direction: Vector3 = (actual_target_velocity-linear_velocity)
var normal: Vector3 = $ShapeCast3D.get_collision_normal(0) var normal: Vector3 = shapecast_3d.get_collision_normal(0)
#DebugDraw3D.draw_line(global_position, global_position + normal, Color.DODGER_BLUE) #DebugDraw3D.draw_line(global_position, global_position + normal, Color.DODGER_BLUE)
var force: Vector3 = (force_direction * movement_force).slide(normal) var force: Vector3 = (force_direction * movement_force).slide(normal)
#DebugDraw3D.draw_line(global_position, global_position + force, Color.GREEN) #DebugDraw3D.draw_line(global_position, global_position + force, Color.GREEN)