diff --git a/godot/nodes/action_decider.gd b/godot/nodes/action_decider.gd index cc7efd9..ed75466 100644 --- a/godot/nodes/action_decider.gd +++ b/godot/nodes/action_decider.gd @@ -2,15 +2,9 @@ class_name ActionDecider extends Node -var actor: TurnActor -var current_action: Action +@export var actor: TurnActor -func get_actor(): - var parent = get_parent() - if parent is TurnActor: - return parent - else: - return null +var current_action: Action func connect_to_actor(): actor.connect("turn_started", handle_turn_start) @@ -71,11 +65,7 @@ func inner_action_cleanup(): actor.end_turn() func _ready(): - actor = get_actor() - if not actor is TurnActor: - push_error("Couldn't get TurnActor from TurnAction") - else: - connect_to_actor() + connect_to_actor() func _process(delta: float): if current_action: diff --git a/godot/nodes/actions/move_action.gd b/godot/nodes/actions/move_action.gd index b090c77..5b662b5 100644 --- a/godot/nodes/actions/move_action.gd +++ b/godot/nodes/actions/move_action.gd @@ -2,10 +2,10 @@ class_name MoveAction extends Action -var mover: GridPosition +var mover: Mover var dir: Vector2i -func _init(new_mover: GridPosition, new_dir: Vector2i) -> void: +func _init(new_mover: Mover, new_dir: Vector2i) -> void: mover = new_mover dir = new_dir diff --git a/godot/prefabs/player/player.tscn b/godot/prefabs/player/player.tscn index 642fa0b..e38f81f 100644 --- a/godot/prefabs/player/player.tscn +++ b/godot/prefabs/player/player.tscn @@ -3,23 +3,31 @@ [ext_resource type="Texture2D" uid="uid://doscvutq8uqmd" path="res://sprites/sheet.png" id="1_72ieh"] [ext_resource type="Script" uid="uid://sxo578w2yds2" path="res://prefabs/player/player_input.gd" id="2_rdx4y"] -[node name="Player" type="TurnActor"] +[node name="Player" type="GridPosition"] -[node name="Input" type="Node2D" parent="."] -script = ExtResource("2_rdx4y") -metadata/_custom_type_script = "uid://okxdlbfuvb1b" - -[node name="GridPosition" type="GridPosition" parent="."] - -[node name="Sprite2D" type="Sprite2D" parent="GridPosition"] +[node name="Sprite2D" type="Sprite2D" parent="."] texture = ExtResource("1_72ieh") centered = false hframes = 8 vframes = 8 frame = 1 -[node name="Camera2D" type="Camera2D" parent="GridPosition"] +[node name="Camera2D" type="Camera2D" parent="."] position = Vector2(16, 16) zoom = Vector2(2, 2) -[node name="Gatherer" type="Gatherer" parent="GridPosition"] +[node name="Gatherer" type="Gatherer" parent="." node_paths=PackedStringArray("grid", "actor")] +grid = NodePath("..") +actor = NodePath("../TurnActor") + +[node name="Mover" type="Mover" parent="."] + +[node name="TurnActor" type="TurnActor" parent="."] +position = Vector2(-1, 0) + +[node name="ActionDecider" type="Node2D" parent="." node_paths=PackedStringArray("grid", "mover", "actor")] +script = ExtResource("2_rdx4y") +grid = NodePath("..") +mover = NodePath("../Mover") +actor = NodePath("../TurnActor") +metadata/_custom_type_script = "uid://okxdlbfuvb1b" diff --git a/godot/prefabs/player/player_input.gd b/godot/prefabs/player/player_input.gd index 93fb811..26ffb16 100644 --- a/godot/prefabs/player/player_input.gd +++ b/godot/prefabs/player/player_input.gd @@ -1,7 +1,8 @@ @icon("res://icons/turn_action.svg") extends ActionDecider -@onready var grid_position: GridPosition = $"../GridPosition" +@export var grid: GridPosition +@export var mover: Mover func poll_movement_dir(): var movement_dir = Vector2i.ZERO @@ -25,23 +26,11 @@ func _input(event: InputEvent) -> void: print("skip turn!") if try_perform(SkipAction.new()): return - #KEY_UP: - #if try_perform(MoveAction.new(grid_position, Vector2i.UP)): - #return - #KEY_DOWN: - #if try_perform(MoveAction.new(grid_position, Vector2i.DOWN)): - #return - #KEY_LEFT: - #if try_perform(MoveAction.new(grid_position, Vector2i.LEFT)): - #return - #KEY_RIGHT: - #if try_perform(MoveAction.new(grid_position, Vector2i.RIGHT)): - #return func _process(_delta: float) -> void: if not is_deciding(): return var movement_dir = poll_movement_dir() if movement_dir != Vector2i.ZERO: - if try_perform(MoveAction.new(grid_position, movement_dir)): + if try_perform(MoveAction.new(mover, movement_dir)): return diff --git a/godot/scenes/overworld.tscn b/godot/scenes/overworld.tscn index 75f56c0..d5d4333 100644 --- a/godot/scenes/overworld.tscn +++ b/godot/scenes/overworld.tscn @@ -4,18 +4,20 @@ [ext_resource type="TileSet" uid="uid://bxwohuw2p43k1" path="res://tilesets/foreground_tileset.tres" id="2_u2ss0"] [ext_resource type="PackedScene" uid="uid://drs6h7ks4r2ta" path="res://prefabs/player/player.tscn" id="3_u2ss0"] -[node name="Root" type="Level" node_paths=PackedStringArray("background", "foreground")] +[node name="TurnManager" type="TurnManager"] + +[node name="Root" type="Level" parent="." node_paths=PackedStringArray("background", "foreground")] background = NodePath("Background") foreground = NodePath("Foreground") -[node name="Background" type="TileMapLayer" parent="."] +[node name="Background" type="TileMapLayer" parent="Root"] tile_map_data = PackedByteArray("AAD8//z/AQAAAAQAAAD8//3/AQAAAAQAAAD8//7/AQAAAAQAAAD8////AQAAAAQAAAD9//z/AQAAAAQAAAD9//3/AQAAAAQAAAD9//7/AQAAAAQAAAD9////AQAAAAQAAAD+//z/AQAAAAQAAAD+//3/AQAAAAQAAAD+//7/AQAAAAQAAAD+////AQAAAAQAAAD///z/AQAAAAQAAAD///3/AQAAAAQAAAD///7/AQAAAAQAAAD/////AQAAAAQAAAD8/wAAAQAAAAQAAAD8/wEAAQAAAAQAAAD8/wIAAQAAAAQAAAD8/wMAAQAAAAQAAAD9/wAAAQAAAAQAAAD9/wEAAQAAAAQAAAD9/wIAAQAAAAQAAAD9/wMAAQAAAAQAAAD+/wAAAQAAAAQAAAD+/wEAAQAAAAQAAAD+/wIAAQAAAAQAAAD+/wMAAQAAAAQAAAD//wAAAQAAAAQAAAD//wEAAQAAAAQAAAD//wIAAQAAAAQAAAD//wMAAQAAAAQAAAAAAPz/AQAAAAQAAAAAAP3/AQAAAAQAAAAAAP7/AQAAAAQAAAAAAP//AQAAAAQAAAAAAAAAAQAAAAQAAAAAAAEAAQAAAAQAAAAAAAIAAQAAAAQAAAAAAAMAAQAAAAQAAAABAPz/AQAAAAQAAAABAP3/AQAAAAQAAAABAP7/AQAAAAQAAAABAP//AQAAAAQAAAABAAAAAQAAAAQAAAABAAEAAQAAAAQAAAABAAIAAQAAAAQAAAABAAMAAQAAAAQAAAACAPz/AQAAAAQAAAACAP3/AQAAAAQAAAACAP7/AQAAAAQAAAACAP//AQAAAAQAAAACAAAAAQAAAAQAAAACAAEAAQAAAAQAAAACAAIAAQAAAAQAAAACAAMAAQAAAAQAAAADAPz/AQAAAAQAAAADAP3/AQAAAAQAAAADAP7/AQAAAAQAAAADAP//AQAAAAQAAAADAAAAAQAAAAQAAAADAAEAAQAAAAQAAAADAAIAAQAAAAQAAAADAAMAAQAAAAQAAAD6//v/AQAAAAQAAAD6//z/AQAAAAQAAAD6//3/AQAAAAQAAAD6//7/AQAAAAQAAAD6////AQAAAAQAAAD6/wAAAQAAAAQAAAD6/wEAAQAAAAQAAAD6/wIAAQAAAAQAAAD6/wMAAQAAAAQAAAD6/wQAAQAAAAQAAAD6/wUAAQAAAAQAAAD7//v/AQAAAAQAAAD7//z/AQAAAAQAAAD7//3/AQAAAAQAAAD7//7/AQAAAAQAAAD7////AQAAAAQAAAD7/wAAAQAAAAQAAAD7/wEAAQAAAAQAAAD7/wIAAQAAAAQAAAD7/wMAAQAAAAQAAAD7/wQAAQAAAAQAAAD7/wUAAQAAAAQAAAD8//v/AQAAAAQAAAD8/wQAAQAAAAQAAAD8/wUAAQAAAAQAAAD9//v/AQAAAAQAAAD9/wQAAQAAAAQAAAD9/wUAAQAAAAQAAAD+//v/AQAAAAQAAAD+/wQAAQAAAAQAAAD+/wUAAQAAAAQAAAD///v/AQAAAAQAAAD//wQAAQAAAAQAAAD//wUAAQAAAAQAAAAAAPv/AQAAAAQAAAAAAAQAAQAAAAQAAAAAAAUAAQAAAAQAAAABAPv/AQAAAAQAAAABAAQAAQAAAAQAAAABAAUAAQAAAAQAAAACAPv/AQAAAAQAAAACAAQAAQAAAAQAAAACAAUAAQAAAAQAAAADAPr/AQABAAQAAAADAPv/AQAAAAQAAAADAAQAAQAAAAQAAAADAAUAAQAAAAQAAAAEAPr/AQABAAQAAAAEAPv/AQABAAQAAAAEAPz/AQABAAQAAAAEAP3/AQABAAQAAAAEAP7/AQAAAAQAAAAEAP//AQAAAAQAAAAEAAAAAQAAAAQAAAAEAAEAAQAAAAQAAAAEAAIAAQAAAAQAAAAEAAMAAQAAAAQAAAAEAAQAAQAAAAQAAAAEAAUAAQAAAAQAAAAFAPr/AQABAAQAAAAFAPv/AQABAAQAAAAFAPz/AQABAAQAAAAFAP3/AQABAAQAAAAFAP7/AQAAAAQAAAAFAP//AQAAAAQAAAAFAAAAAQAAAAQAAAAFAAEAAQAAAAQAAAAFAAIAAQAAAAQAAAAFAAMAAQAAAAQAAAAFAAQAAQAAAAQAAAAFAAUAAQAAAAQAAAAGAPj/AQABAAQAAAAGAPn/AQABAAQAAAAGAPr/AQABAAQAAAAGAPv/AQABAAQAAAAGAPz/AQABAAQAAAAHAPj/AQABAAQAAAAHAPn/AQABAAQAAAAHAPr/AQABAAQAAAAHAPv/AQABAAQAAAAHAPz/AQABAAQAAAAIAPj/AQABAAQAAAAIAPn/AQABAAQAAAAIAPr/AQABAAQAAAAIAPv/AQABAAQAAAAIAPz/AQABAAQAAAAJAPj/AQABAAQAAAAJAPn/AQABAAQAAAAJAPr/AQABAAQAAAAJAPv/AQABAAQAAAAJAPz/AQABAAQAAAAKAPj/AQABAAQAAAAKAPn/AQABAAQAAAAKAPr/AQABAAQAAAAKAPv/AQABAAQAAAAKAPz/AQABAAQAAAAEAPn/AQABAAQAAAAGAP3/AQABAAQAAAAHAP3/AQABAAQAAAAIAP3/AQABAAQAAAAIAP7/AQABAAQAAAAHAP7/AQABAAQAAAAEAPj/AQABAAQAAAAEAPf/AQABAAQAAAAFAPf/AQABAAQAAAAFAPj/AQABAAQAAAAFAPn/AQABAAQAAAAHAPf/AQABAAQAAAAGAPf/AQABAAQAAAAIAPf/AQABAAQAAAAJAPf/AQABAAQAAAAKAPf/AQABAAQAAAALAPn/AQABAAQAAAALAPr/AQABAAQAAAALAPv/AQABAAQAAAAKAP3/AQABAAQAAAAJAP3/AQABAAQAAAD3//v/AQAAAAQAAAD3//z/AQAAAAQAAAD3//3/AQAAAAQAAAD3//7/AQAAAAQAAAD3////AQAAAAQAAAD3/wAAAQAAAAQAAAD3/wEAAQAAAAQAAAD3/wIAAQAAAAQAAAD3/wMAAQAAAAQAAAD3/wQAAQAAAAQAAAD3/wUAAQAAAAQAAAD4//v/AQAAAAQAAAD4//z/AQAAAAQAAAD4//3/AQAAAAQAAAD4//7/AQAAAAQAAAD4////AQAAAAQAAAD4/wAAAQAAAAQAAAD4/wEAAQAAAAQAAAD4/wIAAQAAAAQAAAD4/wMAAQAAAAQAAAD4/wQAAQAAAAQAAAD4/wUAAQAAAAQAAAD5//v/AQAAAAQAAAD5//z/AQAAAAQAAAD5//3/AQAAAAQAAAD5//7/AQAAAAQAAAD5////AQAAAAQAAAD5/wAAAQAAAAQAAAD5/wEAAQAAAAQAAAD5/wIAAQAAAAQAAAD5/wMAAQAAAAQAAAD5/wQAAQAAAAQAAAD5/wUAAQAAAAQAAAAGAP//AQAAAAQAAAAGAAAAAQAAAAQAAAAGAAEAAQAAAAQAAAAGAAIAAQAAAAQAAAAGAAMAAQAAAAQAAAAGAAQAAQAAAAQAAAAGAAUAAQAAAAQAAAAHAP//AQAAAAQAAAAHAAAAAQAAAAQAAAAHAAEAAQAAAAQAAAAHAAIAAQAAAAQAAAAHAAMAAQAAAAQAAAAHAAQAAQAAAAQAAAAHAAUAAQAAAAQAAAAIAP//AQAAAAQAAAAIAAAAAQAAAAQAAAAIAAEAAQAAAAQAAAAIAAIAAQAAAAQAAAAIAAMAAQAAAAQAAAAIAAQAAQAAAAQAAAAIAAUAAQAAAAQAAAAJAP//AQAAAAQAAAAJAAAAAQAAAAQAAAAJAAEAAQAAAAQAAAAJAAIAAQAAAAQAAAAJAAMAAQAAAAQAAAAJAAQAAQAAAAQAAAAJAAUAAQAAAAQAAAAJAP7/AQABAAQAAAAGAP7/AQABAAQAAAA=") tile_set = ExtResource("1_m1b5j") -[node name="Foreground" type="TileMapLayer" parent="."] +[node name="Foreground" type="TileMapLayer" parent="Root"] tile_map_data = PackedByteArray("AAD/////AQAAAAMAAAAEAAEAAQAAAAIAAAADAAEAAQAAAAIAAAADAAIAAQAAAAIAAAADAAMAAQAAAAIAAAACAAMAAQAAAAIAAAAFAAMAAQABAAIAAAAGAAMAAQABAAIAAAD8//3/AQABAAMAAAD9//3/AQABAAMAAAD9//7/AQABAAMAAAD9/wAAAQABAAMAAAD9/wEAAQABAAMAAAD8/wEAAQABAAMAAAAEAPv/AQACAAMAAAAGAP3/AQACAAMAAAAHAP7/AQACAAMAAAAIAP7/AQACAAMAAAAJAP7/AQACAAMAAAAGAPn/AQACAAMAAAAGAPr/AQACAAMAAAAGAPv/AQACAAMAAAAHAPv/AQACAAMAAAAIAPv/AQACAAMAAAAIAPz/AQACAAMAAAAJAPz/AQACAAMAAAAKAPz/AQACAAMAAAAKAPv/AQACAAMAAAAJAPv/AQACAAMAAAAIAPr/AQACAAMAAAAHAPr/AQACAAMAAAAHAPn/AQACAAMAAAD3//v/AQABAAMAAAD3//z/AQABAAMAAAD3//3/AQABAAMAAAD3//7/AQABAAMAAAD3////AQABAAMAAAD3/wAAAQABAAMAAAD3/wEAAQABAAMAAAD3/wIAAQABAAMAAAD4//v/AQABAAMAAAD4//z/AQABAAMAAAD4//3/AQABAAMAAAD4//7/AQABAAMAAAD4////AQABAAMAAAD4/wAAAQABAAMAAAD4/wEAAQABAAMAAAD4/wIAAQABAAMAAAD3/wMAAQABAAMAAAD3/wQAAQABAAMAAAD3/wUAAQABAAMAAAD4/wMAAQABAAMAAAD4/wQAAQABAAMAAAD4/wUAAQABAAMAAAD5/wUAAQABAAMAAAD6/wUAAQABAAMAAAD7/wUAAQABAAMAAAD8/wUAAQABAAMAAAD9/wUAAQABAAMAAAD+/wUAAQABAAMAAAD//wUAAQABAAMAAAAAAAUAAQABAAMAAAABAAUAAQABAAMAAAACAAUAAQABAAMAAAADAAUAAQABAAMAAAAEAAUAAQABAAMAAAAFAAUAAQABAAMAAAAGAAUAAQABAAMAAAAHAAUAAQABAAMAAAAIAAUAAQABAAMAAAAJAAUAAQABAAMAAAD5//v/AQABAAMAAAD6//v/AQABAAMAAAD7//v/AQABAAMAAAD8//v/AQABAAMAAAD9//v/AQABAAMAAAD+//v/AQABAAMAAAD///v/AQABAAMAAAAAAPv/AQABAAMAAAABAPv/AQABAAMAAAACAPv/AQABAAMAAAADAPv/AQABAAMAAAAJAP//AQABAAMAAAAJAAAAAQABAAMAAAAJAAEAAQABAAMAAAAJAAIAAQABAAMAAAAJAAMAAQABAAMAAAAJAAQAAQABAAMAAAD7/wEAAQABAAMAAAD7//3/AQABAAMAAAD6//3/AQABAAMAAAD6/wEAAQABAAMAAAD6//7/AQABAAMAAAD6/wAAAQABAAMAAAA=") tile_set = ExtResource("2_u2ss0") -[node name="Player" parent="." instance=ExtResource("3_u2ss0")] +[node name="Player" parent="Root" instance=ExtResource("3_u2ss0")] -[node name="TurnManager" type="TurnManager" parent="."] +[node name="Camera2D" type="Camera2D" parent="Root"] diff --git a/rust/src/overworld.rs b/rust/src/overworld.rs index d57a7e7..e102014 100644 --- a/rust/src/overworld.rs +++ b/rust/src/overworld.rs @@ -1,6 +1,6 @@ -use godot::{classes::*, obj::WithBaseField, prelude::*}; +use godot::{classes::*, prelude::*}; -use crate::{turn::TurnActor, utils}; +use crate::{turn::*, utils::find_in_parents}; #[derive(Debug, GodotClass)] #[class(init, base=Node)] @@ -78,70 +78,11 @@ pub struct GridPosition { #[init(val = Vector2::splat(32.0))] grid_size: Vector2, - #[export] - #[init(val = 30.0)] - movement_speed: f32, - - #[export_group(name = "Flags")] - #[export] - #[init(val = false)] - ignore_collisions: bool, - - is_moving: bool, - target_coords: Vector2i, - base: Base, } -#[godot_api] -impl INode2D for GridPosition { - fn ready(&mut self) { - self.target_coords = self.get_coords(); - } - - fn process(&mut self, delta: f64) { - if self.is_moving { - let start = self.base().get_global_position(); - let target_coords = self.target_coords; - let movement_speed = self.movement_speed; - let end = self.get_target_pos(); - if start.distance_squared_to(end) <= Self::TILE_SNAP_DIST_SQR { - self.base_mut().set_global_position(end); - self.is_moving = false; - self.signals().finished_moving().emit(target_coords); - } else { - self.base_mut() - .set_global_position(start.lerp(end, movement_speed * delta as f32)); - } - } - } -} - #[godot_api] impl GridPosition { - const TILE_SNAP_DIST_SQR: f32 = 1.0; - - pub fn level(&self) -> Option> { - Level::find_from_node(self.to_gd().upcast::()) - } - - // #[func] - // pub fn find_from_node(node: Gd) -> Option> { - // let mut current = node.clone(); - // while let Some(parent) = current.get_parent() { - // match parent.try_cast::() { - // Ok(level) => return Some(level), - // Err(other) => current = other, - // } - // } - // None - // } - - #[func] - pub fn get_target_pos(&self) -> Vector2 { - self.target_coords.cast_float() * self.grid_size - } - #[func] pub fn get_coords(&self) -> Vector2i { (self.base().get_global_position() / self.grid_size) @@ -155,41 +96,6 @@ impl GridPosition { self.base_mut() .set_global_position(pos.cast_float() * grid_size); } - - #[func] - pub fn can_move(&self, dir: Vector2i) -> bool { - if self.is_moving { - return false; - } - if self.ignore_collisions { - return true; - } - match self.level() { - Some(level) => !level.bind().tile_has_collision(self.get_coords() + dir), - None => true, - } - } - - #[func] - pub fn try_move(&mut self, dir: Vector2i) -> bool { - let start_coords = self.target_coords; - let target_coords = start_coords + dir; - - if !self.can_move(dir) { - return false; - } - - self.is_moving = true; - self.target_coords = target_coords; - self.signals().started_moving().emit(start_coords, dir); - true - } - - #[signal] - fn started_moving(from_coords: Vector2i, dir: Vector2i); - - #[signal] - fn finished_moving(coords: Vector2i); } #[derive(GodotConvert, Var, Export, Clone, Copy, Default, Debug, PartialEq, Eq)] @@ -202,12 +108,16 @@ pub enum ItemKind { #[derive(Debug, GodotClass)] #[class(init, base=Node)] pub struct Gatherer { + #[export] + grid: Option>, + #[export] + actor: Option>, + #[export] #[init(val = 0)] radius: i32, level: Option>, - grid_position: Option>, base: Base, } @@ -215,11 +125,10 @@ pub struct Gatherer { #[godot_api] impl INode for Gatherer { fn ready(&mut self) { - self.level = utils::find_in_parents(self.to_gd()); - self.grid_position = utils::find_in_parents(self.to_gd()); - let actor = TurnActor::find_from_node(self.to_gd().upcast::()) - .expect("Getting Actor in some parent"); - actor + self.level = find_in_parents(self.to_gd()); + self.actor + .as_ref() + .expect("getting Actor") .signals() .turn_ended() .connect_other(self, |this, action| this.on_turn_end(action)); @@ -228,8 +137,8 @@ impl INode for Gatherer { #[godot_api] impl Gatherer { - fn on_turn_end(&self, action: GString) -> Option<()> { - let coords = self.grid_position.clone()?.bind().get_coords(); + fn on_turn_end(&self, _action: GString) -> Option<()> { + let coords = self.grid.clone()?.bind().get_coords(); if let Some((item, count)) = self.try_gather_tile(coords) { godot_print!("Gathered {count} x {:?}", item); } @@ -256,3 +165,97 @@ impl Gatherer { #[signal] fn gathered(item: ItemKind, count: i32); } + +#[derive(Debug, GodotClass)] +#[class(init, base=Node)] +pub struct Mover { + #[export] + #[init(val = 30.0)] + movement_speed: f32, + + #[export_group(name = "Flags")] + #[export] + #[init(val = false)] + ignore_collisions: bool, + + is_moving: bool, + target_coords: Vector2i, + grid: Option>, + + base: Base, +} + +#[godot_api] +impl INode for Mover { + fn ready(&mut self) { + self.grid = find_in_parents(self.to_gd()); + self.target_coords = self.get_grid().bind().get_coords(); + } + + fn process(&mut self, delta: f64) { + if self.is_moving { + let start = self.get_grid().get_global_position(); + let target_coords = self.target_coords; + let movement_speed = self.movement_speed; + let end = self.get_target_pos(); + if start.distance_squared_to(end) <= Self::TILE_SNAP_DIST_SQR { + self.get_grid().set_global_position(end); + self.is_moving = false; + self.signals().finished_moving().emit(target_coords); + } else { + self.get_grid() + .set_global_position(start.lerp(end, movement_speed * delta as f32)); + } + } + } +} + +#[godot_api] +impl Mover { + const TILE_SNAP_DIST_SQR: f32 = 1.0; + + #[func] + pub fn get_grid(&self) -> Gd { + self.grid.clone().unwrap() + } + + #[func] + pub fn get_target_pos(&self) -> Vector2 { + self.target_coords.cast_float() * self.get_grid().bind().grid_size + } + + #[func] + pub fn can_move(&self, dir: Vector2i) -> bool { + if self.is_moving { + return false; + } + if self.ignore_collisions { + return true; + } + let level: Gd = find_in_parents(self.to_gd()).unwrap(); + !level + .bind() + .tile_has_collision(self.get_grid().bind().get_coords() + dir) + } + + #[func] + pub fn try_move(&mut self, dir: Vector2i) -> bool { + let start_coords = self.target_coords; + let target_coords = start_coords + dir; + + if !self.can_move(dir) { + return false; + } + + self.is_moving = true; + self.target_coords = target_coords; + self.signals().started_moving().emit(start_coords, dir); + true + } + + #[signal] + fn started_moving(from_coords: Vector2i, dir: Vector2i); + + #[signal] + fn finished_moving(coords: Vector2i); +} diff --git a/rust/src/turn.rs b/rust/src/turn.rs index 334c1f0..94307ad 100644 --- a/rust/src/turn.rs +++ b/rust/src/turn.rs @@ -1,11 +1,16 @@ +use std::collections::HashSet; + use godot::{ classes::{object::ConnectFlags, *}, prelude::*, }; +use crate::utils::find_in_parents; + #[derive(Debug, GodotClass)] #[class(init, base=Node)] pub struct TurnManager { + registered_actors: HashSet>, round_queue: Array>, current_actor: Option>, @@ -15,6 +20,11 @@ pub struct TurnManager { #[godot_api] impl INode for TurnManager { fn process(&mut self, _delta: f64) { + if let Some(current) = self.current_actor.as_ref() { + if !current.is_instance_valid() { + self.start_next_turn(); + } + } if self.current_actor.is_none() && self.round_queue.is_empty() { self.start_round(); } @@ -23,35 +33,52 @@ impl INode for TurnManager { #[godot_api] impl TurnManager { + pub fn register(&mut self, actor: Gd) { + self.registered_actors.insert(actor); + } + + fn unregister(&mut self, actor: &Gd) { + self.registered_actors.remove(actor); + } + + fn unregister_deleted(&mut self) { + self.registered_actors + .retain(|actor| actor.is_instance_valid() && !actor.is_queued_for_deletion()); + } + + fn new_round(&self) -> Array> { + let mut actors: Array> = self.registered_actors.iter().cloned().collect(); + actors.sort_unstable_by(|a, b| a.instance_id().cmp(&b.instance_id())); + actors + } + fn start_round(&mut self) { - self.round_queue = self.find_sibling_actors(); - godot_print!("New round: {:?}", self.round_queue); + self.unregister_deleted(); + self.round_queue = self.new_round(); self.start_next_turn(); } fn start_next_turn(&mut self) { self.current_actor = self.round_queue.pop(); if let Some(mut actor) = self.current_actor.clone() { - actor - .signals() - .turn_ended() - .builder() - .flags(ConnectFlags::ONE_SHOT) - .connect_other_mut(self, |this, _action| this.start_next_turn()); - actor.bind_mut().start_turn(); + if actor.is_instance_valid() && !actor.is_queued_for_deletion() { + godot_print!("Next up: \"{}\" {:?}", actor.get_path(), actor); + actor + .signals() + .turn_ended() + .builder() + .flags(ConnectFlags::ONE_SHOT) + .connect_other_mut(self, Self::on_actor_turn_end); + actor.bind_mut().start_turn(); + } else { + self.unregister(&actor); + self.start_next_turn(); + } } } - fn find_sibling_actors(&self) -> Array> { - let mut actors: Array> = Array::new(); - self.base() - .get_parent() - .unwrap() - .get_children() - .iter_shared() - .filter_map(|node| node.try_cast::().ok()) - .for_each(|actor| actors.push(&actor)); - actors + fn on_actor_turn_end(&mut self, _action: GString) { + self.start_next_turn(); } } @@ -90,6 +117,14 @@ pub struct TurnActor { #[godot_api] impl INode2D for TurnActor { fn ready(&mut self) {} + + fn enter_tree(&mut self) { + let manager: Option> = find_in_parents(self.to_gd()); + match manager { + Some(mut manager) => manager.bind_mut().register(self.to_gd()), + None => godot_error!("No TurnManager found for TurnActor"), + } + } } #[godot_api] @@ -99,18 +134,6 @@ impl TurnActor { self.state } - #[func] - pub fn find_from_node(node: Gd) -> Option> { - let mut current = node.clone(); - while let Some(parent) = current.get_parent() { - match parent.try_cast::() { - Ok(level) => return Some(level), - Err(other) => current = other, - } - } - None - } - #[func] pub fn get_current_action(&self) -> Variant { match self.current_action.clone() { diff --git a/rust/src/utils.rs b/rust/src/utils.rs index 133886e..48cc39c 100644 --- a/rust/src/utils.rs +++ b/rust/src/utils.rs @@ -14,3 +14,30 @@ where } None } + +// /// Try to find a child of type `T` with the name `T::class_name()` +// pub fn find_by_class_name_in_children(parent: Gd) -> Option> +// where +// T: Inherits, +// U: Inherits, +// { +// parent +// .upcast::() +// .try_get_node_as::(&T::class_name().to_string()) +// } + +// /// Try to find a child of type `T` by iterating over children. +// /// +// /// Returns only the first result. +// pub fn find_by_type_in_children(parent: Gd) -> Option> +// where +// T: Inherits, +// U: Inherits, +// { +// for child in parent.upcast::().get_children().iter_shared() { +// if let Ok(result) = child.try_cast::() { +// return Some(result); +// } +// } +// None +// }