path finding task setup
spacial set wip
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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>);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
|
|||||||
@@ -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>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user