pub struct Scene<'a> { /* private fields */ }
Expand description
Container for GameObject
s.
A scene is initialized with Scene::builder
, which is used to register
the GameObject
types which can be spawned into the scene. The memory for
the game objects is allocated at the end in SceneBuilder::build
.
Game objects are spawned with Scene::spawn
, after which they can be
accessed by running systems (in the Entity-Component-System sense) with
Scene::run_system
. To skip the boilerplate, the define_system
macro
is recommended for defining system functions.
§Example
use engine::{game_objects::Scene, define_system, impl_game_object};
// Define some component types:
// NOTE: Zeroable and Pod are manually implemented here to avoid
// the engine depending on proc macros. They should generally be
// derived, if compile times allow, as Pod has a lot of
// requirements that are easy to forget.
#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct Position { pub x: i32, pub y: i32 }
unsafe impl bytemuck::Zeroable for Position {}
unsafe impl bytemuck::Pod for Position {}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct Velocity { pub x: i32, pub y: i32 }
unsafe impl bytemuck::Zeroable for Velocity {}
unsafe impl bytemuck::Pod for Velocity {}
// Define the "Foo" game object:
#[derive(Debug)]
struct Foo {
pub position: Position,
pub velocity: Velocity,
}
impl_game_object! {
impl GameObject for Foo using components {
position: Position,
velocity: Velocity,
}
}
// Create a Scene that five game objects of type Foo can be spawned in:
let mut scene = Scene::builder()
.with_game_object_type::<Foo>(5)
.build(arena, temp_arena)
.unwrap();
// Spawn a game object of type Foo:
scene.spawn(Foo {
position: Position { x: 100, y: 100 },
velocity: Velocity { x: 20, y: -10 },
}).unwrap();
// Run a "physics simulation" system for all game objects which
// have a Position and Velocity component:
scene.run_system(define_system!(|_, pos: &mut [Position], vel: &[Velocity]| {
// This closure gets called once for each game object type with a Position
// and a Velocity, passing in that type's components, which can be zipped
// and iterated through to operate on a single game object's data at a
// time. In this case, the closure only gets called for Foo as it's our
// only game object type, and these slices are 1 long, as we only spawned
// one game object.
for (pos, vel) in pos.iter_mut().zip(vel) {
pos.x += vel.x;
pos.y += vel.y;
}
}));
// Just assert that we ended up where we intended to end up.
let mut positions_in_scene = 0;
scene.run_system(define_system!(|_, pos: &[Position]| {
for pos in pos {
assert_eq!(120, pos.x);
assert_eq!(90, pos.y);
positions_in_scene += 1;
}
}));
assert_eq!(1, positions_in_scene);
// Game objects can be deleted by collecting and deleting them in batches:
use engine::collections::FixedVec;
let mut handles_to_delete = FixedVec::new(temp_arena, 1).unwrap();
scene.run_system(define_system!(|handles, pos: &[Position]| {
for (handle, pos) in handles.zip(pos) {
if pos.x == 120 {
handles_to_delete.push(handle).unwrap();
}
}
}));
// NOTE: After deletion, all handles get invalidated, so
// handles_to_delete would need to be re-acquired from a run_system call.
scene.delete(&mut handles_to_delete).unwrap();
Implementations§
Source§impl Scene<'_>
impl Scene<'_>
Sourcepub fn builder<'a>() -> SceneBuilder<'a>
pub fn builder<'a>() -> SceneBuilder<'a>
Creates a SceneBuilder
which is used to create a Scene
.
Source§impl Scene<'_>
impl Scene<'_>
Sourcepub fn spawn<G: GameObject>(&mut self, object: G) -> Result<(), SpawnError>
pub fn spawn<G: GameObject>(&mut self, object: G) -> Result<(), SpawnError>
Spawns the game object into this scene if there’s space for it.
See the Scene
documentation for example usage.
Sourcepub fn run_system<F>(&mut self, system_func: F) -> bool
pub fn run_system<F>(&mut self, system_func: F) -> bool
Runs system_func
for each game object type in this Scene
, passing
in the components for each.
Returns false
if all system_func
invocations return false
. When
using define_system
, this happens when the scene doesn’t contain any
game object types with the set of components requested.
The GameObjectHandleIterator
returns handles to the game objects
associated with the components in a particular iteration, if iterated
through at the same pace as the component columns.
Each ComponentColumn
contains tightly packed data for a specific
component type, and the columns can be zipped together to iterate
through sets of components belonging to a single game object, as
component A at index N belongs to the same game object as component B at
index N.
This is intended to be used with define_system
, which can extract
the relevant components from the component columns. See the Scene
documentation for example usage.
Sourcepub fn delete(&mut self, handles: &mut [GameObjectHandle]) -> Result<(), usize>
pub fn delete(&mut self, handles: &mut [GameObjectHandle]) -> Result<(), usize>
Deletes the game objects referred to by the given handles.
If any handles are invalid (e.g. have been invalidated by a previous
call to Scene::delete
), the amount of invalid handles is returned in
an Err.
The slice of handles is mutable to allow sorting the slice, which is needed for a performant implementation of this function.