我正在构建一个类似流氓的人,我已经让数据加载器工作并且ECS的一部分工作(从头开始构建)。数据存储在.yml
文件中,用于描述游戏中的内容(在本例中为小怪)以及这些内容具有的功能,例如:
---
orc:
feature_packs:
- physical
- basic_identifiers_mob
features:
- component: char
initial_value: T
goblin:
feature_packs:
- physical
- basic_identifiers_mob
features:
- component: char
initial_value: t
正如你所看到的,有两个怪物描述,一个地精和一个兽人,它们都拥有两个功能包(特征组),还拥有一个char
功能,用于描述它们对玩家的样子。
initial_value
字段可以是字符串,整数,浮点,bool,范围等,具体取决于组件所需的内容,这将指示组件在实体构建期间生成组件时可能具有的值或可能值创建。
问题是我不知道如何在迭代这些特征时,根据组件的名称选择结构,例如,为Char
特征选择"char"
结构。
为了更好地描述我的意思,我用一种我更好理解的语言编写了一个例子,Ruby:
data_manager = function_that_loads_data('folder_path')
Entity_Manager.build(:mob, :orc, data_manager)
class Entity_Manager
class << self
attr_accessor :entities, :components
end
def self.build(entity_type, template_name, data_manager)
template = data_manager[entity_type][template_name]
entity_id = generate_unique_id
entities[entity_id] = Entity.new(entity_id, components: template.components.keys)
template.components.each do |component|
components[component.name][entity_id] =
Components.get(component.name).new(component.initial_value) # <= This part, how do I do the equivalent in rust, a function that will return or allow me to get or create a struct based on the value of a string variable
end
end
end
现在serde是我所知道的唯一能够读取文本数据并将其转换为数据的东西,所以为此目的
我如何使用serde(或更合适的非serde使用解决方案)获取功能的名称并检索正确的结构,所有实现类型?
顺便说一句,我试图不使用的一个解决方案是一个巨大的匹配声明。
我现在的工作回购是here
我想避免的是做这样的事情:
pub fn get(comp_name: &String) -> impl Component {
match comp_name.as_ref() {
"kind" => Kind,
"location" => Location,
"name" => Name,
"position" => Position,
"char" => Char,
}
}
因为它不是真的可维护,虽然宏会有很多帮助,但我不是很擅长这些atm而且它甚至都不起作用,生锈一直在想我正在尝试初始化类型当我只想返回其中一个几种可能的类型都将实现Component
编辑:因为看起来我不够清楚:
pub enum InitialValue {
Char(char),
String(String),
Int(i32),
Float(f32),
Bool(bool),
Range(Range<i32>),
Point((i32,i32))
}
impl InitialValue {
pub fn unwrap_char(&self) -> &char {
match &self {
InitialValue::Char(val) => val,
_ => panic!("Stored value does not match unwrap type")
}
}
pub fn unwrap_string(&self) -> &String {
match &self {
InitialValue::String(val) => val,
_ => panic!("Stored value does not match unwrap type")
}
}
pub fn unwrap_int(&self) -> &i32 {
match &self {
InitialValue::Int(val) => val,
_ => panic!("Stored value does not match unwrap type")
}
}
pub fn unwrap_float(&self) -> &f32 {
match &self {
InitialValue::Float(val) => val,
_ => panic!("Stored value does not match unwrap type")
}
}
pub fn unwrap_bool(&self) -> &bool {
match &self {
InitialValue::Bool(val) => val,
_ => panic!("Stored value does not match unwrap type")
}
}
pub fn unwrap_range(&self) -> &Range<i32> {
match &self {
InitialValue::Range(val) => val,
_ => panic!("Stored value does not match unwrap type")
}
}
pub fn unwrap_point(&self) -> &(i32, i32) {
match &self {
InitialValue::Point(val) => val,
_ => panic!("Stored value does not match unwrap type")
}
}
}
#[derive(Debug, Deserialize)]
pub struct Component {
#[serde(rename="component")]
name: String,
#[serde(default)]
initial_value: Option<InitialValue>,
}
#[derive(Debug, Deserialize)]
pub struct Template {
pub feature_packs: Vec<String>,
pub features: Vec<Component>,
}
Component.name
找到组件然后初始化它?或者是我的错误,并且有更好的方法。听起来你想要一个标记的联合或总和类型; Rust知道这些是enum
erations。 Serde甚至支持使用container internal tags。所以这是我的小实验:
#[macro_use] extern crate serde_derive;
extern crate serde_yaml;
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag="component")]
enum Feature {
Char { initial_value : char },
Weight { kgs : u32 }
}
fn main() {
let v = vec![
Feature::Char{initial_value:'x'},
Feature::Weight{kgs:12}
];
println!("{}", serde_yaml::to_string(&v).unwrap());
}
这输出:
---
- component: Char
initial_value: x
- component: Weight
kgs: 12
可能下一步是为变体制作专用结构。