From 0af88c213d03354468cc2cb33ba3aa8958520963 Mon Sep 17 00:00:00 2001 From: StephenAdamson Date: Fri, 17 Jan 2025 20:05:08 +0000 Subject: [PATCH] partial a* --- src/citizen.rs | 283 ++++++++++++++++++++++++++++++++++++++++++++----- src/main.rs | 1 + src/tile.rs | 4 +- src/tilemap.rs | 41 ++++--- src/tiles.rs | 4 + 5 files changed, 288 insertions(+), 45 deletions(-) diff --git a/src/citizen.rs b/src/citizen.rs index d2f6ab6..5276d8e 100644 --- a/src/citizen.rs +++ b/src/citizen.rs @@ -1,12 +1,8 @@ -use crate::constants::*; +use crate::{ + constants::*, + tilemap::{generate_surface_noise, ChunkMap, CHUNK_SIZE}, +}; use bevy::prelude::*; -use rand::prelude::*; - -#[derive(Component)] -#[require(Transform)] -pub struct Ambulatory { - speed: f32, -} #[derive(Bundle)] pub struct Citizen { @@ -18,7 +14,12 @@ pub struct Citizen { impl Citizen { pub fn new(asset_server: &Res, position: Vec3) -> Self { Citizen { - walkness: Ambulatory { speed: TILE_SIZE }, + walkness: Ambulatory { + speed: TILE_SIZE, + target: None, + current_path: None, + path_index: 0, + }, sprite: Sprite { image: asset_server.load("dorf.png"), ..Default::default() @@ -28,34 +29,258 @@ impl Citizen { } } -pub fn citizen_movement(mut query: Query<(&Ambulatory, &mut Transform), With>) { - for (citizen, mut transform) in query.iter_mut() { - // Skip processing if the random check fails - if rand::random::() >= 0.66666 { - continue; - } +use crate::constants::TILE_SIZE; +use crate::tile::TileMap; +use rand::{seq::SliceRandom, Rng}; +use std::collections::{BinaryHeap, HashMap, HashSet}; - // Generate random directions - let direction_x = (rand::random::() - rand::random::()).round(); - let direction_y = (rand::random::() - rand::random::()).round(); +#[derive(Component)] +pub struct Ambulatory { + pub speed: f32, + pub current_path: Option>, + pub path_index: usize, + pub target: Option, +} - // Skip if there's no movement - if direction_x == 0.0 && direction_y == 0.0 { - continue; - } +#[derive(Clone, Eq, PartialEq)] +struct PathNode { + position: IVec3, + f_score: i32, + g_score: i32, +} - // Calculate movement only once - let speed = citizen.speed; - transform.translation.x += direction_x * speed; - transform.translation.y += direction_y * speed; +impl Ord for PathNode { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + other.f_score.cmp(&self.f_score) + } +} - // Adjust scale for x direction - if direction_x != 0.0 { - transform.scale.x = PIXEL_RATIO * direction_x.signum(); +impl PartialOrd for PathNode { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +pub struct PathfindingPlugin; + +impl Plugin for PathfindingPlugin { + fn build(&self, app: &mut App) { + app.add_systems(FixedUpdate, (update_citizen_targets, citizen_movement)); + } +} + +pub fn update_citizen_targets( + mut query: Query<(&mut Ambulatory, &Transform)>, + tilemap: Res, + chunk_map: Res, +) { + let mut rng = rand::thread_rng(); + + for (mut ambulatory, transform) in query.iter_mut() { + if ambulatory.target.is_none() + || (ambulatory.current_path.is_some() + && ambulatory.path_index >= ambulatory.current_path.as_ref().unwrap().len()) + { + // Find a random loaded chunk + let loaded_chunks: Vec<&IVec2> = chunk_map.loaded_chunks.keys().collect(); + if let Some(&chunk_pos) = loaded_chunks.choose(&mut rng) { + // Generate random position within chunk + let chunk_x = chunk_pos.x * CHUNK_SIZE; + let chunk_y = chunk_pos.y * CHUNK_SIZE; + + let target_x = chunk_x + rng.gen_range(0..CHUNK_SIZE); + let target_y = chunk_y + rng.gen_range(0..CHUNK_SIZE); + + // Get height at position + let surface_height = generate_surface_noise(target_x, target_y).round() as i32; + + // Find a valid z-level near the surface + for z in (surface_height - 2)..=(surface_height + 2) { + let target_pos = IVec3::new(target_x, target_y, z); + if let Some(floor_tile) = tilemap.floor_tiles.get(&target_pos) { + // If tile is walkable, set target + if floor_tile.2 { + ambulatory.target = Some(Vec3::new( + target_x as f32 * TILE_SIZE, + target_y as f32 * TILE_SIZE, + z as f32 * TILE_SIZE, + )); + ambulatory.current_path = None; + ambulatory.path_index = 0; + break; + } + } + } + } } } } +pub fn citizen_movement( + mut query: Query<(&mut Ambulatory, &mut Transform)>, + tilemap: Res, + time: Res