feat: simulation boundaries

feat/simulation
hheik 2022-12-27 16:07:29 +02:00
parent 6c1b68d1fd
commit c9d7e17a60
4 changed files with 78 additions and 30 deletions

View File

@ -77,7 +77,6 @@ fn camera_system(
None => return, None => return,
}; };
// let offset = Vec3::new(WORLD_WIDTH as f32 / 2.0, 0.0, 999.9);
for (mut camera_transform, projection) in camera_query.iter_mut() { for (mut camera_transform, projection) in camera_query.iter_mut() {
let left_limit = 0.0; let left_limit = 0.0;
let right_limit = WORLD_WIDTH as f32; let right_limit = WORLD_WIDTH as f32;
@ -101,6 +100,7 @@ fn camera_system(
); );
} }
} }
// horizontal boundaries
let camera_x = camera_transform.translation.x; let camera_x = camera_transform.translation.x;
camera_transform.translation += Vec3::new( camera_transform.translation += Vec3::new(
(left_limit - (projection.left * projection.scale + camera_x)).max(0.0), (left_limit - (projection.left * projection.scale + camera_x)).max(0.0),

View File

@ -7,7 +7,7 @@ pub struct TerrainDebugPlugin;
impl Plugin for TerrainDebugPlugin { impl Plugin for TerrainDebugPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.insert_resource(TerrainBrush2D::default()) app.insert_resource(TerrainBrush2D::default())
// .add_system_to_stage(TerrainStages::EventHandler, dirty_rect_visualizer) .add_system_to_stage(TerrainStages::EventHandler, dirty_rect_visualizer)
.add_system(debug_painter); .add_system(debug_painter);
} }
} }

View File

