use bevy::asset::Assets;
use bevy::image::TextureAtlas;
use bevy::prelude::{
Commands,
Entity,
MessageReader,
MessageWriter,
Query,
Res,
Sprite,
TextureAtlasLayout,
Time,
};
use crate::component::*;
pub(crate) fn view_changed_event(
mut events: MessageReader<ViewChanged>,
mut sprites: Query<(&mut View2dActor, &mut Sprite)>,
animation2d: Res<ActorSpriteSheets>,
) {
for event in events.read() {
if let Ok((mut view, mut sprite)) = sprites.get_mut(event.entity) {
let mut action = view.action;
let mut actor = view.actor;
let any = get_act_id("any");
let mut viewsprite = None;
for _actor in [&view.actor, &any] {
if let Some(actor_val) = animation2d.get(_actor) {
for _action in [&view.action, &any] {
if let Some(action_val) = actor_val.get(_action) {
viewsprite = action_val.get(&view.angle);
actor = *_actor;
action = *_action;
break;
}
}
}
}
if view.flipped {
sprite.flip_x = false;
view.flipped = false;
}
if viewsprite.is_none() {
let Some(actor_val) = animation2d.get(&actor) else {
continue;
};
let Some(action_val) = actor_val.get(&action) else {
continue;
};
viewsprite = get_opposite_view(action_val, view.angle);
if viewsprite.is_some() {
sprite.flip_x = true;
view.flipped = true;
}
}
if viewsprite.is_none() {
let Some(actor_val) = animation2d.get(&actor) else {
continue;
};
let Some(action_val) = actor_val.get(&action) else {
continue;
};
viewsprite = action_val.get(&Angle::Any);
if viewsprite.is_none() {
viewsprite = get_opposite_view(&animation2d[&actor][&action], Angle::Any);
if viewsprite.is_some() {
sprite.flip_x = true;
view.flipped = true;
} else {
continue;
}
}
}
let Some(viewsprite) = viewsprite else {
continue;
};
if let Some(sprite_image) = viewsprite.image.as_ref() {
sprite.image = sprite_image.clone();
if let Some(atlas) = &mut sprite.texture_atlas {
if let Some(view_atlas) = &viewsprite.layout {
atlas.layout = view_atlas.clone();
}
} else if let Some(next_layout) = viewsprite.layout.clone() {
sprite.texture_atlas = Some(TextureAtlas {
layout: next_layout,
index: 0,
});
}
}
}
}
}
fn get_opposite_view(texture: &AngleSpriteSheets, direction: Angle) -> Option<&SpriteSheet> {
match direction {
Angle::Left => texture.get(&Angle::Right),
Angle::Right => texture.get(&Angle::Left),
Angle::FrontLeft => texture.get(&Angle::FrontRight),
Angle::FrontRight => texture.get(&Angle::FrontLeft),
Angle::BackLeft => texture.get(&Angle::BackRight),
Angle::BackRight => texture.get(&Angle::BackLeft),
_ => None,
}
}
pub(crate) fn animated_timer(
time: Res<Time>,
mut query: Query<(&mut View2dActor, Entity)>,
mut event: MessageWriter<NextFrame>,
) {
for (mut actor, entity) in &mut query {
if let Some(ref mut animation_timer) = actor.animation_timer {
animation_timer.tick(time.delta());
if animation_timer.just_finished() {
event.write(NextFrame { entity });
}
}
}
}
pub(crate) fn animating(
mut commands: Commands,
atlases: Res<Assets<TextureAtlasLayout>>,
mut query: Query<(&mut View2dActor, &mut Sprite, Entity)>,
mut event: MessageWriter<ViewChanged>,
) {
for (mut actor, mut sprite, entity) in &mut query {
if let Some(atlas) = &mut sprite.texture_atlas {
if let Some(layout) = atlases.get(&atlas.layout) {
for notify in &actor.notify {
match *notify {
Notification::LastFrame => {
if atlas.index == layout.textures.len() - 1 {
commands.trigger(LastFrame { entity });
}
}
}
}
if atlas.index == layout.textures.len() - 1 {
if let Some(next_action) = actor.next_action.first() {
actor.action = *next_action;
event.write(ViewChanged { entity });
actor.next_action.remove(0);
}
}
atlas.index = (atlas.index + 1) % layout.textures.len();
}
}
}
}