144 lines
5.1 KiB
Rust
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),
|
|
};
|
|
}
|
|
_ => (),
|
|
}
|
|
}
|
|
}
|