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
*.dylib 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": {
"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": [
"res://items/"
"res://items/",
"res://objects/buildings/"
],
"table_functions": {
"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

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="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
shape = SubResource("BoxShape3D_k07no")
disabled = true
[node name="NavObstacle" type="Node3D" parent="."]
script = ExtResource("2_0gk2u")
make_solid = false
enabled = true
[node name="NavigationObstacle3D" type="NavigationObstacle3D" parent="."]
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)
visible = false
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="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="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 = {
"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)
}
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"]
transform_format = 1
instance_count = 1
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)
[node name="Conveyor" type="Path3D"]
curve = SubResource("Curve3D_r3fl7")
[node name="Conveyor" type="Node3D"]
script = ExtResource("1_m8ga5")
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")
path_3d = NodePath("..")
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/tilt = true
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="."]
script = ExtResource("3_vjqud")
storage_size = 1
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")
consumers = [null]
metadata/_custom_type_script = "uid://c4fquatkjmsgu"
[node name="MultiMeshInstance3D" type="MultiMeshInstance3D" parent="."]
physics_interpolation_mode = 2
visibility_range_end = 50.0
visibility_range_end_margin = 50.0
visibility_range_fade_mode = 1
multimesh = SubResource("MultiMesh_6iypd")
[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="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="Resource" uid="uid://dbkxys3mr5u80" path="res://items/metal.tres" id="3_8y6s2"]
[ext_resource type="PackedScene" uid="uid://dx13fyjv0d8st" path="res://assets/blends/Miner.blend" id="2_la0h1"]
[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"]
[node name="Miner" instance=ExtResource("1_8r86l")]
script = ExtResource("2_k13eg")
mined_item = ExtResource("3_8y6s2")
mine_period = 1.0
can_stack = false
[node name="MeshInstance3D" parent="." index="0"]
visible = false
@ -18,4 +18,5 @@ visible = false
[node name="Producer" type="Node" parent="." index="6"]
script = ExtResource("5_65oni")
produced_item = ExtResource("3_k13eg")
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="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="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="Resource" uid="uid://dxlb2ixt3fx7l" path="res://items/ore.tres" id="7_dx8de"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_evfwj"]
albedo_color = Color(0.023159, 1, 0, 1)
@ -18,18 +18,19 @@ size = Vector3(2, 2, 2)
[node name="Processor" instance=ExtResource("1_hxugg")]
script = ExtResource("2_evfwj")
ingredients = Dictionary[ExtResource("3_3h7kv"), int]({
ExtResource("4_miqab"): 2
ExtResource("7_dx8de"): 2
})
process_time = 1.0
created_item = ExtResource("4_3h7kv")
[node name="MeshInstance3D" parent="." index="0"]
mesh = SubResource("BoxMesh_3h7kv")
[node name="Consumer" type="Node" parent="." index="2"]
script = ExtResource("4_dx8de")
accepted_items = Array[ExtResource("3_3h7kv")]([ExtResource("7_dx8de")])
metadata/_custom_type_script = "uid://bshiyw2k3op02"
[node name="Producer" type="Node" parent="." index="3"]
script = ExtResource("5_p3dou")
produced_item = ExtResource("4_3h7kv")
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="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="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"]
radius = 0.1
@ -13,21 +14,12 @@ height = 0.3
shader = ExtResource("1_ucnj8")
[sub_resource type="Gradient" id="Gradient_6sxjd"]
offsets = PackedFloat32Array(0, 0.150862, 0.642241, 1)
colors = PackedColorArray(1, 1, 1, 1, 1, 0.920817, 0, 0.849138, 0.695312, 0.044384, 0, 0.357759, 1, 1, 1, 0)
offsets = PackedFloat32Array(0, 0.0818966, 0.965517, 1)
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"]
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"]
_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
@ -41,9 +33,9 @@ shader = ExtResource("2_rsjgb")
shader_parameter/tex = SubResource("CurveTexture_rsjgb")
shader_parameter/uv_offset = Vector2(0, 0)
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/flags = 45
shader_parameter/flags = 47
[sub_resource type="QuadMesh" id="QuadMesh_ucnj8"]
material = SubResource("ShaderMaterial_xbcx7")
@ -63,6 +55,54 @@ height = 0.3
radial_segments = 6
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"]
collision_layer = 16
collision_mask = 5
@ -79,7 +119,7 @@ shape = SubResource("CapsuleShape3D_3ndsa")
[node name="GPUTrail3D" type="GPUParticles3D" parent="."]
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
lifetime = 19.0
explosiveness = 1.0
@ -91,8 +131,8 @@ length = 19
length_seconds = 0.322034
texture = SubResource("CurveTexture_rsjgb")
color_ramp = SubResource("GradientTexture1D_od3fb")
curve = SubResource("CurveTexture_7thed")
vertical_texture = true
use_red_as_alpha = true
billboard = true
_defaults_have_been_set = true
metadata/_custom_type_script = "uid://cdubip3a6325r"
@ -105,4 +145,12 @@ mesh = SubResource("CylinderMesh_xbcx7")
[node name="AudioStreamPlayer3D" type="AudioStreamPlayer3D" parent="."]
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"]

View File

@ -27,7 +27,7 @@ config/name="TowerGame3D"
run/main_scene="uid://bwftban1ppo17"
config/features=PackedStringArray("4.4")
config/icon="uid://u1hpdb62rxlc"
addons/icon_finder/preview_size=24
addons/icon_finder/preview_size=25
[autoload]
@ -36,6 +36,20 @@ IconsFonts="*res://addons/icons-fonts/icons_fonts/IconsFonts.gd"
[debug]
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_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)
]
}
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]
@ -109,6 +140,7 @@ camera_set_target={
3d/default_edge_connection_margin=0.6
3d/default_link_connection_radius=0.5
pathfinding/max_threads=-1
[physics]
@ -118,6 +150,3 @@ common/physics_interpolation=true
lights_and_shadows/directional_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
class_name Building
@export_category("Defence")
@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 {
UNPLACED,
BUILDING,
@ -10,11 +25,88 @@ enum BuildState {
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 stacked_buildings: Array[Building] = []
var build_state: BuildState = BuildState.READY:
set(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:
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
signal item_added(item: Item)
@ -12,7 +12,8 @@ var storage: Dictionary[Item, int] = {}
func can_accept_item(item: Item) -> bool:
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:
if !can_accept_item(item):
@ -30,13 +31,13 @@ func check_storage_for_item(item: Item) -> bool:
return check_storage_for_items({item:1})
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]:
return false
return true
func take_any_item_from_storage() -> Item:
for item in storage.keys():
for item: Item in storage.keys():
if storage[item] >= 1:
storage[item] -= 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:
if !check_storage_for_items(items):
return false
for item in items.keys():
for item: Item in items.keys():
var old_count: int = storage.get(item, 0)
storage.set(item, old_count - items[item])
storage_total -= items[item]

View File

@ -1,11 +1,12 @@
extends Node
extends BuildingPart
class_name Producer
@export var produced_item: Item
@export var output_period: float = 0.1
@export var max_outputs: int = 1
@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_item: Item
@ -14,16 +15,39 @@ var next_consumer_idx: int = 0
#if output_timer >= output_period:
#output_timer -= output_period
#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:
if !enabled:
return false
if consumers.is_empty():
return false
next_consumer_idx += 1
if next_consumer_idx >= consumers.size():
next_consumer_idx = 0
var start_idx: int = last_consumer_idx
var first_try: bool = true
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 accepted: bool = consumer.offer_item(item)
return accepted
var consumer: Consumer = consumers[idx]
var accepted: bool = consumer.offer_item(item)
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 item_offset: Vector3 = Vector3(0,2.0,0)
@export var extra_distance_start: float = 1.0
@export var extra_distance_end: float = 1.0
@export var spacing: float = 1.0
var transported_items: Dictionary[Item, PackedFloat64Array] = {}
var belt_moving: bool = true
var closest_item: float = 0.0
@onready var consumer: Consumer = $Consumer
@onready var producer: Producer = $Producer
@onready var path: Path3D = $Path3D
@onready var multimesh: MultiMeshInstance3D = $MultiMeshInstance3D
var test_timer: float = 0
@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:
multimesh.multimesh = multimesh.multimesh.duplicate()
path.curve = path.curve.duplicate()
func _process(delta: float) -> void:
#test_timer += delta
#if test_timer >= 2.0:
#test_timer -= 2.0
#add_item(test_item)
belt_moving = check_items_at_end()
consumer.enabled = belt_moving and (closest_item >= spacing)
var belt_moving: bool = check_items_at_end()
var movement: float = (delta * speed)
closest_item += movement
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]
multimesh.multimesh.instance_count = offsets.size()
for i in range(offsets.size()):
offsets[i] += (delta * speed)
offsets[i] += movement
position_item(i, transported_item_type, offsets[i])
func consumer_has_item(item: Item) -> void:
@ -47,45 +123,47 @@ func add_item(item: Item) -> void:
offsets = []
offsets.append(get_start_offset())
transported_items[item] = offsets
closest_item = 0.0
func check_items_at_end() -> bool:
var length: float = get_end_offset()
var belt_moving: bool = true
for transported_item_type in transported_items.keys():
var ret: bool = true
for transported_item_type: Item in transported_items.keys():
var offsets: PackedFloat64Array = transported_items[transported_item_type]
var to_delete: Array[int] = []
for i in range(offsets.size()):
if offsets[i] >= length:
var sent: bool = producer.send_item(transported_item_type)
if !sent:
belt_moving = false
ret = false
else:
to_delete.append(i)
for d in to_delete:
offsets.remove_at(d)
return belt_moving
return ret
func get_start_offset() -> float:
return -extra_distance_start
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
trans = sample_curve_with_extrapolation(offset).translated_local(item_offset)
multimesh.multimesh.set_instance_transform(instance, trans)
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:
var zero: Transform3D = curve.sample_baked_with_rotation(0)
var almost_zero: Transform3D = curve.sample_baked_with_rotation(0.1)
var zero: Transform3D = path.curve.sample_baked_with_rotation(0)
var almost_zero: Transform3D = path.curve.sample_baked_with_rotation(0.1)
return almost_zero.interpolate_with(zero, (0.1-offset) * 10)
elif offset > end_offset:
var end: Transform3D = curve.sample_baked_with_rotation(end_offset)
var almost_end: Transform3D = curve.sample_baked_with_rotation(end_offset-0.1)
var end: Transform3D = path.curve.sample_baked_with_rotation(end_offset)
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)
else:
return curve.sample_baked_with_rotation(offset)
return path.curve.sample_baked_with_rotation(offset)

View File

@ -1,16 +1,16 @@
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
@onready var producer: Producer = $Producer
var mine_timer: float = 0.0
func _process(delta: float) -> void:
super(delta)
mine_timer += delta
if mine_timer >= mine_period:
mine_timer -= mine_period
mine()
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 process_time: float = 1.0
@export var created_item: Item
#@export var created_item: Item
var process_timer: float = 0.0
var processing: bool = false
@onready var consumer: Consumer = $Consumer
@onready var producer: Producer = $Producer
func _process(delta: float) -> void:
if is_functional():
super(delta)
if is_functional() and producer.can_produce():
if !processing:
processing = consume_ingredients()
if processing:
@ -24,4 +23,4 @@ func consume_ingredients() -> bool:
return consumer.take_items_from_storage(ingredients)
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 lead_shot_factor: float = 0.01
@onready var consumer: Consumer = $Consumer
enum LoadState {UNLOADED, RELOADING, LOADED}
@onready var ammo: int = 0
@ -17,10 +16,11 @@ var cooldown_timer: float = 0.0
var reload_timer: float = 0.0
var current_target: Enemy = null
func _on_consumer_item_added(item: Item) -> void:
func _on_consumer_item_added(_item: Item) -> void:
pass
func _process(delta: float) -> void:
super(delta)
if loaded == LoadState.UNLOADED:
if consumer.take_any_item_from_storage():
#Engine.time_scale = 1.0
@ -47,25 +47,24 @@ func check_target_status() -> void:
func search_for_enemy() -> void:
var enemies: Array[Node] = get_tree().get_nodes_in_group("Enemies")
var closest: float = 9999999999
for enemy in enemies:
if enemy is Enemy:
if !enemy.sighted:
continue
var distance_sqr = global_position.distance_squared_to(enemy.global_position)
if distance_sqr <= closest:
var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new()
params.collision_mask = 0b00101
params.from = to_global(fire_position)
params.to = enemy.global_position
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)
if result.has("collider"):
if !result["collider"] is PhysicsBody3D:
continue
var body: PhysicsBody3D = result["collider"]
if body is Enemy:
current_target = body
closest = body.global_position.distance_squared_to(global_position)
for enemy: Enemy in enemies:
if !enemy.sighted:
continue
var distance_sqr = global_position.distance_squared_to(enemy.global_position)
if distance_sqr <= closest:
var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new()
params.collision_mask = 0b00101
params.from = to_global(fire_position)
params.to = enemy.global_position
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)
if result.has("collider"):
if !result["collider"] is PhysicsBody3D:
continue
var body: PhysicsBody3D = result["collider"]
if body is Enemy:
current_target = body
closest = body.global_position.distance_squared_to(global_position)
func fire_at_target() -> void:
#Engine.time_scale = 0.1
@ -74,8 +73,8 @@ func fire_at_target() -> void:
bullet.global_position = to_global(fire_position)
var aim_target: Vector3 = current_target.global_position
var range: float = global_position.distance_to(current_target.global_position)
aim_target += current_target.linear_velocity * lead_shot_factor * range
var target_range: float = global_position.distance_to(current_target.global_position)
aim_target += current_target.linear_velocity * lead_shot_factor * target_range
DebugDraw3D.draw_sphere(aim_target, 0.25, Color.RED, 0.1)
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 damage: float = speed * damage_per_speed
if damage >= min_damage:
body.hurt(damage)
(body as Unit).hurt(damage)
func _process(delta: float) -> void:
lifetime -= delta

