various fixes to map size calculations
This commit is contained in:
@@ -2,7 +2,10 @@ use crate::prelude::Chunk;
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
pub const OUTER_RADIUS: f32 = 1.;
|
pub const OUTER_RADIUS: f32 = 1.;
|
||||||
pub const INNER_RADIUS: f32 = OUTER_RADIUS * 0.866025404;
|
pub const INNER_RADIUS: f32 = OUTER_RADIUS * (SQRT_3 / 2.);
|
||||||
|
pub const SHORT_DIAGONAL: f32 = 1. * SQRT_3;
|
||||||
|
pub const LONG_DIAGONAL: f32 = 2. * OUTER_RADIUS;
|
||||||
|
const SQRT_3: f32 = 1.7320508076;
|
||||||
|
|
||||||
pub fn offset3d_to_world(offset: Vec3) -> Vec3 {
|
pub fn offset3d_to_world(offset: Vec3) -> Vec3 {
|
||||||
let x = (offset.x + (offset.z * 0.5) - (offset.z / 2.).floor()) * (INNER_RADIUS * 2.);
|
let x = (offset.x + (offset.z * 0.5) - (offset.z / 2.).floor()) * (INNER_RADIUS * 2.);
|
||||||
@@ -41,11 +44,11 @@ pub fn world_to_offset_pos(world_pos: Vec3) -> IVec2 {
|
|||||||
return IVec2::new(ox, oz);
|
return IVec2::new(ox, oz);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tile_to_world_distance(dist: i32) -> f32 {
|
pub fn tile_to_world_distance(dist: u32) -> f32 {
|
||||||
return dist as f32 * (2. * INNER_RADIUS);
|
return dist as f32 * (2. * INNER_RADIUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tile_count(radius: i32) -> i32 {
|
pub fn get_tile_count(radius: u32) -> u32 {
|
||||||
return 1 + 3 * (radius + 1) * radius;
|
return 1 + 3 * (radius + 1) * radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ pub mod tile_manager;
|
|||||||
pub mod tile_mapper;
|
pub mod tile_mapper;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
use crate::hex_utils::{tile_to_world_distance, HexCoord, INNER_RADIUS, OUTER_RADIUS};
|
use crate::hex_utils::{tile_to_world_distance, HexCoord, INNER_RADIUS, OUTER_RADIUS, SHORT_DIAGONAL};
|
||||||
use bevy::math::{IVec2, UVec2, Vec2, Vec3};
|
use bevy::math::{IVec2, UVec2, Vec2, Vec3};
|
||||||
use bevy::prelude::Resource;
|
use bevy::prelude::Resource;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
@@ -77,6 +77,9 @@ pub mod prelude {
|
|||||||
|
|
||||||
impl Chunk {
|
impl Chunk {
|
||||||
pub const SIZE: usize = 64;
|
pub const SIZE: usize = 64;
|
||||||
|
pub const WORLD_WIDTH: f32 = Chunk::SIZE as f32 * SHORT_DIAGONAL;
|
||||||
|
pub const WORLD_HEIGHT: f32 = Chunk::SIZE as f32 * 1.5;
|
||||||
|
pub const WORLD_SIZE: Vec2 = Vec2::new(Chunk::WORLD_WIDTH, Chunk::WORLD_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
@@ -111,6 +114,10 @@ pub mod prelude {
|
|||||||
return chunk.heights[pos.to_chunk_local_index()];
|
return chunk.heights[pos.to_chunk_local_index()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_in_bounds(&self, pos: &HexCoord) -> bool {
|
||||||
|
return pos.is_in_bounds(self.height * Chunk::SIZE, self.width * Chunk::SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_moisture(&self, pos: &HexCoord) -> f32 {
|
pub fn get_moisture(&self, pos: &HexCoord) -> f32 {
|
||||||
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
|
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
|
||||||
return chunk.moisture[pos.to_chunk_local_index()];
|
return chunk.moisture[pos.to_chunk_local_index()];
|
||||||
@@ -122,20 +129,20 @@ pub mod prelude {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_center(&self) -> Vec3 {
|
pub fn get_center(&self) -> Vec3 {
|
||||||
let w = self.width * Chunk::SIZE;
|
let w = self.get_world_width();
|
||||||
let h = self.height * Chunk::SIZE;
|
let h = self.get_world_height();
|
||||||
return Vec3::new(
|
return Vec3::new(w / 2., self.sea_level, h / 2.);
|
||||||
tile_to_world_distance(w as i32 / 2),
|
|
||||||
self.sea_level,
|
|
||||||
tile_to_world_distance(h as i32 / 2),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_world_width(&self) -> f32 {
|
pub fn get_world_width(&self) -> f32 {
|
||||||
return tile_to_world_distance((self.width * Chunk::SIZE) as i32);
|
return (self.width * Chunk::SIZE) as f32 * SHORT_DIAGONAL;
|
||||||
}
|
}
|
||||||
pub fn get_world_height(&self) -> f32 {
|
pub fn get_world_height(&self) -> f32 {
|
||||||
return tile_to_world_distance((self.height * Chunk::SIZE) as i32);
|
return (self.height * Chunk::SIZE) as f32 * 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_world_size(&self) -> Vec2 {
|
||||||
|
return Vec2::new(self.get_world_width(), self.get_world_height());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub const ATTRIBUTE_PACKED_VERTEX_DATA: MeshVertexAttribute =
|
pub const ATTRIBUTE_PACKED_VERTEX_DATA: MeshVertexAttribute =
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ fn setup(mut commands: Commands, mut msaa: ResMut<Msaa>) {
|
|||||||
PhosCamera::default(),
|
PhosCamera::default(),
|
||||||
PhosCameraTargets::default(),
|
PhosCameraTargets::default(),
|
||||||
))
|
))
|
||||||
.insert(ScreenSpaceAmbientOcclusionBundle::default())
|
|
||||||
.insert(TemporalAntiAliasBundle::default());
|
.insert(TemporalAntiAliasBundle::default());
|
||||||
|
|
||||||
*msaa = Msaa::Off;
|
*msaa = Msaa::Off;
|
||||||
@@ -147,12 +146,13 @@ fn rts_camera_system(
|
|||||||
cam_move.z = -1.;
|
cam_move.z = -1.;
|
||||||
}
|
}
|
||||||
|
|
||||||
if key.pressed(KeyCode::ShiftLeft) {
|
let move_speed = if key.pressed(KeyCode::ShiftLeft) {
|
||||||
cam_move = cam_move.normalize_or_zero() * cam_cfg.speed * time.delta_seconds() * 2.;
|
cam_cfg.speed * 2.
|
||||||
} else {
|
} else {
|
||||||
cam_move = cam_move.normalize_or_zero() * cam_cfg.speed * time.delta_seconds();
|
cam_cfg.speed
|
||||||
}
|
};
|
||||||
|
|
||||||
|
cam_move = cam_move.normalize_or_zero() * move_speed * time.delta_seconds();
|
||||||
cam_pos -= cam_move;
|
cam_pos -= cam_move;
|
||||||
|
|
||||||
let mut scroll = 0.0;
|
let mut scroll = 0.0;
|
||||||
@@ -163,22 +163,13 @@ fn rts_camera_system(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ground_height = sample_ground(cam.translation, &heightmap);
|
||||||
|
|
||||||
cam_targets.height -= scroll;
|
cam_targets.height -= scroll;
|
||||||
if cam_targets.height > cam_cfg.max_height {
|
if cam_targets.height > cam_cfg.max_height {
|
||||||
cam_targets.height = cam_cfg.max_height;
|
cam_targets.height = cam_cfg.max_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
let tile_under = HexCoord::from_world_pos(cam.translation);
|
|
||||||
let neighbors = heightmap.get_neighbors(&tile_under);
|
|
||||||
let mut ground_height = heightmap.sample_height(&tile_under);
|
|
||||||
for n in neighbors {
|
|
||||||
if let Some(h) = n {
|
|
||||||
if h > ground_height {
|
|
||||||
ground_height = h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let min_height = ground_height + cam_cfg.min_height;
|
let min_height = ground_height + cam_cfg.min_height;
|
||||||
|
|
||||||
if min_height != cam_targets.last_height {
|
if min_height != cam_targets.last_height {
|
||||||
@@ -218,4 +209,35 @@ fn rts_camera_system(
|
|||||||
cam.translation = cam_pos;
|
cam.translation = cam_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn limit_camera_bounds(mut cam_query: Query<(&mut Transform, &CameraBounds)>) {}
|
fn sample_ground(pos: Vec3, heightmap: &Map) -> f32 {
|
||||||
|
let tile_under = HexCoord::from_world_pos(pos);
|
||||||
|
let neighbors = heightmap.get_neighbors(&tile_under);
|
||||||
|
let mut ground_height = if heightmap.is_in_bounds(&tile_under) {
|
||||||
|
heightmap.sample_height(&tile_under)
|
||||||
|
} else {
|
||||||
|
heightmap.sea_level
|
||||||
|
};
|
||||||
|
|
||||||
|
for n in neighbors {
|
||||||
|
if let Some(h) = n {
|
||||||
|
if h > ground_height {
|
||||||
|
ground_height = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ground_height < heightmap.sea_level {
|
||||||
|
ground_height = heightmap.sea_level;
|
||||||
|
}
|
||||||
|
return ground_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn limit_camera_bounds(mut cam_query: Query<(&mut Transform, &CameraBounds)>) {
|
||||||
|
let (mut tranform, bounds) = cam_query.single_mut();
|
||||||
|
|
||||||
|
let mut pos = tranform.translation;
|
||||||
|
|
||||||
|
pos.x = pos.x.clamp(bounds.min.x, bounds.max.x);
|
||||||
|
pos.z = pos.z.clamp(bounds.min.y, bounds.max.y);
|
||||||
|
|
||||||
|
tranform.translation = pos;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use world_generation::{
|
||||||
|
hex_utils::{tile_to_world_distance, SHORT_DIAGONAL},
|
||||||
|
prelude::Chunk,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Component, Reflect)]
|
#[derive(Component, Reflect)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
@@ -15,8 +19,8 @@ impl Default for PhosCamera {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
min_height: 10.,
|
min_height: 10.,
|
||||||
max_height: 100.,
|
max_height: 120.,
|
||||||
speed: 20.,
|
speed: 30.,
|
||||||
zoom_speed: 0.3,
|
zoom_speed: 0.3,
|
||||||
min_angle: (20. as f32).to_radians(),
|
min_angle: (20. as f32).to_radians(),
|
||||||
max_angle: 1.,
|
max_angle: 1.,
|
||||||
@@ -24,14 +28,27 @@ impl Default for PhosCamera {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
#[derive(Component)]
|
||||||
pub struct PhosCameraTargets {
|
pub struct PhosCameraTargets {
|
||||||
pub height: f32,
|
pub height: f32,
|
||||||
|
pub forward: Vec3,
|
||||||
pub last_height: f32,
|
pub last_height: f32,
|
||||||
pub anim_time: f32,
|
pub anim_time: f32,
|
||||||
pub rotate_time: f32,
|
pub rotate_time: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for PhosCameraTargets {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
height: Default::default(),
|
||||||
|
forward: Vec3::Z,
|
||||||
|
last_height: Default::default(),
|
||||||
|
anim_time: Default::default(),
|
||||||
|
rotate_time: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
#[derive(Component, Default)]
|
||||||
pub struct CameraBounds {
|
pub struct CameraBounds {
|
||||||
pub min: Vec2,
|
pub min: Vec2,
|
||||||
@@ -40,9 +57,13 @@ pub struct CameraBounds {
|
|||||||
|
|
||||||
impl CameraBounds {
|
impl CameraBounds {
|
||||||
pub fn from_size(size: UVec2) -> Self {
|
pub fn from_size(size: UVec2) -> Self {
|
||||||
|
let padding = Chunk::WORLD_SIZE;
|
||||||
return Self {
|
return Self {
|
||||||
min: Vec2::ZERO,
|
min: Vec2::ZERO - padding,
|
||||||
max: size.as_vec2(),
|
max: Vec2::new(
|
||||||
|
(size.x as usize * Chunk::SIZE) as f32 * SHORT_DIAGONAL,
|
||||||
|
(size.y * Chunk::SIZE as u32) as f32 * 1.5,
|
||||||
|
) + padding,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use world_generation::{
|
|||||||
biome_painter::*,
|
biome_painter::*,
|
||||||
chunk_colliders::generate_chunk_collider,
|
chunk_colliders::generate_chunk_collider,
|
||||||
heightmap::generate_heightmap,
|
heightmap::generate_heightmap,
|
||||||
hex_utils::{offset_to_world, tile_to_world_distance},
|
hex_utils::{offset_to_world, SHORT_DIAGONAL},
|
||||||
mesh_generator::generate_chunk_mesh,
|
mesh_generator::generate_chunk_mesh,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
tile_manager::*,
|
tile_manager::*,
|
||||||
@@ -39,11 +39,23 @@ impl Plugin for MapInitPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_textures(mut commands: Commands, asset_server: Res<AssetServer>) {
|
fn load_textures(
|
||||||
|
mut commands: Commands,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
|
mut standard_materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
) {
|
||||||
let main_tex = asset_server.load("textures/world/stack.png");
|
let main_tex = asset_server.load("textures/world/stack.png");
|
||||||
|
|
||||||
|
let water_material = standard_materials.add(StandardMaterial {
|
||||||
|
base_color: Color::AQUAMARINE.with_a(0.5),
|
||||||
|
alpha_mode: AlphaMode::Blend,
|
||||||
|
..default()
|
||||||
|
});
|
||||||
commands.insert_resource(ChunkAtlas {
|
commands.insert_resource(ChunkAtlas {
|
||||||
handle: main_tex.clone(),
|
handle: main_tex.clone(),
|
||||||
is_loaded: false,
|
is_loaded: false,
|
||||||
|
chunk_material_handle: Handle::default(),
|
||||||
|
water_material: water_material,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
@@ -62,6 +74,7 @@ fn finalize_texture(
|
|||||||
painter: Res<Painter>,
|
painter: Res<Painter>,
|
||||||
painter_load: Res<BiomePainterLoadState>,
|
painter_load: Res<BiomePainterLoadState>,
|
||||||
tile_load: Res<TileAssetLoadState>,
|
tile_load: Res<TileAssetLoadState>,
|
||||||
|
mut chunk_materials: ResMut<Assets<ExtendedMaterial<StandardMaterial, ChunkMaterial>>>,
|
||||||
mapper_load: Res<TileMapperLoadState>,
|
mapper_load: Res<TileMapperLoadState>,
|
||||||
) {
|
) {
|
||||||
if atlas.is_loaded {
|
if atlas.is_loaded {
|
||||||
@@ -84,6 +97,13 @@ fn finalize_texture(
|
|||||||
image.reinterpret_stacked_2d_as_array(array_layers);
|
image.reinterpret_stacked_2d_as_array(array_layers);
|
||||||
|
|
||||||
atlas.is_loaded = true;
|
atlas.is_loaded = true;
|
||||||
|
let chunk_material = chunk_materials.add(ExtendedMaterial {
|
||||||
|
base: StandardMaterial::default(),
|
||||||
|
extension: ChunkMaterial {
|
||||||
|
array_texture: atlas.handle.clone(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
atlas.chunk_material_handle = chunk_material;
|
||||||
map.ready = true;
|
map.ready = true;
|
||||||
map.regenerate = true;
|
map.regenerate = true;
|
||||||
}
|
}
|
||||||
@@ -160,25 +180,18 @@ fn create_map(mut commands: Commands, mut cam: Query<(&mut Transform, Entity), W
|
|||||||
};
|
};
|
||||||
let heightmap = generate_heightmap(&config, 4);
|
let heightmap = generate_heightmap(&config, 4);
|
||||||
|
|
||||||
commands.insert_resource(heightmap);
|
|
||||||
|
|
||||||
let (mut cam_t, cam_entity) = cam.single_mut();
|
let (mut cam_t, cam_entity) = cam.single_mut();
|
||||||
cam_t.translation = Vec3::new(
|
cam_t.translation = heightmap.get_center();
|
||||||
tile_to_world_distance((config.size.x as i32 * Chunk::SIZE as i32) / 2),
|
|
||||||
cam_t.translation.y,
|
|
||||||
tile_to_world_distance((config.size.y as i32 * Chunk::SIZE as i32) / 2),
|
|
||||||
);
|
|
||||||
|
|
||||||
commands.entity(cam_entity).insert(CameraBounds::from_size(config.size));
|
commands.entity(cam_entity).insert(CameraBounds::from_size(config.size));
|
||||||
|
|
||||||
|
commands.insert_resource(heightmap);
|
||||||
commands.insert_resource(config);
|
commands.insert_resource(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_map(
|
fn spawn_map(
|
||||||
heightmap: Res<Map>,
|
heightmap: Res<Map>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut chunk_materials: ResMut<Assets<ExtendedMaterial<StandardMaterial, ChunkMaterial>>>,
|
|
||||||
mut standard_materials: ResMut<Assets<StandardMaterial>>,
|
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
atlas: Res<ChunkAtlas>,
|
atlas: Res<ChunkAtlas>,
|
||||||
mut map: ResMut<PhosMap>,
|
mut map: ResMut<PhosMap>,
|
||||||
@@ -192,12 +205,6 @@ fn spawn_map(
|
|||||||
}
|
}
|
||||||
let b_painter = biome_painters.get(painter.0.clone());
|
let b_painter = biome_painters.get(painter.0.clone());
|
||||||
map.regenerate = false;
|
map.regenerate = false;
|
||||||
let chunk_material = chunk_materials.add(ExtendedMaterial {
|
|
||||||
base: StandardMaterial::default(),
|
|
||||||
extension: ChunkMaterial {
|
|
||||||
array_texture: atlas.handle.clone(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let cur_painter = b_painter.unwrap();
|
let cur_painter = b_painter.unwrap();
|
||||||
|
|
||||||
@@ -219,15 +226,15 @@ fn spawn_map(
|
|||||||
commands.spawn((
|
commands.spawn((
|
||||||
MaterialMeshBundle {
|
MaterialMeshBundle {
|
||||||
mesh: meshes.add(mesh),
|
mesh: meshes.add(mesh),
|
||||||
material: chunk_material.clone(),
|
material: atlas.chunk_material_handle.clone(),
|
||||||
transform: Transform::from_translation(pos),
|
transform: Transform::from_translation(pos),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
PhosChunk,
|
PhosChunk,
|
||||||
RenderDistanceVisibility::default().with_offset(Vec3::new(
|
RenderDistanceVisibility::default().with_offset(Vec3::new(
|
||||||
tile_to_world_distance(Chunk::SIZE as i32 / 2),
|
(Chunk::SIZE / 2) as f32 * SHORT_DIAGONAL,
|
||||||
0.,
|
0.,
|
||||||
tile_to_world_distance(Chunk::SIZE as i32 / 2),
|
(Chunk::SIZE / 2) as f32 * 1.5,
|
||||||
)),
|
)),
|
||||||
Collider::trimesh_with_flags(col_verts, col_indicies, TriMeshFlags::MERGE_DUPLICATE_VERTICES),
|
Collider::trimesh_with_flags(col_verts, col_indicies, TriMeshFlags::MERGE_DUPLICATE_VERTICES),
|
||||||
));
|
));
|
||||||
@@ -240,11 +247,7 @@ fn spawn_map(
|
|||||||
.mesh()
|
.mesh()
|
||||||
.size(heightmap.get_world_width(), heightmap.get_world_height()),
|
.size(heightmap.get_world_width(), heightmap.get_world_height()),
|
||||||
),
|
),
|
||||||
material: standard_materials.add(StandardMaterial {
|
material: atlas.water_material.clone(),
|
||||||
base_color: Color::AQUAMARINE.with_a(0.5),
|
|
||||||
alpha_mode: AlphaMode::Blend,
|
|
||||||
..default()
|
|
||||||
}),
|
|
||||||
..default()
|
..default()
|
||||||
},));
|
},));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
use bevy::asset::Handle;
|
use bevy::asset::Handle;
|
||||||
|
use bevy::pbr::ExtendedMaterial;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::prelude::{Component, Image, Resource};
|
use bevy::prelude::{Component, Image, Resource};
|
||||||
use bevy::reflect::Reflect;
|
use bevy::reflect::Reflect;
|
||||||
|
|
||||||
|
use crate::shader_extensions::chunk_material::ChunkMaterial;
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct ChunkAtlas {
|
pub struct ChunkAtlas {
|
||||||
pub handle: Handle<Image>,
|
pub handle: Handle<Image>,
|
||||||
|
pub chunk_material_handle: Handle<ExtendedMaterial<StandardMaterial, ChunkMaterial>>,
|
||||||
|
pub water_material: Handle<StandardMaterial>,
|
||||||
pub is_loaded: bool,
|
pub is_loaded: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user