Added storage building, added detector building component, and changed citizen behaviour to use pluggable actions.
This commit is contained in:
parent
8a0e163e64
commit
0350d48957
21
node_3d.tscn
21
node_3d.tscn
File diff suppressed because one or more lines are too long
|
@ -34,6 +34,7 @@ ExtResource("3_w18nb"): 5
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
[node name="MeshInstance3D" type="MeshInstance3D" 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)
|
||||||
|
layers = 2
|
||||||
mesh = SubResource("BoxMesh_cee1v")
|
mesh = SubResource("BoxMesh_cee1v")
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
|
|
@ -12,7 +12,7 @@ albedo_color = Color(0, 1, 0.979857, 1)
|
||||||
material = SubResource("StandardMaterial3D_nr174")
|
material = SubResource("StandardMaterial3D_nr174")
|
||||||
size = Vector3(2, 2, 2)
|
size = Vector3(2, 2, 2)
|
||||||
|
|
||||||
[node name="Building" instance=ExtResource("1_7qwib")]
|
[node name="Storage" instance=ExtResource("1_7qwib")]
|
||||||
script = ExtResource("2_evbsr")
|
script = ExtResource("2_evbsr")
|
||||||
|
|
||||||
[node name="MeshInstance3D" parent="." index="0"]
|
[node name="MeshInstance3D" parent="." index="0"]
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
[gd_scene load_steps=9 format=3 uid="uid://cw3vtaevqx20y"]
|
[gd_scene load_steps=10 format=3 uid="uid://cw3vtaevqx20y"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://b1fnsl3k1mo5c" path="res://objects/buildings/building.tscn" id="1_cgb0l"]
|
[ext_resource type="PackedScene" uid="uid://b1fnsl3k1mo5c" path="res://objects/buildings/building.tscn" id="1_cgb0l"]
|
||||||
[ext_resource type="Script" uid="uid://bl78fqp1abxd6" path="res://scripts/buildings/turret.gd" id="2_brx0q"]
|
[ext_resource type="Script" uid="uid://bl78fqp1abxd6" path="res://scripts/buildings/turret.gd" id="2_brx0q"]
|
||||||
[ext_resource type="Script" uid="uid://bshiyw2k3op02" path="res://scripts/building_components/consumer.gd" id="2_wh3b5"]
|
[ext_resource type="Script" uid="uid://bshiyw2k3op02" path="res://scripts/building_components/consumer.gd" id="2_wh3b5"]
|
||||||
[ext_resource type="PackedScene" uid="uid://cav22qho14o47" path="res://objects/bullet.tscn" id="3_kpsgq"]
|
[ext_resource type="PackedScene" uid="uid://cav22qho14o47" path="res://objects/bullet.tscn" id="3_kpsgq"]
|
||||||
|
[ext_resource type="Script" uid="uid://b3jshlhs24s8d" path="res://scripts/building_components/detector.gd" id="5_vuktq"]
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_cgb0l"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_cgb0l"]
|
||||||
albedo_color = Color(0, 0.00397563, 1, 1)
|
albedo_color = Color(0, 0.00397563, 1, 1)
|
||||||
|
@ -34,7 +35,9 @@ fire_cooldown_time = 0.2
|
||||||
reload_time = 1.0
|
reload_time = 1.0
|
||||||
bullet_scene = ExtResource("3_kpsgq")
|
bullet_scene = ExtResource("3_kpsgq")
|
||||||
fire_position = Vector3(0, 2.1, 0)
|
fire_position = Vector3(0, 2.1, 0)
|
||||||
|
bullets_at_once = 1
|
||||||
shot_velocity = 50.0
|
shot_velocity = 50.0
|
||||||
|
deviation = Vector2(1, 1)
|
||||||
lead_shots = true
|
lead_shots = true
|
||||||
compensate_for_gravity = true
|
compensate_for_gravity = true
|
||||||
use_artillery_firing_solution = false
|
use_artillery_firing_solution = false
|
||||||
|
@ -50,8 +53,12 @@ mesh = SubResource("CylinderMesh_kpsgq")
|
||||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 1)
|
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 1)
|
||||||
mesh = SubResource("CylinderMesh_vuktq")
|
mesh = SubResource("CylinderMesh_vuktq")
|
||||||
|
|
||||||
[node name="Consumer" type="Node" parent="." index="5"]
|
[node name="Consumer" type="Node" parent="." index="6"]
|
||||||
script = ExtResource("2_wh3b5")
|
script = ExtResource("2_wh3b5")
|
||||||
metadata/_custom_type_script = "uid://bshiyw2k3op02"
|
metadata/_custom_type_script = "uid://bshiyw2k3op02"
|
||||||
|
|
||||||
|
[node name="Detector" type="Node3D" parent="." index="7"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.31252, 0)
|
||||||
|
script = ExtResource("5_vuktq")
|
||||||
|
|
||||||
[connection signal="item_added" from="Consumer" to="." method="_on_consumer_item_added"]
|
[connection signal="item_added" from="Consumer" to="." method="_on_consumer_item_added"]
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
[gd_scene load_steps=8 format=3 uid="uid://skxli3htgn7"]
|
[gd_scene load_steps=9 format=3 uid="uid://skxli3htgn7"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://1gcj3gixy6hs" path="res://objects/units/unit.tscn" id="1_6046h"]
|
[ext_resource type="PackedScene" uid="uid://1gcj3gixy6hs" path="res://objects/units/unit.tscn" id="1_6046h"]
|
||||||
[ext_resource type="Script" uid="uid://b7xficxq807qd" path="res://objects/units/citizen.gd" id="2_dv62s"]
|
[ext_resource type="Script" uid="uid://b7xficxq807qd" path="res://scripts/units/citizen.gd" id="2_dv62s"]
|
||||||
[ext_resource type="Texture2D" uid="uid://brjswv5ryy8om" path="res://assets/images/lilguy.png" id="3_pedvu"]
|
[ext_resource type="Texture2D" uid="uid://brjswv5ryy8om" path="res://assets/images/lilguy.png" id="3_pedvu"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cpov32m0nxjvh" path="res://assets/images/lilguy_arms.png" id="4_i1unn"]
|
[ext_resource type="Texture2D" uid="uid://cpov32m0nxjvh" path="res://assets/images/lilguy_arms.png" id="4_i1unn"]
|
||||||
[ext_resource type="ArrayMesh" uid="uid://c6yj8uwsgqxv0" path="res://assets/models/Ingot.obj" id="5_dv62s"]
|
[ext_resource type="ArrayMesh" uid="uid://c6yj8uwsgqxv0" path="res://assets/models/Ingot.obj" id="5_dv62s"]
|
||||||
|
[ext_resource type="Script" uid="uid://b3jshlhs24s8d" path="res://scripts/building_components/detector.gd" id="6_pedvu"]
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vpcy6"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vpcy6"]
|
||||||
albedo_texture = ExtResource("3_pedvu")
|
albedo_texture = ExtResource("3_pedvu")
|
||||||
|
@ -32,6 +33,7 @@ text = "HP: 100"
|
||||||
|
|
||||||
[node name="Body" type="Sprite3D" parent="." index="5"]
|
[node name="Body" type="Sprite3D" parent="." index="5"]
|
||||||
transform = Transform3D(3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0)
|
transform = Transform3D(3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0)
|
||||||
|
layers = 4
|
||||||
billboard = 2
|
billboard = 2
|
||||||
shaded = true
|
shaded = true
|
||||||
alpha_cut = 1
|
alpha_cut = 1
|
||||||
|
@ -41,6 +43,7 @@ hframes = 2
|
||||||
|
|
||||||
[node name="Hands" type="Sprite3D" parent="Body" index="0"]
|
[node name="Hands" type="Sprite3D" parent="Body" index="0"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.0522564)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.0522564)
|
||||||
|
layers = 4
|
||||||
billboard = 2
|
billboard = 2
|
||||||
shaded = true
|
shaded = true
|
||||||
alpha_cut = 1
|
alpha_cut = 1
|
||||||
|
@ -52,3 +55,9 @@ transform = Transform3D(0.17, 0, 0, 0, 0.17, 0, 0, 0, 0.17, 5.96046e-08, -0.0189
|
||||||
visible = false
|
visible = false
|
||||||
mesh = ExtResource("5_dv62s")
|
mesh = ExtResource("5_dv62s")
|
||||||
skeleton = NodePath("../../..")
|
skeleton = NodePath("../../..")
|
||||||
|
|
||||||
|
[node name="Detector" type="Node3D" parent="." index="6"]
|
||||||
|
script = ExtResource("6_pedvu")
|
||||||
|
detection_range = 50.0
|
||||||
|
scan_period = 0.5
|
||||||
|
metadata/_custom_type_script = "uid://b3jshlhs24s8d"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[gd_scene load_steps=3 format=3 uid="uid://q80xjurpsmjb"]
|
[gd_scene load_steps=3 format=3 uid="uid://q80xjurpsmjb"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://1gcj3gixy6hs" path="res://objects/units/unit.tscn" id="1_8hi5e"]
|
[ext_resource type="PackedScene" uid="uid://1gcj3gixy6hs" path="res://objects/units/unit.tscn" id="1_8hi5e"]
|
||||||
[ext_resource type="Script" uid="uid://cl0k7xolx5rf2" path="res://scripts/enemy.gd" id="2_14ipn"]
|
[ext_resource type="Script" uid="uid://cl0k7xolx5rf2" path="res://scripts/units/enemy.gd" id="2_14ipn"]
|
||||||
|
|
||||||
[node name="Enemy" groups=["Enemies"] instance=ExtResource("1_8hi5e")]
|
[node name="Enemy" groups=["Enemies"] instance=ExtResource("1_8hi5e")]
|
||||||
collision_layer = 4
|
collision_layer = 4
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[gd_scene load_steps=7 format=3 uid="uid://1gcj3gixy6hs"]
|
[gd_scene load_steps=7 format=3 uid="uid://1gcj3gixy6hs"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://f0j7u0so2ug5" path="res://scripts/unit.gd" id="1_dberb"]
|
[ext_resource type="Script" uid="uid://f0j7u0so2ug5" path="res://scripts/units/unit.gd" id="1_dberb"]
|
||||||
[ext_resource type="Texture2D" uid="uid://3javrn230ddq" path="res://assets/images/enemy.png" id="2_2pk7s"]
|
[ext_resource type="Texture2D" uid="uid://3javrn230ddq" path="res://assets/images/enemy.png" id="2_2pk7s"]
|
||||||
|
|
||||||
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_a0tk4"]
|
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_a0tk4"]
|
||||||
|
@ -43,6 +43,7 @@ debug_path_custom_color = Color(1, 0, 0.0808306, 1)
|
||||||
shape = SubResource("SphereShape3D_a202f")
|
shape = SubResource("SphereShape3D_a202f")
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||||
|
layers = 4
|
||||||
mesh = SubResource("QuadMesh_i5arm")
|
mesh = SubResource("QuadMesh_i5arm")
|
||||||
|
|
||||||
[node name="ShapeCast3D" type="ShapeCast3D" parent="."]
|
[node name="ShapeCast3D" type="ShapeCast3D" parent="."]
|
||||||
|
|
|
@ -28,11 +28,11 @@ 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=25
|
addons/icon_finder/preview_size=25
|
||||||
config/git_describe="78bfcde"
|
|
||||||
|
|
||||||
[autoload]
|
[autoload]
|
||||||
|
|
||||||
IconsFonts="*res://addons/icons-fonts/icons_fonts/IconsFonts.gd"
|
IconsFonts="*res://addons/icons-fonts/icons_fonts/IconsFonts.gd"
|
||||||
|
TowerUtil="*res://scripts/util.gd"
|
||||||
|
|
||||||
[debug]
|
[debug]
|
||||||
|
|
||||||
|
@ -146,6 +146,7 @@ building_cancel={
|
||||||
3d_navigation/layer_3="Citizens"
|
3d_navigation/layer_3="Citizens"
|
||||||
3d_physics/layer_4="Citizens"
|
3d_physics/layer_4="Citizens"
|
||||||
3d_physics/layer_5="Projectiles"
|
3d_physics/layer_5="Projectiles"
|
||||||
|
3d_physics/layer_32="Mouse Selectable"
|
||||||
|
|
||||||
[navigation]
|
[navigation]
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@ class_name Building
|
||||||
@onready var consumer: Consumer = $Consumer
|
@onready var consumer: Consumer = $Consumer
|
||||||
@onready var producer: Producer = $Producer
|
@onready var producer: Producer = $Producer
|
||||||
@onready var collision_shape: CollisionShape3D = $CollisionShape3D
|
@onready var collision_shape: CollisionShape3D = $CollisionShape3D
|
||||||
|
@onready var detector: Detector = $Detector
|
||||||
|
|
||||||
|
var initial_collision_layer: int = 1 << 1 # layer 2: buildings
|
||||||
|
|
||||||
signal functional_changed(functional: bool)
|
signal functional_changed(functional: bool)
|
||||||
|
|
||||||
|
@ -77,7 +80,9 @@ func _ready() -> void:
|
||||||
if producer != null:
|
if producer != null:
|
||||||
functional_changed.connect(func(enable:bool): producer.enabled = enable)
|
functional_changed.connect(func(enable:bool): producer.enabled = enable)
|
||||||
if collision_shape != null:
|
if collision_shape != null:
|
||||||
functional_changed.connect(func(enable:bool): collision_shape.disabled = !enable)
|
functional_changed.connect(set_collision_enabled)
|
||||||
|
if detector != null:
|
||||||
|
functional_changed.connect(func(enable:bool): detector.enabled = enable)
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
if build_state == BuildState.UNPLACED:
|
if build_state == BuildState.UNPLACED:
|
||||||
|
@ -177,3 +182,12 @@ func set_visual_build_progress(ratio: float) -> void:
|
||||||
geometry.set_instance_shader_parameter("built_amount", built_amount)
|
geometry.set_instance_shader_parameter("built_amount", built_amount)
|
||||||
#var opacity: float = 0.5 + (ratio * 0.5)
|
#var opacity: float = 0.5 + (ratio * 0.5)
|
||||||
#geometry.transparency = 1.0 - opacity
|
#geometry.transparency = 1.0 - opacity
|
||||||
|
|
||||||
|
func set_collision_enabled(enabled: bool) -> void:
|
||||||
|
if collision_shape == null:
|
||||||
|
return
|
||||||
|
if !enabled:
|
||||||
|
initial_collision_layer = collision_shape.get_parent().collision_layer
|
||||||
|
collision_shape.get_parent().collision_layer = 1 << 31
|
||||||
|
else:
|
||||||
|
collision_shape.get_parent().collision_layer = initial_collision_layer
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
extends Node3D
|
||||||
|
class_name Detector
|
||||||
|
|
||||||
|
@export var enabled: bool = true
|
||||||
|
@export var detection_range: float = 200.0
|
||||||
|
@export var requires_los: bool = true
|
||||||
|
@export_flags_3d_physics var los_physics_layers: int = 0b001
|
||||||
|
@export var detected_group_name: StringName = "Enemies"
|
||||||
|
@export var scan_period: float = 0.1
|
||||||
|
@export var debug_draw: bool = true
|
||||||
|
|
||||||
|
var scan_timer: float = 0.0
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
if enabled:
|
||||||
|
scan_timer += delta
|
||||||
|
if scan_timer >= scan_period:
|
||||||
|
scan_timer -= scan_period
|
||||||
|
scan()
|
||||||
|
|
||||||
|
func scan() -> void:
|
||||||
|
for node in get_tree().get_nodes_in_group(detected_group_name):
|
||||||
|
var enemy: Enemy = node as Enemy
|
||||||
|
if enemy != null and !enemy.sighted and can_see(enemy):
|
||||||
|
enemy.sighted = true
|
||||||
|
|
||||||
|
func can_see(enemy: Enemy) -> bool:
|
||||||
|
var distance: float = enemy.global_position.distance_to(global_position)
|
||||||
|
if distance >= detection_range:
|
||||||
|
return false
|
||||||
|
if requires_los:
|
||||||
|
var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(global_position, enemy.global_position)
|
||||||
|
params.collision_mask = los_physics_layers
|
||||||
|
var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params)
|
||||||
|
if debug_draw:
|
||||||
|
TowerUtil.draw_raycast_hit(params, result, 1.0)
|
||||||
|
#DebugDraw3D.draw_line_hit(global_position, enemy.global_position, result[''] is_hit)
|
||||||
|
if result.has("collider"):
|
||||||
|
if result.get("collider") == enemy:
|
||||||
|
return true
|
||||||
|
return false # something's in the way
|
||||||
|
return true
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
uid://b3jshlhs24s8d
|
|
@ -31,6 +31,7 @@ func placement_mouse_input(screen_position: Vector2, confirmed: bool) -> void:
|
||||||
var ray_origin: Vector3 = camera.project_ray_origin(screen_position)
|
var ray_origin: Vector3 = camera.project_ray_origin(screen_position)
|
||||||
var ray_normal: Vector3 = ray_origin + camera.project_ray_normal(screen_position) * 200
|
var ray_normal: Vector3 = ray_origin + camera.project_ray_normal(screen_position) * 200
|
||||||
var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(ray_origin, ray_normal)
|
var params: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(ray_origin, ray_normal)
|
||||||
|
params.collision_mask = (1 << 31) | (1 << 1) | (1) # selectables, buildings, terrain
|
||||||
if placing_building.collision_shape != null:
|
if placing_building.collision_shape != null:
|
||||||
params.exclude = [placing_building.get_rid()]
|
params.exclude = [placing_building.get_rid()]
|
||||||
var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params)
|
var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params)
|
||||||
|
|
|
@ -3,8 +3,10 @@ extends Building
|
||||||
var held_item: Item = null
|
var held_item: Item = null
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
if !producer.consumers.is_empty():
|
super(delta)
|
||||||
held_item = consumer.take_any_item_from_storage()
|
if is_functional():
|
||||||
|
if !producer.consumers.is_empty() and held_item == null:
|
||||||
|
held_item = consumer.take_any_item_from_storage()
|
||||||
|
|
||||||
if held_item != null and producer.send_item(held_item):
|
if held_item != null and producer.send_item(held_item):
|
||||||
held_item = null
|
held_item = null
|
||||||
|
|
|
@ -9,13 +9,16 @@ class_name Turret
|
||||||
@export_group("Bullet Spawning")
|
@export_group("Bullet Spawning")
|
||||||
@export var bullet_scene: PackedScene = preload("res://objects/bullet.tscn") ## The entity to spawn as a bullet.
|
@export var bullet_scene: PackedScene = preload("res://objects/bullet.tscn") ## The entity to spawn as a bullet.
|
||||||
@export var fire_position: Vector3 = Vector3(0,1,0) ## The local position to fire from.
|
@export var fire_position: Vector3 = Vector3(0,1,0) ## The local position to fire from.
|
||||||
|
@export var bullets_at_once: int = 5
|
||||||
|
|
||||||
@export_group("Ballistics")
|
@export_group("Ballistics")
|
||||||
@export var shot_velocity: float = 100 ## The velocity that bullets are fired at, in m/s.
|
@export var shot_velocity: float = 100 ## The velocity that bullets are fired at, in m/s.
|
||||||
|
@export var deviation: Vector2 = Vector2(1.0, 1.0)
|
||||||
@export var lead_shots: bool = true ## Turn on to make the turret aim ahead of moving targets.
|
@export var lead_shots: bool = true ## Turn on to make the turret aim ahead of moving targets.
|
||||||
@export var compensate_for_gravity: bool = true ## Turn on to make the turret aim above distant targets to arc it's shots.
|
@export var compensate_for_gravity: bool = true ## Turn on to make the turret aim above distant targets to arc it's shots.
|
||||||
@export var use_artillery_firing_solution: bool = false ## If compensating for gravity, turn this on to make the turret aim high instead of low.
|
@export var use_artillery_firing_solution: bool = false ## If compensating for gravity, turn this on to make the turret aim high instead of low.
|
||||||
|
|
||||||
|
|
||||||
enum LoadState {UNLOADED, RELOADING, LOADED}
|
enum LoadState {UNLOADED, RELOADING, LOADED}
|
||||||
|
|
||||||
@onready var ammo: int = 0
|
@onready var ammo: int = 0
|
||||||
|
@ -42,16 +45,15 @@ func _process(delta: float) -> void:
|
||||||
cooldown_timer += delta
|
cooldown_timer += delta
|
||||||
if cooldown_timer >= fire_cooldown_time:
|
if cooldown_timer >= fire_cooldown_time:
|
||||||
cooldown_timer -= fire_cooldown_time
|
cooldown_timer -= fire_cooldown_time
|
||||||
|
if current_target != null and !is_valid_target(current_target):
|
||||||
|
current_target = null
|
||||||
if current_target == null:
|
if current_target == null:
|
||||||
search_for_enemy()
|
find_target()
|
||||||
if current_target != null:
|
if current_target != null:
|
||||||
fire_at_target()
|
for i in range(bullets_at_once):
|
||||||
|
fire_at_target()
|
||||||
func check_target_status() -> void:
|
|
||||||
if current_target.is_queued_for_deletion():
|
|
||||||
current_target = null
|
|
||||||
|
|
||||||
func search_for_enemy() -> void:
|
func find_target() -> 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: Enemy in enemies:
|
for enemy: Enemy in enemies:
|
||||||
|
@ -59,57 +61,64 @@ func search_for_enemy() -> void:
|
||||||
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()
|
if is_valid_target(enemy):
|
||||||
params.collision_mask = 0b00101
|
current_target = enemy
|
||||||
params.from = to_global(fire_position)
|
closest = distance_sqr
|
||||||
params.to = enemy.global_position
|
|
||||||
var result: Dictionary = get_world_3d().direct_space_state.intersect_ray(params)
|
func is_valid_target(enemy: Enemy) -> bool:
|
||||||
#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 enemy == null:
|
||||||
if result.has("collider"):
|
return false
|
||||||
if !result["collider"] is PhysicsBody3D:
|
if enemy.is_queued_for_deletion():
|
||||||
continue
|
return false
|
||||||
var body: PhysicsBody3D = result["collider"]
|
return detector.can_see(enemy)
|
||||||
if body is Enemy:
|
|
||||||
current_target = body
|
|
||||||
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
|
||||||
|
if ammo <= 0 or current_target == null:
|
||||||
|
return
|
||||||
var bullet: RigidBody3D = bullet_scene.instantiate()
|
var bullet: RigidBody3D = bullet_scene.instantiate()
|
||||||
|
bullet.target = current_target
|
||||||
add_child(bullet)
|
add_child(bullet)
|
||||||
var bullet_pos: Vector3 = to_global(fire_position)
|
var bullet_pos: Vector3 = to_global(fire_position)
|
||||||
bullet.global_position = bullet_pos
|
bullet.global_position = bullet_pos
|
||||||
|
|
||||||
|
var aim_target: Vector3 = current_target.global_position
|
||||||
|
|
||||||
var target_range: float = bullet_pos.distance_to(current_target.global_position)
|
var target_range: float = bullet_pos.distance_to(current_target.global_position)
|
||||||
|
var target_height: float = (aim_target.y - bullet_pos.y)
|
||||||
var shot_time: float = (target_range / shot_velocity)
|
var shot_time: float = (target_range / shot_velocity)
|
||||||
|
|
||||||
var aim_target: Vector3 = current_target.global_position
|
|
||||||
if lead_shots:
|
if lead_shots:
|
||||||
aim_target += current_target.linear_velocity * shot_time
|
aim_target += current_target.linear_velocity * shot_time
|
||||||
target_range = bullet_pos.distance_to(aim_target)
|
target_range = bullet_pos.distance_to(aim_target)
|
||||||
#DebugDraw3D.draw_sphere(aim_target, 0.25, Color.RED, shot_time)
|
#DebugDraw3D.draw_sphere(aim_target, 0.25, Color.RED, shot_time)
|
||||||
|
|
||||||
var fire_direction: Vector3
|
var elevation: float = 0.0
|
||||||
|
var azimuth: float = Vector3.FORWARD.signed_angle_to((aim_target-bullet_pos).slide(Vector3.UP), Vector3.UP)
|
||||||
if compensate_for_gravity:
|
if compensate_for_gravity:
|
||||||
var elevation: float = find_fire_angle(target_range, (aim_target.y - bullet_pos.y), use_artillery_firing_solution)
|
elevation = find_fire_angle(target_range, target_height, use_artillery_firing_solution)
|
||||||
var azimuth: float = Vector3.FORWARD.signed_angle_to((aim_target-bullet_pos).slide(Vector3.UP), Vector3.UP)
|
|
||||||
print("Shot params: θ=%d φ=%d" % [rad_to_deg(elevation), rad_to_deg(azimuth)])
|
print("Shot params: θ=%d φ=%d" % [rad_to_deg(elevation), rad_to_deg(azimuth)])
|
||||||
if elevation < -PI or elevation > PI or is_nan(elevation):
|
if elevation < -PI or elevation > PI or is_nan(elevation):
|
||||||
print("wtf?? θ=%d" % rad_to_deg(elevation))
|
print("wtf?? θ=%d" % rad_to_deg(elevation))
|
||||||
return
|
return
|
||||||
fire_direction = Vector3.FORWARD
|
|
||||||
fire_direction = fire_direction.rotated(Vector3(1,0,0), elevation)
|
|
||||||
fire_direction = fire_direction.rotated(Vector3(0,1,0), azimuth)
|
|
||||||
else:
|
else:
|
||||||
fire_direction = (aim_target - bullet_pos).normalized()
|
elevation = atan2(target_height, target_range)
|
||||||
|
#fire_direction = (aim_target - bullet_pos).normalized()
|
||||||
|
|
||||||
|
# apply deviation
|
||||||
|
elevation += randfn(0, deg_to_rad(deviation.y))
|
||||||
|
azimuth += randfn(0, deg_to_rad(deviation.x))
|
||||||
|
|
||||||
|
var fire_direction: Vector3 = Vector3.FORWARD
|
||||||
|
fire_direction = fire_direction.rotated(Vector3(1,0,0), elevation)
|
||||||
|
fire_direction = fire_direction.rotated(Vector3(0,1,0), azimuth)
|
||||||
#DebugDraw3D.draw_arrow_ray(bullet_pos, fire_direction, target_range, Color.RED, 0.5, true, shot_time)
|
#DebugDraw3D.draw_arrow_ray(bullet_pos, fire_direction, target_range, Color.RED, 0.5, true, shot_time)
|
||||||
|
|
||||||
bullet.look_at(bullet_pos+fire_direction)
|
bullet.look_at(bullet_pos+fire_direction)
|
||||||
bullet.linear_velocity = (-bullet.global_basis.z * shot_velocity)
|
bullet.linear_velocity = (-bullet.global_basis.z * shot_velocity)
|
||||||
#bullet.apply_impulse((aim_target - bullet.global_position).normalized()*shot_impulse)
|
#bullet.apply_impulse((aim_target - bullet.global_position).normalized()*shot_impulse)
|
||||||
bullet.angular_velocity = (bullet.global_basis * Vector3(0,0,deg_to_rad(1080)))
|
bullet.angular_velocity = (bullet.global_basis * Vector3(0,0,deg_to_rad(1080)))
|
||||||
current_target = null
|
#
|
||||||
ammo -= 1
|
ammo -= 1
|
||||||
if ammo <= 0:
|
if ammo <= 0:
|
||||||
Engine.time_scale = 1.0
|
Engine.time_scale = 1.0
|
||||||
|
|
|
@ -3,6 +3,9 @@ extends RigidBody3D
|
||||||
@export var damage_per_speed: float = 1.0
|
@export var damage_per_speed: float = 1.0
|
||||||
@export var min_damage: float = 10.0
|
@export var min_damage: float = 10.0
|
||||||
@export var lifetime: float = 2.0
|
@export var lifetime: float = 2.0
|
||||||
|
@export var homing_force: float = 10.0
|
||||||
|
|
||||||
|
var target: Enemy = null
|
||||||
|
|
||||||
func _on_body_entered(body: Node) -> void:
|
func _on_body_entered(body: Node) -> void:
|
||||||
#print("Bullet collided with %s" % body.name)
|
#print("Bullet collided with %s" % body.name)
|
||||||
|
@ -19,5 +22,10 @@ func _process(delta: float) -> void:
|
||||||
if global_position.y < -10:
|
if global_position.y < -10:
|
||||||
destroy()
|
destroy()
|
||||||
|
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
if homing_force > 0 and target != null:
|
||||||
|
var distance: float = global_position.distance_to(target.global_position)
|
||||||
|
var velocity_direction: Vector3 = linear_velocity.limit_length()
|
||||||
|
|
||||||
func destroy() -> void:
|
func destroy() -> void:
|
||||||
queue_free()
|
queue_free()
|
||||||
|
|
|
@ -3,8 +3,11 @@ class_name GameCamera
|
||||||
|
|
||||||
@export var keyboard_movement_speed: float = 10
|
@export var keyboard_movement_speed: float = 10
|
||||||
@export var maximum_movement_speed: float = 30
|
@export var maximum_movement_speed: float = 30
|
||||||
|
@export var camera_movement_standard_distance: float = 20.0
|
||||||
@export var mouse_orbit_sensitivity: float = 0.003
|
@export var mouse_orbit_sensitivity: float = 0.003
|
||||||
@export var zoom_sensitivity: float = 0.1
|
@export var zoom_sensitivity: float = 0.1
|
||||||
|
@export var minimum_camera_distance: float = 1.0
|
||||||
|
@export var maximum_camera_distance: float = 100.0
|
||||||
@export var focus_follows_terrain: bool = true
|
@export var focus_follows_terrain: bool = true
|
||||||
|
|
||||||
var focus_offset: Vector3 = Vector3(10, 10, 10)
|
var focus_offset: Vector3 = Vector3(10, 10, 10)
|
||||||
|
@ -33,14 +36,16 @@ func _process(delta: float) -> void:
|
||||||
|
|
||||||
if focus_object != null:
|
if focus_object != null:
|
||||||
focus_position = focus_object.global_position
|
focus_position = focus_object.global_position
|
||||||
|
|
||||||
|
var movement_speed_multiplier: float = (global_position.distance_to(focus_position)) / camera_movement_standard_distance
|
||||||
|
|
||||||
process_focus_movement(delta)
|
process_focus_movement(delta, movement_speed_multiplier)
|
||||||
process_camera_rotation(delta)
|
process_camera_rotation(delta, movement_speed_multiplier)
|
||||||
process_camera_zoom(delta)
|
process_camera_zoom(delta, movement_speed_multiplier)
|
||||||
|
|
||||||
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, maximum_movement_speed*delta)
|
global_position = global_position.move_toward(target_position, maximum_movement_speed*delta*movement_speed_multiplier)
|
||||||
#else:
|
#else:
|
||||||
|
|
||||||
basis = basis.slerp(Basis.looking_at(focus_position - target_position), 0.05)
|
basis = basis.slerp(Basis.looking_at(focus_position - target_position), 0.05)
|
||||||
|
@ -53,7 +58,7 @@ func _process(delta: float) -> void:
|
||||||
#look_at(focus_position)
|
#look_at(focus_position)
|
||||||
|
|
||||||
|
|
||||||
func process_focus_movement(delta: float) -> void:
|
func process_focus_movement(delta: float, movement_speed: float) -> void:
|
||||||
var camera_forwards: Vector3 = -global_basis.z
|
var camera_forwards: Vector3 = -global_basis.z
|
||||||
camera_forwards = camera_forwards.slide(Vector3.UP).normalized()
|
camera_forwards = camera_forwards.slide(Vector3.UP).normalized()
|
||||||
|
|
||||||
|
@ -68,7 +73,7 @@ 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 * keyboard_movement_speed * delta
|
var movement: Vector3 = input * keyboard_movement_speed * delta * movement_speed
|
||||||
global_position += movement
|
global_position += movement
|
||||||
focus_position += movement
|
focus_position += movement
|
||||||
|
|
||||||
|
@ -82,7 +87,7 @@ func process_focus_movement(delta: float) -> void:
|
||||||
if result.has("position"):
|
if result.has("position"):
|
||||||
focus_position = result["position"]
|
focus_position = result["position"]
|
||||||
|
|
||||||
func process_camera_rotation(delta: float) -> void:
|
func process_camera_rotation(delta: float, movement_speed: float) -> void:
|
||||||
#var mouse_position: Vector2 = viewport.get_mouse_position()
|
#var mouse_position: Vector2 = viewport.get_mouse_position()
|
||||||
#var mouse_position: Vector2 = Vector2()
|
#var mouse_position: Vector2 = Vector2()
|
||||||
#var mouse_movement: Vector2 = (mouse_position - last_mouse_position) * delta
|
#var mouse_movement: Vector2 = (mouse_position - last_mouse_position) * delta
|
||||||
|
@ -95,10 +100,13 @@ func process_camera_rotation(delta: float) -> void:
|
||||||
look_at(focus_position)
|
look_at(focus_position)
|
||||||
mouse_movement = Vector2()
|
mouse_movement = Vector2()
|
||||||
|
|
||||||
func process_camera_zoom(_delta: float) -> void:
|
func process_camera_zoom(_delta: float, movement_speed: float) -> void:
|
||||||
#var wheel_input: float = Input.get_axis("camera_zoom_in", "camera_zoom_out")
|
#var wheel_input: float = Input.get_axis("camera_zoom_in", "camera_zoom_out")
|
||||||
var change: float = 1.0 + (-mouse_wheel_delta * zoom_sensitivity)
|
var change: float = 1.0 + (-mouse_wheel_delta * zoom_sensitivity)
|
||||||
focus_offset *= change
|
focus_offset *= change
|
||||||
|
focus_offset = focus_offset.limit_length(maximum_camera_distance)
|
||||||
|
if focus_offset.length() < minimum_camera_distance:
|
||||||
|
focus_offset = focus_offset.normalized() * minimum_camera_distance
|
||||||
mouse_wheel_delta = 0
|
mouse_wheel_delta = 0
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
func _input(event: InputEvent) -> void:
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
extends RefCounted
|
||||||
|
class_name UnitAction
|
||||||
|
|
||||||
|
var unit: Unit = null
|
||||||
|
var time_limit: float = 300.0
|
||||||
|
|
||||||
|
func process(delta: float) -> Unit.TaskStatus:
|
||||||
|
time_limit -= delta
|
||||||
|
if time_limit <= 0:
|
||||||
|
return Unit.TaskStatus.TIMED_OUT
|
||||||
|
return Unit.TaskStatus.DONE
|
||||||
|
|
||||||
|
class MoveAction extends UnitAction:
|
||||||
|
var last_distance_to_target: float = 99999999.9
|
||||||
|
var stuck_timer: float = 0.0
|
||||||
|
var move_target: Vector3 = Vector3(16, 1, 13):
|
||||||
|
set(target):
|
||||||
|
move_target = target
|
||||||
|
unit.nav_agent_3d.target_position = move_target
|
||||||
|
|
||||||
|
func process(delta: float) -> Unit.TaskStatus:
|
||||||
|
if unit.nav_agent_3d.is_navigation_finished():
|
||||||
|
#task_updated.emit(TaskStatus.DONE)
|
||||||
|
unit.target_velocity = Vector3()
|
||||||
|
#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()
|
||||||
|
if unit.nav_agent_3d.is_target_reachable():
|
||||||
|
return Unit.TaskStatus.DONE
|
||||||
|
else:
|
||||||
|
return Unit.TaskStatus.IMPOSSIBLE
|
||||||
|
else:
|
||||||
|
var next_point: Vector3 = unit.nav_agent_3d.get_next_path_position()
|
||||||
|
if unit.shapecast_3d.is_colliding():
|
||||||
|
var distance_to_target: float = unit.global_position.distance_to(next_point)
|
||||||
|
var progress_rate: float = (last_distance_to_target - distance_to_target) / delta
|
||||||
|
last_distance_to_target = distance_to_target
|
||||||
|
if progress_rate < unit.minimum_progress_rate:
|
||||||
|
stuck_timer += delta
|
||||||
|
if stuck_timer >= unit.stuck_time:
|
||||||
|
unit.unstuck()
|
||||||
|
else:
|
||||||
|
unit.label_3d.modulate = Color.WHITE
|
||||||
|
stuck_timer = 0
|
||||||
|
DebugDraw3D.draw_sphere(unit.nav_agent_3d.target_position, 0.5, Color.RED)
|
||||||
|
#DebugDraw3D.draw_sphere(next_point, 0.1, Color.YELLOW)
|
||||||
|
var direction: Vector3 = (next_point - unit.global_position).normalized()
|
||||||
|
#basis = Basis.looking_at(direction)
|
||||||
|
#DebugDraw3D.draw_line(global_position, global_position + linear_velocity, Color.BLUE)
|
||||||
|
unit.target_velocity = direction * unit.max_speed
|
||||||
|
unit.nav_agent_3d.velocity = unit.target_velocity
|
||||||
|
#DebugDraw3D.draw_line(global_position, global_positiaon + target_velocity, Color.MAGENTA)
|
||||||
|
#DebugDraw3D.draw_text(global_position + Vector3(0,1,0), "%f" % nav_agent_3d.distance_to_target())
|
||||||
|
return Unit.TaskStatus.IN_PROGRESS
|
||||||
|
|
||||||
|
class BuildAction extends UnitAction:
|
||||||
|
var building: Building
|
||||||
|
|
||||||
|
func process(delta: float) -> Unit.TaskStatus:
|
||||||
|
if building == null or building.is_queued_for_deletion():
|
||||||
|
return Unit.TaskStatus.IMPOSSIBLE
|
||||||
|
building.build_progress += delta
|
||||||
|
if building.build_state == Building.BuildState.READY:
|
||||||
|
return Unit.TaskStatus.DONE
|
||||||
|
elif building.build_state != Building.BuildState.BUILDING:
|
||||||
|
return Unit.TaskStatus.IMPOSSIBLE # can't build if the building's not there
|
||||||
|
else:
|
||||||
|
return Unit.TaskStatus.IN_PROGRESS
|
||||||
|
|
||||||
|
class RepairAction extends UnitAction:
|
||||||
|
var building: Building
|
||||||
|
|
||||||
|
func process(delta: float) -> Unit.TaskStatus:
|
||||||
|
if building == null or building.is_queued_for_deletion() or building.build_state != Building.BuildState.READY:
|
||||||
|
return Unit.TaskStatus.IMPOSSIBLE
|
||||||
|
building.hp += delta * 10.0
|
||||||
|
if building.hp >= building.max_hp:
|
||||||
|
building.hp = building.max_hp
|
||||||
|
return Unit.TaskStatus.DONE
|
||||||
|
return Unit.TaskStatus.IN_PROGRESS
|
|
@ -0,0 +1 @@
|
||||||
|
uid://cvmoolyvemu8s
|
|
@ -7,10 +7,6 @@ class_name Citizen
|
||||||
var task: Task = null
|
var task: Task = null
|
||||||
var working: bool = false
|
var working: bool = false
|
||||||
|
|
||||||
enum WorkStatus { NONE, CONSTRUCTING_BUILDING }
|
|
||||||
var work_status: WorkStatus
|
|
||||||
var work_building: Building = null
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
held_item_meshinstance = $"Body/Hands/Held Item"
|
held_item_meshinstance = $"Body/Hands/Held Item"
|
||||||
|
|
||||||
|
@ -39,13 +35,6 @@ func _process(delta: float) -> void:
|
||||||
CitizenManager._instance.add_task(task)
|
CitizenManager._instance.add_task(task)
|
||||||
task = null
|
task = null
|
||||||
working = false
|
working = false
|
||||||
|
|
||||||
if work_status == WorkStatus.CONSTRUCTING_BUILDING:
|
|
||||||
work_building.build_progress += delta
|
|
||||||
if work_building.build_state == Building.BuildState.READY:
|
|
||||||
send_task_update(TaskStatus.DONE)
|
|
||||||
elif work_building.build_state != Building.BuildState.BUILDING:
|
|
||||||
send_task_update(TaskStatus.IMPOSSIBLE)
|
|
||||||
|
|
||||||
func assign_task(t: Task) -> void:
|
func assign_task(t: Task) -> void:
|
||||||
task = t
|
task = t
|
||||||
|
@ -67,9 +56,8 @@ func put_item_in_building_storage(building: Building) -> bool:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
func build_building(building: Building) -> bool:
|
func build_building(building: Building) -> bool:
|
||||||
work_building = building
|
var build_action: UnitAction.BuildAction = UnitAction.BuildAction.new()
|
||||||
work_status = WorkStatus.CONSTRUCTING_BUILDING
|
build_action.building = building
|
||||||
|
action = build_action
|
||||||
var ok: bool = await wait_for_task_update() == TaskStatus.DONE
|
var ok: bool = await wait_for_task_update() == TaskStatus.DONE
|
||||||
work_building = null
|
|
||||||
work_status = WorkStatus.NONE
|
|
||||||
return ok
|
return ok
|
|
@ -1,7 +1,11 @@
|
||||||
extends Unit
|
extends Unit
|
||||||
class_name Enemy
|
class_name Enemy
|
||||||
|
|
||||||
var sighted: bool = true
|
var sighted: bool = true:
|
||||||
|
set(val):
|
||||||
|
sighted = val
|
||||||
|
visible = sighted
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
sighted = false
|
||||||
go_to_destination(Vector3(17,1,15))
|
go_to_destination(Vector3(17,1,15))
|
|
@ -17,13 +17,6 @@ class_name Unit
|
||||||
var target_velocity: Vector3 = Vector3()
|
var target_velocity: Vector3 = Vector3()
|
||||||
var avoidance_velocity: Vector3 = Vector3()
|
var avoidance_velocity: Vector3 = Vector3()
|
||||||
var avoidance_timeout: float = 0.0
|
var avoidance_timeout: float = 0.0
|
||||||
var last_distance_to_target: float = 0.0
|
|
||||||
var stuck_timer: float = 0.0
|
|
||||||
var moving: bool = false
|
|
||||||
var move_target: Vector3 = Vector3(16, 1, 13):
|
|
||||||
set(target):
|
|
||||||
move_target = target
|
|
||||||
nav_agent_3d.target_position = move_target
|
|
||||||
var move_radius: float = 5.0
|
var move_radius: float = 5.0
|
||||||
|
|
||||||
var held_item: Item = null:
|
var held_item: Item = null:
|
||||||
|
@ -39,9 +32,12 @@ var held_item: Item = null:
|
||||||
@onready var label_3d: Label3D = $Label3D
|
@onready var label_3d: Label3D = $Label3D
|
||||||
@onready var held_item_meshinstance: MeshInstance3D = null
|
@onready var held_item_meshinstance: MeshInstance3D = null
|
||||||
|
|
||||||
var action_timeout: float = 0.0
|
var action: UnitAction = null
|
||||||
|
|
||||||
|
var task_timeout: float = 0.0
|
||||||
|
|
||||||
enum TaskStatus {
|
enum TaskStatus {
|
||||||
|
IN_PROGRESS,
|
||||||
INTERRUPTED,
|
INTERRUPTED,
|
||||||
TIMED_OUT,
|
TIMED_OUT,
|
||||||
IMPOSSIBLE,
|
IMPOSSIBLE,
|
||||||
|
@ -61,59 +57,34 @@ func avoidance_velocity_computed(velocity: Vector3) -> void:
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
label_3d.text = "HP: %d" % hp
|
label_3d.text = "HP: %d" % hp
|
||||||
|
|
||||||
if action_timeout > 0:
|
if task_timeout > 0:
|
||||||
action_timeout -= delta
|
task_timeout -= delta
|
||||||
if action_timeout <= 0:
|
if task_timeout <= 0:
|
||||||
task_updated.emit(TaskStatus.TIMED_OUT)
|
send_task_update(TaskStatus.TIMED_OUT)
|
||||||
|
|
||||||
if moving:
|
if action != null:
|
||||||
if nav_agent_3d.is_target_reached() \
|
var status: TaskStatus = action.process(delta)
|
||||||
or nav_agent_3d.target_position.is_zero_approx() \
|
if status != TaskStatus.IN_PROGRESS:
|
||||||
or !nav_agent_3d.is_target_reachable():
|
action = null
|
||||||
moving = false
|
send_task_update(status)
|
||||||
task_updated.emit(TaskStatus.DONE)
|
|
||||||
target_velocity = Vector3()
|
if global_position.y <= -10:
|
||||||
#nav_agent_3d.target_position = move_target + Vector3(randfn(0, move_radius), 0, randfn(0, move_radius))
|
unstuck()
|
||||||
#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:
|
|
||||||
var next_point: Vector3 = nav_agent_3d.get_next_path_position()
|
|
||||||
if shapecast_3d.is_colliding():
|
|
||||||
var distance_to_target: float = global_position.distance_to(next_point)
|
|
||||||
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:
|
|
||||||
stuck_timer += delta
|
|
||||||
if stuck_timer >= stuck_time:
|
|
||||||
unstuck()
|
|
||||||
else:
|
|
||||||
label_3d.modulate = Color.WHITE
|
|
||||||
stuck_timer = 0
|
|
||||||
if global_position.y <= -10:
|
|
||||||
unstuck()
|
|
||||||
DebugDraw3D.draw_sphere(nav_agent_3d.target_position, 0.5, Color.RED)
|
|
||||||
#DebugDraw3D.draw_sphere(next_point, 0.1, Color.YELLOW)
|
|
||||||
var direction: Vector3 = (next_point - global_position).normalized()
|
|
||||||
#basis = Basis.looking_at(direction)
|
|
||||||
#DebugDraw3D.draw_line(global_position, global_position + linear_velocity, Color.BLUE)
|
|
||||||
target_velocity = direction * max_speed
|
|
||||||
nav_agent_3d.velocity = target_velocity
|
|
||||||
#DebugDraw3D.draw_line(global_position, global_positiaon + target_velocity, Color.MAGENTA)
|
|
||||||
#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 = nav_agent_3d.get_next_path_position()
|
global_position = nav_agent_3d.get_next_path_position()
|
||||||
stuck_timer = 0
|
|
||||||
|
|
||||||
func hurt(damage: float) -> void:
|
func hurt(damage: float) -> void:
|
||||||
hp -= damage
|
hp -= damage
|
||||||
|
interrupt()
|
||||||
#print("%s hit for %f damage, HP=%f" % [name, damage, hp])
|
#print("%s hit for %f damage, HP=%f" % [name, damage, hp])
|
||||||
if hp <= 0:
|
if hp <= 0:
|
||||||
die()
|
die()
|
||||||
|
|
||||||
func die() -> void:
|
func die() -> void:
|
||||||
|
interrupt()
|
||||||
queue_free()
|
queue_free()
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
|
@ -133,6 +104,9 @@ func _physics_process(delta: float) -> void:
|
||||||
#DebugDraw3D.draw_line(global_position, global_position - global_basis.z, Color.BLUE)
|
#DebugDraw3D.draw_line(global_position, global_position - global_basis.z, Color.BLUE)
|
||||||
#DebugDraw3D.draw_line(global_position, global_position + force_direction, Color.RED)
|
#DebugDraw3D.draw_line(global_position, global_position + force_direction, Color.RED)
|
||||||
|
|
||||||
|
func interrupt() -> void:
|
||||||
|
send_task_update(TaskStatus.INTERRUPTED)
|
||||||
|
|
||||||
func send_task_update(task_status: TaskStatus) -> void:
|
func send_task_update(task_status: TaskStatus) -> void:
|
||||||
task_updated.emit(task_status)
|
task_updated.emit(task_status)
|
||||||
|
|
||||||
|
@ -141,8 +115,11 @@ func wait_for_task_update() -> TaskStatus:
|
||||||
return status_received
|
return status_received
|
||||||
|
|
||||||
func go_to_destination(destination: Vector3) -> bool:
|
func go_to_destination(destination: Vector3) -> bool:
|
||||||
move_target = destination
|
var move_action: UnitAction.MoveAction = UnitAction.MoveAction.new()
|
||||||
moving = true
|
move_action.unit = self
|
||||||
|
move_action.move_target = destination
|
||||||
|
action = move_action
|
||||||
|
#move_target = destination
|
||||||
return (await wait_for_task_update()) == TaskStatus.DONE
|
return (await wait_for_task_update()) == TaskStatus.DONE
|
||||||
|
|
||||||
func take_item_from_building(item: Item, building: Building) -> bool:
|
func take_item_from_building(item: Item, building: Building) -> bool:
|
|
@ -0,0 +1,6 @@
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
func draw_raycast_hit(params: PhysicsRayQueryParameters3D, result: Dictionary, duration: float = 0.0) -> void:
|
||||||
|
var is_hit: bool = result.has("collider")
|
||||||
|
var hit_loc: Vector3 = result.get("position", params.to)
|
||||||
|
DebugDraw3D.draw_line_hit(params.from, params.to, hit_loc, is_hit, 0.25, Color.RED, Color.BLACK, duration)
|
|
@ -0,0 +1 @@
|
||||||
|
uid://c42mpvgqhysam
|
Loading…
Reference in New Issue