From adf1438bc86b1ee3e1b9b915794979e5fd3c93c5 Mon Sep 17 00:00:00 2001 From: djairoh Date: Mon, 26 Jan 2026 23:54:15 +0100 Subject: [PATCH] ft: nucleotide prey FSM --- .../molecular/molecular_player.gd | 2 +- .../molecular/molecular_stage.tscn | 5 ++- .../molecular/nucleotide_prey_foraging.gd | 17 --------- .../molecular/nucleotide_prey_state.gd | 6 ---- .../molecular/nucleotide_prey_state.gd.uid | 1 - .../molecular/{ => prey}/nucleotide_prey.gd | 11 ++++-- .../{ => prey}/nucleotide_prey.gd.uid | 0 .../molecular/{ => prey}/nucleotide_prey.tscn | 35 +++++++++++++------ .../molecular/prey/nucleotide_prey_fleeing.gd | 22 ++++++++++++ .../prey/nucleotide_prey_fleeing.gd.uid | 1 + .../molecular/prey/nucleotide_prey_idle.gd | 19 ++++++++++ .../prey/nucleotide_prey_idle.gd.uid | 1 + .../prey/nucleotide_prey_random_movement.gd | 20 +++++++++++ .../nucleotide_prey_random_movement.gd.uid} | 0 .../prey/nucleotide_prey_state_machine.gd | 17 +++++++++ .../prey/nucleotide_prey_state_machine.gd.uid | 1 + evolve-die-repeat/shared/npc/prey2D.gd | 3 -- evolve-die-repeat/shared/state_machine.gd | 5 ++- 18 files changed, 121 insertions(+), 45 deletions(-) delete mode 100644 evolve-die-repeat/molecular/nucleotide_prey_foraging.gd delete mode 100644 evolve-die-repeat/molecular/nucleotide_prey_state.gd delete mode 100644 evolve-die-repeat/molecular/nucleotide_prey_state.gd.uid rename evolve-die-repeat/molecular/{ => prey}/nucleotide_prey.gd (94%) rename evolve-die-repeat/molecular/{ => prey}/nucleotide_prey.gd.uid (100%) rename evolve-die-repeat/molecular/{ => prey}/nucleotide_prey.tscn (58%) create mode 100644 evolve-die-repeat/molecular/prey/nucleotide_prey_fleeing.gd create mode 100644 evolve-die-repeat/molecular/prey/nucleotide_prey_fleeing.gd.uid create mode 100644 evolve-die-repeat/molecular/prey/nucleotide_prey_idle.gd create mode 100644 evolve-die-repeat/molecular/prey/nucleotide_prey_idle.gd.uid create mode 100644 evolve-die-repeat/molecular/prey/nucleotide_prey_random_movement.gd rename evolve-die-repeat/molecular/{nucleotide_prey_foraging.gd.uid => prey/nucleotide_prey_random_movement.gd.uid} (100%) create mode 100644 evolve-die-repeat/molecular/prey/nucleotide_prey_state_machine.gd create mode 100644 evolve-die-repeat/molecular/prey/nucleotide_prey_state_machine.gd.uid diff --git a/evolve-die-repeat/molecular/molecular_player.gd b/evolve-die-repeat/molecular/molecular_player.gd index 534f636..3b0ee49 100644 --- a/evolve-die-repeat/molecular/molecular_player.gd +++ b/evolve-die-repeat/molecular/molecular_player.gd @@ -63,7 +63,7 @@ func _on_attack_hit(body: Node2D) -> void: var hit_hittable = false if body.is_in_group("prey") or body.is_in_group("predators"): if body.has_method("handle_damage"): - body.handle_damage(damage) + body.handle_damage(damage, self) hit_hittable = true elif body.is_in_group("resources"): pass diff --git a/evolve-die-repeat/molecular/molecular_stage.tscn b/evolve-die-repeat/molecular/molecular_stage.tscn index 15636f5..8db2608 100644 --- a/evolve-die-repeat/molecular/molecular_stage.tscn +++ b/evolve-die-repeat/molecular/molecular_stage.tscn @@ -5,7 +5,7 @@ [ext_resource type="Texture2D" uid="uid://c3cuhrmulyy1s" path="res://molecular/assets/background/bg-near.png" id="4_b1jr0"] [ext_resource type="Script" uid="uid://ceut2lrvkns75" path="res://debug_label.gd" id="4_mys4o"] [ext_resource type="Script" uid="uid://umx4w11edif" path="res://molecular/prey_manager.gd" id="5_cthuy"] -[ext_resource type="PackedScene" uid="uid://c3iw2v3x6ngrb" path="res://molecular/nucleotide_prey.tscn" id="6_a5cls"] +[ext_resource type="PackedScene" uid="uid://c3iw2v3x6ngrb" path="res://molecular/prey/nucleotide_prey.tscn" id="6_a5cls"] [sub_resource type="TileMapPattern" id="TileMapPattern_a5cls"] tile_data = PackedInt32Array(0, 65536, 2, 65536, 65536, 3, 1, 131072, 2, 65537, 131072, 3) @@ -108,9 +108,8 @@ text = "Debug: You made it into the game! This is running from C++: " script = ExtResource("4_mys4o") -[node name="PreyManager" type="Node" parent="." node_paths=PackedStringArray("cam")] +[node name="PreyManager" type="Node" parent="."] script = ExtResource("5_cthuy") -cam = NodePath("../player/Camera2D") scene = ExtResource("6_a5cls") minCount = 100 maxCount = 300 diff --git a/evolve-die-repeat/molecular/nucleotide_prey_foraging.gd b/evolve-die-repeat/molecular/nucleotide_prey_foraging.gd deleted file mode 100644 index 11f1757..0000000 --- a/evolve-die-repeat/molecular/nucleotide_prey_foraging.gd +++ /dev/null @@ -1,17 +0,0 @@ -extends NucleotidePreyState - -@onready var timer = $Timer -var dir: float = 0.0 - -func enter(previous_state_path: String, data := {}) -> void: - timer.start(randi() % 5) - dir = randi() % 360 - -func physics_update(_delta: float) -> void: - # TODO: move in direction of dir - pass - - -func _on_timer_timeout() -> void: - dir = randi() % 360 - timer.start(randi() % 5) diff --git a/evolve-die-repeat/molecular/nucleotide_prey_state.gd b/evolve-die-repeat/molecular/nucleotide_prey_state.gd deleted file mode 100644 index f3140c5..0000000 --- a/evolve-die-repeat/molecular/nucleotide_prey_state.gd +++ /dev/null @@ -1,6 +0,0 @@ -class_name NucleotidePreyState extends State - -enum State {IDLE, FORAGING, FEEDING, FLEEING} - -func _ready() -> void: - await owner.ready diff --git a/evolve-die-repeat/molecular/nucleotide_prey_state.gd.uid b/evolve-die-repeat/molecular/nucleotide_prey_state.gd.uid deleted file mode 100644 index 55b2c6a..0000000 --- a/evolve-die-repeat/molecular/nucleotide_prey_state.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c7o7sp02u0wkv diff --git a/evolve-die-repeat/molecular/nucleotide_prey.gd b/evolve-die-repeat/molecular/prey/nucleotide_prey.gd similarity index 94% rename from evolve-die-repeat/molecular/nucleotide_prey.gd rename to evolve-die-repeat/molecular/prey/nucleotide_prey.gd index f1ca09c..337ae27 100644 --- a/evolve-die-repeat/molecular/nucleotide_prey.gd +++ b/evolve-die-repeat/molecular/prey/nucleotide_prey.gd @@ -1,6 +1,7 @@ extends AbstractPrey2D @onready var sprite = get_node("AnimatedSprite2D") +@onready var fsm = $StateMachine # Mirroed sprites for periodic boundary var mirrorSprite1: Node2D @@ -29,6 +30,7 @@ func _process(delta: float) -> void: func _physics_process(delta: float) -> void: #self.move(Vector3(randfn(0, 1), randfn(0, 1), 0)) + # TODO: state transition logic (bot controller code) pass func move(motion: Vector3) -> void: @@ -37,13 +39,14 @@ func move(motion: Vector3) -> void: # Apply boundary to new position position = GameManager.get_boundaried_position(position) -func handle_damage(dmg: int) -> void: +func handle_damage(dmg: int, src: Node) -> void: health = max(0, health-dmg) if health == 0: die() if health < maxHealth: become_injured() - + fsm.transition_to_next_state(fsm.States.FLEEING, {"threat": src}) + func die() -> void: sprite.play("Dying") super.die() @@ -143,3 +146,7 @@ func _handle_wrapping(): mirrorSprite3.position = Vector2(0, - GameManager.screen_size.y) + + +func _on_timer_timeout() -> void: + pass # Replace with function body. diff --git a/evolve-die-repeat/molecular/nucleotide_prey.gd.uid b/evolve-die-repeat/molecular/prey/nucleotide_prey.gd.uid similarity index 100% rename from evolve-die-repeat/molecular/nucleotide_prey.gd.uid rename to evolve-die-repeat/molecular/prey/nucleotide_prey.gd.uid diff --git a/evolve-die-repeat/molecular/nucleotide_prey.tscn b/evolve-die-repeat/molecular/prey/nucleotide_prey.tscn similarity index 58% rename from evolve-die-repeat/molecular/nucleotide_prey.tscn rename to evolve-die-repeat/molecular/prey/nucleotide_prey.tscn index e40fea2..0d61720 100644 --- a/evolve-die-repeat/molecular/nucleotide_prey.tscn +++ b/evolve-die-repeat/molecular/prey/nucleotide_prey.tscn @@ -1,15 +1,17 @@ -[gd_scene load_steps=12 format=3 uid="uid://c3iw2v3x6ngrb"] +[gd_scene load_steps=14 format=3 uid="uid://c3iw2v3x6ngrb"] [ext_resource type="PackedScene" uid="uid://bvsdg1v3ksixy" path="res://shared/npc/prey2D.tscn" id="1_qvulj"] -[ext_resource type="Script" uid="uid://bgossk6xo31gi" path="res://molecular/nucleotide_prey.gd" id="2_0227s"] +[ext_resource type="Script" uid="uid://bgossk6xo31gi" path="res://molecular/prey/nucleotide_prey.gd" id="2_0227s"] [ext_resource type="Texture2D" uid="uid://bhcb5g7g7um8" path="res://molecular/assets/prey/prey-dying-frame0.png" id="2_lkj7f"] [ext_resource type="Texture2D" uid="uid://bxn11avw7dykl" path="res://molecular/assets/prey/prey-dying-frame1.png" id="3_svqyr"] [ext_resource type="Texture2D" uid="uid://ctkehsavw6ghx" path="res://molecular/assets/prey/prey-healthy-frame0.png" id="4_ee1gb"] [ext_resource type="Texture2D" uid="uid://uy28y3mkk6nt" path="res://molecular/assets/prey/prey-healthy-frame1.png" id="5_ae5nf"] [ext_resource type="Texture2D" uid="uid://btnyajci8ptb2" path="res://molecular/assets/prey/prey-injured-frame0.png" id="6_0f87h"] [ext_resource type="Texture2D" uid="uid://bqll8ge4cr2uf" path="res://molecular/assets/prey/prey-injured-frame1.png" id="7_w7inl"] -[ext_resource type="Script" uid="uid://c7o7sp02u0wkv" path="res://molecular/nucleotide_prey_state.gd" id="9_guu3v"] -[ext_resource type="Script" uid="uid://ubcu8fdfxxj1" path="res://molecular/nucleotide_prey_foraging.gd" id="10_rgguv"] +[ext_resource type="Script" uid="uid://0vwv2nt16gpv" path="res://molecular/prey/nucleotide_prey_state_machine.gd" id="9_xxtgy"] +[ext_resource type="Script" uid="uid://ubcu8fdfxxj1" path="res://molecular/prey/nucleotide_prey_random_movement.gd" id="10_rgguv"] +[ext_resource type="Script" uid="uid://xbiqj7ubmj7d" path="res://molecular/prey/nucleotide_prey_idle.gd" id="12_ubfhk"] +[ext_resource type="Script" uid="uid://dlw7inlh6asvu" path="res://molecular/prey/nucleotide_prey_fleeing.gd" id="12_xxtgy"] [sub_resource type="SpriteFrames" id="SpriteFrames_66x8p"] animations = [{ @@ -58,15 +60,26 @@ scale = Vector2(0.1, 0.1) sprite_frames = SubResource("SpriteFrames_66x8p") animation = &"Injured" -[node name="State" type="Node" parent="." index="2"] -script = ExtResource("9_guu3v") -metadata/_custom_type_script = "uid://co2xp7gauamql" +[node name="StateMachine" type="Node" parent="." index="2" node_paths=PackedStringArray("initial_state")] +script = ExtResource("9_xxtgy") +initial_state = NodePath("Idle") +metadata/_custom_type_script = "uid://ck7k8ht54snsy" -[node name="Foraging" type="Node" parent="State" index="0"] +[node name="RandomMovement" type="Node" parent="StateMachine" index="0"] script = ExtResource("10_rgguv") -metadata/_custom_type_script = "uid://c7o7sp02u0wkv" -[node name="Timer" type="Timer" parent="State/Foraging" index="0"] +[node name="Timer" type="Timer" parent="StateMachine/RandomMovement" index="0"] one_shot = true -[connection signal="timeout" from="State/Foraging/Timer" to="State/Foraging" method="_on_timer_timeout"] +[node name="Fleeing" type="Node" parent="StateMachine" index="1"] +script = ExtResource("12_xxtgy") + +[node name="Idle" type="Node" parent="StateMachine" index="2"] +script = ExtResource("12_ubfhk") +metadata/_custom_type_script = "uid://co2xp7gauamql" + +[node name="Timer" type="Timer" parent="StateMachine/Idle" index="0"] +one_shot = true + +[connection signal="timeout" from="StateMachine/RandomMovement/Timer" to="StateMachine/RandomMovement" method="_on_timer_timeout"] +[connection signal="timeout" from="StateMachine/Idle/Timer" to="StateMachine/Idle" method="_on_timer_timeout"] diff --git a/evolve-die-repeat/molecular/prey/nucleotide_prey_fleeing.gd b/evolve-die-repeat/molecular/prey/nucleotide_prey_fleeing.gd new file mode 100644 index 0000000..8d95e07 --- /dev/null +++ b/evolve-die-repeat/molecular/prey/nucleotide_prey_fleeing.gd @@ -0,0 +1,22 @@ +extends State + +var threat: Node2D +var threshold: float = 100 + +func enter(previous_state_path: String, data := {}) -> void: + if data.has("threat"): + threat = data["threat"] + else: + # default behaviour; do nothing + threat = owner + +func physics_update(_delta: float) -> void: + if owner.position.distance_to(threat.position) > threshold: + finished.emit(owner.fsm.States.IDLE, {}) + return + owner.move(flee_from(threat.position)) + +func flee_from(pos: Vector2) -> Vector3: + var diff = threat.position - owner.position + diff = diff.normalized() * -1 + return Vector3(diff.x, diff.y ,0) diff --git a/evolve-die-repeat/molecular/prey/nucleotide_prey_fleeing.gd.uid b/evolve-die-repeat/molecular/prey/nucleotide_prey_fleeing.gd.uid new file mode 100644 index 0000000..5dcef9a --- /dev/null +++ b/evolve-die-repeat/molecular/prey/nucleotide_prey_fleeing.gd.uid @@ -0,0 +1 @@ +uid://dlw7inlh6asvu diff --git a/evolve-die-repeat/molecular/prey/nucleotide_prey_idle.gd b/evolve-die-repeat/molecular/prey/nucleotide_prey_idle.gd new file mode 100644 index 0000000..9759503 --- /dev/null +++ b/evolve-die-repeat/molecular/prey/nucleotide_prey_idle.gd @@ -0,0 +1,19 @@ +extends State + +@onready var timer = $Timer + + +func enter(previous_state_path: String, data := {}) -> void: + timer.start((float)(randi() % 5)/5) + +func physics_update(_delta: float) -> void: + owner.move(Vector3(randfn(0, 1), randfn(0, 1), 0)) + +func _on_timer_timeout() -> void: + if (randi() % 4 != 0): + finished.emit(owner.fsm.States.RANDOMMOVEMENT, {}) + else: + finished.emit(owner.fsm.States.IDLE, {}) + +func exit() -> void: + timer.stop() diff --git a/evolve-die-repeat/molecular/prey/nucleotide_prey_idle.gd.uid b/evolve-die-repeat/molecular/prey/nucleotide_prey_idle.gd.uid new file mode 100644 index 0000000..7500f86 --- /dev/null +++ b/evolve-die-repeat/molecular/prey/nucleotide_prey_idle.gd.uid @@ -0,0 +1 @@ +uid://xbiqj7ubmj7d diff --git a/evolve-die-repeat/molecular/prey/nucleotide_prey_random_movement.gd b/evolve-die-repeat/molecular/prey/nucleotide_prey_random_movement.gd new file mode 100644 index 0000000..3a48457 --- /dev/null +++ b/evolve-die-repeat/molecular/prey/nucleotide_prey_random_movement.gd @@ -0,0 +1,20 @@ +extends State + +@onready var timer = $Timer +var dir: Vector3 = Vector3(0,0,0); + +func enter(previous_state_path: String, data := {}) -> void: + timer.start((float)(randi() % 10)/20) + dir = calc_dir(randi() % 360) + +func physics_update(_delta: float) -> void: + owner.move(dir) + +func calc_dir(angle: float) -> Vector3: + return Vector3(cos(angle), sin(angle), 0) + +func _on_timer_timeout() -> void: + finished.emit(owner.fsm.States.IDLE, {}) + +func exit() -> void: + timer.stop() diff --git a/evolve-die-repeat/molecular/nucleotide_prey_foraging.gd.uid b/evolve-die-repeat/molecular/prey/nucleotide_prey_random_movement.gd.uid similarity index 100% rename from evolve-die-repeat/molecular/nucleotide_prey_foraging.gd.uid rename to evolve-die-repeat/molecular/prey/nucleotide_prey_random_movement.gd.uid diff --git a/evolve-die-repeat/molecular/prey/nucleotide_prey_state_machine.gd b/evolve-die-repeat/molecular/prey/nucleotide_prey_state_machine.gd new file mode 100644 index 0000000..6a1fe5f --- /dev/null +++ b/evolve-die-repeat/molecular/prey/nucleotide_prey_state_machine.gd @@ -0,0 +1,17 @@ +extends StateMachine + +enum States {IDLE, RANDOMMOVEMENT, FEEDING, FLEEING} + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + super() + await owner.ready + + +func transition_to_next_state(target: int, data: Dictionary = {}) -> void: + match target: + States.IDLE: _transition_to_next_state("Idle", data) + States.RANDOMMOVEMENT: _transition_to_next_state("RandomMovement", data) + States.FEEDING: _transition_to_next_state("Feeding", data) + States.FLEEING: _transition_to_next_state("Fleeing", data) + _: push_error("Trying to transition to unknown state {target}") diff --git a/evolve-die-repeat/molecular/prey/nucleotide_prey_state_machine.gd.uid b/evolve-die-repeat/molecular/prey/nucleotide_prey_state_machine.gd.uid new file mode 100644 index 0000000..b13f908 --- /dev/null +++ b/evolve-die-repeat/molecular/prey/nucleotide_prey_state_machine.gd.uid @@ -0,0 +1 @@ +uid://0vwv2nt16gpv diff --git a/evolve-die-repeat/shared/npc/prey2D.gd b/evolve-die-repeat/shared/npc/prey2D.gd index 1013af6..1f2091f 100644 --- a/evolve-die-repeat/shared/npc/prey2D.gd +++ b/evolve-die-repeat/shared/npc/prey2D.gd @@ -1,9 +1,6 @@ extends NPC2D class_name AbstractPrey2D -enum States {IDLE, FORAGING, FLEEING} -var state = States.IDLE - # Called when the node enters the scene tree for the first time. func _ready() -> void: diff --git a/evolve-die-repeat/shared/state_machine.gd b/evolve-die-repeat/shared/state_machine.gd index 33fd0f2..4af2e2b 100644 --- a/evolve-die-repeat/shared/state_machine.gd +++ b/evolve-die-repeat/shared/state_machine.gd @@ -10,7 +10,7 @@ class_name StateMachine extends Node # Connect states on ready, then wait. func _ready() -> void: for node: State in find_children("*", "State"): - node.finished.connect(_transition_to_next_state) + node.finished.connect(transition_to_next_state) await owner.ready state.enter("") @@ -37,3 +37,6 @@ func _transition_to_next_state(target_path: String, data: Dictionary = {}) -> vo state.exit() state = get_node(target_path) state.enter(previous_state_path, data) + +func transition_to_next_state(target: int, data: Dictionary = {}) -> void: + push_error("Child FSM failed to implement transition function.")