This commit is contained in:
Corwin 2023-08-27 16:47:00 +01:00
parent 9a6f96b2ba
commit b9e6e09fe1
No known key found for this signature in database
4 changed files with 139 additions and 145 deletions

View file

@ -5,7 +5,7 @@
use core::ops::Neg; use core::ops::Neg;
use agb::fixnum::Vector2D; use agb::fixnum::Vector2D;
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, collections::VecDeque, vec::Vec};
use slotmap::{new_key_type, SlotMap}; use slotmap::{new_key_type, SlotMap};
use crate::{ use crate::{
@ -91,82 +91,85 @@ impl EntityMap {
let mut animations = Vec::new(); let mut animations = Vec::new();
let desired_actions: Vec<(EntityKey, Action)> = self let mut entities_to_try_update = self
.map .map
.iter() .iter()
.map(|(key, entity)| (key, entity.desired_action(map, self, hero))) .map(|(key, entity)| (key, entity.desired_action(map, self, hero)))
.collect(); .collect::<VecDeque<_>>();
for (entity_key, action) in desired_actions {
if !self.map.contains_key(entity_key) {
continue;
}
match action {
Action::Nothing => {
// nothing does nothing and causes nothing to happen
}
while let Some((entity_to_update_key, desired_action)) = entities_to_try_update.pop_front()
{
match desired_action {
Action::Nothing => {}
Action::Direction(direction) | Action::ChangeDirection(direction) => { Action::Direction(direction) | Action::ChangeDirection(direction) => {
if matches!(action, Action::ChangeDirection(_)) { if matches!(desired_action, Action::ChangeDirection(_)) {
if let Some(change) = self // first change the direction before processing the rest of the instructions
if let Some((Some(change), change_effect)) = self
.map .map
.get_mut(entity_key) .get_mut(entity_to_update_key)
.and_then(|e| e.change_direction()) .map(|e| (e.change_direction(), e.change_effect()))
{ {
animations.push(AnimationInstruction::PriorityChange( animations.push(AnimationInstruction::PriorityChange(
entity_key, entity_to_update_key,
change, change,
self.map.get(entity_key).and_then(|e| e.change_effect()), change_effect,
)); ));
} }
} }
let Some(entity) = &self.map.get(entity_key) else { let Some(entity_to_update) = self.map.get(entity_to_update_key) else {
continue; continue;
}; };
let desired_location = entity.location + direction.into(); let entity_location = entity_to_update.location;
let desired_location = entity_location + direction.into();
let surface = map.get(desired_location); let surface = map.get(desired_location);
if surface == MapElement::Wall { if surface == MapElement::Wall {
let wall_resolution = resolve_wall_move(&entity.entity); animations.push(AnimationInstruction::FakeOutMove(
match wall_resolution { entity_to_update_key,
WallResolution::StayPut => { direction,
animations.push(AnimationInstruction::FakeOutMove( self.map
entity_key, .get(entity_to_update_key)
direction, .and_then(|e| e.fake_out_wall_effect()),
entity.fake_out_wall_effect(), ));
)); continue;
} }
}
} else {
// what is at that location
let resolutions: Vec<_> = self
.whats_at(desired_location)
.filter(|(k, _)| *k != entity_key)
.map(|(key, other_entity)| (key, resolve_move(entity, other_entity)))
.collect();
let (can_move, explicit_stay_put, fake_out_effect) = {
let mut can_move = true; let mut can_move = true;
let mut explicit_stay_put = false; let mut explicit_stay_put = false;
let mut fake_out_effect = None; let mut fake_out_effect = None;
for (other, resolution) in resolutions { let move_attempt_resolutions: Vec<_> = self
match resolution { .whats_at(desired_location)
.filter(|(k, _)| *k != entity_to_update_key)
.map(|(key, other_entity)| {
(key, resolve_move(entity_to_update, other_entity))
})
.collect();
for (other_entity_key, move_resolution) in move_attempt_resolutions {
match move_resolution {
MoveAttemptResolution::KillDie => { MoveAttemptResolution::KillDie => {
hero_has_died |= self.kill_entity(other, &mut animations); hero_has_died |=
hero_has_died |= self.kill_entity(entity_key, &mut animations); self.kill_entity(other_entity_key, &mut animations);
hero_has_died |=
self.kill_entity(entity_to_update_key, &mut animations);
can_move = false; can_move = false;
} }
MoveAttemptResolution::Kill => { MoveAttemptResolution::Kill => {
hero_has_died |= self.kill_entity(other, &mut animations); hero_has_died |=
self.kill_entity(other_entity_key, &mut animations);
fake_out_effect = self fake_out_effect = self
.map .map
.get(entity_key) .get(entity_to_update_key)
.and_then(|x| x.kill_sound_effect()); .and_then(|x| x.kill_sound_effect());
can_move = false; can_move = false;
} }
MoveAttemptResolution::Die => { MoveAttemptResolution::Die => {
hero_has_died |= self.kill_entity(entity_key, &mut animations); hero_has_died |=
self.kill_entity(entity_to_update_key, &mut animations);
can_move = false; can_move = false;
} }
MoveAttemptResolution::CoExist => {} MoveAttemptResolution::CoExist => {}
@ -174,106 +177,99 @@ impl EntityMap {
can_move = false; can_move = false;
explicit_stay_put = true; explicit_stay_put = true;
} }
MoveAttemptResolution::AttemptPush => todo!(),
} }
} }
if can_move { (can_move, explicit_stay_put, fake_out_effect)
if let Some(e) = self.map.get_mut(entity_key) { };
e.location = desired_location;
}
let Some(entity) = &self.map.get(entity_key) else {
continue;
};
animations.push(AnimationInstruction::Move( if can_move {
entity_key, let Some(entity_to_update) = self.map.get(entity_to_update_key) else {
desired_location, continue;
entity.move_effect(), };
));
let overlap_resolutions: Vec<_> = self let overlap_resolutions: Vec<_> = self
.whats_at(desired_location) .whats_at(desired_location)
.filter(|(k, _)| *k != entity_key) .filter(|(k, _)| *k != entity_to_update_key)
.map(|(key, other_entity)| { .map(|(key, other_entity)| {
(key, resolve_overlap(entity, other_entity)) (key, resolve_overlap(entity_to_update, other_entity))
}) })
.collect(); .collect();
if overlap_resolutions for (other_entity_key, move_resolution) in overlap_resolutions {
.iter() match move_resolution {
.filter(|(_, r)| *r == OverlapResolution::Die) OverlapResolution::Pickup => {
.count() animations.push(AnimationInstruction::Attach(
!= 0 entity_to_update_key,
{ other_entity_key,
hero_has_died |= self.kill_entity(entity_key, &mut animations); self.map
} else { .get(other_entity_key)
for (other, resolution) in overlap_resolutions { .and_then(|x| x.pickup_sound_effect()),
match resolution { ));
OverlapResolution::Pickup => { let other = self.map.remove(other_entity_key).unwrap();
animations.push(AnimationInstruction::Attach(
entity_key, if let Some((location, dropped)) =
other, self.map.get_mut(entity_to_update_key).and_then(|x| {
self.map x.pickup(other.entity).map(|y| (x.location, y))
.get(other) })
.and_then(|x| x.pickup_sound_effect()), {
let new_key = self.map.insert(Entity {
location,
entity: dropped,
});
animations.push(AnimationInstruction::Detatch(
entity_to_update_key,
new_key,
self.map.get(new_key).and_then(|x| x.drop_effect()),
));
}
}
OverlapResolution::CoExist => {}
OverlapResolution::Win => {
win_has_triggered = true;
}
OverlapResolution::ToggleSystem(system) => {
for (k, e) in self.map.iter_mut() {
if let Some(change) = e.switch(system) {
animations.push(AnimationInstruction::Change(
k,
change,
e.change_effect(),
)); ));
let other = self.map.remove(other).unwrap();
if let Some((location, dropped)) =
self.map.get_mut(entity_key).and_then(|x| {
x.pickup(other.entity).map(|y| (x.location, y))
})
{
let new_key = self.map.insert(Entity {
location,
entity: dropped,
});
animations.push(AnimationInstruction::Detatch(
entity_key,
new_key,
self.map
.get(new_key)
.and_then(|x| x.drop_effect()),
));
}
}
OverlapResolution::CoExist => {}
OverlapResolution::Win => {
win_has_triggered = true;
}
OverlapResolution::ToggleSystem(system) => {
for (k, e) in self.map.iter_mut() {
if let Some(change) = e.switch(system) {
animations.push(AnimationInstruction::Change(
k,
change,
e.change_effect(),
));
}
}
}
OverlapResolution::Die => {
// already handled
} }
} }
} }
OverlapResolution::Die => {
hero_has_died |=
self.kill_entity(entity_to_update_key, &mut animations);
break;
}
OverlapResolution::MoveAgain => {
entities_to_try_update.push_front((
entity_to_update_key,
Action::Direction(direction),
));
}
} }
} else {
animations.push(AnimationInstruction::FakeOutMove(
entity_key,
direction,
if explicit_stay_put {
self.map
.get(entity_key)
.and_then(|e| e.fake_out_wall_effect())
} else {
fake_out_effect.or_else(|| {
self.map.get(entity_key).and_then(|e| e.fake_out_effect())
})
},
));
} }
} else {
animations.push(AnimationInstruction::FakeOutMove(
entity_to_update_key,
direction,
if explicit_stay_put {
self.map
.get(entity_to_update_key)
.and_then(|e| e.fake_out_wall_effect())
} else {
fake_out_effect.or_else(|| {
self.map
.get(entity_to_update_key)
.and_then(|e| e.fake_out_effect())
})
},
));
} }
} }
} }
@ -298,22 +294,20 @@ enum MoveAttemptResolution {
KillDie, KillDie,
CoExist, CoExist,
StayPut, StayPut,
AttemptPush,
} }
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub struct SwitchSystem(usize); pub struct SwitchSystem(usize);
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum OverlapResolution { enum OverlapResolution {
Pickup, Pickup,
CoExist, CoExist,
Win, Win,
ToggleSystem(SwitchSystem), ToggleSystem(SwitchSystem),
Die, Die,
} MoveAgain,
enum WallResolution {
StayPut,
} }
fn resolve_spikes(switable: &Switchable) -> OverlapResolution { fn resolve_spikes(switable: &Switchable) -> OverlapResolution {
@ -331,15 +325,12 @@ fn resolve_overlap(me: &Entity, other: &Entity) -> OverlapResolution {
(_, EntityType::Spikes(switch)) => resolve_spikes(switch), (_, EntityType::Spikes(switch)) => resolve_spikes(switch),
(_, EntityType::Switch(switch)) => OverlapResolution::ToggleSystem(switch.system), (_, EntityType::Switch(switch)) => OverlapResolution::ToggleSystem(switch.system),
(_, EntityType::Enemy(_) | EntityType::Hero(_)) => OverlapResolution::Die, (_, EntityType::Enemy(_) | EntityType::Hero(_)) => OverlapResolution::Die,
(_, EntityType::Ice) => OverlapResolution::MoveAgain,
_ => OverlapResolution::CoExist, _ => OverlapResolution::CoExist,
} }
} }
fn resolve_wall_move(_entity: &EntityType) -> WallResolution {
WallResolution::StayPut
}
fn holding_attack_resolve(holding: Option<&EntityType>) -> MoveAttemptResolution { fn holding_attack_resolve(holding: Option<&EntityType>) -> MoveAttemptResolution {
match holding { match holding {
Some(&EntityType::Item(Item::Sword)) => MoveAttemptResolution::Kill, Some(&EntityType::Item(Item::Sword)) => MoveAttemptResolution::Kill,
@ -438,6 +429,7 @@ pub enum EntityType {
SwitchedDoor(Switchable), SwitchedDoor(Switchable),
Switch(Switchable), Switch(Switchable),
Spikes(Switchable), Spikes(Switchable),
Ice,
} }
#[derive(Debug)] #[derive(Debug)]
@ -577,10 +569,6 @@ impl Entity {
} }
} }
fn move_effect(&self) -> Option<SoundEffect> {
None
}
fn kill_sound_effect(&self) -> Option<SoundEffect> { fn kill_sound_effect(&self) -> Option<SoundEffect> {
match self.holding() { match self.holding() {
Some(EntityType::Item(Item::Sword)) => Some(SoundEffect::SwordKill), Some(EntityType::Item(Item::Sword)) => Some(SoundEffect::SwordKill),
@ -719,6 +707,7 @@ impl From<level::Item> for EntityType {
direction: Direction::Down, direction: Direction::Down,
holding: None, holding: None,
})), })),
level::Item::Ice => EntityType::Ice,
} }
} }
} }

