Hello I've been trying to implement a small game using an EntityComponentSystem in rust. But am getting stuck with lifetimes quite a bit. In this particular case I'm trying to store an sdl2::render::Texture
EntitySystem struct
The EntitySystem came from this blog post: Tutorial: Writing a tiny Entity Component System in Rust
The "working" code is available here: GitHub - yaspoon/bomberus: My failing attempt at Rust ECS it has some current hacks such as requiring the system_drawable to be a closure so that it can capture the texture variable for later use
I'm trying to make this better/more useable by instead having singleton components stored on the EntitySystem struct but getting stuck at the same problem I did before which is the lifetime of the game_texture which is a sdl2::render::Texture<'_>
Essentially the working code looks approximately like this:
pub trait ComponentHashMap {
fn as_any(&self) -> & dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl<T: 'static> ComponentHashMap for RefCell<HashMap<u64, T>> {
fn as_any(&self) -> &dyn Any {
return self as &dyn Any;
}
fn as_any_mut(&mut self) -> &mut dyn Any {
return self as &mut dyn Any;
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Entity {
id: u64,
}
pub struct EntitySystem<'a> {
next_id: u64,
entities: HashMap<u64, String>,
entity_names: HashMap<String, u64>,
components: HashMap<TypeId, Box<dyn ComponentHashMap>>,
}
impl EntitySystem {
pub fn new() -> EntitySystem<'static> {
return EntitySystem {next_id: 0, entities: HashMap::new(), entity_names: HashMap::new(), components: HashMap::new()};
}
--snip--
--endsnip--
}
let mut es = EntitySystem::new();
--snip--
Setup the sdl2 context, windows etc and get a canvas for the window
--endsnip--
let texture_creator = canvas.texture_creator();
let game_texture = match texture_creator.load_texture(Path::new("assets/bomb_party_v4.png")) {
Ok(gt) => gt,
Err(e) => {
println!("Unable to load game texture:{}", e);
return;
},
};
let mut system_drawable = move |es: &mut EntitySystem, _dt: f64| -> Result<(), String> {
--snip--
"capture" the game_texture variable for later use by this closure in the game loop to draw things to the screen
--endsnip--
}
//use the system_drawable closure
The not compiling code is available here in the texture_component_broken
branch. (Sorry new users can only have two links ) pretty much the same as above but with a few changes to store the game_texture as a member of the EntitySystem struct, I followed the compiler recommendations of adding lifetimes but eventually it gets really upset
pub struct EntitySystem<'a> {
next_id: u64,
entities: HashMap<u64, String>,
entity_names: HashMap<String, u64>,
components: HashMap<TypeId, Box<dyn ComponentHashMap>>,
texture: Option<Texture<'a>>
}
impl EntitySystem {
pub fn new() -> EntitySystem<'static> { //Compiler recommends 'static? Probably because of the static lifetime for the hashmaps?
return EntitySystem {next_id: 0, entities: HashMap::new(), entity_names: HashMap::new(), components: HashMap::new(), texture: None};
}
pub fn set_texture_component(&mut self, texture: Option<Texture<'a>) {
self.texture = texture;
}
--snip--
--endsnip--
}
es.set_texture_component(Some(game_texture))
//system_drawable is commented out for now
Following the compilers recommendation results lots of:
error[E0308]: mismatched types
--> src/main.rs:55:24
|
55 | let player = match es.new_entity_with_name("Player".to_string()) {
| ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected mutable reference `&mut EntitySystem<'static>`
found mutable reference `&mut EntitySystem<'_>`
note: the anonymous lifetime defined here...
--> src/main.rs:54:34
|
54 | fn create_player_entity(es: &mut EntitySystem) -> Result<Entity, String> {
| ^^^^^^^^^^^^
= note: ...does not necessarily outlive the static lifetime
I'm guessing this is because of the use of the static lifetime in other parts of the EntitySystem code
which I was following from the tutorial for reference I'm only upto Chapter 10 of the rust book so appologies if this is something simple....