【问题标题】:Rust - Get component in Vec<Box dyn ComponentTrait>> (ECS)Rust - 在 Vec<Box dyn ComponentTrait>> (ECS) 中获取组件
【发布时间】:2020-12-15 05:27:57
【问题描述】:

我是一名使用 Rust 语言的初级开发人员。 我来自 JavaScript,很多特性和特性我还不清楚。

目前,我正在寻找在 Rust 中构建自己的 ECS(实体组件系统)系统。 当我想从实体中获取组件时,我被卡住了。

实际上我用 dyn 盒装向量将组件存储在实体中,这是一个好方法吗?

我的代码:

enum ComponentEnum {
    Position,
    Size
}

trait Component {}

// Position Component
#[derive(PartialEq, PartialOrd, Debug)]
struct Position {
    x: i32,
    y: i32
}

// Size Component
#[derive(PartialEq, PartialOrd, Debug)]
struct Size {
    height: i32,
    width: i32
}

impl Component for Position {}
impl Component for Size {}

struct Entity {
    id: usize,
    components: Vec<Box<dyn Component>>
}

impl Entity {
    fn new(index: usize) -> Self {
        Entity { id: index, components: vec![] }
    }

    // Add a component in Entity
    fn add_component<T: 'static + Component>(&mut self, component: T) {
        self.components.push(Box::new(component));
    }
}

struct EntityStore {
    entities: Vec<Entity>,
    current_index: usize,
}
impl EntityStore {
    fn new() -> EntityStore {
        EntityStore { entities: vec![], current_index: 0 }
    }

    fn generate_index(&self) -> usize {
        unimplemented!();
    }

    // Stop creation system and update EntityStore current_index
    fn end(&mut self) -> &mut Entity {
        let entity = self.entities.get_mut(self.current_index).unwrap();
        self.current_index = self.current_index + 1;
        entity
    }

    fn create_entity(&mut self) -> &mut Self {
        let mut entity = Entity::new(self.current_index);
        self.entities.push(entity);

        self
    }

    // Add component to entity
    fn with_component<T: 'static + Component>(&mut self, component: T) ->  &mut Self {
        let mut entity = self.entities.get_mut(self.current_index).unwrap();
        entity.add_component(component);

        self
    }
}

fn main() {
    let mut es = EntityStore::new();

    // Make entity
    let mut entity1 = es
        .create_entity()
        .with_component(Position { x: 0, y: 0 })
        .with_component(Size { height: 10, width: 10 })
        .end();

    // Get entity position component
    // let component_position_entity1 = entity1.get_component(ComponentEnum::Position);
}

如何从我的实体中取回我的位置组件?

编辑:

这里是获取组件的测试函数(在实体实现中):

fn get_component(&mut self, component_enum: ComponentEnum) { //want return Position or Size component
        let mut entity_components = &self.components;

        // Search component by Name ?
        // Currently, i try to compare Component trait with Component Enum element...
        let component = entity_components
            .iter_mut()
            .find(|component| component == component_enum)
            .unwrap();

        // Here, the component type is "&mut Box<dyn Component>" but i want type like "&mut Position" or "&mut Size"

        component // Here i need to return a Position or Size struct component, but i have Component Trait so i can't use Position/Size functions
}

谢谢。

【问题讨论】:

  • 这里的实际问题是什么?代码是否无法编译,或者它没有按预期工作 - 或者您只是在寻找代码审查?如果你描述的是你想要解决的实际问题,而不是像“实体组件系统”这样的完全抽象的模式,这会有所帮助,它可能无法很好地映射到 Rust,甚至可能不需要你正在处理的工作。
  • 嗨!抱歉,我的问题是:使用我当前的代码,如何从实体中获取组件?
  • 查看您的代码,看起来&amp;entity[index] 应该可以工作。请向我们展示您尝试了什么以及在哪里卡住了 - 例如,您是否编写了 get_component() 函数,但编译失败?另外,请记住,并不是每个人都熟悉您尝试实施的特定模式。
  • 我已经用测试功能更新了我的帖子以获得组件^^

标签: rust entity-component-system


【解决方案1】:

我会使用枚举来区分组件类型(请记住,我一般对 ECS 系统的经验很少)。然后你有多种方法来获取一种类型,但我已经创建了一个方法get_component,它在找到正确的组件时需要一个闭包。然后,您可以向它传递一个闭包,专门检查位置组件。

这是我的实现,基于您的示例:


// Position Component
#[derive(PartialEq, PartialOrd, Debug)]
struct Position {
    x: i32,
    y: i32
}

// Size Component
#[derive(PartialEq, PartialOrd, Debug)]
struct Size {
    height: i32,
    width: i32
}

#[derive(PartialEq, PartialOrd, Debug)]
enum Component {
    Position(Position),
    Size(Size)
}

struct Entity {
    id: usize,
    components: Vec<Component>
}

impl Entity {
    fn new(index: usize) -> Self {
        Entity { id: index, components: vec![] }
    }

    // Add a component in Entity
    fn add_component(&mut self, component: Component) {
        self.components.push(component);
    }
    
    fn get_component(&self, pred: impl Fn(&&Component) -> bool) -> Option<&Component>{
        self.components.iter().find(pred)
    }
    
}

struct EntityStore {
    entities: Vec<Entity>,
    current_index: usize,
}
impl EntityStore {
    fn new() -> EntityStore {
        EntityStore { entities: vec![], current_index: 0 }
    }

    fn generate_index(&self) -> usize {
        unimplemented!();
    }

    // Stop creation system and update EntityStore current_index
    fn end(&mut self) -> &mut Entity {
        let entity = self.entities.get_mut(self.current_index).unwrap();
        self.current_index = self.current_index + 1;
        entity
    }

    fn create_entity(&mut self) -> &mut Self {
        let mut entity = Entity::new(self.current_index);
        self.entities.push(entity);

        self
    }

    // Add component to entity
    fn with_component(&mut self, component: Component) ->  &mut Self {
        let mut entity = self.entities.get_mut(self.current_index).unwrap();
        entity.add_component(component);

        self
    }
}

fn main() {
    let mut es = EntityStore::new();

    // Make entity
    let mut entity1 = es
        .create_entity()
        .with_component(Component::Position(Position { x: 0, y: 0 }))
        .with_component(Component::Size(Size { height: 10, width: 10 }))
        .end();

    // Get entity position component
    let component_position_entity1 = entity1.get_component(|c| if let Component::Position(_) = c { true} else {false});
    println!("{:?}", component_position_entity1);
}

请注意,我的get_component 有很多替代方案,但我的主要观点是使用枚举来区分组件类型,而不是使用Box&lt;dyn Component&gt;

【讨论】:

    【解决方案2】:

    @user4815162342 将此贴在 cmets 中以直接索引到 entity.components

    像这样:

        fn main() {
            let mut es = EntityStore::new();
        
            // Make entity
            let mut entity1 = es
                .create_entity()
                .with_component(Position { x: 0, y: 0 })
                .with_component(Size { height: 10, width: 10 })
                .end();
        
            // Get entity position component
            let v0 = &entity1.components[0];
            let v1 = &entity1.components[1];
            v0.display();
            v1.display();
        }   
    

    但是由于索引取决于添加实体的顺序,那么最好将实体组件存储在哈希映射中,或者使用enum 标记以更清楚每个组件是什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 2020-01-09
      • 1970-01-01
      • 1970-01-01
      • 2020-03-26
      • 1970-01-01
      相关资源
      最近更新 更多