1个不稳定版本
| 0.1.2 | 2024年1月18日 |
|---|
#1923 in 游戏开发
26 每月下载次数
在 2 crates 中使用
23KB
265 行
gdrust_export_node_path_macro
通过NodePath获取引用时减少样板代码。使用方法包括(下文几段完整的示例)
- 将
#[derive(NativeClass, Default)] #[inherit(Node)]替换为#[extends(Node)] - 删除带有
#[property]标记的NodePath字段 - 在您希望通过
NodePath获取的字段之后放置#[export_path] - 删除您的
fn new(&mut self, _owner: &Node)实现 - 在您的
_ready()声明中手动调用self.grab_nodes_by_path(_owner);
#[extends] 属性宏
- 用
#[derive(NativeClass)] #[inherit(Node)]替换自身 - 然后,对于每个标记有
#[export_path]- 声明另一个同名但带有
path_前缀和NodePath类型的字段,以及一个常规的#[property]属性。 (Vec<Ref<Node>>使用Vec<NodePath>类型) - 示例输入/输出:
#[export_path] node: Option<Ref<Node>>/#[property] path_node: NodePath, node: Option<Ref<Node>>,
- 声明另一个同名但带有
- 声明一个包含两个函数的 impl 块
fn grab_nodes_by_path(&mut self, _owner: &Node) { //搜索从生成的 NodePath 字段中生成的所有节点/实例,并将每个分配给 self 中的原始字段}fn new(_owner: &Node) -> Self { Self::default() }
支持导出
Option<Ref<T>>其中 T 是继承自Node的 Godot 内置类型(例如:Node2D,Control,ProgressBar,KinematicBody,...)Vec<Ref<T>>其中 T 是继承自Node的 Godot 内置类型Option<Instance<T>>其中 T 是您定义的自定义原生脚本,只要该脚本继承自 Godot 内置类型NodeVec<Instance<T>>其中 T 是您定义的自定义原生脚本,只要该脚本继承自 Godot 内置类型Node
PS 1:请注意,Vec<Ref<T>>/Vec<Instance<T>> 使用 Ref<T>/Instance<T> 直接,而不是 Option<Ref<T>>/Option<Instance<T>>
PS 2:这与本 crate 无关,而是与 gdnative-rust 本身相关:在编辑器中,Vec<NodePath> 将显示为 Variant 数组,您必须点击数组中的每个元素,选择 NodePath,然后您就可以拖动节点了。
实现的基础取自 gdrust。
用法
替换
#[derive(NativeClass)]
#[inherit(Node)]
struct MyGodotScript {
#[property] path_exported_node: NodePath,
exported_node: Option<Ref<Node>>,
#[property] path_exported_instance: NodePath,
exported_instance: Option<Instance<NativeScriptTest>>,
#[property] paths_exported_nodes: Vec<NodePath>,
vec_nodes: Vec<Ref<Node>>,
#[property] paths_exported_instances: Vec<NodePath>,
vec_instances: Vec<Instance<NativeScriptTest>>,
}
impl MyGodotScript {
fn new(_owner: &Node) -> Self {
return Self {
path_exported_node: NodePath::default(),
exported_node: None,
path_exported_instance: NodePath::default(),
exported_instance: None,
paths_exported_nodes: Vec::new(),
vec_nodes: Vec::new(),
paths_exported_instances: Vec::new(),
vec_instances: Vec::new(),
};
}
}
#[methods]
impl MyGodotScript {
#[method]
fn _ready(&mut self, #[base] _owner: &Node) {
self.exported_node = Some(unsafe {_owner.get_node_as::<Node>(self.path_exported_node.new_ref()).unwrap().assume_shared()});
self.exported_instance = Some(unsafe {_owner.get_node_as_instance::<NativeScriptTest>(self.path_exported_instance.new_ref()).unwrap().claim()});
for path in self.paths_exported_nodes.iter() {
self.vec_nodes.push(unsafe { _owner.get_node_as::<Node>(path.new_ref()).unwrap().assume_shared()});
}
for path in self.paths_exported_instances.iter() {
self.vec_instances.push(unsafe { _owner.get_node_as_instance::<NativeScriptTest>(path.new_ref()).unwrap().claim()});
}
}
}
#[derive(NativeClass)]
#[inherit(Node)]
pub struct NativeScriptTest { }
impl NativeScriptTest {
fn new(_owner: &Node) -> Self {
return Self {};
}
}
为
#[extends(Node)] // you can replace Node with any other Godot built-in node type
struct MyGodotScript {
#[export_path] exported_node: Option<Ref<Node>>, // you can replace Node with any other Godot built-in node type
#[export_path] exported_instance: Option<Instance<NativeScriptTest>>, // replace NativeScriptTest with your own type
#[export_path] vec_nodes: Vec<Ref<Node>>, // you can replace Node with any other Godot built-in node type
#[export_path] vec_instances: Vec<Instance<NativeScriptTest>>, // replace NativeScriptTest with your own type
}
#[methods]
impl MyGodotScript {
#[method]
fn _ready(&mut self, #[base] _owner: &Node) { // replace Node with the extended type
self.grab_nodes_by_path(_owner); // you must call this manually, it replaces your old _ready() call
}
}
#[extends(Node)]
pub struct NativeScriptTest { }
它扩展为(手动格式化以增强可读性)
#[derive(gdnative::prelude::NativeClass, Default)]
#[inherit(Node)]
struct MyGodotScript {
#[property] path_vec_instances: Vec<gdnative::prelude::NodePath>,
#[property] path_vec_nodes : Vec<gdnative::prelude::NodePath>,
#[property] path_exported_instance: gdnative::prelude::NodePath,
#[property] path_exported_node : gdnative::prelude::NodePath,
exported_node: Option<Ref<Node>>,
exported_instance: Option<Instance<NativeScriptTest>>,
vec_nodes: Vec<Ref<Node>>,
vec_instances: Vec<Instance<NativeScriptTest>>,
}
impl MyGodotScript {
fn new(_owner: &Node) -> Self { Self::default() }
fn grab_nodes_by_path(&mut self, owner: &Node) {
self.exported_node = Some(unsafe { owner.get_node_as::<Node>(self.path_exported_node.new_ref()).unwrap().assume_shared() });
self.exported_instance = Some(unsafe { owner.get_node_as_instance::<NativeScriptTest>(self.path_exported_instance.new_ref()).unwrap().claim() });
for path in self.path_vec_nodes.iter() {
self.vec_nodes.push(unsafe { owner.get_node_as::<Node>(path.new_ref()).unwrap().assume_shared() });
}
for path in self.path_vec_instances.iter() {
self.vec_instances.push(unsafe { owner.get_node_as_instance::<NativeScriptTest>(path.new_ref()).unwrap().claim() });
}
}
}
杂项/限制
- 您仍然可以自由使用其他
gdnative属性,如#[register_with]#[no_constructor]#[user_data]#[property]。只需确保始终将它们放置在#[extends]下方,除了#[property],它仍然位于字段之后。 grab_nodes_by_path(&&mut self, owner: &Node)如果在验证任何导出路径失败时将引发恐慌。- 您不能定义自己的
Self::new()。 _owner在grab_nodes_by_path(&mut self, owner: &Node)中使用了硬编码的&,因此您不能在_ready(&mut self, #[base] _owner: &Node)中将owner声明为owner: TRef<Node>。
依赖项
~3–4.5MB
~88K SLoC