diff --git a/src/debug.rs b/src/debug.rs index 891cc46..37bebb1 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,4 +1,5 @@ use bevy::prelude::*; +use bevy_prototype_lyon::prelude::*; pub struct DebugPlugin; @@ -11,12 +12,18 @@ impl Plugin for DebugPlugin { .configure_sets(PostUpdate, DebugSet.run_if(is_debug_enabled)); app.insert_resource(DebugMode::off()) - .add_plugins(( - bevy_inspector_egui::quick::WorldInspectorPlugin::new().run_if(is_debug_enabled), - bevy_rapier2d::prelude::RapierDebugRenderPlugin::default(), - )) + .insert_resource(DebugDraw::default()); + + app.add_plugins(( + bevy_inspector_egui::quick::WorldInspectorPlugin::new().run_if(is_debug_enabled), + bevy_rapier2d::prelude::RapierDebugRenderPlugin::default(), + )); + + app.register_type::() + .add_systems(First, clear_shapes) .add_systems(Update, debug_toggle) - .add_systems(PostUpdate, draw_debug.in_set(DebugSet)); + // TODO: Check if this could be scheduled just before render instead + .add_systems(PostUpdate, draw_shapes); } } @@ -36,6 +43,43 @@ impl DebugMode { } } +/// TODO: Rename to something smarter +#[derive(Clone, Copy, Debug, Reflect)] +pub struct Draw { + pub shape: Shape, + pub color: Srgba, +} + +#[derive(Clone, Copy, Debug, Reflect)] +pub enum Shape { + Line { + from: Vec2, + to: Vec2, + }, + Polygon { + center: Vec2, + sides: usize, + radius: f32, + }, +} + +#[derive(Clone, Debug, Default, Component, Reflect)] +#[reflect(Component)] +#[require(Transform, Visibility)] +pub struct DebugCanvas; + +#[derive(Debug, Default, Resource, Reflect)] +#[reflect(Resource)] +pub struct DebugDraw { + pub draw_queue: Vec, +} + +impl DebugDraw { + pub fn shape(&mut self, draw: Draw) { + self.draw_queue.push(draw); + } +} + pub fn is_debug_enabled(debug_mode: Res) -> bool { debug_mode.enabled } @@ -46,6 +90,44 @@ fn debug_toggle(input: Res>, mut debug_mode: ResMut>) { + for parent in canvas_query.iter() { + commands.entity(parent).despawn_descendants(); + } +} + +fn draw_shapes( + mut commands: Commands, + canvas: Option>>, + mut debug_draw: ResMut, +) { + let canvas = match canvas { + Some(canvas) => *canvas, + None => commands + .spawn((Name::new("Debug Canvas"), DebugCanvas)) + .id(), + }; + commands.entity(canvas).with_children(|builder| { + for draw in debug_draw.draw_queue.drain(..) { + // TODO + let path = match draw.shape { + Shape::Line { from, to } => GeometryBuilder::build_as(&shapes::Line(from, to)), + Shape::Polygon { + center, + sides, + radius, + } => GeometryBuilder::build_as(&shapes::RegularPolygon { + center, + sides, + feature: RegularPolygonFeature::Radius(radius), + }), + }; + + builder.spawn(( + ShapeBundle { path, ..default() }, + Fill::color(Srgba::NONE), + Stroke::color(draw.color), + )); + } + }); } diff --git a/src/game.rs b/src/game.rs index c9fec69..ad13dcd 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,5 +1,6 @@ use crate::{debug, game_setup, util}; use bevy::prelude::*; +use bevy_prototype_lyon::prelude::*; use bevy_rapier2d::prelude::*; mod item; @@ -10,6 +11,7 @@ mod work; pub fn init(app: &mut App) { let app = app.add_plugins(( game_setup::GameSetupPlugin, + ShapePlugin, RapierPhysicsPlugin::::default(), util::UtilPlugin, debug::DebugPlugin, @@ -24,5 +26,6 @@ pub fn init(app: &mut App) { .register_type::() .add_systems(Startup, systems::setup_2d) .add_systems(Update, (systems::demo_2d, systems::work_select)) - .add_systems(PostUpdate, item::update_item_sprite); + .add_systems(PostUpdate, item::update_item_sprite) + .add_systems(Update, (systems::draw_job_targets).in_set(debug::DebugSet)); } diff --git a/src/game/systems/demo.rs b/src/game/systems/demo.rs index a288725..dcd9521 100644 --- a/src/game/systems/demo.rs +++ b/src/game/systems/demo.rs @@ -1,6 +1,9 @@ use bevy::prelude::*; -use crate::game::{item::Item, prefab}; +use crate::game::{ + item::{Inventory, Item, ItemStack}, + prefab, +}; pub fn setup_2d(mut commands: Commands) { commands.spawn(( @@ -9,13 +12,23 @@ pub fn setup_2d(mut commands: Commands) { Transform::from_xyz(0.0, 0.0, 10.0), )); - commands.spawn((Transform::from_xyz(-200.0, 0.0, 0.0), prefab::Glorb)); + commands.spawn(( + Transform::from_xyz(-300.0, 0.0, 0.0), + prefab::Glorb, + Inventory { + items: vec![ItemStack { + item: Item::Wood, + count: 1, + }], + capacity: Some(1), + }, + )); commands.spawn((Transform::from_xyz(-200.0, 100.0, 0.0), prefab::Glorb)); commands.spawn((Transform::from_xyz(-200.0, -100.0, 0.0), prefab::Glorb)); commands.spawn((Transform::from_xyz(200.0, 0.0, 0.0), prefab::Tree)); - commands.spawn((Name::from("Wood"), Item::Wood)); + // commands.spawn((Name::from("Wood"), Item::Wood)); commands.spawn((Transform::from_xyz(-200.0, -150.0, 0.0), prefab::Chest)); } diff --git a/src/game/systems/worker.rs b/src/game/systems/worker.rs index abf267e..c134d05 100644 --- a/src/game/systems/worker.rs +++ b/src/game/systems/worker.rs @@ -1,8 +1,11 @@ -use bevy::prelude::*; +use bevy::{color::palettes::css, prelude::*}; -use crate::game::{ - item::{Inventory, ItemSource, Stockpile}, - work::{Task, WorkType, Worker}, +use crate::{ + debug::{DebugDraw, Draw, Shape}, + game::{ + item::{Inventory, ItemSource, Stockpile}, + work::{Task, WorkType, Worker}, + }, }; pub fn work_select( @@ -26,7 +29,7 @@ pub fn work_select( let stockpile_dist_squared = worker_transform .translation() .distance_squared(stockpile_transform.translation()); - if task_by_distance.map_or(true, |(_, closest_task_dist)| { + if task_by_distance.is_none_or(|(_, closest_task_dist)| { stockpile_dist_squared < closest_task_dist }) { task_by_distance = Some(( @@ -52,9 +55,9 @@ pub fn work_select( let source_dist_squared = worker_transform .translation() .distance_squared(item_source_transform.translation()); - if task_by_distance.map_or(true, |(_, closest_task_dist)| { - source_dist_squared < closest_task_dist - }) { + if task_by_distance + .is_none_or(|(_, closest_task_dist)| source_dist_squared < closest_task_dist) + { task_by_distance = Some(( Task { target: item_source_entity, @@ -70,3 +73,63 @@ pub fn work_select( worker.0 = task_by_distance.map(|(task, _)| task); } } + +/// Example of DebugDraw usage +pub fn draw_job_targets( + mut debug_draw: ResMut, + worker_query: Query<(Entity, &Worker)>, + global_query: Query<&GlobalTransform>, +) { + for (worker_entity, worker) in worker_query.iter() { + let worker_global = global_query.get(worker_entity).unwrap(); + let draws = match worker.0 { + Some(task) => match task.work_type { + WorkType::Gather => vec![ + Draw { + shape: Shape::Polygon { + center: worker_global.translation().xy(), + sides: 3, + radius: 16., + }, + color: css::GREEN, + }, + Draw { + shape: Shape::Line { + from: worker_global.translation().xy(), + to: global_query.get(task.target).unwrap().translation().xy(), + }, + color: css::GREEN, + }, + ], + WorkType::Store(_) => vec![ + Draw { + shape: Shape::Polygon { + center: worker_global.translation().xy(), + sides: 3, + radius: 16., + }, + color: css::YELLOW, + }, + Draw { + shape: Shape::Line { + from: worker_global.translation().xy(), + to: global_query.get(task.target).unwrap().translation().xy(), + }, + color: css::YELLOW, + }, + ], + }, + None => vec![Draw { + shape: Shape::Polygon { + center: worker_global.translation().xy(), + sides: 3, + radius: 16., + }, + color: css::RED, + }], + }; + for draw in draws { + debug_draw.shape(draw); + } + } +}