Я создаю мошенническое приложение, у меня уже работает загрузчик данных и часть 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
поле может быть строкой, целым числом, с плавающей запятой, логическим значением, диапазоном и т. д., в зависимости от того, что требуется компоненту, это будет указывать значение или возможные значения, которые может иметь компонент, когда компонент генерируется во время построения / создания сущности.
Проблема в том, что я не знаю, как при итерации по объектам выбирать структуру на основе имени компонента, например, выбирать структуру 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), чтобы взять именафункции и получить правильную структуру, все реализующие тип?
Кстати, единственное решение, которое я пытаюсь не использовать, - это гигантское выражение соответствия.
Репозиторий моей работы какстоит здесь
- Диспетчер данных - Загружает и управляет данными, загруженными в игру
- Диспетчер сущностей - Управляет объектами и их компонентами (не поддерживает битовые ключи)
- Entity Builder - Где объекты будут создаваться с использованием данных из диспетчера данных (это то, где я сейчас застрял)
- Компоненты - список простых компонентов
То, чего я пытаюсь избежать, делает что-то вроде этого:
pub fn get(comp_name: &String) -> impl Component {
match comp_name.as_ref() {
"kind" => Kind,
"location" => Location,
"name" => Name,
"position" => Position,
"char" => Char,
}
}
потому что это не совсем поддерживаемо, хотя макрос поможетт, я не очень хорош в этих банкоматах, и это даже не работает, Руст продолжает думать, что я пытаюсь инициализировать типы, когда я просто хочу вернуть один из нескольких возможных типов, которые все будут реализовывать 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
найти компонент и затем инициализировать его?ИЛИ мой подход неверен, и есть лучший способ.
- И если я делаю это неправильно, как другие игры загружают данные, а затем используют их для создания игровых объектов?