From a3d98df9ff78b685ed4a3d8786ee878d54c6f4c2 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 16 Apr 2024 02:47:31 +0200 Subject: [PATCH] Refactor movement and entity logic --- behaviours/ai_hunter_erratic.tscn | 23 ++++++++++++ behaviours/ai_hunter_latest.tscn | 19 ++++++++++ behaviours/ai_hunter_persistent.tscn | 19 ++++++++++ behaviours/ai_hunter_random.tscn | 23 ++++++++++++ behaviours/edible_tracker.gd | 26 ++----------- behaviours/edible_tracker.tscn | 11 ++++-- behaviours/hunt_target.gd | 55 ---------------------------- behaviours/hunt_target.tscn | 18 --------- behaviours/move_towards.gd | 14 +++++-- behaviours/move_towards_mouse.tscn | 2 +- behaviours/skitter_from_mouse.tscn | 2 +- behaviours/target_picker.gd | 44 ++++++++++++++++++++++ behaviours/target_picker.svg | 39 ++++++++++++++++++++ behaviours/target_picker.svg.import | 37 +++++++++++++++++++ behaviours/target_picker.tscn | 6 +++ behaviours/tracker.gd | 31 ++++++++++++++++ 16 files changed, 265 insertions(+), 104 deletions(-) create mode 100644 behaviours/ai_hunter_erratic.tscn create mode 100644 behaviours/ai_hunter_latest.tscn create mode 100644 behaviours/ai_hunter_persistent.tscn create mode 100644 behaviours/ai_hunter_random.tscn delete mode 100644 behaviours/hunt_target.gd delete mode 100644 behaviours/hunt_target.tscn create mode 100644 behaviours/target_picker.gd create mode 100644 behaviours/target_picker.svg create mode 100644 behaviours/target_picker.svg.import create mode 100644 behaviours/target_picker.tscn create mode 100644 behaviours/tracker.gd diff --git a/behaviours/ai_hunter_erratic.tscn b/behaviours/ai_hunter_erratic.tscn new file mode 100644 index 0000000..b901118 --- /dev/null +++ b/behaviours/ai_hunter_erratic.tscn @@ -0,0 +1,23 @@ +[gd_scene load_steps=4 format=3 uid="uid://cgq2jkbrw1y0o"] + +[ext_resource type="PackedScene" uid="uid://ctpn4hvkhxoi3" path="res://behaviours/edible_tracker.tscn" id="1_h53ag"] +[ext_resource type="PackedScene" uid="uid://dti7l0d40hhgt" path="res://behaviours/target_picker.tscn" id="2_h4v3e"] +[ext_resource type="Script" path="res://behaviours/move_towards.gd" id="3_ucief"] + +[node name="AIHunterRandom" type="Node2D"] + +[node name="EdibleTracker" parent="." instance=ExtResource("1_h53ag")] + +[node name="Timer" type="Timer" parent="."] +wait_time = 2.4 +autostart = true + +[node name="TargetPicker" parent="." node_paths=PackedStringArray("tracker") instance=ExtResource("2_h4v3e")] +tracker = NodePath("../EdibleTracker") + +[node name="MoveTowards" type="Node2D" parent="."] +script = ExtResource("3_ucief") + +[connection signal="untracked" from="EdibleTracker" to="TargetPicker" method="clear_if_target"] +[connection signal="timeout" from="Timer" to="TargetPicker" method="sample_target"] +[connection signal="target_changed" from="TargetPicker" to="MoveTowards" method="set_target" unbinds=1] diff --git a/behaviours/ai_hunter_latest.tscn b/behaviours/ai_hunter_latest.tscn new file mode 100644 index 0000000..35f9a37 --- /dev/null +++ b/behaviours/ai_hunter_latest.tscn @@ -0,0 +1,19 @@ +[gd_scene load_steps=4 format=3 uid="uid://cgnvp5bmtbpxr"] + +[ext_resource type="Script" path="res://behaviours/move_towards.gd" id="1_demja"] +[ext_resource type="PackedScene" uid="uid://ctpn4hvkhxoi3" path="res://behaviours/edible_tracker.tscn" id="2_jlt4x"] +[ext_resource type="PackedScene" uid="uid://dti7l0d40hhgt" path="res://behaviours/target_picker.tscn" id="3_lfvrb"] + +[node name="AIHunterLatest" type="Node2D"] + +[node name="EdibleTracker" parent="." instance=ExtResource("2_jlt4x")] + +[node name="TargetPicker" parent="." node_paths=PackedStringArray("tracker") instance=ExtResource("3_lfvrb")] +tracker = NodePath("../EdibleTracker") + +[node name="MoveTowards" type="Node2D" parent="."] +script = ExtResource("1_demja") + +[connection signal="tracked" from="EdibleTracker" to="TargetPicker" method="set_target"] +[connection signal="untracked" from="EdibleTracker" to="TargetPicker" method="clear_if_target"] +[connection signal="target_changed" from="TargetPicker" to="MoveTowards" method="set_target" unbinds=1] diff --git a/behaviours/ai_hunter_persistent.tscn b/behaviours/ai_hunter_persistent.tscn new file mode 100644 index 0000000..7574354 --- /dev/null +++ b/behaviours/ai_hunter_persistent.tscn @@ -0,0 +1,19 @@ +[gd_scene load_steps=4 format=3 uid="uid://cpq0ubwun5wec"] + +[ext_resource type="PackedScene" uid="uid://ctpn4hvkhxoi3" path="res://behaviours/edible_tracker.tscn" id="1_j87ny"] +[ext_resource type="PackedScene" uid="uid://dti7l0d40hhgt" path="res://behaviours/target_picker.tscn" id="2_w2vxl"] +[ext_resource type="Script" path="res://behaviours/move_towards.gd" id="3_14yk3"] + +[node name="AIHunterLatest" type="Node2D"] + +[node name="EdibleTracker" parent="." instance=ExtResource("1_j87ny")] + +[node name="TargetPicker" parent="." node_paths=PackedStringArray("tracker") instance=ExtResource("2_w2vxl")] +tracker = NodePath("../EdibleTracker") + +[node name="MoveTowards" type="Node2D" parent="."] +script = ExtResource("3_14yk3") + +[connection signal="tracked" from="EdibleTracker" to="TargetPicker" method="set_target_if_null"] +[connection signal="untracked" from="EdibleTracker" to="TargetPicker" method="clear_if_target"] +[connection signal="target_changed" from="TargetPicker" to="MoveTowards" method="set_target" unbinds=1] diff --git a/behaviours/ai_hunter_random.tscn b/behaviours/ai_hunter_random.tscn new file mode 100644 index 0000000..e97f0d4 --- /dev/null +++ b/behaviours/ai_hunter_random.tscn @@ -0,0 +1,23 @@ +[gd_scene load_steps=4 format=3 uid="uid://baiq3nu3p03rh"] + +[ext_resource type="Script" path="res://behaviours/move_towards.gd" id="1_wlo1a"] +[ext_resource type="PackedScene" uid="uid://ctpn4hvkhxoi3" path="res://behaviours/edible_tracker.tscn" id="2_suoff"] +[ext_resource type="PackedScene" uid="uid://dti7l0d40hhgt" path="res://behaviours/target_picker.tscn" id="3_0uxc2"] + +[node name="AIHunterRandom" type="Node2D"] + +[node name="EdibleTracker" parent="." instance=ExtResource("2_suoff")] + +[node name="Timer" type="Timer" parent="."] +wait_time = 2.4 +autostart = true + +[node name="TargetPicker" parent="." node_paths=PackedStringArray("tracker") instance=ExtResource("3_0uxc2")] +tracker = NodePath("../EdibleTracker") + +[node name="MoveTowards" type="Node2D" parent="."] +script = ExtResource("1_wlo1a") + +[connection signal="untracked" from="EdibleTracker" to="TargetPicker" method="clear_if_target"] +[connection signal="timeout" from="Timer" to="TargetPicker" method="sample_target_if_null"] +[connection signal="target_changed" from="TargetPicker" to="MoveTowards" method="set_target" unbinds=1] diff --git a/behaviours/edible_tracker.gd b/behaviours/edible_tracker.gd index bcf1bef..6580828 100644 --- a/behaviours/edible_tracker.gd +++ b/behaviours/edible_tracker.gd @@ -1,34 +1,16 @@ @icon("res://behaviours/edible_tracker.svg") -extends Area2D +extends Tracker class_name EdibleTracker ## Keeps track of what [Edible]s are inside the area. -signal tracked(body: Node2D) -signal untracked(body: Node2D) - - @export var acceptable_diets: Array[StringName] = [] -var tracking: Array = [] - -func _on_body_entered(body: Node2D) -> void: +func check_diet_then_track(body: Node2D) -> void: var edibles: Array = body.find_children("Edible", "Edible", false, false) for edible in edibles: if edible.tag in acceptable_diets: - tracking.push_back(body) - tracked.emit(body) - -func _on_body_exited(body: Node2D) -> void: - if body in tracking: - tracking.erase(body) - untracked.emit(body) - - -func _on_tracked(body: Node2D) -> void: - Log.p(self, "Tracking a new target: %s" % body) - -func _on_untracked(body:Node2D) -> void: - Log.p(self, "Not tracking anymore target: %s" % body) + track(body) + break diff --git a/behaviours/edible_tracker.tscn b/behaviours/edible_tracker.tscn index 2d75fbd..ebad30a 100644 --- a/behaviours/edible_tracker.tscn +++ b/behaviours/edible_tracker.tscn @@ -3,9 +3,12 @@ [ext_resource type="Script" path="res://behaviours/edible_tracker.gd" id="1_vo18u"] [node name="EdibleTracker" type="Area2D"] +collision_layer = 0 +collision_mask = 56 +monitorable = false script = ExtResource("1_vo18u") -[connection signal="body_entered" from="." to="." method="_on_body_entered"] -[connection signal="body_exited" from="." to="." method="_on_body_exited"] -[connection signal="tracked" from="." to="." method="_on_tracked"] -[connection signal="untracked" from="." to="." method="_on_untracked"] +[connection signal="body_entered" from="." to="." method="check_diet_then_track"] +[connection signal="body_exited" from="." to="." method="untrack"] +[connection signal="tracked" from="." to="." method="log_tracked"] +[connection signal="untracked" from="." to="." method="log_untracked"] diff --git a/behaviours/hunt_target.gd b/behaviours/hunt_target.gd deleted file mode 100644 index cdd7f9c..0000000 --- a/behaviours/hunt_target.gd +++ /dev/null @@ -1,55 +0,0 @@ -extends Node2D -class_name HuntTarget - - -signal target_selected(target: Node2D) -signal target_abandoned(target: Node2D) - - -@export var tag: StringName: - get: - return tag - set(value): - tag = value - if hunter != null: - hunter.tag = value - -@export var give_up_secs: float = 5.0 - -@onready var give_up_timer: Timer = $"GiveUpTimer" -@onready var hunter: Hunter = $"Hunter" - -var target: Node2D = null - - -func pick_new_target(): - if hunter.possible_targets.is_empty(): - return - - var idx = Random.rng.randi_range(0, len(hunter.possible_targets) - 1) - target = hunter.possible_targets[idx] - target_selected.emit(target) - give_up_timer.start(give_up_secs) - -func _ready(): - hunter.tag = tag - -func _on_hunter_tracked(_body: Node2D): - if target == null: - pick_new_target() - -func _on_hunter_untracked(body: Node2D): - if body == target: - target = null - target_abandoned.emit(body) - pick_new_target() - -func _on_give_up_timer_timeout() -> void: - target = null - pick_new_target() - -func _on_target_selected(body: Node2D) -> void: - Log.p(self, "Target selected: %s" % body) - -func _on_target_abandoned(body: Node2D) -> void: - Log.p(self, "Target abandoned: %s" % body) diff --git a/behaviours/hunt_target.tscn b/behaviours/hunt_target.tscn deleted file mode 100644 index dc8bf57..0000000 --- a/behaviours/hunt_target.tscn +++ /dev/null @@ -1,18 +0,0 @@ -[gd_scene load_steps=3 format=3 uid="uid://dxmodn8mbvw0i"] - -[ext_resource type="Script" path="res://behaviours/hunt_target.gd" id="1_1ex7u"] -[ext_resource type="PackedScene" uid="uid://ctpn4hvkhxoi3" path="res://behaviours/edible_tracker.tscn" id="2_vjdtc"] - -[node name="HuntTarget" type="Node2D"] -script = ExtResource("1_1ex7u") -give_up_secs = null - -[node name="Hunter" parent="." instance=ExtResource("2_vjdtc")] - -[node name="GiveUpTimer" type="Timer" parent="."] - -[connection signal="target_abandoned" from="." to="." method="_on_target_abandoned"] -[connection signal="target_selected" from="." to="." method="_on_target_selected"] -[connection signal="tracked" from="Hunter" to="." method="_on_hunter_tracked"] -[connection signal="untracked" from="Hunter" to="." method="_on_hunter_untracked"] -[connection signal="timeout" from="GiveUpTimer" to="." method="_on_give_up_timer_timeout"] diff --git a/behaviours/move_towards.gd b/behaviours/move_towards.gd index e0593a5..2c24b82 100644 --- a/behaviours/move_towards.gd +++ b/behaviours/move_towards.gd @@ -12,11 +12,19 @@ signal move(norm: Vector2) @export var target: Node2D = null +func set_target(value: Node2D) -> void: + target = value + +func clear_target() -> void: + target = null + + func _ready() -> void: if target == null: Log.w(self, "No target is set, no signals will be emitted.") func _physics_process(_delta: float) -> void: - var gap = target.global_position - global_position - var norm = gap.normalized() - move.emit(norm) + if target: + var gap = target.global_position - global_position + var norm = gap.normalized() + move.emit(norm) diff --git a/behaviours/move_towards_mouse.tscn b/behaviours/move_towards_mouse.tscn index ab15a6f..b971d07 100644 --- a/behaviours/move_towards_mouse.tscn +++ b/behaviours/move_towards_mouse.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=3 uid="uid://bvrxvrjlo5130"] [ext_resource type="Script" path="res://behaviours/move_towards_mouse.gd" id="1_nbja1"] -[ext_resource type="PackedScene" uid="uid://cbg5kgwxusvxf" path="res://behaviours/hover_detector.tscn" id="2_qru2e"] +[ext_resource type="PackedScene" uid="uid://cbg5kgwxusvxf" path="res://behaviours/cursor_detector.tscn" id="2_qru2e"] [node name="MoveTowardsMouse" type="Node2D"] script = ExtResource("1_nbja1") diff --git a/behaviours/skitter_from_mouse.tscn b/behaviours/skitter_from_mouse.tscn index 8984d7a..e931c06 100644 --- a/behaviours/skitter_from_mouse.tscn +++ b/behaviours/skitter_from_mouse.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=3 uid="uid://c1wqgyakaultt"] [ext_resource type="Script" path="res://behaviours/skitter_from_mouse.gd" id="1_ftcf8"] -[ext_resource type="PackedScene" uid="uid://cbg5kgwxusvxf" path="res://behaviours/hover_detector.tscn" id="2_cuaq0"] +[ext_resource type="PackedScene" uid="uid://cbg5kgwxusvxf" path="res://behaviours/cursor_detector.tscn" id="2_cuaq0"] [node name="SkitterFromMouse" type="Node2D"] script = ExtResource("1_ftcf8") diff --git a/behaviours/target_picker.gd b/behaviours/target_picker.gd new file mode 100644 index 0000000..d2f2f72 --- /dev/null +++ b/behaviours/target_picker.gd @@ -0,0 +1,44 @@ +@icon("res://behaviours/target_picker.svg") +extends Node +class_name TargetPicker + + +## Pick a random target at random from [field Tracker.tracked], then emit it via [signal target_changed]. + + +signal target_changed(new: Node2D, old: Node2D) + + +@export var tracker: Tracker + + +var target: Node2D: + get: + return target + set(value): + if target != value: + var old = target + target = value + target_changed.emit(old, target) + + +func set_target(body: Node2D) -> void: + target = body + +func set_target_if_null(body: Node2D) -> void: + if target == null: + target = body + +func clear_target() -> void: + target = null + +func clear_if_target(body: Node2D) -> void: + if target == body: + clear_target() + +func sample_target() -> void: + target = Random.sample(tracker.tracking) + +func sample_target_if_null() -> void: + if target == null: + sample_target() diff --git a/behaviours/target_picker.svg b/behaviours/target_picker.svg new file mode 100644 index 0000000..d8fead7 --- /dev/null +++ b/behaviours/target_picker.svg @@ -0,0 +1,39 @@ + + + + + + + diff --git a/behaviours/target_picker.svg.import b/behaviours/target_picker.svg.import new file mode 100644 index 0000000..43feff3 --- /dev/null +++ b/behaviours/target_picker.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dd7uvjl416h2k" +path="res://.godot/imported/target_picker.svg-d96365c33742930a50d2b51102fd20f0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://behaviours/target_picker.svg" +dest_files=["res://.godot/imported/target_picker.svg-d96365c33742930a50d2b51102fd20f0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/behaviours/target_picker.tscn b/behaviours/target_picker.tscn new file mode 100644 index 0000000..8056ebd --- /dev/null +++ b/behaviours/target_picker.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://dti7l0d40hhgt"] + +[ext_resource type="Script" path="res://behaviours/target_picker.gd" id="1_ldiw7"] + +[node name="TargetPicker" type="Node"] +script = ExtResource("1_ldiw7") diff --git a/behaviours/tracker.gd b/behaviours/tracker.gd new file mode 100644 index 0000000..111072f --- /dev/null +++ b/behaviours/tracker.gd @@ -0,0 +1,31 @@ +extends Area2D +class_name Tracker + +## Abstract base class for [Area2D]s tracking a certain subset of [Node2D]s. + + +signal tracked(body: Node2D) +signal untracked(body: Node2D) + +var tracking: Array = [] + + +func track(body: Node2D) -> bool: + var act: bool = not body in tracking + if act: + tracking.push_back(body) + tracked.emit(body) + return act + +func untrack(body: Node2D) -> bool: + var act: bool = body in tracking + if act: + tracking.erase(body) + untracked.emit(body) + return act + +func log_tracked(body: Node2D) -> void: + Log.p(self, "Tracking a new target: %s" % body) + +func log_untracked(body: Node2D) -> void: + Log.p(self, "Not tracking anymore target: %s" % body)