3个版本
0.1.2 | 2024年4月8日 |
---|---|
0.1.1 | 2024年4月8日 |
0.1.0 | 2024年4月8日 |
#1186 在 #工具
每月 35 次下载
在 node_tree 中使用
11KB
NodeTree
NodeTree是一个通过进程树创建大型可扩展程序和游戏的框架。每个进程都是完全自主的,能够存储自己的状态或数据,并与其他进程进行通信。这些进程被称为节点。
⚠️警告⚠️
这是一个依赖夜间构建版本的库。
此库处于早期开发阶段。请注意可能存在的错误或不安全行为。
此库使用的具体夜间版本是v1.78。
入门!
只需在指向您项目目录的终端中运行cargo add node_tree
,或者在cargo.toml
文件中添加node_tree = X.X
即可。
要开始创建利用NodeTree
的Rust程序,我们首先需要创建一个根Node
。为了减少样板代码,我们将使用包含的NodeSys
derive宏来实现所需的Dynamic
和NodeAbstract
特质。然后我们将自己实现Node
特质。
#![feature(arbitrary_self_types)] // Required for now.
use node_tree::prelude::*;
#[derive(Debug, Clone, NodeSys)]
pub struct NodeA {
base: Rc<NodeBase> // Required for Nodes.
}
// To make things simple, it is advised to have most node constructors return the node
// instance wrapped inside of this crate's `Hp<T>` pointer.
impl NodeA {
fn new(name: String) -> Hp<Self> {
Hp::new(NodeA { base: NodeBase::new(name) })
}
}
// Example implementation of the Node trait with custom behaviours.
impl Node for NodeA {
/// Run once the Node is added to the NodeTree.
fn ready(self: Hp<Self>) -> () {
// To show off how you could add children nodes.
if self.depth() < 3 {
self.add_child(NodeA::new(format!("{}_Node", self.depth() + 1)));
self.add_child(NodeA::new(format!("{}_Node", self.depth() + 1)));
self.add_child(NodeA::new(format!("{}_Node", self.depth() + 1)));
}
if self.is_root() {
println!("{:#?}", self.children());
}
}
/// Run once per frame. Provides a delta value in seconds between frames.
fn process(self: Hp<Self>, delta: f32) -> () {
// Example of using the delta value to calculate the current framerate.
println!("{} | {}", self.name(), 1f32 / delta);
// Using the NodePath, you can reference other nodes in the NodeTree from this node.
if self.is_root() {
match self.get_node(NodePath::from_str("1_Node/2_Node1/3_Node2")) {
Some(node) => println!("{:?}", node),
None => ()
}
}
// Nodes can be destroyed. When destroyed, their references from the NodeTree are cleaned up as well.
// If the root node is destroyed, then the program automatically exits. (There are other ways to
// terminate the program such as the queue_termination() function on the NodeTree instance).
if self.children().is_empty() {
self.free(); // We test the progressive destruction of nodes from the tip of the tree
// to the base.
}
}
/// Runs once a Node is removed from the NodeTree, whether that is from the program itself terminating or not.
fn terminal(self: Hp<Self>) -> () {} // We do not do anything here for this example.
/// Returns this node's process mode.
/// Each process mode controls how the process() function behaves when the NodeTree is paused or not.
/// (The NodeTree can be paused or unpaused with the pause() or unpause() functions respectively.)
fn process_mode(self: Hp<Self>) -> ProcessMode {
ProcessMode::Inherit // We will return the default value, which inherits the behaviour from
// the parent node.
}
}
最后,为了激活我们的NodeTree
,我们必须实例化根Node
并将其传递给NodeTree
构造函数。
// ...previous implementations
fn main() -> () {
// Create the tree.
let root: Hp<NodeA> = NodeA::new("Root".to_string());
let tree: Hp<NodeTree> = NodeTree::new(root);
// Begin operations on the tree.
tree.start();
tree.process(); // This will run an indefinite loop until the program exits.
}
特性
- 🏗️一个易于抽象的框架,不同的进程可以以可扩展的方式相互通信和交互。灵感来自Godot!
- ⏯️能够暂停和恢复
NodeTree
,并针对树暂停/恢复时的单个Node
行为进行微调。 - 📡 与其他节点通信的多种方法,例如
owner()
、parent()
、get_child()
、children()
和get_node()
。 - 🔗 一个名为
Hp<T>
的抽象智能指针,它可以隐式克隆以减少语法噪音,并允许低样板。 - 👪 能够通过
add_child()
和remove_child()
管理节点。 - 🌲 允许通过节点的
root()
函数直接引用NodeTree
。 - 📚 TODO:在
NodeTree
上托管一个缓存系统,作为确保Hp<T>
正确性和提高性能的安全接口! - 📜 TODO:包括一个保存和处理单个节点场景的方法,例如方便的视觉宏
Scene!
。
依赖项
~1.5MB
~36K SLoC