Fix 1 — insert_fixture now updates ChunkData bitsets: Log trunks (can_stand_in=false) now block movement in is_standable. Leaf canopy (can_stand_in=true) remains walkable. Fix 2 — Diagonal-aware collision avoidance: Sidestep priority: left+forward, left, right+forward, right. If all blocked: push through (excuse me), advance path, apply one-step delay (speed-modulated recovery). Does not stack delays. Fix 3 — Movement direction tracking: Ambulatory now has move_direction (Vec2) and step_history ([i16; 4]). TileOccupancy tracks per-tile direction hints for Stage 2 collision (convoy skip, E/S yield) via direction_at(). move_direction is smoothed from: 2 historical steps, current confirmed step, and 2-step path lookahead. Ignore: add *.patch and *.diff to .gitignore
80 lines
2.2 KiB
Rust
80 lines
2.2 KiB
Rust
use crate::config::GameConfig;
|
|
use crate::constants::TILE_SIZE;
|
|
use crate::constants::*;
|
|
use crate::entities::shared_components::Ambulatory;
|
|
use crate::game::SpawnDelay;
|
|
use crate::world::VisibleGameEntity;
|
|
use bevy::prelude::*;
|
|
use bevy_rand::prelude::*;
|
|
use rand::RngExt;
|
|
|
|
#[derive(Bundle)]
|
|
pub struct Rabbit {
|
|
ambulatory: Ambulatory,
|
|
sprite: Sprite,
|
|
transform: Transform,
|
|
visibility: Visibility,
|
|
}
|
|
|
|
impl Rabbit {
|
|
pub fn new(asset_server: &Res<AssetServer>, position: Vec3) -> Self {
|
|
Rabbit {
|
|
ambulatory: Ambulatory {
|
|
walk_speed: 1.,
|
|
run_speed: 6.,
|
|
target: None,
|
|
current_path: None,
|
|
path_index: 0,
|
|
step_recovery: 0,
|
|
validation_cooldown: 0,
|
|
move_direction: Vec2::ZERO,
|
|
step_history: [0i16; 4],
|
|
},
|
|
sprite: Sprite {
|
|
image: asset_server.load("rabbit.png"),
|
|
..Default::default()
|
|
},
|
|
transform: Transform::from_translation(position).with_scale(Vec3::splat(PIXEL_RATIO)),
|
|
visibility: Visibility::Hidden,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn spawn_rabbits(
|
|
mut commands: Commands,
|
|
asset_server: Res<AssetServer>,
|
|
mut rng_q: Query<&mut WyRand, With<GlobalRng>>,
|
|
config: Res<GameConfig>,
|
|
mut delay: ResMut<SpawnDelay>,
|
|
mut has_spawned: Local<bool>,
|
|
) {
|
|
if *has_spawned {
|
|
return;
|
|
}
|
|
|
|
if delay.0 < 60 {
|
|
delay.0 += 1;
|
|
return;
|
|
}
|
|
|
|
*has_spawned = true;
|
|
|
|
if let Ok(mut rng) = rng_q.single_mut() {
|
|
for _ in 0..config.spawn_counts.rabbits {
|
|
let raw_x = rng.random_range(-32.0f32..32.0f32);
|
|
let raw_y = rng.random_range(-32.0f32..32.0f32);
|
|
let grid_x = (raw_x / TILE_SIZE).round() * TILE_SIZE;
|
|
let grid_y = (raw_y / TILE_SIZE).round() * TILE_SIZE;
|
|
let grid_z = 35.0 * TILE_SIZE;
|
|
|
|
let rab = commands
|
|
.spawn(Rabbit::new(
|
|
&asset_server,
|
|
Vec3::new(grid_x, grid_y, grid_z),
|
|
))
|
|
.id();
|
|
commands.entity(rab).insert(VisibleGameEntity);
|
|
}
|
|
}
|
|
}
|