View file

@ -18,6 +18,7 @@ pub enum Item {
SpikesDown, SpikesDown,
SquidUp, SquidUp,
SquidDown, SquidDown,
Ice,
} }
impl Item { impl Item {
@ -37,6 +38,7 @@ impl Item {
Item::SpikesDown => resources::SPIKES_OFF, Item::SpikesDown => resources::SPIKES_OFF,
Item::SquidUp => resources::SQUID_UP_SHADOW, Item::SquidUp => resources::SQUID_UP_SHADOW,
Item::SquidDown => resources::SQUID_DOWN_SHADOW, Item::SquidDown => resources::SQUID_DOWN_SHADOW,
Item::Ice => resources::ICE,
} }
} }
@ -56,6 +58,7 @@ impl Item {
Item::SpikesDown => resources::SPIKES_OFF, Item::SpikesDown => resources::SPIKES_OFF,
Item::SquidUp => resources::SQUID_UP, Item::SquidUp => resources::SQUID_UP,
Item::SquidDown => resources::SQUID_DOWN, Item::SquidDown => resources::SQUID_DOWN,
Item::Ice => resources::ICE,
} }
} }
@ -78,6 +81,7 @@ impl Item {
Item::SpikesDown => ZERO, Item::SpikesDown => ZERO,
Item::SquidUp => STANDARD, Item::SquidUp => STANDARD,
Item::SquidDown => STANDARD, Item::SquidDown => STANDARD,
Item::Ice => ZERO,
} }
} }
} }

View file

@ -49,6 +49,7 @@ named_tag!(
SQUID_DOWN, SQUID_DOWN,
SQUID_UP_SHADOW, SQUID_UP_SHADOW,
SQUID_DOWN_SHADOW, SQUID_DOWN_SHADOW,
ICE,
] ]
); );