update example project entity system component store usage

i think i prefer this style. it's not _technically_ as safe as it was
before, but i prefer the explicitness of it (and it results in a little
bit less nesting in system functions which is nice).

i don't much like the need for an explicit `unwrap()` call however
but that's the tradeoff!
This commit is contained in:
Gered 2023-01-01 12:22:03 -05:00
parent 2b33a64120
commit ed754cb9ac
4 changed files with 389 additions and 371 deletions

View file

@ -95,127 +95,118 @@ fn new_ball_entity(entities: &mut Entities) {
}
fn update_system_movement(context: &mut Context) {
if let Some(mut positions) = context.entities.components_mut::<Position>() {
let velocities = context.entities.components::<Velocity>();
let mut positions = context.entities.components_mut::<Position>().unwrap();
let velocities = context.entities.components::<Velocity>();
for (entity, position) in positions.iter_mut() {
if let Some(velocity) = velocities.get(&entity) {
position.0 += velocity.0 * context.delta;
}
for (entity, position) in positions.iter_mut() {
if let Some(velocity) = velocities.get(&entity) {
position.0 += velocity.0 * context.delta;
}
}
}
fn update_system_collision(context: &mut Context) {
if let Some(bounceable) = context.entities.components::<BouncesAgainstEdge>() {
let mut positions = context.entities.components_mut::<Position>();
let mut velocities = context.entities.components_mut::<Velocity>();
let bounceables = context.entities.components::<BouncesAgainstEdge>().unwrap();
let mut positions = context.entities.components_mut::<Position>();
let mut velocities = context.entities.components_mut::<Velocity>();
for (entity, _) in bounceable.iter() {
let mut position = positions.get_mut(&entity).unwrap();
let mut velocity = velocities.get_mut(&entity).unwrap();
for (entity, _) in bounceables.iter() {
let mut position = positions.get_mut(&entity).unwrap();
let mut velocity = velocities.get_mut(&entity).unwrap();
let mut bounced = false;
if position.0.x as i32 <= SCREEN_LEFT as i32 || position.0.x as i32 + BALL_SIZE >= SCREEN_RIGHT as i32 {
position.0.x -= velocity.0.x * context.delta;
velocity.0.x = -velocity.0.x;
bounced = true;
}
if position.0.y as i32 <= SCREEN_TOP as i32 || position.0.y as i32 + BALL_SIZE >= SCREEN_BOTTOM as i32 {
position.0.y -= velocity.0.y * context.delta;
velocity.0.y = -velocity.0.y;
bounced = true;
}
if bounced {
context.event_publisher.queue(Event::CollideAgainstEdge(*entity));
}
let mut bounced = false;
if position.0.x as i32 <= SCREEN_LEFT as i32 || position.0.x as i32 + BALL_SIZE >= SCREEN_RIGHT as i32 {
position.0.x -= velocity.0.x * context.delta;
velocity.0.x = -velocity.0.x;
bounced = true;
}
if position.0.y as i32 <= SCREEN_TOP as i32 || position.0.y as i32 + BALL_SIZE >= SCREEN_BOTTOM as i32 {
position.0.y -= velocity.0.y * context.delta;
velocity.0.y = -velocity.0.y;
bounced = true;
}
if bounced {
context.event_publisher.queue(Event::CollideAgainstEdge(*entity));
}
}
}
fn update_system_lifetime(context: &mut Context) {
if let Some(mut lifetimes) = context.entities.components_mut::<LifeLeft>() {
for (entity, lifetime) in lifetimes.iter_mut() {
lifetime.life -= context.delta;
if lifetime.life < 0.0 {
context.event_publisher.queue(Event::Kill(*entity));
}
let mut lifetimes = context.entities.components_mut::<LifeLeft>().unwrap();
for (entity, lifetime) in lifetimes.iter_mut() {
lifetime.life -= context.delta;
if lifetime.life < 0.0 {
context.event_publisher.queue(Event::Kill(*entity));
}
}
}
fn update_system_leave_particle_trail(context: &mut Context) {
if let Some(mut leaves_trails) = context.entities.components_mut::<LeavesTrail>() {
let mut leaves_trails = context.entities.components_mut::<LeavesTrail>().unwrap();
let positions = context.entities.components::<Position>();
let positions = context.entities.components::<Position>();
for (entity, leaves_trail) in leaves_trails.iter_mut() {
leaves_trail.timer -= context.delta;
for (entity, leaves_trail) in leaves_trails.iter_mut() {
leaves_trail.timer -= context.delta;
if leaves_trail.timer <= 0.0 {
leaves_trail.timer = BALL_TRAIL_PARTICLE_INTERVAL;
let position = positions.get(&entity).unwrap();
let mut trail_position = position.0;
trail_position.x += (BALL_SIZE / 2) as f32;
trail_position.y += (BALL_SIZE / 2) as f32;
context.event_publisher.queue(Event::LeaveTrail(trail_position));
}
if leaves_trail.timer <= 0.0 {
leaves_trail.timer = BALL_TRAIL_PARTICLE_INTERVAL;
let position = positions.get(&entity).unwrap();
let mut trail_position = position.0;
trail_position.x += (BALL_SIZE / 2) as f32;
trail_position.y += (BALL_SIZE / 2) as f32;
context.event_publisher.queue(Event::LeaveTrail(trail_position));
}
}
}
fn render_system_sprites(context: &mut Context) {
if let Some(sprite_indices) = context.entities.components::<SpriteIndex>() {
let sprite_indices = context.entities.components::<SpriteIndex>().unwrap();
let positions = context.entities.components::<Position>();
let positions = context.entities.components::<Position>();
for (entity, sprite_index) in sprite_indices.iter() {
let position = positions.get(&entity).unwrap();
context.system.video.blit(
BlitMethod::Transparent(0),
&context.sprites[sprite_index.0],
position.0.x as i32,
position.0.y as i32
);
}
for (entity, sprite_index) in sprite_indices.iter() {
let position = positions.get(&entity).unwrap();
context.system.video.blit(
BlitMethod::Transparent(0),
&context.sprites[sprite_index.0],
position.0.x as i32,
position.0.y as i32
);
}
}
fn render_system_particles(context: &mut Context) {
if let Some(particles) = context.entities.components::<Particle>() {
let particles = context.entities.components::<Particle>().unwrap();
let positions = context.entities.components::<Position>();
let colors = context.entities.components::<Color>();
let colors_by_lifetime = context.entities.components::<ColorByLifeTime>();
let lifetimes = context.entities.components::<LifeLeft>();
let positions = context.entities.components::<Position>();
let colors = context.entities.components::<Color>();
let colors_by_lifetime = context.entities.components::<ColorByLifeTime>();
let lifetimes = context.entities.components::<LifeLeft>();
for (entity, _) in particles.iter() {
let position = positions.get(&entity).unwrap();
for (entity, _) in particles.iter() {
let position = positions.get(&entity).unwrap();
let pixel_color;
if let Some(color) = colors.get(&entity) {
pixel_color = Some(color.0);
} else if let Some(color_by_lifetime) = colors_by_lifetime.get(&entity) {
let lifetime = lifetimes.get(&entity).unwrap();
let percent_life = lifetime.life / lifetime.initial;
pixel_color = Some(if percent_life >= 0.8 {
color_by_lifetime.0
} else if percent_life >= 0.6 {
color_by_lifetime.1
} else if percent_life >= 0.4 {
color_by_lifetime.2
} else if percent_life >= 0.2 {
color_by_lifetime.3
} else {
color_by_lifetime.4
});
let pixel_color;
if let Some(color) = colors.get(&entity) {
pixel_color = Some(color.0);
} else if let Some(color_by_lifetime) = colors_by_lifetime.get(&entity) {
let lifetime = lifetimes.get(&entity).unwrap();
let percent_life = lifetime.life / lifetime.initial;
pixel_color = Some(if percent_life >= 0.8 {
color_by_lifetime.0
} else if percent_life >= 0.6 {
color_by_lifetime.1
} else if percent_life >= 0.4 {
color_by_lifetime.2
} else if percent_life >= 0.2 {
color_by_lifetime.3
} else {
pixel_color = None;
}
color_by_lifetime.4
});
} else {
pixel_color = None;
}
if let Some(color) = pixel_color {
context.system.video.set_pixel(position.0.x as i32, position.0.y as i32, color);
}
if let Some(color) = pixel_color {
context.system.video.set_pixel(position.0.x as i32, position.0.y as i32, color);
}
}
}
@ -241,6 +232,16 @@ fn event_handler(event: &Event, context: &mut Context) -> bool {
}
pub fn init_entities(entities: &mut Entities) {
entities.init_components::<Position>();
entities.init_components::<Velocity>();
entities.init_components::<SpriteIndex>();
entities.init_components::<BouncesAgainstEdge>();
entities.init_components::<Particle>();
entities.init_components::<Color>();
entities.init_components::<LifeLeft>();
entities.init_components::<LeavesTrail>();
entities.init_components::<ColorByLifeTime>();
entities.remove_all_entities();
for _ in 0..NUM_BALLS {
new_ball_entity(entities);

View file

@ -395,12 +395,45 @@ pub fn init_everything(context: &mut Game, map_file: &Path, min_spawn_time: f32,
}
pub fn init_entities(entities: &mut Entities) {
entities.remove_all_entities();
entities.init_components::<Weapon>();
entities.init_components::<Player>();
entities.init_components::<Slime>();
entities.init_components::<Activity>();
entities.init_components::<AnimationDef>();
entities.init_components::<AnimationInstance>();
entities.init_components::<AnimateByActivity>();
entities.init_components::<KillWhenAnimationFinishes>();
entities.init_components::<Position>();
entities.init_components::<Velocity>();
entities.init_components::<Forces>();
entities.init_components::<Bounds>();
entities.init_components::<FacingDirection>();
entities.init_components::<IgnoresCollision>();
entities.init_components::<IgnoresFriction>();
entities.init_components::<Particle>();
entities.init_components::<LifeTime>();
entities.init_components::<Pixel>();
entities.init_components::<Sprite>();
entities.init_components::<RandomlyWalksAround>();
entities.init_components::<WalkingTime>();
entities.init_components::<MovementSpeed>();
entities.init_components::<World>();
entities.init_components::<SpawnTimer>();
entities.init_components::<Camera>();
entities.init_components::<Pushable>();
entities.init_components::<Pusher>();
entities.init_components::<AttachedTo>();
entities.init_components::<Attachment>();
entities.init_components::<AttachmentOffset>();
entities.init_components::<AttachmentOffsetByDirection>();
entities.init_components::<Attackable>();
entities.init_components::<SpriteIndexByDirection>();
entities.init_components::<Weapon>();
entities.init_components::<Life>();
entities.init_components::<TimedFlicker>();
entities.init_components::<HitParticleColor>();
entities.init_components::<Pickupable>();
entities.init_components::<Pickuper>();
entities.remove_all_entities();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

View file

@ -267,56 +267,53 @@ pub fn pickup(context: &mut Core, picked_up_by: EntityId, picked_up: EntityId) {
///////////////////////////////////////////////////////////////////////////////////////////////////
fn update_system_movement(context: &mut Core) {
if let Some(mut positions) = context.entities.components_mut::<Position>() {
let velocities = context.entities.components::<Velocity>();
let forces = context.entities.components::<Forces>();
let bounds = context.entities.components::<Bounds>();
let ignores_collision = context.entities.components::<IgnoresCollision>();
let mut positions = context.entities.components_mut::<Position>().unwrap();
let velocities = context.entities.components::<Velocity>();
let forces = context.entities.components::<Forces>();
let bounds = context.entities.components::<Bounds>();
let ignores_collision = context.entities.components::<IgnoresCollision>();
for (entity, position) in positions.iter_mut() {
if ignores_collision.contains_key(entity) {
if let Some(velocity) = velocities.get(entity) {
position.0 += velocity.0 * context.delta;
}
} else {
let velocity = velocities.get(entity);
let force = forces.get(entity);
for (entity, position) in positions.iter_mut() {
if ignores_collision.contains_key(entity) {
if let Some(velocity) = velocities.get(entity) {
position.0 += velocity.0 * context.delta;
}
} else {
let velocity = velocities.get(entity);
let force = forces.get(entity);
if velocity.is_some() || force.is_some() {
move_entity_with_collision(
position,
bounds.get(entity).unwrap(),
velocity,
force,
&context.tilemap,
context.delta,
);
}
if velocity.is_some() || force.is_some() {
move_entity_with_collision(
position,
bounds.get(entity).unwrap(),
velocity,
force,
&context.tilemap,
context.delta,
);
}
}
}
}
fn update_system_friction(context: &mut Core) {
if let Some(mut velocities) = context.entities.components_mut::<Velocity>() {
let ignores_friction = context.entities.components::<IgnoresFriction>();
let mut velocities = context.entities.components_mut::<Velocity>().unwrap();
let ignores_friction = context.entities.components::<IgnoresFriction>();
for (entity, velocity) in velocities.iter_mut() {
if !ignores_friction.contains_key(entity) {
velocity.0 *= FRICTION;
if velocity.0.almost_zero(0.001) {
velocity.0 = Vector2::ZERO;
}
for (entity, velocity) in velocities.iter_mut() {
if !ignores_friction.contains_key(entity) {
velocity.0 *= FRICTION;
if velocity.0.almost_zero(0.001) {
velocity.0 = Vector2::ZERO;
}
}
}
}
fn update_system_force_decay(context: &mut Core) {
if let Some(mut forces) = context.entities.components_mut::<Forces>() {
for (_, force) in forces.iter_mut() {
force.decay();
}
let mut forces = context.entities.components_mut::<Forces>().unwrap();
for (_, force) in forces.iter_mut() {
force.decay();
}
}
@ -355,138 +352,132 @@ fn update_system_pushing(context: &mut Core) {
}
fn update_system_lifetime(context: &mut Core) {
if let Some(mut lifetimes) = context.entities.components_mut::<LifeTime>() {
for (entity, lifetime) in lifetimes.iter_mut() {
lifetime.0 -= context.delta;
if lifetime.0 < 0.0 {
context.event_publisher.queue(Event::Remove(*entity));
}
let mut lifetimes = context.entities.components_mut::<LifeTime>().unwrap();
for (entity, lifetime) in lifetimes.iter_mut() {
lifetime.0 -= context.delta;
if lifetime.0 < 0.0 {
context.event_publisher.queue(Event::Remove(*entity));
}
}
}
fn update_system_animation(context: &mut Core) {
if let Some(mut animations) = context.entities.components_mut::<AnimationInstance>() {
let kill_when_animation_finishes = context.entities.components::<KillWhenAnimationFinishes>();
let mut animations = context.entities.components_mut::<AnimationInstance>().unwrap();
let kill_when_animation_finishes = context.entities.components::<KillWhenAnimationFinishes>();
for (entity, animation) in animations.iter_mut() {
if animation.complete {
continue;
}
for (entity, animation) in animations.iter_mut() {
if animation.complete {
continue;
}
animation.frame_timer += context.delta;
animation.frame_timer += context.delta;
let delay = if let Some(delay_override) = animation.delay_override {
delay_override
} else {
animation.def.delay
};
let delay = if let Some(delay_override) = animation.delay_override {
delay_override
} else {
animation.def.delay
};
if animation.frame_timer >= delay {
// move to the next frame in the current sequence
animation.frame_timer = 0.0;
if animation.frame_index == (animation.def.frames.len() - 1) {
// we're at the last frame in the current sequence
if !animation.def.loops {
animation.complete = true;
if animation.frame_timer >= delay {
// move to the next frame in the current sequence
animation.frame_timer = 0.0;
if animation.frame_index == (animation.def.frames.len() - 1) {
// we're at the last frame in the current sequence
if !animation.def.loops {
animation.complete = true;
context.event_publisher.queue(Event::AnimationFinished(*entity));
if kill_when_animation_finishes.contains_key(entity) {
context.event_publisher.queue(Event::Remove(*entity));
}
} else {
animation.frame_index = 0;
context.event_publisher.queue(Event::AnimationFinished(*entity));
if kill_when_animation_finishes.contains_key(entity) {
context.event_publisher.queue(Event::Remove(*entity));
}
} else {
animation.frame_index += 1;
animation.frame_index = 0;
}
} else {
animation.frame_index += 1;
}
}
}
}
fn update_system_set_sprite_index_from_animation(context: &mut Core) {
if let Some(animations) = context.entities.components::<AnimationInstance>() {
let mut sprites = context.entities.components_mut::<Sprite>();
let facing_directions = context.entities.components::<FacingDirection>();
let animations = context.entities.components::<AnimationInstance>().unwrap();
let mut sprites = context.entities.components_mut::<Sprite>();
let facing_directions = context.entities.components::<FacingDirection>();
for (entity, animation) in animations.iter() {
if let Some(sprite) = sprites.get_mut(entity) {
// base animation sprite-sheet index for the current animation state
let mut index = animation.def.frames[animation.frame_index];
for (entity, animation) in animations.iter() {
if let Some(sprite) = sprites.get_mut(entity) {
// base animation sprite-sheet index for the current animation state
let mut index = animation.def.frames[animation.frame_index];
// add multi-direction offset if applicable
let multi_direction_offset = animation.def.multi_direction_offset;
let facing_direction = facing_directions.get(entity);
if multi_direction_offset.is_some() && facing_direction.is_some() {
index += multi_direction_offset.unwrap() * facing_direction.unwrap().0 as usize;
}
sprite.index = index;
// add multi-direction offset if applicable
let multi_direction_offset = animation.def.multi_direction_offset;
let facing_direction = facing_directions.get(entity);
if multi_direction_offset.is_some() && facing_direction.is_some() {
index += multi_direction_offset.unwrap() * facing_direction.unwrap().0 as usize;
}
sprite.index = index;
}
}
}
fn update_system_set_sprite_index_by_direction(context: &mut Core) {
if let Some(sprite_index_by_directions) = context.entities.components::<SpriteIndexByDirection>() {
let mut sprites = context.entities.components_mut::<Sprite>();
let facing_directions = context.entities.components::<FacingDirection>();
let sprite_index_by_directions = context.entities.components::<SpriteIndexByDirection>().unwrap();
let mut sprites = context.entities.components_mut::<Sprite>();
let facing_directions = context.entities.components::<FacingDirection>();
for (entity, sprite_index_by_direction) in sprite_index_by_directions.iter() {
if let Some(sprite) = sprites.get_mut(entity) {
if let Some(facing_direction) = facing_directions.get(entity) {
sprite.index = sprite_index_by_direction.base_index + facing_direction.0 as usize;
}
for (entity, sprite_index_by_direction) in sprite_index_by_directions.iter() {
if let Some(sprite) = sprites.get_mut(entity) {
if let Some(facing_direction) = facing_directions.get(entity) {
sprite.index = sprite_index_by_direction.base_index + facing_direction.0 as usize;
}
}
}
}
fn update_system_walking_time(context: &mut Core) {
if let Some(mut walking_times) = context.entities.components_mut::<WalkingTime>() {
let activities = context.entities.components::<Activity>();
let mut walking_times = context.entities.components_mut::<WalkingTime>().unwrap();
let activities = context.entities.components::<Activity>();
for (entity, walking_time) in walking_times.iter_mut() {
if let Some(activity) = activities.get(entity) {
// dead entities can't walk!
if activity.0 == EntityActivity::Dead {
continue;
}
}
if walking_time.0 > 0.0 {
walking_time.0 -= context.delta;
context.event_publisher.queue(Event::MoveForward(*entity));
for (entity, walking_time) in walking_times.iter_mut() {
if let Some(activity) = activities.get(entity) {
// dead entities can't walk!
if activity.0 == EntityActivity::Dead {
continue;
}
}
// remove walking time components whose timers have elapsed
walking_times.retain(|_, comp| comp.0 > 0.0);
if walking_time.0 > 0.0 {
walking_time.0 -= context.delta;
context.event_publisher.queue(Event::MoveForward(*entity));
}
}
// remove walking time components whose timers have elapsed
walking_times.retain(|_, comp| comp.0 > 0.0);
}
fn update_system_randomly_walk_around(context: &mut Core) {
if let Some(mut randomly_walk_arounds) = context.entities.components_mut::<RandomlyWalksAround>() {
let activities = context.entities.components::<Activity>();
let mut walking_times = context.entities.components_mut::<WalkingTime>().unwrap();
let mut randomly_walk_arounds = context.entities.components_mut::<RandomlyWalksAround>().unwrap();
let activities = context.entities.components::<Activity>();
let mut walking_times = context.entities.components_mut::<WalkingTime>().unwrap();
for (entity, randomly_walk_around) in randomly_walk_arounds.iter_mut() {
if let Some(activity) = activities.get(entity) {
if activity.0 == EntityActivity::Idle {
if randomly_walk_around.cooldown_timer > 0.0 {
randomly_walk_around.cooldown_timer -= context.delta;
if randomly_walk_around.cooldown_timer < 0.0 {
randomly_walk_around.cooldown_timer = 0.0;
}
} else if randomly_walk_around.should_start_walking() {
randomly_walk_around.cooldown_timer = rnd_value(randomly_walk_around.min_cooldown, randomly_walk_around.max_cooldown);
let direction = Direction::new_random();
let walk_time = rnd_value(randomly_walk_around.min_walk_time, randomly_walk_around.max_walk_time);
walking_times.insert(*entity, WalkingTime(walk_time));
context.event_publisher.queue(Event::TurnAndMove(*entity, direction));
for (entity, randomly_walk_around) in randomly_walk_arounds.iter_mut() {
if let Some(activity) = activities.get(entity) {
if activity.0 == EntityActivity::Idle {
if randomly_walk_around.cooldown_timer > 0.0 {
randomly_walk_around.cooldown_timer -= context.delta;
if randomly_walk_around.cooldown_timer < 0.0 {
randomly_walk_around.cooldown_timer = 0.0;
}
} else if randomly_walk_around.should_start_walking() {
randomly_walk_around.cooldown_timer = rnd_value(randomly_walk_around.min_cooldown, randomly_walk_around.max_cooldown);
let direction = Direction::new_random();
let walk_time = rnd_value(randomly_walk_around.min_walk_time, randomly_walk_around.max_walk_time);
walking_times.insert(*entity, WalkingTime(walk_time));
context.event_publisher.queue(Event::TurnAndMove(*entity, direction));
}
}
}
@ -494,26 +485,25 @@ fn update_system_randomly_walk_around(context: &mut Core) {
}
fn update_system_current_entity_activity(context: &mut Core) {
if let Some(activities) = context.entities.components::<Activity>() {
let velocities = context.entities.components::<Velocity>();
let activities = context.entities.components::<Activity>().unwrap();
let velocities = context.entities.components::<Velocity>();
for (entity, activity) in activities.iter() {
// try to detect current entity activity based on it's own movement speed
// (intentionally NOT checking force velocity!)
if let Some(velocity) = velocities.get(entity) {
match activity.0 {
EntityActivity::Idle => {
if velocity.0.length_squared() > 0.0 {
context.event_publisher.queue(Event::SetActivity(*entity, EntityActivity::Walking));
}
for (entity, activity) in activities.iter() {
// try to detect current entity activity based on it's own movement speed
// (intentionally NOT checking force velocity!)
if let Some(velocity) = velocities.get(entity) {
match activity.0 {
EntityActivity::Idle => {
if velocity.0.length_squared() > 0.0 {
context.event_publisher.queue(Event::SetActivity(*entity, EntityActivity::Walking));
}
EntityActivity::Walking => {
if velocity.0.almost_zero(0.001) {
context.event_publisher.queue(Event::SetActivity(*entity, EntityActivity::Idle));
}
}
_ => {}
}
EntityActivity::Walking => {
if velocity.0.almost_zero(0.001) {
context.event_publisher.queue(Event::SetActivity(*entity, EntityActivity::Idle));
}
}
_ => {}
}
}
}
@ -557,56 +547,54 @@ fn update_system_camera_follows_player(context: &mut Core) {
}
fn update_system_turn_attached_entities(context: &mut Core) {
if let Some(attachments) = context.entities.components::<Attachment>() {
let mut facing_directions = context.entities.components_mut::<FacingDirection>();
let attachments = context.entities.components::<Attachment>().unwrap();
let mut facing_directions = context.entities.components_mut::<FacingDirection>();
for (parent_entity, attachment) in attachments.iter() {
// the parent may not have a facing direction. and if so, we don't need to change the
// attachment (child)
let parent_facing_direction = if let Some(facing_direction) = facing_directions.get(&parent_entity) {
facing_direction.0
} else {
continue;
};
for (parent_entity, attachment) in attachments.iter() {
// the parent may not have a facing direction. and if so, we don't need to change the
// attachment (child)
let parent_facing_direction = if let Some(facing_direction) = facing_directions.get(&parent_entity) {
facing_direction.0
} else {
continue;
};
// change the direction of the attachment (child) to match the parent ... if the
// attachment even has a direction itself ...
if let Some(mut facing_direction) = facing_directions.get_mut(&attachment.0) {
facing_direction.0 = parent_facing_direction;
}
// change the direction of the attachment (child) to match the parent ... if the
// attachment even has a direction itself ...
if let Some(mut facing_direction) = facing_directions.get_mut(&attachment.0) {
facing_direction.0 = parent_facing_direction;
}
}
}
fn update_system_position_attached_entities(context: &mut Core) {
if let Some(attachments) = context.entities.components::<Attachment>() {
let mut positions = context.entities.components_mut::<Position>();
let facing_directions = context.entities.components::<FacingDirection>();
let offsets = context.entities.components::<AttachmentOffset>();
let offset_by_directions = context.entities.components::<AttachmentOffsetByDirection>();
let attachments = context.entities.components::<Attachment>().unwrap();
let mut positions = context.entities.components_mut::<Position>();
let facing_directions = context.entities.components::<FacingDirection>();
let offsets = context.entities.components::<AttachmentOffset>();
let offset_by_directions = context.entities.components::<AttachmentOffsetByDirection>();
for (parent_entity, attachment) in attachments.iter() {
// get the parent position used as the base for the attached (child) entity. if the
// parent doesn't have one (probably it is dead?), then skip this attachment
let parent_position;
if let Some(position) = positions.get(&parent_entity) {
parent_position = position.0;
} else {
continue;
}
for (parent_entity, attachment) in attachments.iter() {
// get the parent position used as the base for the attached (child) entity. if the
// parent doesn't have one (probably it is dead?), then skip this attachment
let parent_position;
if let Some(position) = positions.get(&parent_entity) {
parent_position = position.0;
} else {
continue;
}
let attached_entity = attachment.0;
if let Some(mut attachment_position) = positions.get_mut(&attached_entity) {
// start off the attachment by placing it directly at the parent
attachment_position.0 = parent_position;
let attached_entity = attachment.0;
if let Some(mut attachment_position) = positions.get_mut(&attached_entity) {
// start off the attachment by placing it directly at the parent
attachment_position.0 = parent_position;
// then add whatever position offset it needs
if let Some(offset) = offsets.get(&attached_entity) {
attachment_position.0 += offset.0;
} else if let Some(offset_by_direction) = offset_by_directions.get(&attached_entity) {
if let Some(facing_direction) = facing_directions.get(&attached_entity) {
attachment_position.0 += offset_by_direction.offsets[facing_direction.0 as usize];
}
// then add whatever position offset it needs
if let Some(offset) = offsets.get(&attached_entity) {
attachment_position.0 += offset.0;
} else if let Some(offset_by_direction) = offset_by_directions.get(&attached_entity) {
if let Some(facing_direction) = facing_directions.get(&attached_entity) {
attachment_position.0 += offset_by_direction.offsets[facing_direction.0 as usize];
}
}
}
@ -614,52 +602,49 @@ fn update_system_position_attached_entities(context: &mut Core) {
}
fn update_system_timed_flicker(context: &mut Core) {
if let Some(mut timed_flicker) = context.entities.components_mut::<TimedFlicker>() {
for (_, flicker) in timed_flicker.iter_mut() {
flicker.update(context.delta);
}
timed_flicker.retain(|_, flicker| flicker.timer > 0.0);
let mut timed_flickers = context.entities.components_mut::<TimedFlicker>().unwrap();
for (_, flicker) in timed_flickers.iter_mut() {
flicker.update(context.delta);
}
timed_flickers.retain(|_, flicker| flicker.timer > 0.0);
}
fn update_system_pickups(context: &mut Core) {
if let Some(mut pickupables) = context.entities.components_mut::<Pickupable>() {
let pickupers = context.entities.components::<Pickuper>().unwrap();
let positions = context.entities.components::<Position>();
let bounds = context.entities.components::<Bounds>();
let mut pickupables = context.entities.components_mut::<Pickupable>().unwrap();
let pickupers = context.entities.components::<Pickuper>().unwrap();
let positions = context.entities.components::<Position>();
let bounds = context.entities.components::<Bounds>();
// don't really think this pre_timer thing is necessary anymore ... ?
for (_, pickupable) in pickupables.iter_mut() {
if pickupable.pre_timer > 0.0 {
pickupable.pre_timer -= context.delta;
}
// don't really think this pre_timer thing is necessary anymore ... ?
for (_, pickupable) in pickupables.iter_mut() {
if pickupable.pre_timer > 0.0 {
pickupable.pre_timer -= context.delta;
}
}
// TODO: this is slow
// TODO: this is slow
for (pickuper_entity, _) in pickupers.iter() {
let pickuper_position = positions.get(pickuper_entity).unwrap();
let pickuper_bounds = bounds.get(pickuper_entity).unwrap();
let pickuper_circle = Circle::new(
pickuper_position.0.x as i32 + pickuper_bounds.width as i32 / 2,
pickuper_position.0.y as i32 + pickuper_bounds.height as i32 / 2,
pickuper_bounds.radius
);
for (pickuper_entity, _) in pickupers.iter() {
let pickuper_position = positions.get(pickuper_entity).unwrap();
let pickuper_bounds = bounds.get(pickuper_entity).unwrap();
let pickuper_circle = Circle::new(
pickuper_position.0.x as i32 + pickuper_bounds.width as i32 / 2,
pickuper_position.0.y as i32 + pickuper_bounds.height as i32 / 2,
pickuper_bounds.radius
);
for (pickupable_entity, pickupable) in pickupables.iter() {
if pickupable.pre_timer <= 0.0 {
let pickupable_position = positions.get(pickupable_entity).unwrap();
let pickupable_bounds = bounds.get(pickupable_entity).unwrap();
let pickupable_circle = Circle::new(
pickupable_position.0.x as i32 + pickupable_bounds.width as i32 / 2,
pickupable_position.0.y as i32 + pickupable_bounds.height as i32 / 2,
pickupable_bounds.radius
);
for (pickupable_entity, pickupable) in pickupables.iter() {
if pickupable.pre_timer <= 0.0 {
let pickupable_position = positions.get(pickupable_entity).unwrap();
let pickupable_bounds = bounds.get(pickupable_entity).unwrap();
let pickupable_circle = Circle::new(
pickupable_position.0.x as i32 + pickupable_bounds.width as i32 / 2,
pickupable_position.0.y as i32 + pickupable_bounds.height as i32 / 2,
pickupable_bounds.radius
);
if pickupable_circle.overlaps(&pickuper_circle) {
context.event_publisher.queue(Event::Pickup(*pickuper_entity, *pickupable_entity));
}
if pickupable_circle.overlaps(&pickuper_circle) {
context.event_publisher.queue(Event::Pickup(*pickuper_entity, *pickupable_entity));
}
}
}
@ -671,67 +656,65 @@ fn update_system_pickups(context: &mut Core) {
fn render_system_sprites(context: &mut Core) {
context.sprite_render_list.clear();
if let Some(sprites) = context.entities.components::<Sprite>() {
if let Some((_, camera)) = context.entities.components::<Camera>().single() {
let positions = context.entities.components::<Position>().unwrap();
let timed_flickers = context.entities.components::<TimedFlicker>().unwrap();
let sprites = context.entities.components::<Sprite>().unwrap();
let positions = context.entities.components::<Position>().unwrap();
let timed_flickers = context.entities.components::<TimedFlicker>().unwrap();
// build up list of entities to be rendered with their positions so we can sort them
// and render these entities with a proper y-based sort order
for (entity, _) in sprites.iter() {
let mut blit_method = BlitMethod::Transparent(0);
if let Some((_, camera)) = context.entities.components::<Camera>().single() {
// build up list of entities to be rendered with their positions so we can sort them
// and render these entities with a proper y-based sort order
for (entity, _) in sprites.iter() {
let mut blit_method = BlitMethod::Transparent(0);
// check for flicker effects
if let Some(flicker) = timed_flickers.get(entity) {
if !flicker.flick {
match flicker.method {
FlickerMethod::OnOff => {
// skip to the next entity, this one isn't visible
continue;
},
FlickerMethod::Color(draw_color) => {
blit_method = BlitMethod::TransparentSingle {
transparent_color: 0,
draw_color
};
}
// check for flicker effects
if let Some(flicker) = timed_flickers.get(entity) {
if !flicker.flick {
match flicker.method {
FlickerMethod::OnOff => {
// skip to the next entity, this one isn't visible
continue;
},
FlickerMethod::Color(draw_color) => {
blit_method = BlitMethod::TransparentSingle {
transparent_color: 0,
draw_color
};
}
}
}
let position = positions.get(entity).unwrap();
context.sprite_render_list.push((*entity, position.0, blit_method));
}
context.sprite_render_list.sort_unstable_by(|a, b| (a.1.y as i32).cmp(&(b.1.y as i32)));
// now render them in the correct order ...
for (entity, position, blit_method) in context.sprite_render_list.iter() {
let sprite = sprites.get(entity).unwrap();
context.system.video.blit_atlas(
blit_method.clone(),
&sprite.atlas,
sprite.index,
position.x as i32 - camera.x,
position.y as i32 - camera.y,
);
}
let position = positions.get(entity).unwrap();
context.sprite_render_list.push((*entity, position.0, blit_method));
}
context.sprite_render_list.sort_unstable_by(|a, b| (a.1.y as i32).cmp(&(b.1.y as i32)));
// now render them in the correct order ...
for (entity, position, blit_method) in context.sprite_render_list.iter() {
let sprite = sprites.get(entity).unwrap();
context.system.video.blit_atlas(
blit_method.clone(),
&sprite.atlas,
sprite.index,
position.x as i32 - camera.x,
position.y as i32 - camera.y,
);
}
}
}
fn render_system_pixels(context: &mut Core) {
if let Some(pixels) = context.entities.components::<Pixel>() {
if let Some((_, camera)) = context.entities.components::<Camera>().single() {
let positions = context.entities.components::<Position>();
let pixels = context.entities.components::<Pixel>().unwrap();
let positions = context.entities.components::<Position>();
for (entity, pixel) in pixels.iter() {
if let Some(position) = positions.get(entity) {
context.system.video.set_pixel(
position.0.x as i32 - camera.x,
position.0.y as i32 - camera.y,
pixel.0,
);
}
if let Some((_, camera)) = context.entities.components::<Camera>().single() {
for (entity, pixel) in pixels.iter() {
if let Some(position) = positions.get(entity) {
context.system.video.set_pixel(
position.0.x as i32 - camera.x,
position.0.y as i32 - camera.y,
pixel.0,
);
}
}
}

View file

@ -50,34 +50,31 @@ pub struct Color(u8);
//////////////////////////////////////////////////////////////////////////////////////////////////
pub fn update_system_movement(context: &mut Core) {
if let Some(mut positions) = context.entities.components_mut::<Position>() {
let velocities = context.entities.components::<Velocity>().unwrap();
let mut positions = context.entities.components_mut::<Position>().unwrap();
let velocities = context.entities.components::<Velocity>().unwrap();
for (entity, position) in positions.iter_mut() {
let velocity = velocities.get(entity).unwrap();
position.0 += velocity.0 * context.delta;
}
for (entity, position) in positions.iter_mut() {
let velocity = velocities.get(entity).unwrap();
position.0 += velocity.0 * context.delta;
}
}
pub fn update_system_remove_offscreen(context: &mut Core) {
if let Some(positions) = context.entities.components::<Position>() {
for (entity, position) in positions.iter() {
if !context.system.video.is_xy_visible(position.0.x as i32, position.0.y as i32) {
context.event_publisher.queue(Event::Remove(*entity));
}
let positions = context.entities.components::<Position>().unwrap();
for (entity, position) in positions.iter() {
if !context.system.video.is_xy_visible(position.0.x as i32, position.0.y as i32) {
context.event_publisher.queue(Event::Remove(*entity));
}
}
}
pub fn render_system_pixels(context: &mut Core) {
if let Some(positions) = context.entities.components::<Position>() {
let colors = context.entities.components::<Color>().unwrap();
let positions = context.entities.components::<Position>().unwrap();
let colors = context.entities.components::<Color>().unwrap();
for (entity, position) in positions.iter() {
let color = colors.get(entity).unwrap();
context.system.video.set_pixel(position.0.x as i32, position.0.y as i32, color.0);
}
for (entity, position) in positions.iter() {
let color = colors.get(entity).unwrap();
context.system.video.set_pixel(position.0.x as i32, position.0.y as i32, color.0);
}
}
@ -87,6 +84,10 @@ pub struct DemoState;
impl DemoState {
fn init(&mut self, context: &mut Game) {
context.core.entities.init_components::<Position>();
context.core.entities.init_components::<Velocity>();
context.core.entities.init_components::<Color>();
context.component_systems.reset();
context.component_systems.add_update_system(update_system_movement);
context.component_systems.add_update_system(update_system_remove_offscreen);