如何在Godot Rust扩展中将自定义类转为Node并添加为子节点
我在Godot Rust扩展中尝试向Node父节点添加自定义子节点时遇到了类型转换问题。自定义的BackgroundTile类继承自AnimatedSprite2D,但在Background类的ready方法中创建该类实例并调用add_child时(第22行),出现以下编译错误:
godot::prelude::Gd<BackgroundTile>类型的参数无法传递给impl AsObjectArg<Node>参数, trait约束godot::prelude::Gd<BackgroundTile>: AsObjectArg<Node>未满足 [E0277]- 该调用引入的约束要求未被满足 [E0277]
- 建议在此处借用:
&[E0277]
明明BackgroundTile已经实现了AnimatedSprite2D,但却不被识别为Node,即使尝试直接使用Godot原生对象也存在同样问题,参考的一年前教程里的方法也失效了。相关代码如下:
use godot::{ classes::{AnimatedSprite2D, IAnimatedSprite2D}, prelude::*, }; #[derive(GodotClass)] #[class(base=AnimatedSprite2D)] pub struct BackgroundTile { pub base: Base<AnimatedSprite2D>, pub position: Vector2, } #[godot_api] pub impl IAnimatedSprite2D for BackgroundTile { fn init(base: Base<AnimatedSprite2D>) -> Self { return Self { base, position: Vector2::ZERO, }; } fn ready(&mut self) { let actual_position = self.position; self.base_mut().set_global_position(actual_position); } } #[godot_api] impl BackgroundTile { #[signal] fn on_create(position: Vector2); }
use crate::background_scripts::background_tile::BackgroundTile; use godot::classes::AnimatableBody2D; use godot::classes::INode2D; use godot::classes::Node2D; use godot::prelude::*; #[derive(GodotClass)] #[class(base=Node2D)] struct Background { base: Base<Node2D>, } #[godot_api] impl INode2D for Background { fn init(base: Base<Node2D>) -> Self { return Self { base }; } fn ready(&mut self) { for _index in 0..10 { let mut tile = BackgroundTile::new_alloc(); self.base_mut().add_child(tile); } } }
解决方法
这个问题的核心是Godot Rust绑定中Gd<T>类型需要显式向上转型,因为add_child期望的是实现AsObjectArg<Node>的类型,而Gd<BackgroundTile>不会自动向上转换为Gd<Node>。你可以通过以下两种方式修复:
方法1:使用upcast方法显式转型
在调用add_child前,将Gd<BackgroundTile>向上转换为Gd<Node>:
fn ready(&mut self) { for _index in 0..10 { let tile = BackgroundTile::new_alloc(); // 显式向上转型为Node类型 self.base_mut().add_child(tile.upcast()); } }
方法2:传递引用并自动转型
如果不想显式调用upcast,可以传递Gd<T>的引用,此时AsObjectArg trait会自动处理向上转型:
fn ready(&mut self) { for _index in 0..10 { let tile = BackgroundTile::new_alloc(); // 传递引用,自动满足AsObjectArg<Node>约束 self.base_mut().add_child(&tile); } }
原因说明
Godot Rust的Gd<T>类型是类型安全的包装器,不会自动进行隐式向上转型(比如从Gd<AnimatedSprite2D>到Gd<Node>)。add_child方法的参数要求实现AsObjectArg<Node>,而Gd<T>只有在T是Node的子类型且显式转型(或通过引用触发自动转型)时才满足该trait约束。旧教程方法失效可能是因为Godot Rust绑定的API更新,比如AsObjectArg trait的实现逻辑发生了变化,现在需要显式处理向上转型。
内容的提问来源于stack exchange,提问作者ElMagoPerodelDQ

