From b156a33a54b1b9d11aecb520dd84b696ffa40bfd Mon Sep 17 00:00:00 2001 From: Amatsugu Date: Tue, 10 Sep 2024 20:41:33 -0400 Subject: [PATCH] units testing --- game/buildings/src/assets/building_asset.rs | 2 +- game/buildings/src/building_plugin.rs | 33 ++------- game/main/src/map_rendering/map_init.rs | 1 + .../src/map_rendering/terraforming_test.rs | 32 ++------- game/main/src/phos.rs | 36 ++++++++++ game/main/src/utlis/debug_plugin.rs | 67 ++++++------------- game/main/src/utlis/mod.rs | 1 + game/main/src/utlis/tile_selection_plugin.rs | 62 +++++++++++++++++ .../src/{resource.rs => identifiers.rs} | 2 + game/shared/src/lib.rs | 3 +- game/shared/src/resources.rs | 22 ++++++ game/units/src/assets/unit_asset.rs | 11 ++- game/units/src/components.rs | 14 +++- game/units/src/units_debug_plugin.rs | 64 +++++++++++++++--- game/units/src/units_plugin.rs | 35 ++++++---- 15 files changed, 254 insertions(+), 131 deletions(-) create mode 100644 game/main/src/utlis/tile_selection_plugin.rs rename game/shared/src/{resource.rs => identifiers.rs} (66%) create mode 100644 game/shared/src/resources.rs diff --git a/game/buildings/src/assets/building_asset.rs b/game/buildings/src/assets/building_asset.rs index 3911809..5aea700 100644 --- a/game/buildings/src/assets/building_asset.rs +++ b/game/buildings/src/assets/building_asset.rs @@ -1,7 +1,7 @@ use asset_loader::create_asset_loader; use bevy::prelude::*; use serde::{Deserialize, Serialize}; -use shared::resource::ResourceIdentifier; +use shared::identifiers::ResourceIdentifier; use crate::footprint::BuildingFootprint; diff --git a/game/buildings/src/building_plugin.rs b/game/buildings/src/building_plugin.rs index 2115002..5d63463 100644 --- a/game/buildings/src/building_plugin.rs +++ b/game/buildings/src/building_plugin.rs @@ -9,6 +9,7 @@ use bevy_rapier3d::{parry::transformation::utils::transform, pipeline::QueryFilt use shared::{ despawn::Despawn, events::TileModifiedEvent, + resources::TileUnderCursor, states::{AssetLoadState, GameplayState}, tags::MainCamera, }; @@ -78,47 +79,23 @@ fn init(mut commands: Commands, mut meshes: ResMut>, mut materials: } fn hq_placement( - cam_query: Query<(&GlobalTransform, &Camera), With>, mut commands: Commands, - window: Query<&Window, With>, mouse: Res>, - rapier_context: Res, + tile_under_cursor: Res, map: Res, indicator: Res, mut build_queue: ResMut, mut next_state: ResMut>, ) { - let win = window.single(); - let (cam_transform, camera) = cam_query.single(); - let Some(cursor_pos) = win.cursor_position() else { - return; - }; - let Some(cam_ray) = camera.viewport_to_world(cam_transform, cursor_pos) else { - return; - }; - - let collision = rapier_context.cast_ray( - cam_ray.origin, - cam_ray.direction.into(), - 500., - true, - QueryFilter::only_fixed(), - ); - - if let Some((_e, dist)) = collision { - let contact_point = cam_ray.get_point(dist); - let contact_coord = HexCoord::from_world_pos(contact_point); - if !map.is_in_bounds(&contact_coord) { - return; - } - let positions = map.hex_select(&contact_coord, 3, true, |pos, h, _| pos.to_world(h)); + if let Some(contact) = tile_under_cursor.0 { + let positions = map.hex_select(&contact.tile, 3, true, |pos, h, _| pos.to_world(h)); show_indicators(positions, &mut commands, &indicator); if mouse.just_pressed(MouseButton::Left) { build_queue.queue.push(QueueEntry { building: 0.into(), - pos: contact_coord, + pos: contact.tile, }); next_state.set(GameplayState::Playing); diff --git a/game/main/src/map_rendering/map_init.rs b/game/main/src/map_rendering/map_init.rs index 3de9084..213eda3 100644 --- a/game/main/src/map_rendering/map_init.rs +++ b/game/main/src/map_rendering/map_init.rs @@ -107,6 +107,7 @@ fn setup_materials( base: StandardMaterial { base_color: Color::srgb(0., 0.878, 1.), alpha_mode: AlphaMode::Blend, + metallic: 1.0, ..Default::default() }, extension: WaterMaterial { diff --git a/game/main/src/map_rendering/terraforming_test.rs b/game/main/src/map_rendering/terraforming_test.rs index 53edbcd..909fdea 100644 --- a/game/main/src/map_rendering/terraforming_test.rs +++ b/game/main/src/map_rendering/terraforming_test.rs @@ -2,6 +2,7 @@ use bevy::{prelude::*, utils::hashbrown::HashSet, window::PrimaryWindow}; use bevy_rapier3d::{pipeline::QueryFilter, plugin::RapierContext}; use shared::{ events::{ChunkModifiedEvent, TileModifiedEvent}, + resources::TileUnderCursor, states::GameplayState, }; use world_generation::{hex_utils::HexCoord, prelude::Map, states::GeneratorState}; @@ -25,13 +26,11 @@ impl Plugin for TerraFormingTestPlugin { } fn deform( - cam_query: Query<(&GlobalTransform, &Camera), With>, mut commands: Commands, - window: Query<&Window, With>, mouse: Res>, - rapier_context: Res, mut heightmap: ResMut, chunks: Res, + tile_under_cursor: Res, mut chunk_modified: EventWriter, mut tile_modified: EventWriter, ) { @@ -46,33 +45,10 @@ fn deform( return; } - let win = window.single(); - let (cam_transform, camera) = cam_query.single(); - let Some(cursor_pos) = win.cursor_position() else { - return; - }; - - let Some(cam_ray) = camera.viewport_to_world(cam_transform, cursor_pos) else { - return; - }; - - let collision = rapier_context.cast_ray( - cam_ray.origin, - cam_ray.direction.into(), - 500., - true, - QueryFilter::only_fixed(), - ); - - if let Some((_, dist)) = collision { + if let Some(contact) = tile_under_cursor.0 { #[cfg(feature = "tracing")] let span = info_span!("Deform Mesh").entered(); - let contact_point = cam_ray.get_point(dist); - let contact_coord = HexCoord::from_world_pos(contact_point); - if !heightmap.is_in_bounds(&contact_coord) { - return; - } - let modified_tiles = heightmap.create_crater(&contact_coord, 5, 5. * multi); + let modified_tiles = heightmap.create_crater(&contact.tile, 5, 5. * multi); let mut chunk_set: HashSet = HashSet::new(); for (tile, height) in modified_tiles { let chunk = tile.to_chunk_index(heightmap.width); diff --git a/game/main/src/phos.rs b/game/main/src/phos.rs index 7ed8296..fbbc7eb 100644 --- a/game/main/src/phos.rs +++ b/game/main/src/phos.rs @@ -2,6 +2,7 @@ use crate::camera_system::components::PhosCamera; use crate::map_rendering::map_init::MapInitPlugin; use crate::utlis::editor_plugin::EditorPlugin; use crate::utlis::render_distance_system::RenderDistancePlugin; +use crate::utlis::tile_selection_plugin::TileSelectionPlugin; use crate::{camera_system::camera_plugin::PhosCameraPlugin, utlis::debug_plugin::DebugPlugin}; use bevy::{ pbr::{wireframe::WireframeConfig, CascadeShadowConfig}, @@ -13,8 +14,11 @@ use bevy_rapier3d::geometry::Collider; use bevy_rapier3d::plugin::{NoUserData, RapierPhysicsPlugin}; use buildings::BuildingPugin; use iyes_perf_ui::prelude::*; +use shared::sets::GameplaySet; use shared::states::{GameplayState, MenuState}; use shared::{despawn::DespawnPuglin, states::AssetLoadState}; +use units::units_plugin::UnitsPlugin; +use world_generation::states::GeneratorState; pub struct PhosGamePlugin; @@ -33,13 +37,17 @@ impl Plugin for PhosGamePlugin { MapInitPlugin, RenderDistancePlugin, BuildingPugin, + UnitsPlugin, DespawnPuglin, + TileSelectionPlugin, #[cfg(debug_assertions)] EditorPlugin, #[cfg(debug_assertions)] DebugPlugin, )); + configure_gameplay_set(app); + //Systems - Startup app.add_systems(Startup, init_game); @@ -63,6 +71,34 @@ impl Plugin for PhosGamePlugin { } } +fn configure_gameplay_set(app: &mut App) { + app.configure_sets( + Update, + GameplaySet.run_if(in_state(GeneratorState::Idle).and_then(in_state(MenuState::InGame))), + ); + app.configure_sets( + PreUpdate, + GameplaySet.run_if(in_state(GeneratorState::Idle).and_then(in_state(MenuState::InGame))), + ); + app.configure_sets( + PostUpdate, + GameplaySet.run_if(in_state(GeneratorState::Idle).and_then(in_state(MenuState::InGame))), + ); + + app.configure_sets( + FixedUpdate, + GameplaySet.run_if(in_state(GeneratorState::Idle).and_then(in_state(MenuState::InGame))), + ); + app.configure_sets( + FixedPreUpdate, + GameplaySet.run_if(in_state(GeneratorState::Idle).and_then(in_state(MenuState::InGame))), + ); + app.configure_sets( + FixedPostUpdate, + GameplaySet.run_if(in_state(GeneratorState::Idle).and_then(in_state(MenuState::InGame))), + ); +} + fn init_game(mut commands: Commands, mut materials: ResMut>) { commands.spawn(( PerfUiRoot::default(), diff --git a/game/main/src/utlis/debug_plugin.rs b/game/main/src/utlis/debug_plugin.rs index 411a16c..2ae5a24 100644 --- a/game/main/src/utlis/debug_plugin.rs +++ b/game/main/src/utlis/debug_plugin.rs @@ -2,6 +2,7 @@ use bevy::{prelude::*, window::PrimaryWindow}; use bevy_inspector_egui::bevy_egui::{systems::InputEvents, EguiContexts}; use bevy_inspector_egui::egui; use bevy_rapier3d::prelude::*; +use shared::resources::TileUnderCursor; use shared::states::GameplayState; use shared::tags::MainCamera; use world_generation::{ @@ -66,62 +67,32 @@ fn regenerate_map( } } -fn show_tile_heights( - cam_query: Query<(&GlobalTransform, &Camera), With>, - window: Query<&Window, With>, - rapier_context: Res, - map: Res, - mut gizmos: Gizmos, - shape: Res, -) { - let win = window.single(); - let (cam_transform, camera) = cam_query.single(); - let Some(cursor_pos) = win.cursor_position() else { - return; - }; - - let Some(cam_ray) = camera.viewport_to_world(cam_transform, cursor_pos) else { - return; - }; - - let collision = rapier_context.cast_ray( - cam_ray.origin, - cam_ray.direction.into(), - 500., - true, - QueryFilter::only_fixed(), - ); - - if let Some((_e, dist)) = collision { - let contact_point = cam_ray.get_point(dist); - let contact_coord = HexCoord::from_world_pos(contact_point); - if !map.is_in_bounds(&contact_coord) { - return; - } - let height = map.sample_height(&contact_coord); +fn show_tile_heights(map: Res, mut gizmos: Gizmos, shape: Res, tile_under_cursor: Res) { + if let Some(contact) = tile_under_cursor.0 { + let height = map.sample_height(&contact.tile); gizmos.primitive_3d( &shape.0, - contact_coord.to_world(height + 0.01), + contact.tile.to_world(height + 0.01), Quat::IDENTITY, Color::WHITE, ); - let nbors = map.get_neighbors(&contact_coord); - let contact_tile_pos = contact_coord.to_world(map.sample_height(&contact_coord)); + let nbors = map.get_neighbors(&contact.tile); + let contact_tile_pos = contact.tile.to_world(map.sample_height(&contact.tile)); - for i in 0..6 { - if let Some(s) = nbors[i] { - let coord = contact_coord.get_neighbor(i); - let p = coord.to_world(s); - gizmos.arrow(p, p + Vec3::Y * (i as f32 + 1.0), Color::WHITE); - } + // for i in 0..6 { + // if let Some(s) = nbors[i] { + // let coord = contact.tile.get_neighbor(i); + // let p = coord.to_world(s); + // gizmos.arrow(p, p + Vec3::Y * (i as f32 + 1.0), Color::WHITE); + // } - let p = HEX_CORNERS[i] + contact_tile_pos; - gizmos.arrow(p, p + Vec3::Y * (i as f32 + 1.0), LinearRgba::rgb(1.0, 0.0, 0.5)); - } + // let p = HEX_CORNERS[i] + contact_tile_pos; + // gizmos.arrow(p, p + Vec3::Y * (i as f32 + 1.0), LinearRgba::rgb(1.0, 0.0, 0.5)); + // } - gizmos.line(contact_point, contact_point + Vec3::X, LinearRgba::RED); - gizmos.line(contact_point, contact_point + Vec3::Y, LinearRgba::GREEN); - gizmos.line(contact_point, contact_point + Vec3::Z, LinearRgba::BLUE); + gizmos.line(contact.point, contact.point + Vec3::X, LinearRgba::RED); + gizmos.line(contact.point, contact.point + Vec3::Y, LinearRgba::GREEN); + gizmos.line(contact.point, contact.point + Vec3::Z, LinearRgba::BLUE); //gizmos.sphere(contact_point, Quat::IDENTITY, 0.1, LinearRgba::rgb(1., 0., 0.5)); } } diff --git a/game/main/src/utlis/mod.rs b/game/main/src/utlis/mod.rs index c307916..86dcd04 100644 --- a/game/main/src/utlis/mod.rs +++ b/game/main/src/utlis/mod.rs @@ -2,3 +2,4 @@ pub mod chunk_utils; pub mod render_distance_system; pub mod debug_plugin; pub mod editor_plugin; +pub mod tile_selection_plugin; diff --git a/game/main/src/utlis/tile_selection_plugin.rs b/game/main/src/utlis/tile_selection_plugin.rs new file mode 100644 index 0000000..08216d9 --- /dev/null +++ b/game/main/src/utlis/tile_selection_plugin.rs @@ -0,0 +1,62 @@ +use bevy::{prelude::*, window::PrimaryWindow}; +use bevy_rapier3d::{plugin::RapierContext, prelude::QueryFilter}; +use shared::{ + resources::{TileContact, TileUnderCursor}, + tags::MainCamera, +}; +use world_generation::{hex_utils::HexCoord, prelude::Map, states::GeneratorState}; +pub struct TileSelectionPlugin; + +impl Plugin for TileSelectionPlugin { + fn build(&self, app: &mut App) { + app.init_resource::(); + app.add_systems( + PreUpdate, + update_tile_under_cursor.run_if(in_state(GeneratorState::Idle)), + ); + } +} + +fn update_tile_under_cursor( + cam_query: Query<(&GlobalTransform, &Camera), With>, + window: Query<&Window, With>, + rapier_context: Res, + map: Res, + mut tile_under_cursor: ResMut, +) { + let win = window.single(); + let (cam_transform, camera) = cam_query.single(); + let Some(cursor_pos) = win.cursor_position() else { + return; + }; + + let Some(cam_ray) = camera.viewport_to_world(cam_transform, cursor_pos) else { + return; + }; + + let collision = rapier_context.cast_ray( + cam_ray.origin, + cam_ray.direction.into(), + 500., + true, + QueryFilter::only_fixed(), + ); + + if let Some((_e, dist)) = collision { + let contact_point = cam_ray.get_point(dist); + let contact_coord = HexCoord::from_world_pos(contact_point); + //todo: handle correct tile detection when contacting a tile from the side + if !map.is_in_bounds(&contact_coord) { + tile_under_cursor.0 = None; + return; + } + let surface = map.sample_height(&contact_coord); + tile_under_cursor.0 = Some(TileContact::new( + contact_coord, + contact_point, + contact_coord.to_world(surface), + )); + } else { + tile_under_cursor.0 = None; + } +} diff --git a/game/shared/src/resource.rs b/game/shared/src/identifiers.rs similarity index 66% rename from game/shared/src/resource.rs rename to game/shared/src/identifiers.rs index f9ad934..f1947d9 100644 --- a/game/shared/src/resource.rs +++ b/game/shared/src/identifiers.rs @@ -1,4 +1,6 @@ +use bevy::prelude::Resource; use serde::{Deserialize, Serialize}; +use world_generation::hex_utils::HexCoord; #[derive(Serialize, Deserialize, Debug)] pub struct ResourceIdentifier { diff --git a/game/shared/src/lib.rs b/game/shared/src/lib.rs index 0d6610b..2c2f7cf 100644 --- a/game/shared/src/lib.rs +++ b/game/shared/src/lib.rs @@ -1,7 +1,8 @@ pub mod building; pub mod despawn; -pub mod resource; +pub mod identifiers; pub mod states; pub mod tags; pub mod events; pub mod sets; +pub mod resources; diff --git a/game/shared/src/resources.rs b/game/shared/src/resources.rs new file mode 100644 index 0000000..7a53ef9 --- /dev/null +++ b/game/shared/src/resources.rs @@ -0,0 +1,22 @@ +use bevy::prelude::*; +use world_generation::hex_utils::HexCoord; + +#[derive(Resource, Default)] +pub struct TileUnderCursor(pub Option); + +#[derive(Clone, Copy)] +pub struct TileContact { + pub tile: HexCoord, + pub point: Vec3, + pub surface: Vec3, +} + +impl TileContact { + pub fn new(tile: HexCoord, contact: Vec3, surface: Vec3) -> Self { + return Self { + tile, + point: contact, + surface, + }; + } +} diff --git a/game/units/src/assets/unit_asset.rs b/game/units/src/assets/unit_asset.rs index 94c077d..e49d929 100644 --- a/game/units/src/assets/unit_asset.rs +++ b/game/units/src/assets/unit_asset.rs @@ -2,7 +2,7 @@ use asset_loader::create_asset_loader; use bevy::{ecs::world::CommandQueue, prelude::*}; use serde::{Deserialize, Serialize}; -use crate::components::{Unit, UnitDomain}; +use crate::components::{AirUnit, LandUnit, NavalUnit, Unit, UnitDomain}; #[derive(Asset, TypePath, Debug, Serialize, Deserialize)] pub struct UnitAsset { @@ -26,10 +26,15 @@ impl UnitAsset { ..default() }, Unit, - self.domain.clone(), ); + let domain = self.domain.clone(); commands.push(move |world: &mut World| { - world.spawn(bundle); + let mut e = world.spawn(bundle); + match domain { + UnitDomain::Land => e.insert(LandUnit), + UnitDomain::Air => e.insert(AirUnit), + UnitDomain::Naval => e.insert(NavalUnit), + }; }); todo!(); diff --git a/game/units/src/components.rs b/game/units/src/components.rs index ff9be19..e5276f3 100644 --- a/game/units/src/components.rs +++ b/game/units/src/components.rs @@ -4,9 +4,19 @@ use serde::{Deserialize, Serialize}; #[derive(Component, Debug)] pub struct Unit; -#[derive(Component, Serialize, Deserialize, Debug, Clone, Copy)] +#[derive(Component, Debug)] +pub struct AirUnit; +#[derive(Component, Debug)] +pub struct LandUnit; +#[derive(Component, Debug)] +pub struct NavalUnit; + +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub enum UnitDomain { Land, Air, - Navy, + Naval, } + +#[derive(Component, Debug)] +pub struct Target(pub Vec3); diff --git a/game/units/src/units_debug_plugin.rs b/game/units/src/units_debug_plugin.rs index bca2d0c..e8ad741 100644 --- a/game/units/src/units_debug_plugin.rs +++ b/game/units/src/units_debug_plugin.rs @@ -1,18 +1,66 @@ +use std::f32::consts::E; + use bevy::prelude::*; -use shared::states::GameplayState; -use world_generation::states::GeneratorState; +use shared::{resources::TileUnderCursor, sets::GameplaySet, states::AssetLoadState}; +use world_generation::{heightmap, prelude::Map}; + +use crate::components::{LandUnit, Target, Unit}; pub struct UnitsDebugPlugin; impl Plugin for UnitsDebugPlugin { fn build(&self, app: &mut App) { - app.add_systems( - Update, - spawn_test_unit.run_if(in_state(GeneratorState::Idle).and_then(in_state(GameplayState::Playing))), - ); + app.add_systems(Update, init.run_if(in_state(AssetLoadState::Loading))); + + app.add_systems(Update, (spawn_test_unit, set_unit_target).in_set(GameplaySet)); } } -fn spawn_test_unit(mut commands: Commands, input: Res>) { - +#[derive(Resource)] +struct TestUnit(pub Handle); + +fn init(mut meshes: ResMut>, mut commands: Commands) { + let mesh_handle = meshes.add(Cuboid::from_length(1.0)); + commands.insert_resource(TestUnit(mesh_handle)); +} + +fn spawn_test_unit( + mut commands: Commands, + input: Res>, + tile_under_cursor: Res, + unit: Res, +) { + if !input.just_pressed(KeyCode::KeyT) { + return; + } + if let Some(contact) = tile_under_cursor.0 { + info!("Spawning Test Unit"); + commands.spawn(( + PbrBundle { + transform: Transform::from_translation(contact.surface), + mesh: unit.0.clone(), + ..default() + }, + Unit, + LandUnit, + )); + } +} + +fn set_unit_target( + mut commands: Commands, + units: Query>, + input: Res>, + tile_under_cursor: Res, +) { + if !input.just_pressed(MouseButton::Right) { + return; + } + if let Some(contact) = tile_under_cursor.0 { + for e in units.iter() { + info!("Setting Target"); + let mut e = commands.entity(e); + e.insert(Target(contact.surface)); + } + } } diff --git a/game/units/src/units_plugin.rs b/game/units/src/units_plugin.rs index a89e0df..eb1c078 100644 --- a/game/units/src/units_plugin.rs +++ b/game/units/src/units_plugin.rs @@ -3,10 +3,14 @@ use bevy_asset_loader::loading_state::{ config::{ConfigureLoadingState, LoadingStateConfig}, LoadingStateAppExt, }; -use shared::states::{AssetLoadState, GameplayState}; -use world_generation::states::GeneratorState; +use shared::{sets::GameplaySet, states::AssetLoadState}; +use world_generation::{hex_utils::HexCoord, prelude::Map}; -use crate::assets::{unit_asset::UnitAssetPlugin, unit_database::UnitDatabase}; +use crate::{ + assets::{unit_asset::UnitAssetPlugin, unit_database::UnitDatabase}, + components::{Target, Unit}, + units_debug_plugin::UnitsDebugPlugin, +}; pub struct UnitsPlugin; @@ -14,20 +18,16 @@ impl Plugin for UnitsPlugin { fn build(&self, app: &mut App) { app.add_plugins(UnitAssetPlugin); - app.configure_loading_state(LoadingStateConfig::new(AssetLoadState::Loading).load_collection::()); + #[cfg(debug_assertions)] + app.add_plugins(UnitsDebugPlugin); - app.add_systems(Update, units_control.in_set(UnitUpdateSet)); + // app.configure_loading_state(LoadingStateConfig::new(AssetLoadState::Loading).load_collection::()); - app.configure_sets( - Update, - UnitUpdateSet.run_if(in_state(GameplayState::Playing).and_then(in_state(GeneratorState::Idle))), - ); + app.add_systems(Update, units_control.in_set(GameplaySet)); + app.add_systems(Update, move_unit.in_set(GameplaySet)); } } -#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] -struct UnitUpdateSet; - fn units_control(input: Res>, window: Query<&Window, With>) { let win = window.single(); @@ -35,3 +35,14 @@ fn units_control(input: Res>, window: Query<&Window, With

>, time: Res