View File

@ -1,40 +1,50 @@
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_object: Node3D = null
var focus_position: Vector3
var last_mouse_position: Vector2
var mouse_movement: Vector2
var mouse_wheel_delta: int = 0
@onready var focus_marker: Node3D = $"Camera Focus"
@onready var viewport: Viewport = get_viewport()
func _physics_process(delta: float) -> void:
var mouse_position: Vector2 = get_viewport().get_mouse_position()
var ray_origin: Vector3 = project_ray_origin(mouse_position)
var ray_normal: Vector3 = ray_origin + project_ray_normal(mouse_position) * 200
var params = PhysicsRayQueryParameters3D.create(ray_origin, ray_normal)
var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params)
if result.has("position"):
DebugDraw3D.draw_sphere(result["position"], 0.5, Color.REBECCA_PURPLE)
if Input.is_action_just_released("camera_set_target"):
if result.has("collider") and !(result["collider"] is GridMap):
focus_object = result["collider"]
else:
focus_object = null
focus_position = result["position"]
func _process(delta: float) -> void:
if Input.is_action_just_released("camera_set_target"):
var mouse_position: Vector2 = get_viewport().get_mouse_position()
var ray_origin: Vector3 = project_ray_origin(mouse_position)
var ray_normal: Vector3 = ray_origin + project_ray_normal(mouse_position) * 200
var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(ray_origin, ray_normal)
var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params)
if result.has("position"):
#DebugDraw3D.draw_sphere(result["position"], 0.5, Color.REBECCA_PURPLE)
if result.has("collider") and !(result["collider"] is GridMap):
focus_object = result["collider"]
else:
focus_object = null
focus_position = result["position"]
if focus_object != null:
focus_position = focus_object.global_position
process_focus_movement(delta)
process_camera_rotation(delta)
process_camera_zoom(delta)
var target_position: Vector3 = focus_position + focus_offset
if target_position.distance_squared_to(global_position) > 0:
global_position = global_position.move_toward(target_position, 30*(1/60.0))
else:
look_at(focus_position)
global_position = global_position.move_toward(target_position, maximum_movement_speed*delta)
#else:
basis = basis.slerp(Basis.looking_at(focus_position - 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)
@ -58,29 +68,46 @@ func process_focus_movement(delta: float) -> void:
focus_object = null
input = input_basis * input
var movement: Vector3 = input * pan_speed * delta
var movement: Vector3 = input * keyboard_movement_speed * delta
global_position += movement
focus_position += movement
# handle moving on/off ramps
var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new()
params.from = focus_position + Vector3(0,2,0)
params.to = focus_position - Vector3(0,2,0)
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))
if focus_follows_terrain:
var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new()
params.from = focus_position + Vector3(0,2,0)
params.to = focus_position - Vector3(0,2,0)
params.collision_mask = 1
var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params)
if result.has("position"):
focus_position = result["position"]
func process_camera_rotation(delta: float) -> void:
var mouse_position: Vector2 = get_viewport().get_mouse_position()
var mouse_movement: Vector2 = mouse_position - last_mouse_position
last_mouse_position = mouse_position
#var mouse_position: Vector2 = viewport.get_mouse_position()
#var mouse_position: Vector2 = Vector2()
#var mouse_movement: Vector2 = (mouse_position - last_mouse_position) * delta
#last_mouse_position = mouse_position
if Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT):
focus_offset = focus_offset.rotated(Vector3.UP, -mouse_movement.x * 0.006)
focus_offset = focus_offset.rotated(Vector3.UP, -mouse_movement.x * mouse_orbit_sensitivity)
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
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
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 weight: float = 10.0
@export var make_solid: bool = true
@export var make_solid: bool = false
var enable_timer: float = 1.0
var enabled: bool = false
var updated_regions: Array[RID] = []
func _process(delta: float) -> void:
if enable_timer > 0:
enable_timer -= delta
if !enabled and enable_timer <= 0:
enabled = true
update()
func _exit_tree() -> void:
update(false)
func update() -> void:
func update(enable: bool) -> void:
if !is_node_ready():
await ready
var global_aabb: AABB = global_transform * aabb
#DebugDraw3D.draw_aabb(global_aabb, Color.DARK_CYAN, 5)
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)
#DebugDraw3D.draw_aabb(region_aabb, Color.YELLOW, 5)
if global_aabb.intersects(region_aabb):
NavigationServer3D.region_set_travel_cost(region_rid, weight)
#NavigationServer3D.region_set_enabled(region_rid, false)
DebugDraw3D.draw_aabb(region_aabb, Color.RED, 5)
var old_weight: float = NavigationServer3D.region_get_travel_cost(region_rid)
var new_weight: float = (old_weight * weight) if enable else (old_weight / weight)
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()
add_child(node)
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_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:
$NavigationAgent3D.connect("velocity_computed", avoidance_velocity_computed)
nav_agent_3d.connect("velocity_computed", avoidance_velocity_computed)
pass
func avoidance_velocity_computed(velocity: Vector3) -> void:
@ -26,17 +30,17 @@ func avoidance_velocity_computed(velocity: Vector3) -> void:
avoidance_timeout = 0.5
func _process(delta: float) -> void:
$Label3D.text = "HP: %d" % hp
label_3d.text = "HP: %d" % hp
if $NavigationAgent3D.is_target_reached() \
or $NavigationAgent3D.target_position.is_zero_approx() \
or !$NavigationAgent3D.is_target_reachable():
$NavigationAgent3D.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)
last_distance_to_target = $NavigationAgent3D.distance_to_target()
if nav_agent_3d.is_target_reached() \
or nav_agent_3d.target_position.is_zero_approx() \
or !nav_agent_3d.is_target_reachable():
nav_agent_3d.target_position = move_target + Vector3(randfn(0, move_radius), 0, randfn(0, move_radius))
#nav_agent_3d.target_position = NavigationServer3D.map_get_random_point(NavigationServer3D.get_maps()[0], 1, true)
last_distance_to_target = nav_agent_3d.distance_to_target()
else:
if $ShapeCast3D.is_colliding():
var distance_to_target: float = $NavigationAgent3D.distance_to_target()
if shapecast_3d.is_colliding():
var distance_to_target: float = nav_agent_3d.distance_to_target()
var progress_rate: float = (last_distance_to_target - distance_to_target) / delta
last_distance_to_target = distance_to_target
if progress_rate < minimum_progress_rate:
@ -44,24 +48,24 @@ func _process(delta: float) -> void:
if stuck_timer >= stuck_time:
unstuck()
else:
$Label3D.modulate = Color.WHITE
label_3d.modulate = Color.WHITE
stuck_timer = 0
if global_position.y <= -10:
unstuck()
#DebugDraw3D.draw_sphere($NavigationAgent3D.target_position, 0.5, Color.RED)
var next_point: Vector3 = $NavigationAgent3D.get_next_path_position()
#DebugDraw3D.draw_sphere(nav_agent_3d.target_position, 0.5, Color.RED)
var next_point: Vector3 = nav_agent_3d.get_next_path_position()
#DebugDraw3D.draw_sphere(next_point, 0.1, Color.YELLOW)
var direction: Vector3 = (next_point - global_position).normalized()
#DebugDraw3D.draw_line(global_position, global_position + linear_velocity, Color.BLUE)
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_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:
# teleport to next path point
linear_velocity = Vector3()
global_position = $NavigationAgent3D.get_next_path_position()
global_position = nav_agent_3d.get_next_path_position()
stuck_timer = 0
func hurt(damage: float) -> void:
@ -74,14 +78,14 @@ func die() -> void:
queue_free()
func _physics_process(delta: float) -> void:
if $ShapeCast3D.is_colliding():
if shapecast_3d.is_colliding():
var actual_target_velocity: Vector3 = target_velocity
if avoidance_timeout > 0:
avoidance_timeout -= delta
actual_target_velocity = actual_target_velocity.slerp(avoidance_velocity, 0.25)
#DebugDraw3D.draw_line(global_position, global_position + actual_target_velocity, Color.ORANGE)
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)
var force: Vector3 = (force_direction * movement_force).slide(normal)
#DebugDraw3D.draw_line(global_position, global_position + force, Color.GREEN)