我正在尝试在Rust(版本rustc 1.19.0-nightly (557967766 2017-05-26)
)中编写实体组件系统而不使用向下转换,最好也不使用宏。一般架构是specs
和calx-ecs
的松散合并。
我正在努力定义一个基于所选组件执行系统操作的工作run
方法。要求是系统可以可变地借用每个相关实体的组成部分。但是,我真的和借阅检查员打架,我有点迷茫。
run
方法由Scheduler
结构实现,该结构拥有World
结构和盒装系统特征对象的向量。
pub type ComponentMask = u8;
pub trait AssemblyTrait {
fn new() -> Self;
fn match_mask(&self, entity: &Entity, mask: ComponentMask) -> bool;
fn remove(&mut self, entity: &Entity);
}
pub trait ViewTrait<'a> {
type View;
fn get_view(&'a mut self, entity: &Entity) -> Self::View;
}
pub struct World<'a, A: 'a + AssemblyTrait + ViewTrait<'a>> {
next_idx: usize,
next_uuid: UUID,
free_indices: Vec<usize>,
entities: ComponentContainer<bool>,
pub components: A,
phantom: marker::PhantomData<&'a A>,
}
pub struct Scheduler<'a, A> where A: 'a + AssemblyTrait + ViewTrait<'a> {
world: World<'a, A>,
systems: Vec<Box<'static + SystemTrait<'a, A>>>,
}
impl<'a, A> Scheduler<'a, A> where A: 'a + AssemblyTrait + ViewTrait<'a> {
// Some methods ommitted.
pub fn run(&'a mut self) {
for system in self.systems.iter() {
let mask = system.get_mask();
let mut components: Vec<A::View> = self.world.iter()
.filter(|e| self.world.match_mask(e, mask))
.map(|e| self.world.components.get_view(e))
.collect();
if components.len() > 0 {
system.run(&components);
}
}
}
}
系统特征定义如下:
pub trait SystemTrait<'a, A> where A: AssemblyTrait + ViewTrait<'a> {
fn get_name(&self) -> &'static str;
fn get_mask(&self) -> ComponentMask;
fn run(&mut self, components: &mut [A::View]);
}
我也发布了the full implementation。
ViewTrait
的定义可以在this minimal working example中找到,由于Lifetime parameters in associated type,我设法开始工作。
虽然上面的示例工作正常,但我仍然会为Scheduler::run
方法获取生命周期错误:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src\lib.rs:261:48
|
261 | .map(|e| self.world.components.get_view(e))
| ^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime as defined on the body at 261:22...
--> src\lib.rs:261:22
|
261 | .map(|e| self.world.components.get_view(e))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that closure can access `self`
--> src\lib.rs:261:26
|
261 | .map(|e| self.world.components.get_view(e))
| ^^^^^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 244:1...
--> src\lib.rs:244:1
|
244 | / impl<'a, A> Scheduler<'a, A> where A: 'a + AssemblyTrait + ViewTrait<'a> {
245 | | pub fn new(world: World<'a, A>) -> Scheduler<'a, A> {
246 | | Scheduler {
247 | | world: world,
... |
267 | | }
268 | | }
| |_^
note: ...so that types are compatible (expected &'a mut A, found &mut A)
--> src\lib.rs:261:48
|
261 | .map(|e| self.world.components.get_view(e))
| ^^^^^^^^