From c9d7e17a604e3615cfc0154b6944927449581a55 Mon Sep 17 00:00:00 2001 From: hheik <4469778+hheik@users.noreply.github.com> Date: Tue, 27 Dec 2022 16:07:29 +0200 Subject: [PATCH] feat: simulation boundaries --- src/game/camera.rs | 2 +- src/game/debug/terrain.rs | 2 +- src/terrain2d.rs | 55 +++++++++++++++++++++++++++--- src/terrain2d/texel_behaviour2d.rs | 49 +++++++++++++------------- 4 files changed, 78 insertions(+), 30 deletions(-) diff --git a/src/game/camera.rs b/src/game/camera.rs index cd1df8e..7c4b52b 100644 --- a/src/game/camera.rs +++ b/src/game/camera.rs @@ -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), diff --git a/src/game/debug/terrain.rs b/src/game/debug/terrain.rs index e8d94dc..83ba786 100644 --- a/src/game/debug/terrain.rs +++ b/src/game/debug/terrain.rs @@ -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); } } diff --git a/src/terrain2d.rs b/src/terrain2d.rs index a18e754..144cf12 100644 --- a/src/terrain2d.rs +++ b/src/terrain2d.rs @@ -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::() - .insert_resource(Terrain2D::new()) + .insert_resource(Terrain2D::new(Some(WORLD_WIDTH * 2), Some(0), Some(0), Some(WORLD_WIDTH))) .add_event::() .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, events: Vec, + pub top_boundary: Option, + pub bottom_boundary: Option, + pub left_boundary: Option, + pub right_boundary: Option, } impl Terrain2D { - pub fn new() -> Terrain2D { + pub fn new( + top_boundary: Option, + bottom_boundary: Option, + left_boundary: Option, + right_boundary: Option, + ) -> 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 { 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) { + 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), diff --git a/src/terrain2d/texel_behaviour2d.rs b/src/terrain2d/texel_behaviour2d.rs index acaa1db..7c2be5f 100644 --- a/src/terrain2d/texel_behaviour2d.rs +++ b/src/terrain2d/texel_behaviour2d.rs @@ -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 = { @@ -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 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 { 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) -> 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 } } }