-
Notifications
You must be signed in to change notification settings - Fork 199
/
chunking.rs
131 lines (121 loc) · 4.74 KB
/
chunking.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use bevy::{math::Vec3Swizzles, prelude::*, utils::HashSet};
use bevy_ecs_tilemap::prelude::*;
mod helpers;
/// Press WASD to move the camera around, and watch as chunks spawn/despawn in response.
const TILE_SIZE: TilemapTileSize = TilemapTileSize { x: 16.0, y: 16.0 };
// For this example, don't choose too large a chunk size.
const CHUNK_SIZE: UVec2 = UVec2 { x: 4, y: 4 };
// Render chunk sizes are set to 4 render chunks per user specified chunk.
const RENDER_CHUNK_SIZE: UVec2 = UVec2 {
x: CHUNK_SIZE.x * 2,
y: CHUNK_SIZE.y * 2,
};
fn spawn_chunk(commands: &mut Commands, asset_server: &AssetServer, chunk_pos: IVec2) {
let tilemap_entity = commands.spawn_empty().id();
let mut tile_storage = TileStorage::empty(CHUNK_SIZE.into());
// Spawn the elements of the tilemap.
for x in 0..CHUNK_SIZE.x {
for y in 0..CHUNK_SIZE.y {
let tile_pos = TilePos { x, y };
let tile_entity = commands
.spawn(TileBundle {
position: tile_pos,
tilemap_id: TilemapId(tilemap_entity),
..Default::default()
})
.id();
commands.entity(tilemap_entity).add_child(tile_entity);
tile_storage.set(&tile_pos, tile_entity);
}
}
let transform = Transform::from_translation(Vec3::new(
chunk_pos.x as f32 * CHUNK_SIZE.x as f32 * TILE_SIZE.x,
chunk_pos.y as f32 * CHUNK_SIZE.y as f32 * TILE_SIZE.y,
0.0,
));
let texture_handle: Handle<Image> = asset_server.load("tiles.png");
commands.entity(tilemap_entity).insert(TilemapBundle {
grid_size: TILE_SIZE.into(),
size: CHUNK_SIZE.into(),
storage: tile_storage,
texture: TilemapTexture::Single(texture_handle),
tile_size: TILE_SIZE,
transform,
render_settings: TilemapRenderSettings {
render_chunk_size: RENDER_CHUNK_SIZE,
..Default::default()
},
..Default::default()
});
}
fn startup(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
}
fn camera_pos_to_chunk_pos(camera_pos: &Vec2) -> IVec2 {
let camera_pos = camera_pos.as_ivec2();
let chunk_size: IVec2 = IVec2::new(CHUNK_SIZE.x as i32, CHUNK_SIZE.y as i32);
let tile_size: IVec2 = IVec2::new(TILE_SIZE.x as i32, TILE_SIZE.y as i32);
camera_pos / (chunk_size * tile_size)
}
fn spawn_chunks_around_camera(
mut commands: Commands,
asset_server: Res<AssetServer>,
camera_query: Query<&Transform, With<Camera>>,
mut chunk_manager: ResMut<ChunkManager>,
) {
for transform in camera_query.iter() {
let camera_chunk_pos = camera_pos_to_chunk_pos(&transform.translation.xy());
for y in (camera_chunk_pos.y - 2)..(camera_chunk_pos.y + 2) {
for x in (camera_chunk_pos.x - 2)..(camera_chunk_pos.x + 2) {
if !chunk_manager.spawned_chunks.contains(&IVec2::new(x, y)) {
chunk_manager.spawned_chunks.insert(IVec2::new(x, y));
spawn_chunk(&mut commands, &asset_server, IVec2::new(x, y));
}
}
}
}
}
fn despawn_outofrange_chunks(
mut commands: Commands,
camera_query: Query<&Transform, With<Camera>>,
chunks_query: Query<(Entity, &Transform)>,
mut chunk_manager: ResMut<ChunkManager>,
) {
for camera_transform in camera_query.iter() {
for (entity, chunk_transform) in chunks_query.iter() {
let chunk_pos = chunk_transform.translation.xy();
let distance = camera_transform.translation.xy().distance(chunk_pos);
if distance > 320.0 {
let x = (chunk_pos.x / (CHUNK_SIZE.x as f32 * TILE_SIZE.x)).floor() as i32;
let y = (chunk_pos.y / (CHUNK_SIZE.y as f32 * TILE_SIZE.y)).floor() as i32;
chunk_manager.spawned_chunks.remove(&IVec2::new(x, y));
commands.entity(entity).despawn_recursive();
}
}
}
}
#[derive(Default, Debug, Resource)]
struct ChunkManager {
pub spawned_chunks: HashSet<IVec2>,
}
fn main() {
App::new()
.add_plugins(
DefaultPlugins
.set(WindowPlugin {
primary_window: Some(Window {
title: String::from("Basic Chunking Example"),
..Default::default()
}),
..default()
})
.set(ImagePlugin::default_nearest()),
)
.add_plugins(TilemapPlugin)
.insert_resource(ChunkManager::default())
.add_systems(Startup, startup)
.add_systems(Update, helpers::camera::movement)
.add_systems(Update, spawn_chunks_around_camera)
.add_systems(Update, despawn_outofrange_chunks)
.run();
}