Files
pomomon-garden/src/plugins/pom.rs
2025-11-24 13:37:30 +01:00

144 lines
5.1 KiB
Rust

use crate::components::pom::{GridPosition, MovingState, PathQueue, Pom};
use crate::components::tile::{Grid, TileState};
use crate::messages::{InvalidMoveMessage, MoveMessage};
use crate::plugins::grid::{GRID_WIDTH, grid_to_world_coords};
use crate::states::*;
use crate::utils::pathfinding::find_path;
use bevy::prelude::*;
use bevy_aseprite_ultra::prelude::*;
const MOVE_SPEED: f32 = 2.0 * GRID_WIDTH as f32;
pub struct PomPlugin;
impl Plugin for PomPlugin {
fn build(&self, app: &mut App) {
app.add_systems(OnEnter(AppState::GameScreen), setup);
app.add_systems(OnExit(AppState::GameScreen), cleanup);
app.add_systems(
Update,
(handle_move, move_pom, update_pom).run_if(in_state(AppState::GameScreen)),
);
}
}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn((
Pom,
GridPosition { x: 0, y: 0 },
PathQueue::default(),
MovingState::default(),
AseAnimation {
aseprite: asset_server.load("pom/pom-sleep.aseprite"),
animation: Animation::tag("sleep-sit-start").with_repeat(AnimationRepeat::Loop),
},
Sprite::default(),
Transform::from_translation(grid_to_world_coords(0, 0, Some(1.0))),
));
}
fn cleanup(mut commands: Commands, pom_query: Query<Entity, With<Pom>>) {
for pom_entity in pom_query.iter() {
commands.entity(pom_entity).despawn();
}
}
fn handle_move(
mut move_messages: MessageReader<MoveMessage>,
mut invalid_move_messages: MessageWriter<InvalidMoveMessage>,
grid: Res<Grid>,
tile_query: Query<&TileState>,
mut pom_query: Query<(&GridPosition, &mut PathQueue)>,
) {
for message in move_messages.read() {
for (grid_pos, mut path_queue) in pom_query.iter_mut() {
let grid_start = (grid_pos.x, grid_pos.y);
let start = path_queue.steps.front().unwrap_or(&grid_start);
let end = (message.x, message.y);
match find_path(*start, end, &grid, &tile_query) {
Some(new_path) => {
path_queue.steps = new_path;
}
None => {
let msg = format!(
"Cannot move to ({}, {}). Path blocked or invalid.",
message.x, message.y
);
dbg!(&msg);
invalid_move_messages.write(InvalidMoveMessage { message: msg });
}
}
}
}
}
fn move_pom(
time: Res<Time>,
mut query: Query<(
&mut Transform,
&mut GridPosition,
&mut PathQueue,
&mut MovingState,
)>,
) {
let dt = time.delta_secs();
for (mut transform, mut grid_pos, mut path_queue, mut moving_state) in query.iter_mut() {
if let Some(&target) = path_queue.steps.front() {
let target_pos = grid_to_world_coords(target.0, target.1, Some(1.0));
let distance = transform.translation.distance(target_pos);
let dx = target.0 as i32 - grid_pos.x as i32;
let dy = target.1 as i32 - grid_pos.y as i32;
match (dx, dy) {
(0, 1) => *moving_state = MovingState::MovingUp,
(0, -1) => *moving_state = MovingState::MovingDown,
(1, 0) => *moving_state = MovingState::MovingRight,
(-1, 0) => *moving_state = MovingState::MovingLeft,
_ => (),
}
if distance < MOVE_SPEED * dt {
transform.translation = target_pos;
grid_pos.x = target.0;
grid_pos.y = target.1;
path_queue.steps.pop_front();
} else {
let direction = (target_pos - transform.translation).normalize();
transform.translation += direction * MOVE_SPEED * dt;
}
} else {
*moving_state = MovingState::Idle;
}
}
}
fn update_pom(asset_server: Res<AssetServer>, mut query: Query<(&MovingState, &mut AseAnimation)>) {
for (moving_state, mut animation) in query.iter_mut() {
match moving_state {
MovingState::Idle => {
*animation = AseAnimation {
aseprite: asset_server.load("pom/pom-sleep.aseprite"),
animation: Animation::tag("sleep-sit-start").with_repeat(AnimationRepeat::Loop),
};
}
s if s.is_moving() => {
*animation = AseAnimation {
aseprite: asset_server.load("pom/pom-walk.aseprite"),
animation: (match s {
MovingState::MovingUp => Animation::tag("walk_up"),
MovingState::MovingDown => Animation::tag("walk_down"),
MovingState::MovingLeft => Animation::tag("walk_left"),
MovingState::MovingRight => Animation::tag("walk_right"),
_ => panic!("This shouldn't be reachable"),
})
.with_repeat(AnimationRepeat::Loop),
};
}
_ => (),
}
}
}