partial chunking
This commit is contained in:
+192
@@ -0,0 +1,192 @@
|
||||
use crate::constants::TILE_SIZE;
|
||||
use crate::tiles::{FixtureTilePrefab, FloorTilePrefab};
|
||||
use bevy::prelude::*;
|
||||
use noise::{NoiseFn, Perlin};
|
||||
use std::collections::HashMap;
|
||||
use std::process::exit;
|
||||
|
||||
pub const CHUNK_SIZE: i32 = 8;
|
||||
pub const CHUNK_HEIGHT: i32 = 200;
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct ChunkMap {
|
||||
pub loaded_chunks: HashMap<IVec2, bool>,
|
||||
}
|
||||
|
||||
impl Default for ChunkMap {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
loaded_chunks: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Event)]
|
||||
pub struct LoadChunkEvent {
|
||||
pub chunk_position: IVec2,
|
||||
}
|
||||
|
||||
fn setup_chunk_system(mut commands: Commands) {
|
||||
commands.insert_resource(ChunkMap::default());
|
||||
}
|
||||
|
||||
fn handle_chunk_loading(
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut events: EventReader<LoadChunkEvent>,
|
||||
mut chunk_map: ResMut<ChunkMap>,
|
||||
) {
|
||||
let noise = Perlin::new(0);
|
||||
|
||||
for event in events.read() {
|
||||
let chunk_pos = event.chunk_position;
|
||||
// Skip if chunk is already loaded
|
||||
if chunk_map.loaded_chunks.contains_key(&chunk_pos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Mark chunk as loaded
|
||||
chunk_map.loaded_chunks.insert(chunk_pos, true);
|
||||
|
||||
// Calculate world space coordinates for chunk
|
||||
let start_x = chunk_pos.x * CHUNK_SIZE;
|
||||
let start_y = chunk_pos.y * CHUNK_SIZE;
|
||||
|
||||
let mut floor_positions = Vec::new();
|
||||
|
||||
// Generate tiles for this chunk
|
||||
for local_y in 0..CHUNK_SIZE {
|
||||
for local_x in 0..CHUNK_SIZE {
|
||||
let world_x = start_x + local_x;
|
||||
let world_y = start_y + local_y;
|
||||
|
||||
let noise_value_a =
|
||||
noise.get([world_x as f64 * 0.01, world_y as f64 * 0.01]) * 1.25;
|
||||
let noise_value_b =
|
||||
noise.get([world_x as f64 * 0.05, world_y as f64 * 0.05]) * 0.25;
|
||||
let combined_noise_value = noise_value_a + noise_value_b;
|
||||
|
||||
let noise_position = Vec3::new(
|
||||
(world_x as f32 * TILE_SIZE).round(),
|
||||
(world_y as f32 * TILE_SIZE).round(),
|
||||
(combined_noise_value * 4.).round() as f32 * TILE_SIZE,
|
||||
);
|
||||
generate_vertical_slice(
|
||||
&mut commands,
|
||||
&asset_server,
|
||||
world_x,
|
||||
world_y,
|
||||
&noise,
|
||||
noise_position,
|
||||
&mut floor_positions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate fixtures after floor tiles
|
||||
generate_fixtures_for_chunk(&mut commands, &asset_server, &floor_positions);
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_vertical_slice(
|
||||
commands: &mut Commands,
|
||||
asset_server: &Res<AssetServer>,
|
||||
x: i32,
|
||||
y: i32,
|
||||
noise: &Perlin,
|
||||
noise_position: Vec3,
|
||||
floor_positions: &mut Vec<(Vec3, &'static str)>,
|
||||
) {
|
||||
for z in -150..50 {
|
||||
let position = Vec3::new(
|
||||
(x as f32 * TILE_SIZE).round(),
|
||||
(y as f32 * TILE_SIZE).round(),
|
||||
(z as f32 * TILE_SIZE).round(),
|
||||
);
|
||||
|
||||
let floor_type = if noise_position.z > position.z {
|
||||
if z < -15 {
|
||||
let noise_value = noise.get([x as f64 * 0.05, y as f64 * 0.05, z as f64 * 0.05]);
|
||||
if noise_value < -0.5 {
|
||||
spawn_tile(commands, FloorTilePrefab::air(position, asset_server));
|
||||
Some("air")
|
||||
} else if noise_value < 0.8 {
|
||||
spawn_tile(commands, FloorTilePrefab::rock(position, asset_server));
|
||||
Some("rock")
|
||||
} else {
|
||||
spawn_tile(commands, FloorTilePrefab::dirt(position, asset_server));
|
||||
Some("dirt")
|
||||
}
|
||||
} else {
|
||||
spawn_tile(commands, FloorTilePrefab::dirt(position, asset_server));
|
||||
Some("dirt")
|
||||
}
|
||||
} else if noise_position.z < position.z {
|
||||
spawn_tile(commands, FloorTilePrefab::air(position, asset_server));
|
||||
Some("air")
|
||||
} else {
|
||||
spawn_tile(commands, FloorTilePrefab::dirt(position, asset_server));
|
||||
Some("dirt")
|
||||
};
|
||||
|
||||
if let Some(floor_type) = floor_type {
|
||||
floor_positions.push((position, floor_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_tile(commands: &mut Commands, bundle: impl Bundle) -> Entity {
|
||||
commands.spawn(bundle).id()
|
||||
}
|
||||
|
||||
fn generate_fixtures_for_chunk(
|
||||
commands: &mut Commands,
|
||||
asset_server: &Res<AssetServer>,
|
||||
floor_positions: &[(Vec3, &str)],
|
||||
) {
|
||||
let floor_map: HashMap<(i32, i32, i32), &str> = floor_positions
|
||||
.iter()
|
||||
.map(|(pos, floor_type)| ((pos.x as i32, pos.y as i32, pos.z as i32), *floor_type))
|
||||
.collect();
|
||||
|
||||
for (position, _) in floor_positions {
|
||||
let x = position.x as i32;
|
||||
let y = position.y as i32;
|
||||
let z = position.z as i32;
|
||||
|
||||
if let Some(&above_floor_type) = floor_map.get(&(x, y, z + TILE_SIZE as i32)) {
|
||||
if above_floor_type == "air" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let fixture_position = Vec3::new(position.x, position.y, position.z + 1.);
|
||||
|
||||
match above_floor_type {
|
||||
"dirt" => {
|
||||
commands.spawn(FixtureTilePrefab::dirt_wall(fixture_position, asset_server));
|
||||
}
|
||||
"rock" => {
|
||||
commands.spawn(FixtureTilePrefab::rock_wall(fixture_position, asset_server));
|
||||
}
|
||||
"bedrock" => {
|
||||
commands.spawn(FixtureTilePrefab::bedrock_wall(
|
||||
fixture_position,
|
||||
asset_server,
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TilemapPlugin;
|
||||
|
||||
impl Plugin for TilemapPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.init_resource::<ChunkMap>()
|
||||
.add_event::<LoadChunkEvent>()
|
||||
.add_systems(Startup, setup_chunk_system)
|
||||
.add_systems(Update, handle_chunk_loading);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user