From bc582efb90505dab8b4b1c5cabad7df5ea843447 Mon Sep 17 00:00:00 2001 From: Djairo Date: Sat, 7 Feb 2026 18:01:17 +0100 Subject: [PATCH] ft (wip): tracking across boundaries --- evolve-die-repeat/game_manager.gd | 40 ++++++++++++- .../molecular/food/food_mol.tscn | 3 +- .../molecular/predator/hammerhead_predator.gd | 3 +- .../predator/hammerhead_predator.tscn | 17 +++--- .../molecular/predator/state_hunting.gd | 4 +- .../molecular/prey/nucleotide_prey.tscn | 3 +- .../molecular/prey/state_fleeing.gd | 2 +- evolve-die-repeat/shared/npc/npc2D.gd | 1 + evolve-die-repeat/shared/npc/predator2D.gd | 1 + evolve-die-repeat/shared/npc/prey2D.gd | 1 + evolve-die-repeat/shared/state_machine.gd | 1 + evolve-die-repeat/shared/wrapping_manager.gd | 60 +++++++++++-------- 12 files changed, 93 insertions(+), 43 deletions(-) diff --git a/evolve-die-repeat/game_manager.gd b/evolve-die-repeat/game_manager.gd index 6388cce..4e75c16 100644 --- a/evolve-die-repeat/game_manager.gd +++ b/evolve-die-repeat/game_manager.gd @@ -60,10 +60,10 @@ func init_screen_size(x:float, y:float) -> void: # This can take a vector of any size (but should be 2d, other components are unused) func get_boundaried_position(position): - ## clamp + # clamp #return position.clamp(Vector2.ZERO, screen_size) - ## periodic + # periodic position.x = wrapf(position.x, 0, screen_size.x) position.y = wrapf(position.y, 0, screen_size.y) return position @@ -76,3 +76,39 @@ func get_new_flow(): flow_y = flow_mag * sin(flow_dir) + +func calc_distance(one, two) -> float: + var candidate = one.distance_to(two) + var onedup = one + # FIXME: doesnt work-- predators lose track across game boundary + if one.x < screen_size.x/2: + if one.y < screen_size.y/2: + # top left + onedup.y -= screen_size.y + candidate = min(candidate, onedup.distance_to(two)) + onedup.y += screen_size.y + onedup.x -= screen_size.x + candidate = min(candidate, onedup.distance_to(two)) + else: + # bottom left + onedup.y += screen_size.y + candidate = min(candidate, onedup.distance_to(two)) + onedup.y -= screen_size.y + onedup.x -= screen_size.x + candidate = min(candidate, onedup.distance_to(two)) + else: + if one.y < screen_size.y/2: + # top right + onedup.y -= screen_size.y + candidate = min(candidate, onedup.distance_to(two)) + onedup.y += screen_size.y + onedup.x += screen_size.x + candidate = min(candidate, onedup.distance_to(two)) + else: + # botom right + onedup.y += screen_size.y + candidate = min(candidate, onedup.distance_to(two)) + onedup.y -= screen_size.y + onedup.x += screen_size.x + candidate = min(candidate, onedup.distance_to(two)) + return candidate diff --git a/evolve-die-repeat/molecular/food/food_mol.tscn b/evolve-die-repeat/molecular/food/food_mol.tscn index 2e15269..f4a1f3e 100644 --- a/evolve-die-repeat/molecular/food/food_mol.tscn +++ b/evolve-die-repeat/molecular/food/food_mol.tscn @@ -64,9 +64,10 @@ visible = false scale = Vector2(0.385, 0.385) texture = ExtResource("2_68e2u") -[node name="WrappingManager" type="Node" parent="." unique_id=1406150436 node_paths=PackedStringArray("sprite")] +[node name="WrappingManager" type="Node" parent="." unique_id=1406150436 node_paths=PackedStringArray("sprite", "shape")] script = ExtResource("3_8lhj0") sprite = NodePath("../AnimatedSprite2D") +shape = NodePath("../CollisionShape2D") metadata/_custom_type_script = "uid://bvbc0n0pslq7p" [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." unique_id=1856148995] diff --git a/evolve-die-repeat/molecular/predator/hammerhead_predator.gd b/evolve-die-repeat/molecular/predator/hammerhead_predator.gd index e309926..cb8d4fd 100644 --- a/evolve-die-repeat/molecular/predator/hammerhead_predator.gd +++ b/evolve-die-repeat/molecular/predator/hammerhead_predator.gd @@ -1,7 +1,6 @@ extends AbstractPredator2D # FIXME: (general) tracking across wrapping boundary -# TODO: mirroring (thought, extracct that to general function/resource? var can_attack: bool = true var desired_rotation: float = self.rotation @@ -19,7 +18,7 @@ func _ready() -> void: health = maxHealth sprite.play("Healthy") - + # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta: float) -> void: # smoothly rotate diff --git a/evolve-die-repeat/molecular/predator/hammerhead_predator.tscn b/evolve-die-repeat/molecular/predator/hammerhead_predator.tscn index f4b3bc1..f99b979 100644 --- a/evolve-die-repeat/molecular/predator/hammerhead_predator.tscn +++ b/evolve-die-repeat/molecular/predator/hammerhead_predator.tscn @@ -100,23 +100,24 @@ script = ExtResource("1_xp037") maxHealth = 50 metadata/_custom_type_script = "uid://dgfimmq53whll" -[node name="WrappingManager" type="Node" parent="." unique_id=826586678 node_paths=PackedStringArray("sprite")] +[node name="WrappingManager" type="Node" parent="." unique_id=826586678 node_paths=PackedStringArray("sprite", "shape")] script = ExtResource("9_shhro") sprite = NodePath("../AnimatedSprite2D") +shape = NodePath("../CollisionPolygon2D") metadata/_custom_type_script = "uid://bvbc0n0pslq7p" +[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="." unique_id=1596156928] +light_mask = 4 +visibility_layer = 4 +position = Vector2(0.111679085, 1.1167793) +rotation = -1.5707964 +polygon = PackedVector2Array(-22.184862, -27.994831, 23.481365, -27.21198, 13.82622, 25.891317, -6.005971, 25.891317) + [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." unique_id=410999609] rotation = 4.712389 sprite_frames = SubResource("SpriteFrames_shhro") animation = &"Hunting" -[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="." unique_id=1596156928] -light_mask = 4 -visibility_layer = 4 -position = Vector2(0.11167908, 1.1167793) -rotation = -1.5707964 -polygon = PackedVector2Array(-22.184862, -27.994831, 23.481365, -27.21198, 13.82622, 25.891317, -6.005971, 25.891317) - [node name="StateMachine" type="Node" parent="." unique_id=1857729810 node_paths=PackedStringArray("initial_state")] script = ExtResource("3_xp037") initial_state = NodePath("RandomMovement") diff --git a/evolve-die-repeat/molecular/predator/state_hunting.gd b/evolve-die-repeat/molecular/predator/state_hunting.gd index 05c79cb..cb52d8c 100644 --- a/evolve-die-repeat/molecular/predator/state_hunting.gd +++ b/evolve-die-repeat/molecular/predator/state_hunting.gd @@ -11,12 +11,12 @@ func enter(previous_state_path: String, data := {}) -> void: finished.emit(owner.fsm.States.IDLE, {}) func physics_update(_delta: float) -> void: - if target == owner or target == null or owner.position.distance_to(target.position) > owner.sight_range: + if target == null or GameManager.calc_distance(owner.position, target.position) > owner.sight_range: finished.emit(owner.fsm.States.IDLE, {}) return # alternatively, we could use a collision shape and inbuilt signals, but im not sure if that works better (mixing signals and custom fsm stuff i mean - if owner.position.distance_to(target.position) > owner.attack_range: + if GameManager.calc_distance(owner.position, target.position) > owner.attack_range: owner.move(move_towards(target.position)) else: owner.attack(target) diff --git a/evolve-die-repeat/molecular/prey/nucleotide_prey.tscn b/evolve-die-repeat/molecular/prey/nucleotide_prey.tscn index 1710bdc..64890a7 100644 --- a/evolve-die-repeat/molecular/prey/nucleotide_prey.tscn +++ b/evolve-die-repeat/molecular/prey/nucleotide_prey.tscn @@ -58,9 +58,10 @@ script = ExtResource("2_0227s") speed = 0.5 maxHealth = 20 -[node name="WrappingManager" type="Node" parent="." index="0" unique_id=407460873 node_paths=PackedStringArray("sprite")] +[node name="WrappingManager" type="Node" parent="." index="0" unique_id=407460873 node_paths=PackedStringArray("sprite", "shape")] script = ExtResource("3_lecx4") sprite = NodePath("../AnimatedSprite2D") +shape = NodePath("../CollisionPolygon2D") metadata/_custom_type_script = "uid://bvbc0n0pslq7p" [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." index="1" unique_id=788182944] diff --git a/evolve-die-repeat/molecular/prey/state_fleeing.gd b/evolve-die-repeat/molecular/prey/state_fleeing.gd index 659b39f..3e28abd 100644 --- a/evolve-die-repeat/molecular/prey/state_fleeing.gd +++ b/evolve-die-repeat/molecular/prey/state_fleeing.gd @@ -11,7 +11,7 @@ func enter(previous_state_path: String, data := {}) -> void: finished.emit(owner.fsm.States.IDLE, {}) func physics_update(_delta: float) -> void: - if owner.position.distance_to(threat.position) > threshold or threat == owner: + if GameManager.calc_distance(owner.position, threat.position) > threshold: finished.emit(owner.fsm.States.IDLE, {}) return owner.move(flee_from(threat.position)) diff --git a/evolve-die-repeat/shared/npc/npc2D.gd b/evolve-die-repeat/shared/npc/npc2D.gd index 323da73..d2e25fb 100644 --- a/evolve-die-repeat/shared/npc/npc2D.gd +++ b/evolve-die-repeat/shared/npc/npc2D.gd @@ -1,3 +1,4 @@ +@abstract extends CharacterBody2D class_name NPC2D diff --git a/evolve-die-repeat/shared/npc/predator2D.gd b/evolve-die-repeat/shared/npc/predator2D.gd index b5d4b5d..ab8ea46 100644 --- a/evolve-die-repeat/shared/npc/predator2D.gd +++ b/evolve-die-repeat/shared/npc/predator2D.gd @@ -1,3 +1,4 @@ +@abstract extends NPC2D class_name AbstractPredator2D diff --git a/evolve-die-repeat/shared/npc/prey2D.gd b/evolve-die-repeat/shared/npc/prey2D.gd index 1f2091f..2065f74 100644 --- a/evolve-die-repeat/shared/npc/prey2D.gd +++ b/evolve-die-repeat/shared/npc/prey2D.gd @@ -1,3 +1,4 @@ +@abstract extends NPC2D class_name AbstractPrey2D diff --git a/evolve-die-repeat/shared/state_machine.gd b/evolve-die-repeat/shared/state_machine.gd index 0a1ec17..de9f3c3 100644 --- a/evolve-die-repeat/shared/state_machine.gd +++ b/evolve-die-repeat/shared/state_machine.gd @@ -1,3 +1,4 @@ +@abstract class_name StateMachine extends Node @export var initial_state: State = null diff --git a/evolve-die-repeat/shared/wrapping_manager.gd b/evolve-die-repeat/shared/wrapping_manager.gd index 20cf3b8..6c3d998 100644 --- a/evolve-die-repeat/shared/wrapping_manager.gd +++ b/evolve-die-repeat/shared/wrapping_manager.gd @@ -1,30 +1,38 @@ class_name WrappingManager extends Node @export var sprite: AnimatedSprite2D +@export var shape: Node # FIXME (also in refactor see below) this is bad. # Mirrored sprites for periodic boundary -var mirrorSprite1: Node2D -var mirrorSprite2: Node2D -var mirrorSprite3: Node2D - +var mirrors: Array # Called when the node enters the scene tree for the first time. func _ready() -> void: await owner.ready - mirrorSprite1 = sprite.duplicate() - mirrorSprite2 = sprite.duplicate() - mirrorSprite3 = sprite.duplicate() - - owner.add_child(mirrorSprite1) - owner.add_child(mirrorSprite2) - owner.add_child(mirrorSprite3) + + mirrors.append(Area2D.new()) + mirrors.append(Area2D.new()) + mirrors.append(Area2D.new()) + + # TODO: npc overhaul; make npc2d (and child classes) inherit from Node instead of Area2d. + # Each entity should have Area2d -> collisionshape2d + animatedsprite2d. We then duplicate this area2d instead of the bullshit thats happening here + # note taht the below bs also does not work, as the (freshly instantiated) area2ds have none of the signals connected. The above refactor will fix this. + for m in mirrors: + for i in owner.get_groups(): + if not str(i).begins_with("_"): + m.add_to_group(i) + m.set_collision_layer(owner.get_collision_layer()) + m.set_collision_mask(owner.get_collision_mask()) + m.add_child(sprite.duplicate()) + m.add_child(shape.duplicate()) + owner.add_child(m) _handle_wrapping() func play_sprite(anim: String) -> void: - mirrorSprite1.play(anim) - mirrorSprite2.play(anim) - mirrorSprite3.play(anim) + mirrors[0].get_node("AnimatedSprite2D").play(anim) + mirrors[1].get_node("AnimatedSprite2D").play(anim) + mirrors[2].get_node("AnimatedSprite2D").play(anim) func _process(delta: float) -> void: _handle_wrapping() @@ -49,34 +57,34 @@ func _handle_wrapping(): # Find corresponding section of the screen if owner.position.x < GameManager.screen_size.x/2 and owner.position.y < GameManager.screen_size.y/2: # Right - mirrorSprite1.global_position = owner.global_position + Vector2(GameManager.screen_size.x, 0) + mirrors[0].global_position = owner.global_position + Vector2(GameManager.screen_size.x, 0) # Diag - mirrorSprite3.global_position = owner.global_position + Vector2(GameManager.screen_size.x, GameManager.screen_size.y) + mirrors[2].global_position = owner.global_position + Vector2(GameManager.screen_size.x, GameManager.screen_size.y) # Bottom - mirrorSprite2.global_position = owner.global_position + Vector2(0, GameManager.screen_size.y) + mirrors[1].global_position = owner.global_position + Vector2(0, GameManager.screen_size.y) elif owner.position.x < GameManager.screen_size.x/2: # Top - mirrorSprite1.global_position = owner.global_position + Vector2(0, - GameManager.screen_size.y) + mirrors[0].global_position = owner.global_position + Vector2(0, - GameManager.screen_size.y) # Diag - mirrorSprite2.global_position = owner.global_position + Vector2(GameManager.screen_size.x, - GameManager.screen_size.y) + mirrors[1].global_position = owner.global_position + Vector2(GameManager.screen_size.x, - GameManager.screen_size.y) # Right - mirrorSprite3.global_position = owner.global_position + Vector2(GameManager.screen_size.x, 0) + mirrors[2].global_position = owner.global_position + Vector2(GameManager.screen_size.x, 0) elif owner.position.y < GameManager.screen_size.y/2: # Left - mirrorSprite1.global_position = owner.global_position + Vector2(- GameManager.screen_size.x, 0) + mirrors[0].global_position = owner.global_position + Vector2(- GameManager.screen_size.x, 0) # Bottom - mirrorSprite2.global_position = owner.global_position + Vector2(0, GameManager.screen_size.y) + mirrors[1].global_position = owner.global_position + Vector2(0, GameManager.screen_size.y) # Diag - mirrorSprite3.global_position = owner.global_position + Vector2(- GameManager.screen_size.x, GameManager.screen_size.y) + mirrors[2].global_position = owner.global_position + Vector2(- GameManager.screen_size.x, GameManager.screen_size.y) else: # Left - mirrorSprite1.global_position = owner.global_position + Vector2(- GameManager.screen_size.x, 0) + mirrors[0].global_position = owner.global_position + Vector2(- GameManager.screen_size.x, 0) # Diag - mirrorSprite2.global_position = owner.global_position + Vector2(- GameManager.screen_size.x, - GameManager.screen_size.y) + mirrors[1].global_position = owner.global_position + Vector2(- GameManager.screen_size.x, - GameManager.screen_size.y) # Top - mirrorSprite3.global_position = owner.global_position + Vector2(0, - GameManager.screen_size.y) + mirrors[2].global_position = owner.global_position + Vector2(0, - GameManager.screen_size.y)