path finding task setup

spacial set wip
This commit is contained in:
2024-09-30 22:14:57 -04:00
parent 47c0732f23
commit 5adfbd5de5
5 changed files with 127 additions and 29 deletions

View File

@@ -2,7 +2,7 @@ use bevy::prelude::*;
#[derive(Component)] #[derive(Component)]
pub struct MainCamera; pub struct MainCamera;
#[derive(Component)] #[derive(Component, Clone, Copy)]
pub enum Faction { pub enum Faction {
Player, Player,
Phos, Phos,

View File

@@ -1,4 +1,4 @@
use bevy::prelude::*; use bevy::{ecs::world::CommandQueue, prelude::*, tasks::Task};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Component, Debug)] #[derive(Component, Debug)]
@@ -20,3 +20,9 @@ pub enum UnitDomain {
#[derive(Component, Debug)] #[derive(Component, Debug)]
pub struct Target(pub Vec3); pub struct Target(pub Vec3);
#[derive(Component, Debug)]
pub struct Path(pub Vec<Vec3>, pub usize);
#[derive(Component, Debug)]
pub struct PathTask(pub Task<CommandQueue>);

View File

@@ -4,3 +4,8 @@ pub mod components;
pub mod units_debug_plugin; pub mod units_debug_plugin;
pub mod units_plugin; pub mod units_plugin;
pub mod units_spacial_set; pub mod units_spacial_set;
#[derive(Clone, Copy)]
pub enum UnitType {
Basic,
}

View File

@@ -1,14 +1,17 @@
use bevy::{prelude::*, window::PrimaryWindow}; use bevy::{
ecs::world::CommandQueue, prelude::*, tasks::AsyncComputeTaskPool, transform::commands, utils::futures,
window::PrimaryWindow,
};
use bevy_asset_loader::loading_state::{ use bevy_asset_loader::loading_state::{
config::{ConfigureLoadingState, LoadingStateConfig}, config::{ConfigureLoadingState, LoadingStateConfig},
LoadingStateAppExt, LoadingStateAppExt,
}; };
use shared::{sets::GameplaySet, states::AssetLoadState}; use shared::{resources::TileUnderCursor, sets::GameplaySet, states::AssetLoadState};
use world_generation::{hex_utils::HexCoord, prelude::Map}; use world_generation::{hex_utils::HexCoord, prelude::Map};
use crate::{ use crate::{
assets::{unit_asset::UnitAssetPlugin, unit_database::UnitDatabase}, assets::{unit_asset::UnitAssetPlugin, unit_database::UnitDatabase},
components::{Target, Unit}, components::{Path, PathTask, Target, Unit},
units_debug_plugin::UnitsDebugPlugin, units_debug_plugin::UnitsDebugPlugin,
}; };
@@ -25,20 +28,30 @@ impl Plugin for UnitsPlugin {
app.add_systems(Update, units_control.in_set(GameplaySet)); app.add_systems(Update, units_control.in_set(GameplaySet));
app.add_systems(Update, move_unit.in_set(GameplaySet)); app.add_systems(Update, move_unit.in_set(GameplaySet));
app.add_systems(FixedPreUpdate, (calculate_path, resolve_path_task).in_set(GameplaySet));
} }
} }
fn units_control(input: Res<ButtonInput<KeyCode>>, window: Query<&Window, With<PrimaryWindow>>) { fn units_control(tile_under_cursor: Res<TileUnderCursor>) {}
let win = window.single();
let Some(cursor_pos) = win.cursor_position() else { fn move_unit(
return; mut units: Query<(&mut Transform, &mut Path, Entity), With<Unit>>,
}; time: Res<Time>,
} map: Res<Map>,
mut commands: Commands,
fn move_unit(mut units: Query<(&mut Transform, &Target), With<Unit>>, time: Res<Time>, map: Res<Map>) { ) {
for (mut t, target) in units.iter_mut() { for (mut t, mut path, entity) in units.iter_mut() {
let vel = (target.0 - t.translation).normalize() * 10.0 * time.delta_seconds(); if path.1 >= path.0.len() {
commands.entity(entity).remove::<Path>();
continue;
}
let p = path.0[path.1];
let d = p - t.translation;
if d.length() < 0.1 {
path.1 += 1;
continue;
}
let vel = d.normalize() * 10.0 * time.delta_seconds();
t.translation += vel; t.translation += vel;
let coord = HexCoord::from_world_pos(t.translation); let coord = HexCoord::from_world_pos(t.translation);
if map.is_in_bounds(&coord) { if map.is_in_bounds(&coord) {
@@ -46,3 +59,36 @@ fn move_unit(mut units: Query<(&mut Transform, &Target), With<Unit>>, time: Res<
} }
} }
} }
fn calculate_path(
units: Query<(&Transform, &Target, Entity), (With<Unit>, Without<PathTask>)>,
map: Res<Map>,
mut commands: Commands,
) {
let pool = AsyncComputeTaskPool::get();
for (transform, target, entity) in units.iter() {
let from = transform.translation;
let to = target.0;
let task = pool.spawn(async move {
let mut queue = CommandQueue::default();
queue.push(move |world: &mut World| {
//todo: calculate path
world.entity_mut(entity).insert(Path(vec![from, to], 0));
});
return queue;
});
commands.entity(entity).insert(PathTask(task)).remove::<Target>();
}
}
fn resolve_path_task(mut tasks: Query<(&mut PathTask, Entity), With<Unit>>, mut commands: Commands) {
for (mut task, entity) in tasks.iter_mut() {
if let Some(mut c) = futures::check_ready(&mut task.0) {
commands.append(&mut c);
commands.entity(entity).remove::<PathTask>();
}
}
}

View File

@@ -1,15 +1,16 @@
use bevy::prelude::*; use bevy::prelude::*;
use quadtree_rs::{point::Point, Quadtree}; use quadtree_rs::{area::AreaBuilder, point::Point, Quadtree};
use shared::tags::Faction; use shared::tags::Faction;
use world_generation::hex_utils::HexCoord;
use crate::components::UnitDomain; use crate::{components::UnitDomain, UnitType};
#[derive(Clone, Copy)]
pub struct UnitEntity { pub struct UnitEntity {
pub entity: Entity, pub entity: Entity,
pub domain: UnitDomain, pub domain: UnitDomain,
pub unitType: (), pub unit_type: UnitType,
pub faction: Faction, pub faction: Faction,
pub position: Vec3,
} }
pub struct UnitSpacialSet { pub struct UnitSpacialSet {
@@ -25,17 +26,57 @@ impl UnitSpacialSet {
} }
pub fn add_unit(&mut self, unit: UnitEntity, pos: Vec3) -> Option<u64> { pub fn add_unit(&mut self, unit: UnitEntity, pos: Vec3) -> Option<u64> {
let p = pos.xz().as_uvec2(); return self.tree.insert_pt(convert_to_point(pos.xz()), unit);
return self.tree.insert_pt(
Point {
x: p.x as usize,
y: p.y as usize,
},
unit,
);
} }
pub fn move_unit(&mut self, handle: u64) { pub fn move_unit(&mut self, handle: u64, pos: Vec3) -> Option<u64> {
todo!(); if let Some(existing) = self.tree.get(handle) {
if existing.anchor() == convert_to_point(pos.xz()) {
return None;
}
} else {
return None;
}
if let Some(entry) = self.tree.delete_by_handle(handle) {
let p = convert_to_point(pos.xz());
let mut entry = *entry.value_ref();
entry.position = pos;
return self.tree.insert_pt(p, entry);
}
return None;
}
pub fn get_units_in_circle(self, center: Vec3, radius: f32) -> Vec<Entity> {
let anchor = center.xz() - Vec2::new(radius, radius);
let d = (radius * 2.0) as usize;
let area = AreaBuilder::default()
.anchor(convert_to_point(anchor))
.dimensions((d, d))
.build()
.unwrap();
let query = self.tree.query(area);
return query
.filter(|e| e.value_ref().position.distance(center) <= radius)
.map(|e| e.value_ref().entity)
.collect();
}
pub fn get_units_in_rect(self, anchor: Vec2, size: Vec2) -> Vec<Entity> {
let area = AreaBuilder::default()
.anchor(convert_to_point(anchor))
.dimensions((size.x as usize, size.y as usize))
.build()
.unwrap();
let query = self.tree.query(area);
return query.map(|e| e.value_ref().entity).collect();
} }
} }
fn convert_to_point(pos: Vec2) -> Point<usize> {
let p = pos.as_uvec2();
return Point {
x: p.x as usize,
y: p.y as usize,
};
}