diff --git a/Cargo.lock b/Cargo.lock index da16aa4..e6579aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3622,6 +3622,8 @@ dependencies = [ "bevy", "bevy_aseprite_ultra", "bevy_dev_tools", + "serde", + "serde_json", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c72a83a..529d8e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,5 @@ lto = "thin" bevy = "0.17.2" bevy_aseprite_ultra = "0.7.0" bevy_dev_tools = "0.17.2" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/assets/config.json b/assets/config.json new file mode 100644 index 0000000..fa9d4aa --- /dev/null +++ b/assets/config.json @@ -0,0 +1,5 @@ +{ + "grid_width": 10, + "grid_height": 10, + "pom_speed": 2 +} diff --git a/flake.nix b/flake.nix index e054130..e0e87c2 100644 --- a/flake.nix +++ b/flake.nix @@ -24,10 +24,10 @@ rust-toolchain = with fenix.packages.${system}; combine [ - beta.rustc - beta.cargo - beta.rust-src - beta.rust-analyzer + stable.rustc + stable.cargo + stable.rust-src + stable.rust-analyzer ]; bevyDeps = with pkgs; [ diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..979ccb8 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,17 @@ +use bevy::prelude::*; +use serde::Deserialize; +use std::fs::File; +use std::io::BufReader; + +#[derive(Resource, Deserialize, Debug)] +pub struct GameConfig { + pub grid_width: u32, + pub grid_height: u32, + pub pom_speed: f32, +} + +pub fn read_config() -> Option { + let file = File::open("assets/config.json").ok()?; + let reader = BufReader::new(file); + serde_json::from_reader(reader).ok() +} diff --git a/src/lib.rs b/src/lib.rs index c45b318..4c07870 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub mod components; +pub mod config; pub mod errors; pub mod messages; pub mod plugins; diff --git a/src/main.rs b/src/main.rs index 12401b6..c045bd4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,12 @@ use bevy::prelude::*; use bevy_aseprite_ultra::prelude::*; use bevy_dev_tools::fps_overlay::*; +use pomomon_garden::config::read_config; use pomomon_garden::plugins; fn main() { + let config = read_config().expect("Error reading config"); + App::new() .add_plugins(( DefaultPlugins.set(ImagePlugin::default_nearest()), @@ -29,5 +32,6 @@ fn main() { plugins::PomPlugin, plugins::InputPlugin, )) + .insert_resource(config) .run(); } diff --git a/src/plugins/grid.rs b/src/plugins/grid.rs index d8a4f75..d6e6026 100644 --- a/src/plugins/grid.rs +++ b/src/plugins/grid.rs @@ -1,16 +1,19 @@ use crate::{ components::tile::{Grid, Tile, TileState}, + config::GameConfig, states::AppState, }; use bevy::prelude::*; use bevy_aseprite_ultra::prelude::AseSlice; pub const TILE_SIZE: f32 = 32.0; -pub const GRID_WIDTH: u32 = 10; -pub const GRID_HEIGHT: u32 = 10; -pub const GRID_START_X: f32 = -(GRID_WIDTH as f32 * TILE_SIZE) / 2.0 + TILE_SIZE / 2.0; -pub const GRID_START_Y: f32 = -(GRID_HEIGHT as f32 * TILE_SIZE) / 2.0 + TILE_SIZE / 2.0; +pub fn grid_start_x(grid_width: u32) -> f32 { + -(grid_width as f32 * TILE_SIZE) / 2.0 + TILE_SIZE / 2.0 +} +pub fn grid_start_y(grid_height: u32) -> f32 { + -(grid_height as f32 * TILE_SIZE) / 2.0 + TILE_SIZE / 2.0 +} pub struct GridPlugin; @@ -26,13 +29,15 @@ impl Plugin for GridPlugin { } } -fn setup(mut commands: Commands, asset_server: Res) { - let mut tiles = Vec::with_capacity(GRID_WIDTH as usize); +fn setup(mut commands: Commands, asset_server: Res, config: Res) { + let grid_width = config.grid_width; + let grid_height = config.grid_height; + let mut tiles = Vec::with_capacity(grid_width as usize); - for x in 0..GRID_WIDTH { - let mut column = Vec::with_capacity(GRID_HEIGHT as usize); + for x in 0..grid_width { + let mut column = Vec::with_capacity(grid_height as usize); - for y in 0..GRID_HEIGHT { + for y in 0..grid_height { let tile_entity = commands .spawn(( Tile { x, y }, @@ -42,7 +47,13 @@ fn setup(mut commands: Commands, asset_server: Res) { aseprite: asset_server.load("tiles/tile-unclaimed.aseprite"), }, Sprite::default(), - Transform::from_translation(grid_to_world_coords(x, y, None)), + Transform::from_translation(grid_to_world_coords( + x, + y, + None, + grid_width, + grid_height, + )), )) .id(); column.push(tile_entity); @@ -51,8 +62,8 @@ fn setup(mut commands: Commands, asset_server: Res) { } commands.insert_resource(Grid { - width: GRID_WIDTH, - height: GRID_HEIGHT, + width: grid_width, + height: grid_height, tiles, }); } @@ -84,27 +95,36 @@ fn update_tile_colors( } } -pub fn world_to_grid_coords(world_pos: Vec3) -> (u32, u32) { - let x = ((world_pos.x - GRID_START_X + TILE_SIZE / 2.0) / TILE_SIZE).floor(); - let y = ((world_pos.y - GRID_START_Y + TILE_SIZE / 2.0) / TILE_SIZE).floor(); +pub fn world_to_grid_coords(world_pos: Vec3, grid_width: u32, grid_height: u32) -> (u32, u32) { + let start_x = grid_start_x(grid_width); + let start_y = grid_start_y(grid_height); + + let x = ((world_pos.x - start_x + TILE_SIZE / 2.0) / TILE_SIZE).floor(); + let y = ((world_pos.y - start_y + TILE_SIZE / 2.0) / TILE_SIZE).floor(); let mut x_u32 = x as u32; let mut y_u32 = y as u32; - if x_u32 >= GRID_WIDTH { - x_u32 = GRID_WIDTH - 1; + if x_u32 >= grid_width { + x_u32 = grid_width - 1; } - if y_u32 >= GRID_HEIGHT { - y_u32 = GRID_HEIGHT - 1; + if y_u32 >= grid_height { + y_u32 = grid_height - 1; } (x_u32, y_u32) } -pub fn grid_to_world_coords(grid_x: u32, grid_y: u32, z: Option) -> Vec3 { +pub fn grid_to_world_coords( + grid_x: u32, + grid_y: u32, + z: Option, + grid_width: u32, + grid_height: u32, +) -> Vec3 { Vec3::new( - GRID_START_X + grid_x as f32 * TILE_SIZE, - GRID_START_Y + grid_y as f32 * TILE_SIZE, + grid_start_x(grid_width) + grid_x as f32 * TILE_SIZE, + grid_start_y(grid_height) + grid_y as f32 * TILE_SIZE, z.unwrap_or(0.0), ) } diff --git a/src/plugins/input.rs b/src/plugins/input.rs index c16b1ad..1a9f77b 100644 --- a/src/plugins/input.rs +++ b/src/plugins/input.rs @@ -3,6 +3,7 @@ use bevy::prelude::*; use bevy::window::PrimaryWindow; use crate::components::tile::{Grid, TileState}; +use crate::config::GameConfig; use crate::messages::{InteractStartMessage, InvalidMoveMessage, MoveMessage}; use crate::plugins::grid::world_to_grid_coords; use crate::states::AppState; @@ -28,6 +29,7 @@ fn move_click( mouse_btn: Res>, window: Single<&Window, With>, camera: Single<(&Camera, &GlobalTransform), With>, + config: Res, ) { if mouse_btn.just_pressed(MouseButton::Right) { let (cam, cam_transform) = *camera; @@ -38,7 +40,7 @@ fn move_click( let Ok(world_pos) = cam.viewport_to_world(cam_transform, cursor_pos) else { return; }; - let (x, y) = world_to_grid_coords(world_pos.origin); + let (x, y) = world_to_grid_coords(world_pos.origin, config.grid_width, config.grid_height); println!("Move Click: ({}, {})", x, y); move_messages.write(MoveMessage { x, y }); @@ -50,6 +52,7 @@ fn interact_click( mouse_btn: Res>, window: Single<&Window, With>, camera: Single<(&Camera, &GlobalTransform), With>, + config: Res, // for debug grid: ResMut, tile_query: Query<&mut TileState>, @@ -63,7 +66,7 @@ fn interact_click( let Ok(world_pos) = cam.viewport_to_world(cam_transform, cursor_pos) else { return; }; - let (x, y) = world_to_grid_coords(world_pos.origin); + let (x, y) = world_to_grid_coords(world_pos.origin, config.grid_width, config.grid_height); println!("Interact Click: ({}, {})", x, y); interact_messages.write(InteractStartMessage { x, y }); diff --git a/src/plugins/pom.rs b/src/plugins/pom.rs index 71eefda..c096822 100644 --- a/src/plugins/pom.rs +++ b/src/plugins/pom.rs @@ -1,14 +1,13 @@ use crate::components::pom::{GridPosition, MovingState, PathQueue, Pom}; use crate::components::tile::{Grid, TileState}; +use crate::config::GameConfig; use crate::messages::{InvalidMoveMessage, MoveMessage}; -use crate::plugins::grid::{GRID_WIDTH, grid_to_world_coords}; +use crate::plugins::grid::{TILE_SIZE, 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 { @@ -23,7 +22,7 @@ impl Plugin for PomPlugin { } } -fn setup(mut commands: Commands, asset_server: Res) { +fn setup(mut commands: Commands, asset_server: Res, config: Res) { commands.spawn(( Pom, GridPosition { x: 0, y: 0 }, @@ -34,7 +33,13 @@ fn setup(mut commands: Commands, asset_server: Res) { animation: Animation::tag("sleep-sit-start").with_repeat(AnimationRepeat::Loop), }, Sprite::default(), - Transform::from_translation(grid_to_world_coords(0, 0, Some(1.0))), + Transform::from_translation(grid_to_world_coords( + 0, + 0, + Some(1.0), + config.grid_width, + config.grid_height, + )), )); } @@ -82,12 +87,20 @@ fn move_pom( &mut PathQueue, &mut MovingState, )>, + config: Res, ) { let dt = time.delta_secs(); + let move_speed = config.pom_speed * TILE_SIZE; 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 target_pos = grid_to_world_coords( + target.0, + target.1, + Some(1.0), + config.grid_width, + config.grid_height, + ); let distance = transform.translation.distance(target_pos); let dx = target.0 as i32 - grid_pos.x as i32; @@ -100,14 +113,14 @@ fn move_pom( _ => (), } - if distance < MOVE_SPEED * dt { + 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; + transform.translation += direction * move_speed * dt; } } else { *moving_state = MovingState::Idle;