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

View File

@ -7,7 +7,7 @@ pub struct TerrainDebugPlugin;
impl Plugin for TerrainDebugPlugin {
fn build(&self, app: &mut App) {
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);
}
}

View File

@ -17,7 +17,10 @@ pub use terrain_gen2d::*;
pub use texel2d::*;
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;
@ -42,7 +45,7 @@ impl Plugin for Terrain2DPlugin {
);
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_system_to_stage(TerrainStages::Simulation, terrain_simulation)
.add_system_to_stage(TerrainStages::EventHandler, emit_terrain_events)
@ -191,13 +194,26 @@ pub enum TerrainEvent2D {
pub struct Terrain2D {
chunk_map: HashMap<Chunk2DIndex, Chunk2D>,
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 {
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 {
chunk_map: HashMap::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> {
self.global_to_chunk(global)
.map_or(None, |chunk| chunk.get_texel(&global_to_local(global)))
@ -268,11 +308,18 @@ impl Terrain2D {
let texel = self.get_texel(global);
(
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>) {
if !self.is_within_boundaries(global) {
return
}
let index = global_to_chunk_index(global);
let changed = match self.index_to_chunk_mut(&index) {
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 bevy::prelude::*;
use lazy_static::lazy_static;
use std::collections::HashMap;
use std::{collections::HashMap, borrow::Cow};
lazy_static! {
static ref ID_MAP: HashMap<TexelID, TexelBehaviour2D> = {
@ -12,7 +12,7 @@ lazy_static! {
result.insert(
1,
TexelBehaviour2D {
name: String::from("loose sand"),
name: Cow::Borrowed("loose sand"),
color: Color::rgb(0.61, 0.49, 0.38),
gravity: Some(TexelGravity::Down(100)),
has_collision: true,
@ -23,7 +23,7 @@ lazy_static! {
result.insert(
2,
TexelBehaviour2D {
name: String::from("loose stone"),
name: Cow::Borrowed("loose stone"),
color: Color::rgb(0.21, 0.19, 0.17),
gravity: Some(TexelGravity::Down(100)),
has_collision: true,
@ -34,7 +34,7 @@ lazy_static! {
result.insert(
3,
TexelBehaviour2D {
name: String::from("loose sturdy stone"),
name: Cow::Borrowed("loose sturdy stone"),
color: Color::rgb(0.11, 0.11, 0.11),
gravity: Some(TexelGravity::Down(100)),
has_collision: true,
@ -45,7 +45,7 @@ lazy_static! {
result.insert(
4,
TexelBehaviour2D {
name: String::from("water"),
name: Cow::Borrowed("water"),
color: Color::rgba(0.0, 0.0, 1.0, 0.5),
form: TexelForm::Liquid,
gravity: Some(TexelGravity::Down(10)),
@ -56,7 +56,7 @@ lazy_static! {
result.insert(
5,
TexelBehaviour2D {
name: String::from("oil"),
name: Cow::Borrowed("oil"),
color: Color::rgba(0.0, 1.0, 0.0, 0.5),
form: TexelForm::Gas,
gravity: Some(TexelGravity::Up(50)),
@ -67,7 +67,7 @@ lazy_static! {
result.insert(
6,
TexelBehaviour2D {
name: String::from("gas"),
name: Cow::Borrowed("gas"),
color: Color::rgba(0.5, 0.5, 0.25, 0.5),
form: TexelForm::Liquid,
gravity: Some(TexelGravity::Down(5)),
@ -78,7 +78,7 @@ lazy_static! {
result.insert(
11,
TexelBehaviour2D {
name: String::from("sand"),
name: Cow::Borrowed("sand"),
color: Color::rgb(0.61, 0.49, 0.38),
has_collision: true,
..default()
@ -88,7 +88,7 @@ lazy_static! {
result.insert(
12,
TexelBehaviour2D {
name: String::from("stone"),
name: Cow::Borrowed("stone"),
color: Color::rgb(0.21, 0.19, 0.17),
has_collision: true,
..default()
@ -98,22 +98,13 @@ lazy_static! {
result.insert(
13,
TexelBehaviour2D {
name: String::from("sturdy stone"),
name: Cow::Borrowed("sturdy stone"),
color: Color::rgb(0.11, 0.11, 0.11),
has_collision: true,
..default()
},
);
result.insert(
u8::MAX,
TexelBehaviour2D {
color: Color::BLACK,
has_collision: true,
..default()
},
);
result
};
}
@ -146,7 +137,7 @@ impl From<TexelGravity> for Vector2I {
#[derive(Clone)]
pub struct TexelBehaviour2D {
pub name: String,
pub name: Cow<'static, str>,
pub color: Color,
pub form: TexelForm,
pub has_collision: bool,
@ -157,7 +148,7 @@ pub struct TexelBehaviour2D {
impl Default for TexelBehaviour2D {
fn default() -> Self {
TexelBehaviour2D {
name: "Unnamed material".to_string(),
name: Cow::Borrowed("Unnamed material"),
color: Color::PINK,
form: TexelForm::Solid,
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)
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> {
ID_MAP.get(id).cloned()
}
@ -181,12 +181,12 @@ impl TexelBehaviour2D {
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 {
let to = if let Some(to) = to { to } else { return true };
match (from.form, to.form) {
(_, TexelForm::Solid) => false,
(_, _) => {
(_, to_form) => {
if let (Some(from_grav), Some(to_grav)) = (from.gravity, to.gravity) {
match (from_grav, to_grav) {
(TexelGravity::Down(from_grav), TexelGravity::Down(to_grav)) => {
@ -198,7 +198,8 @@ impl TexelBehaviour2D {
(_, _) => true,
}
} else {
true
// Solids can also be displaced, but only if the other material has gravity
to_form != TexelForm::Solid
}
}
}