Added berry picking

master
hheik 2025-09-11 13:41:03 +03:00
parent 3f75d5a616
commit f74dcdba2c
16 changed files with 319 additions and 126 deletions

View File

@ -0,0 +1,13 @@
class_name Player
extends GridPosition
@export var gatherer: Gatherer
static func is_player(node: Node) -> bool:
return node is Player || node.get_parent() is Player
func _ready() -> void:
gatherer.gathered.connect(_on_gathered)
func _on_gathered(item: String, count: int):
print("gathered: ", count, " x ", item)

View File

@ -0,0 +1 @@
uid://cvviym6gdlod8

View File

@ -1,29 +1,27 @@
[gd_scene load_steps=3 format=3 uid="uid://drs6h7ks4r2ta"]
[gd_scene load_steps=4 format=3 uid="uid://drs6h7ks4r2ta"]
[ext_resource type="Texture2D" uid="uid://doscvutq8uqmd" path="res://sprites/sheet.png" id="1_72ieh"]
[ext_resource type="Script" uid="uid://cvviym6gdlod8" path="res://prefabs/player/player.gd" id="1_wv1mm"]
[ext_resource type="Script" uid="uid://sxo578w2yds2" path="res://prefabs/player/player_input.gd" id="2_rdx4y"]
[node name="Player" type="GridPosition"]
[node name="Player" type="GridPosition" node_paths=PackedStringArray("gatherer")]
script = ExtResource("1_wv1mm")
gatherer = NodePath("Gatherer")
[node name="Sprite2D" type="Sprite2D" parent="."]
texture = ExtResource("1_72ieh")
centered = false
hframes = 8
vframes = 8
frame = 1
[node name="Camera2D" type="Camera2D" parent="."]
position = Vector2(16, 16)
zoom = Vector2(2, 2)
[node name="Gatherer" type="Gatherer" parent="." node_paths=PackedStringArray("grid", "actor")]
grid = NodePath("..")
actor = NodePath("../TurnActor")
[node name="Gatherer" type="Gatherer" parent="."]
[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")

View File

@ -0,0 +1,26 @@
[gd_scene load_steps=3 format=3 uid="uid://8xuvjmyjkpeo"]
[ext_resource type="Texture2D" uid="uid://doscvutq8uqmd" path="res://sprites/sheet.png" id="1_gjkx7"]
[ext_resource type="Script" uid="uid://jd6ce3f7e1bh" path="res://prefabs/tiles/gatherable_animation.gd" id="1_jqgth"]
[node name="Blueberry" type="GridPosition" node_paths=PackedStringArray("gatherable", "picked", "not_picked")]
script = ExtResource("1_jqgth")
gatherable = NodePath("Gatherable")
picked = NodePath("Picked")
not_picked = NodePath("Not Picked")
[node name="Not Picked" type="Sprite2D" parent="."]
texture = ExtResource("1_gjkx7")
hframes = 8
vframes = 8
frame = 16
[node name="Picked" type="Sprite2D" parent="."]
visible = false
texture = ExtResource("1_gjkx7")
hframes = 8
vframes = 8
frame = 17
[node name="Gatherable" type="Gatherable" parent="." node_paths=PackedStringArray("grid")]
grid = NodePath("..")

View File

@ -0,0 +1,27 @@
[gd_scene load_steps=3 format=3 uid="uid://l72f05nek0y4"]
[ext_resource type="Texture2D" uid="uid://doscvutq8uqmd" path="res://sprites/sheet.png" id="1_e3ld6"]
[ext_resource type="Script" uid="uid://jd6ce3f7e1bh" path="res://prefabs/tiles/gatherable_animation.gd" id="2_kod7n"]
[node name="Blueberry" type="GridPosition" node_paths=PackedStringArray("gatherable", "picked", "not_picked")]
script = ExtResource("2_kod7n")
gatherable = NodePath("Gatherable")
picked = NodePath("Picked")
not_picked = NodePath("Not Picked")
[node name="Not Picked" type="Sprite2D" parent="."]
texture = ExtResource("1_e3ld6")
hframes = 8
vframes = 8
frame = 20
[node name="Picked" type="Sprite2D" parent="."]
visible = false
texture = ExtResource("1_e3ld6")
hframes = 8
vframes = 8
frame = 17
[node name="Gatherable" type="Gatherable" parent="." node_paths=PackedStringArray("grid")]
grid = NodePath("..")
item = "Cowberry"

View File

@ -0,0 +1,16 @@
extends Node
@export var gatherable: Gatherable
@export var picked: CanvasItem
@export var not_picked: CanvasItem
func _ready() -> void:
update_visibility(gatherable.get_is_picked())
gatherable.picked_state_changed.connect(_on_gatherable_state_changed)
func _on_gatherable_state_changed(is_picked):
update_visibility(is_picked)
func update_visibility(is_picked: bool):
picked.visible = is_picked
not_picked.visible = not is_picked

View File

@ -0,0 +1 @@
uid://jd6ce3f7e1bh

View File

@ -15,9 +15,8 @@ tile_map_data = PackedByteArray("AAD8//z/AQAAAAQAAAD8//3/AQAAAAQAAAD8//7/AQAAAAQ
tile_set = ExtResource("1_m1b5j")
[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_map_data = PackedByteArray("AAD/////AQAAAAMAAAD8//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/wAAAQABAAMAAAD6/wQAAAAAAAAAAgD5/wQAAAAAAAAAAgD5/wMAAAAAAAAAAgAEAAEAAAAAAAAAAQADAAEAAAAAAAAAAQADAAIAAAAAAAAAAQADAAMAAAAAAAAAAQACAAMAAAAAAAAAAQA=")
tile_set = ExtResource("2_u2ss0")
[node name="Player" parent="Root" instance=ExtResource("3_u2ss0")]
[node name="Camera2D" type="Camera2D" parent="Root"]
position = Vector2(16, 16)

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -1,24 +1,26 @@
[gd_resource type="TileSet" load_steps=3 format=3 uid="uid://bxwohuw2p43k1"]
[gd_resource type="TileSet" load_steps=6 format=3 uid="uid://bxwohuw2p43k1"]
[ext_resource type="Texture2D" uid="uid://doscvutq8uqmd" path="res://sprites/sheet.png" id="1_oe62d"]
[ext_resource type="PackedScene" uid="uid://8xuvjmyjkpeo" path="res://prefabs/tiles/blueberry.tscn" id="1_rc83b"]
[ext_resource type="PackedScene" uid="uid://l72f05nek0y4" path="res://prefabs/tiles/cowberry.tscn" id="2_w3v7n"]
[sub_resource type="TileSetScenesCollectionSource" id="TileSetScenesCollectionSource_w3v7n"]
resource_name = "Entities"
scenes/1/scene = ExtResource("1_rc83b")
scenes/2/scene = ExtResource("2_w3v7n")
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_rc83b"]
texture = ExtResource("1_oe62d")
texture_region_size = Vector2i(32, 32)
0:3/0 = 0
0:3/0/custom_data_0 = true
0:2/0 = 0
0:2/0/custom_data_1 = true
1:2/0 = 0
1:3/0 = 0
1:3/0/custom_data_0 = true
2:3/0 = 0
2:3/0/custom_data_0 = true
0:3/0 = 0
[resource]
tile_size = Vector2i(32, 32)
custom_data_layer_0/name = "has_collision"
custom_data_layer_0/type = 1
custom_data_layer_1/name = "is_berry"
custom_data_layer_1/type = 1
sources/1 = SubResource("TileSetAtlasSource_rc83b")
sources/0 = SubResource("TileSetScenesCollectionSource_w3v7n")

124
rust/src/gathering.rs Normal file
View File

@ -0,0 +1,124 @@
use godot::{classes::*, obj::WithUserSignals, prelude::*};
use crate::{
grid::*,
turn::*,
utils::{find_by_type_in_children, find_in_parents},
};
#[derive(GodotConvert, Var, Export, Clone, Copy, Default, Debug, PartialEq, Eq)]
#[godot(via = GString)]
pub enum ItemKind {
#[default]
Blueberry,
Cowberry,
}
#[derive(Debug, GodotClass)]
#[class(init, base=Node)]
pub struct Gatherer {
#[export]
#[init(val = 0)]
radius: i32,
base: Base<Node>,
}
#[godot_api]
impl INode for Gatherer {}
#[godot_api]
impl Gatherer {
#[func]
pub fn gather(&mut self, item: ItemKind, count: i32) {
self.signals().gathered().emit(&item.to_godot(), count);
}
#[signal]
fn gathered(item: GString, count: i32);
}
#[derive(Debug, GodotClass)]
#[class(init, base=Node)]
pub struct Gatherable {
#[export]
grid: Option<Gd<GridPosition>>,
#[export]
item: ItemKind,
#[export]
#[init(val = 1)]
count: i32,
#[export]
#[init(val = true)]
pick_automatically: bool,
#[var(get = get_is_picked, set = set_is_picked)]
_is_picked: bool,
base: Base<Node>,
}
#[godot_api]
impl INode for Gatherable {}
#[godot_api]
impl Gatherable {
#[func]
pub fn get_is_picked(&self) -> bool {
self._is_picked
}
#[func]
pub fn set_is_picked(&mut self, value: bool) {
let old = self._is_picked;
self._is_picked = value;
if old != value {
self.signals().picked_state_changed().emit(value);
}
}
#[func]
fn on_turn_end(&mut self, actor: Option<Gd<TurnActor>>, _action: GString) {
if self.get_is_picked() {
return;
}
let actor = match actor {
Some(actor) => actor,
None => return,
};
let actor_grid = match find_in_parents::<GridPosition, TurnActor>(actor.clone()) {
Some(grid) => grid,
None => return,
};
let gatherer = match find_by_type_in_children::<Gatherer, _>(actor_grid.clone()) {
Some(gatherer) => gatherer,
None => return,
};
let my_coords = self
.grid
.as_ref()
.expect("Getting Grid from EnterTrigger")
.bind()
.get_coords();
let coords = actor_grid.bind().get_coords();
if my_coords.distance_squared_to(coords) <= (gatherer.bind().get_radius() as i64).pow(2) {
self.pick_for_gatherer(gatherer);
}
}
fn pick_for_gatherer(&mut self, mut gatherer: Gd<Gatherer>) {
gatherer.bind_mut().gather(self.item, self.count);
let item = self.item.to_godot().clone();
let count = self.count;
if self.pick_automatically {
self.set_is_picked(true);
}
self.signals().gathered().emit(&item, count);
}
#[signal]
fn picked_state_changed(is_picked: bool);
#[signal]
fn gathered(item: GString, count: i32);
}

View File

@ -1,6 +1,6 @@
use godot::{classes::*, prelude::*};
use godot::{classes::*, obj::WithUserSignals, prelude::*};
use crate::{turn::*, utils::find_in_parents};
use crate::utils::find_in_parents;
#[derive(Debug, GodotClass)]
#[class(init, base=Node)]
@ -78,6 +78,10 @@ pub struct GridPosition {
#[init(val = Vector2::splat(32.0))]
grid_size: Vector2,
#[export]
#[init(val = Vector2::splat(0.5))]
grid_anchor: Vector2,
base: Base<Node2D>,
}
@ -85,85 +89,29 @@ pub struct GridPosition {
impl GridPosition {
#[func]
pub fn get_coords(&self) -> Vector2i {
(self.base().get_global_position() / self.grid_size)
self.world_to_coords(self.base().get_global_position())
}
#[func]
pub fn set_coords(&mut self, coords: Vector2i) {
let old = self.get_coords();
let pos = self.coords_to_world(coords);
self.base_mut().set_global_position(pos);
self.signals().coords_set().emit(old, coords);
}
pub fn coords_to_world(&self, coords: Vector2i) -> Vector2 {
(coords.cast_float() + self.grid_anchor) * self.grid_size
}
pub fn world_to_coords(&self, pos: Vector2) -> Vector2i {
((pos / self.grid_size) - self.grid_anchor)
.round()
.cast_int()
}
#[func]
pub fn set_coords(&mut self, pos: Vector2i) {
let grid_size = self.grid_size;
self.base_mut()
.set_global_position(pos.cast_float() * grid_size);
}
}
#[derive(GodotConvert, Var, Export, Clone, Copy, Default, Debug, PartialEq, Eq)]
#[godot(via = GString)]
pub enum ItemKind {
#[default]
Blueberry,
}
#[derive(Debug, GodotClass)]
#[class(init, base=Node)]
pub struct Gatherer {
#[export]
grid: Option<Gd<GridPosition>>,
#[export]
actor: Option<Gd<TurnActor>>,
#[export]
#[init(val = 0)]
radius: i32,
level: Option<Gd<Level>>,
base: Base<Node>,
}
#[godot_api]
impl INode for Gatherer {
fn ready(&mut self) {
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));
}
}
#[godot_api]
impl Gatherer {
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);
}
Some(())
}
fn try_gather_tile(&self, coords: Vector2i) -> Option<(ItemKind, i32)> {
let mut fg = self.level.clone()?.bind().get_fg();
// TODO: This is a horrible way to handle this
if get_custom_data_bool(&fg, coords, "is_berry") {
let source_id = fg.get_cell_source_id(coords);
let alternative_tile = fg.get_cell_alternative_tile(coords);
let new_atlas_coords = fg.get_cell_atlas_coords(coords) + Vector2i::RIGHT;
fg.set_cell_ex(coords)
.source_id(source_id)
.alternative_tile(alternative_tile)
.atlas_coords(new_atlas_coords)
.done();
return Some((ItemKind::Blueberry, 1));
}
None
}
#[signal]
fn gathered(item: ItemKind, count: i32);
fn coords_set(old: Vector2i, new: Vector2i);
}
#[derive(Debug, GodotClass)]
@ -190,6 +138,10 @@ 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();
self.get_grid()
.signals()
.coords_set()
.connect_other(self, |this, _old, new| this.on_grid_coords_set(new));
}
fn process(&mut self, delta: f64) {
@ -216,12 +168,12 @@ impl Mover {
#[func]
pub fn get_grid(&self) -> Gd<GridPosition> {
self.grid.clone().unwrap()
self.grid.clone().expect("Getting Grid for Mover")
}
#[func]
pub fn get_target_pos(&self) -> Vector2 {
self.target_coords.cast_float() * self.get_grid().bind().grid_size
self.get_grid().bind().coords_to_world(self.target_coords)
}
#[func]
@ -240,7 +192,7 @@ impl Mover {
#[func]
pub fn try_move(&mut self, dir: Vector2i) -> bool {
let start_coords = self.target_coords;
let start_coords = self.get_grid().bind().get_coords();
let target_coords = start_coords + dir;
if !self.can_move(dir) {
@ -253,6 +205,26 @@ impl Mover {
true
}
#[func]
pub fn try_move_instant(&mut self, dir: Vector2i) -> bool {
if !self.try_move(dir) {
return false;
}
let start_coords = self.get_grid().bind().get_coords();
self.get_grid().bind_mut().set_coords(start_coords + dir);
true
}
fn on_grid_coords_set(&mut self, coords: Vector2i) {
// Warning!
// Calling self.get_grid().set_coords() would cause infinite recursion.
if self.is_moving {
self.is_moving = false;
self.target_coords = coords;
self.signals().finished_moving().emit(coords);
}
}
#[signal]
fn started_moving(from_coords: Vector2i, dir: Vector2i);

View File

@ -2,7 +2,8 @@ use godot::prelude::*;
pub struct VelhoExtension;
mod overworld;
mod gathering;
mod grid;
mod turn;
mod utils;

View File

@ -54,9 +54,13 @@ impl TurnManager {
fn start_round(&mut self) {
self.unregister_deleted();
self.current_actor = None;
self.round_queue = self.new_round();
if !self.round_queue.is_empty() {
self.base_mut().propagate_call_ex("on_round_start").done();
self.start_next_turn();
}
}
fn start_next_turn(&mut self) {
self.current_actor = self.round_queue.pop();
@ -77,7 +81,12 @@ impl TurnManager {
}
}
fn on_actor_turn_end(&mut self, _action: GString) {
fn on_actor_turn_end(&mut self, action: GString) {
let actor = self.current_actor.clone();
self.base_mut()
.propagate_call_ex("on_turn_end")
.args(&varray![actor, action])
.done();
self.start_next_turn();
}
}

View File

@ -15,29 +15,33 @@ where
None
}
// /// Try to find a child of type `T` with the name `T::class_name()`
// pub fn find_by_class_name_in_children<T, U>(parent: Gd<U>) -> Option<Gd<T>>
// where
// T: Inherits<Node>,
// U: Inherits<Node>,
// {
// parent
// .upcast::<Node>()
// .try_get_node_as::<T>(&T::class_name().to_string())
// }
/// Try to find a child of type `T` with the name `T::class_name()`
pub fn find_by_class_name_in_children<T, U>(parent: Gd<U>) -> Option<Gd<T>>
where
T: Inherits<Node>,
U: Inherits<Node>,
{
parent
.upcast::<Node>()
.try_get_node_as::<T>(&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<T, U>(parent: Gd<U>) -> Option<Gd<T>>
// where
// T: Inherits<Node>,
// U: Inherits<Node>,
// {
// for child in parent.upcast::<Node>().get_children().iter_shared() {
// if let Ok(result) = child.try_cast::<T>() {
// return Some(result);
// }
// }
// None
// }
/// Try to find a child of type `T` by iterating over children.
/// It first checks for a child with the name of `T::class_name()` before iterating.
///
/// Returns only the first result.
pub fn find_by_type_in_children<T, U>(parent: Gd<U>) -> Option<Gd<T>>
where
T: Inherits<Node>,
U: Inherits<Node>,
{
if let Some(found) = find_by_class_name_in_children::<T, _>(parent.clone()) {
return Some(found);
}
for child in parent.upcast::<Node>().get_children().iter_shared() {
if let Ok(result) = child.try_cast::<T>() {
return Some(result);
}
}
None
}