@ -17,7 +17,10 @@ pub use terrain_gen2d::*;
pub use texel2d::*; pub use texel2d::*;
pub use texel_behaviour2d::*; pub use texel_behaviour2d::*;
use crate::util::{frame_counter::FrameCounter, math::*, Vector2I}; use crate::{
game::camera::WORLD_WIDTH,
util::{frame_counter::FrameCounter, math::*, Vector2I},
};
pub struct Terrain2DPlugin; pub struct Terrain2DPlugin;
@ -42,7 +45,7 @@ impl Plugin for Terrain2DPlugin {
); );
app.register_type::<TerrainChunk2D>() app.register_type::<TerrainChunk2D>()
.insert_resource(Terrain2D::new()) .insert_resource(Terrain2D::new(Some(WORLD_WIDTH * 2), Some(0), Some(0), Some(WORLD_WIDTH)))
.add_event::<TerrainEvent2D>() .add_event::<TerrainEvent2D>()
.add_system_to_stage(TerrainStages::Simulation, terrain_simulation) .add_system_to_stage(TerrainStages::Simulation, terrain_simulation)
.add_system_to_stage(TerrainStages::EventHandler, emit_terrain_events) .add_system_to_stage(TerrainStages::EventHandler, emit_terrain_events)
@ -191,13 +194,26 @@ pub enum TerrainEvent2D {
pub struct Terrain2D { pub struct Terrain2D {
chunk_map: HashMap<Chunk2DIndex, Chunk2D>, chunk_map: HashMap<Chunk2DIndex, Chunk2D>,
events: Vec<TerrainEvent2D>, events: Vec<TerrainEvent2D>,
pub top_boundary: Option<i32>,
pub bottom_boundary: Option<i32>,
pub left_boundary: Option<i32>,
pub right_boundary: Option<i32>,
} }
impl Terrain2D { impl Terrain2D {
pub fn new() -> Terrain2D { pub fn new(
top_boundary: Option<i32>,
bottom_boundary: Option<i32>,
left_boundary: Option<i32>,
right_boundary: Option<i32>,
) -> Terrain2D {
Terrain2D { Terrain2D {
chunk_map: HashMap::new(), chunk_map: HashMap::new(),
events: Vec::new(), events: Vec::new(),
top_boundary,
bottom_boundary,
left_boundary,
right_boundary,
} }
} }
@ -256,6 +272,30 @@ impl Terrain2D {
} }
} }
pub fn is_within_boundaries(&self, global: &Vector2I) -> bool {
if let Some(top) = self.top_boundary {
if global.y > top {
return false;
}
}
if let Some(bottom) = self.bottom_boundary {
if global.y < bottom {
return false;
}
}
if let Some(left) = self.left_boundary {
if global.x < left {
return false;
}
}
if let Some(right) = self.right_boundary {
if global.x > right {
return false;
}
}
return true;
}
pub fn get_texel(&self, global: &Vector2I) -> Option<Texel2D> { pub fn get_texel(&self, global: &Vector2I) -> Option<Texel2D> {
self.global_to_chunk(global) self.global_to_chunk(global)
.map_or(None, |chunk| chunk.get_texel(&global_to_local(global))) .map_or(None, |chunk| chunk.get_texel(&global_to_local(global)))
@ -268,11 +308,18 @@ impl Terrain2D {
let texel = self.get_texel(global); let texel = self.get_texel(global);
( (
texel, texel,
texel.map_or(None, |t| TexelBehaviour2D::from_id(&t.id)), if self.is_within_boundaries(global) {
texel.map_or(None, |t| TexelBehaviour2D::from_id(&t.id))
} else {
Some(TexelBehaviour2D::OUT_OF_BOUNDS)
},
) )
} }
pub fn set_texel(&mut self, global: &Vector2I, id: TexelID, simulation_frame: Option<u8>) { pub fn set_texel(&mut self, global: &Vector2I, id: TexelID, simulation_frame: Option<u8>) {
if !self.is_within_boundaries(global) {
return
}
let index = global_to_chunk_index(global); let index = global_to_chunk_index(global);
let changed = match self.index_to_chunk_mut(&index) { let changed = match self.index_to_chunk_mut(&index) {
Some(chunk) => chunk.set_texel(&global_to_local(global), id, simulation_frame), Some(chunk) => chunk.set_texel(&global_to_local(global), id, simulation_frame),

View File

@ -3,7 +3,7 @@ use crate::util::Vector2I;
use super::TexelID; use super::TexelID;
use bevy::prelude::*; use bevy::prelude::*;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use std::collections::HashMap; use std::{collections::HashMap, borrow::Cow};
lazy_static! { lazy_static! {
static ref ID_MAP: HashMap<TexelID, TexelBehaviour2D> = { static ref ID_MAP: HashMap<TexelID, TexelBehaviour2D> = {
@ -12,7 +12,7 @@ lazy_static! {
result.insert( result.insert(
1, 1,
TexelBehaviour2D { TexelBehaviour2D {
name: String::from("loose sand"), name: Cow::Borrowed("loose sand"),
color: Color::rgb(0.61, 0.49, 0.38), color: Color::rgb(0.61, 0.49, 0.38),
gravity: Some(TexelGravity::Down(100)), gravity: Some(TexelGravity::Down(100)),
has_collision: true, has_collision: true,
@ -23,7 +23,7 @@ lazy_static! {
result.insert( result.insert(
2, 2,
TexelBehaviour2D { TexelBehaviour2D {
name: String::from("loose stone"), name: Cow::Borrowed("loose stone"),
color: Color::rgb(0.21, 0.19, 0.17), color: Color::rgb(0.21, 0.19, 0.17),
gravity: Some(TexelGravity::Down(100)), gravity: Some(TexelGravity::Down(100)),
has_collision: true, has_collision: true,
@ -34,7 +34,7 @@ lazy_static! {
result.insert( result.insert(
3, 3,
TexelBehaviour2D { TexelBehaviour2D {
name: String::from("loose sturdy stone"), name: Cow::Borrowed("loose sturdy stone"),
color: Color::rgb(0.11, 0.11, 0.11), color: Color::rgb(0.11, 0.11, 0.11),
gravity: Some(TexelGravity::Down(100)), gravity: Some(TexelGravity::Down(100)),
has_collision: true, has_collision: true,
@ -45,7 +45,7 @@ lazy_static! {
result.insert( result.insert(
4, 4,
TexelBehaviour2D { TexelBehaviour2D {
name: String::from("water"), name: Cow::Borrowed("water"),
color: Color::rgba(0.0, 0.0, 1.0, 0.5), color: Color::rgba(0.0, 0.0, 1.0, 0.5),
form: TexelForm::Liquid, form: TexelForm::Liquid,
gravity: Some(TexelGravity::Down(10)), gravity: Some(TexelGravity::Down(10)),
@ -56,7 +56,7 @@ lazy_static! {
result.insert( result.insert(
5, 5,
TexelBehaviour2D { TexelBehaviour2D {
name: String::from("oil"), name: Cow::Borrowed("oil"),
color: Color::rgba(0.0, 1.0, 0.0, 0.5), color: Color::rgba(0.0, 1.0, 0.0, 0.5),
form: TexelForm::Gas, form: TexelForm::Gas,
gravity: Some(TexelGravity::Up(50)), gravity: Some(TexelGravity::Up(50)),
@ -67,7 +67,7 @@ lazy_static! {
result.insert( result.insert(
6, 6,
TexelBehaviour2D { TexelBehaviour2D {
name: String::from("gas"), name: Cow::Borrowed("gas"),
color: Color::rgba(0.5, 0.5, 0.25, 0.5), color: Color::rgba(0.5, 0.5, 0.25, 0.5),
form: TexelForm::Liquid, form: TexelForm::Liquid,
gravity: Some(TexelGravity::Down(5)), gravity: Some(TexelGravity::Down(5)),
@ -78,7 +78,7 @@ lazy_static! {
result.insert( result.insert(
11, 11,
TexelBehaviour2D { TexelBehaviour2D {
name: String::from("sand"), name: Cow::Borrowed("sand"),
color: Color::rgb(0.61, 0.49, 0.38), color: Color::rgb(0.61, 0.49, 0.38),
has_collision: true, has_collision: true,
..default() ..default()
@ -88,7 +88,7 @@ lazy_static! {
result.insert( result.insert(
12, 12,
TexelBehaviour2D { TexelBehaviour2D {
name: String::from("stone"), name: Cow::Borrowed("stone"),
color: Color::rgb(0.21, 0.19, 0.17), color: Color::rgb(0.21, 0.19, 0.17),
has_collision: true, has_collision: true,
..default() ..default()
@ -98,22 +98,13 @@ lazy_static! {
result.insert( result.insert(
13, 13,
TexelBehaviour2D { TexelBehaviour2D {
name: String::from("sturdy stone"), name: Cow::Borrowed("sturdy stone"),
color: Color::rgb(0.11, 0.11, 0.11), color: Color::rgb(0.11, 0.11, 0.11),
has_collision: true, has_collision: true,
..default() ..default()
}, },
); );
result.insert(
u8::MAX,
TexelBehaviour2D {
color: Color::BLACK,
has_collision: true,
..default()
},
);
result result
}; };
} }
@ -146,7 +137,7 @@ impl From<TexelGravity> for Vector2I {
#[derive(Clone)] #[derive(Clone)]
pub struct TexelBehaviour2D { pub struct TexelBehaviour2D {
pub name: String, pub name: Cow<'static, str>,
pub color: Color, pub color: Color,
pub form: TexelForm, pub form: TexelForm,
pub has_collision: bool, pub has_collision: bool,
@ -157,7 +148,7 @@ pub struct TexelBehaviour2D {
impl Default for TexelBehaviour2D { impl Default for TexelBehaviour2D {
fn default() -> Self { fn default() -> Self {
TexelBehaviour2D { TexelBehaviour2D {
name: "Unnamed material".to_string(), name: Cow::Borrowed("Unnamed material"),
color: Color::PINK, color: Color::PINK,
form: TexelForm::Solid, form: TexelForm::Solid,
has_collision: false, has_collision: false,
@ -169,6 +160,15 @@ impl Default for TexelBehaviour2D {
// TODO: change form-based functions like is_solid to behaviour based (e.g. has_collision) // TODO: change form-based functions like is_solid to behaviour based (e.g. has_collision)
impl TexelBehaviour2D { impl TexelBehaviour2D {
pub const OUT_OF_BOUNDS: Self = TexelBehaviour2D {
name: Cow::Borrowed(":)"),
color: Color::BLACK,
has_collision: true,
form: TexelForm::Solid,
gravity: None,
toughness: None,
};
pub fn from_id(id: &TexelID) -> Option<Self> { pub fn from_id(id: &TexelID) -> Option<Self> {
ID_MAP.get(id).cloned() ID_MAP.get(id).cloned()
} }
@ -181,12 +181,12 @@ impl TexelBehaviour2D {
ID_MAP.get(id).map_or(false, |b| b.has_collision) ID_MAP.get(id).map_or(false, |b| b.has_collision)
} }
/// Can this type of material displace another?
pub fn can_displace(from: &TexelBehaviour2D, to: &Option<TexelBehaviour2D>) -> bool { pub fn can_displace(from: &TexelBehaviour2D, to: &Option<TexelBehaviour2D>) -> bool {
let to = if let Some(to) = to { to } else { return true }; let to = if let Some(to) = to { to } else { return true };
match (from.form, to.form) { match (from.form, to.form) {
(_, TexelForm::Solid) => false, (_, to_form) => {
(_, _) => {
if let (Some(from_grav), Some(to_grav)) = (from.gravity, to.gravity) { if let (Some(from_grav), Some(to_grav)) = (from.gravity, to.gravity) {
match (from_grav, to_grav) { match (from_grav, to_grav) {
(TexelGravity::Down(from_grav), TexelGravity::Down(to_grav)) => { (TexelGravity::Down(from_grav), TexelGravity::Down(to_grav)) => {
@ -198,7 +198,8 @@ impl TexelBehaviour2D {
(_, _) => true, (_, _) => true,
} }
} else { } else {
true // Solids can also be displaced, but only if the other material has gravity
to_form != TexelForm::Solid
} }
} }
} }