From f1e10be5da0f67c72ea43097a7494bdc5c75d6fe Mon Sep 17 00:00:00 2001
From: Evan Pratten <ewpratten@gmail.com>
Date: Sat, 2 Oct 2021 16:53:50 -0400
Subject: [PATCH] Very basic collisions with the world (janky)

---
 game/assets/levels/level_0/platforms.png | Bin 16762 -> 16797 bytes
 game/src/character/collisions.rs         |  38 +++++++++++++++++++----
 game/src/character/mod.rs                |  14 +++++++--
 game/src/scenes/ingame_scene/mod.rs      |  11 +++++--
 game/src/scenes/ingame_scene/update.rs   |  17 +++++++---
 game/src/scenes/ingame_scene/world.rs    |   4 ++-
 6 files changed, 67 insertions(+), 17 deletions(-)

diff --git a/game/assets/levels/level_0/platforms.png b/game/assets/levels/level_0/platforms.png
index 94fecb2d76389669f2733fd577d1726a54aed51d..cfa8c08f0066bdbff45b98a28e911cefef3cba26 100644
GIT binary patch
delta 407
zcmey>#5lK^al=zaHcRbmduC>Ae$B|Qz}n~O;utbnP)J%X@xEV{00V;rhu#kduBZ!b
zVoMZQ>_Q!!4jC#he6P1zkSUDI_=6*#8Uq;Ao%~r>8^OrH&=7vtPkg@>Sn%Jii!2an
zI5}mrf|)Mk<o#xSSg_k>d8WmTK|gfZh2a_)KIA?B{WY=meW7*ipB|tE4F9fxOtrba
zyIG2biGi)jyU1)plh~GptePB+{-Pfm5A?MBGiOB@z`&rf`J$y7lR`TuQ1D)H<(+w9
z4gbsR<Nd>s6xDUIPu^%fZ}SDqnT%3kl|QEZ{#mt&2}w;2KmX>3#?p+N9~jFZ5tAPn
t*GPo|^}PDD!*(r_dLZ+UH7+fEqHz;dg*4X)_Z|Xi@pScbS?83{1OR~%ey{)l

literal 16762
zcmeAS@N?(olHy`uVBq!ia0y~y;9tPN!2E)P4JdNz3S&6~17l03vvYu_v$H}$QGQxx
zPAUU~#>Co*wjPHAL|XlWmj-Dyl?fD{2$-wW(Pfb(+7+O9g=?+Vj6GlYXPKyI>h(2c
zA3Qk!=&I)K&FlEqH7WdHe)R0wk{3#<_oj<P9jSQu(eB*t=O6CXHe6U?aQ2lHyUAU%
z%O_iAoL$?sFuX-^fjlEiYMNy6q$y4LwReN%ug1<v|M~rI<ld}%Ne&Jw^HSR~h4Tgc
z^KY>|uYIJUeNyYA<;NMG;wp7dc0Kwi{e01Brt>|sW`40LoD!i^w&BvjH7Qv~f{z%6
zUe=61QMIP%-lH|4S!+uD{~hv(i;sL}wKh>@V~47Tz`_M>Mp_#Lm&d9fb((cf*zTX=
zb^VFnis6zyGTbYin&137`2WH8oVACZv`iQAWVox}_t}uCrK~aSZsERu+2xf?Eb|++
z_r6_k)-com((7E^GL|p7%;MK`eQz@Bl{XwzcQ#86=ei`s#roiH&pu6do;yqrP4n~C
z7SFL`ken6zip|1;#jShF-glqh%{#aA@9oR8?(-kKUX<YI=PM127PcgBcNd2LAh=-f
z^2tCE&H|6fVg?3oVGw3ym^DWND9B#o>Fdh=l#5ANRmoGlW+DTF0)wZEV@SoVHwPIR
zfeIQX{9FHy0~Gb6U^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(ScgEv
z&1PoMU;u-{|Lbl6p`&0l1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtt2h
zzzW8?e+&%r*`T!mcs!JNpD#~>g+Zc2_RW6dzbVaL9b(ljdw{D9M!{$ZjE2By2#kin
zXb6mkz-S1JhQMeDP#OXUnq|}=X8b#o$^>NXdl1eJ5;(AWE>r>{4I~$^ynwSIj2;GA
zRFMX+20m1g0~{B?vs?(#6{E&L17kF7V5wp>-M~VEVOZuVxbH?8gERyVY=%_?AO}8R
zo6cF+HQx}(Jm3wj2p(L%Cwtp~hs8j^ntA{KQ+|s%FIjY)6uctO0{2n?Qwf|6VYs2!
z2M($Z;Q9rjE&-!H2pKg78a%@@Z2CBX-rH9;n<4JK5mMvegTKuJW<<IGu>v^JTMrV9
zR;WrCreZWg1V@d5hS3NK8%t1A^?~DbP`ZMF2jvy$CCvgM^n_u6QPOB(q%Y-BW1wL=
z8aA-RHJWZ<Au*b#U?IUUkOjpmD>a4{ugs8YQ=qdxl*yr2pQD{`SagkczF{FT+WCfs
j#PIBV56ck+VmwvDP*={T8N_#|1r))au6{1-oD!M<>%)IG

diff --git a/game/src/character/collisions.rs b/game/src/character/collisions.rs
index 1c571c7..c802015 100644
--- a/game/src/character/collisions.rs
+++ b/game/src/character/collisions.rs
@@ -2,11 +2,17 @@ use std::ops::Mul;
 
 use raylib::math::{Rectangle, Vector2};
 
+use crate::scenes::ingame_scene::world::WORLD_LEVEL_X_OFFSET;
+
 use super::{CharacterState, MainCharacter};
 
 pub const GRAVITY_PPS: f32 = 2.0;
 
-pub fn modify_player_based_on_forces(player: &mut MainCharacter) -> Result<(), ()> {
+pub fn modify_player_based_on_forces(
+    player: &mut MainCharacter,
+    colliders: &Vec<Rectangle>,
+    level_height_offset: f32,
+) -> Result<(), ()> {
     // Modify the player's velocity by the forces
     player.movement_force += player.base_velocity;
     player.velocity = player.movement_force;
@@ -14,7 +20,7 @@ pub fn modify_player_based_on_forces(player: &mut MainCharacter) -> Result<(), (
     // Predict the player's position next frame
     let predicted_player_position = player.position + player.velocity;
 
-    // Calculate a bounding rect around the player
+    // Calculate a bounding rect around the player both now, and one frame in the future
     let player_rect = Rectangle::new(
         predicted_player_position.x - (player.size.x / 2.0),
         predicted_player_position.y - (player.size.x / 2.0),
@@ -25,10 +31,24 @@ pub fn modify_player_based_on_forces(player: &mut MainCharacter) -> Result<(), (
     // Calculate a generic "floor" to always collide with
     let floor_rect = Rectangle::new(f32::MIN, 0.0, f32::MAX, 1.0);
 
+    // Check collision conditions
+    let check_player_colliding_with_floor = || floor_rect.check_collision_recs(&player_rect);
+    let check_player_colliding_with_floor_next_frame =
+        || player_rect.y + player_rect.height > floor_rect.y;
+    let check_player_colliding_with_colliders = || {
+        colliders.iter().any(|rect| {
+            let mut translated_rect = rect.clone();
+            translated_rect.y += level_height_offset;
+            translated_rect.x += WORLD_LEVEL_X_OFFSET;
+            translated_rect.check_collision_recs(&player_rect)
+        })
+    };
+
     // If the player is colliding, only apply the x force
-    if (floor_rect.check_collision_recs(&player_rect)
-        || player_rect.y + player_rect.height > floor_rect.y)
-        && player.velocity.y > 0.0
+    if (check_player_colliding_with_floor()
+        || check_player_colliding_with_floor_next_frame()
+        || check_player_colliding_with_colliders())
+        && player.velocity.y != 0.0
     {
         player.velocity.y = 0.0;
 
@@ -36,11 +56,17 @@ pub fn modify_player_based_on_forces(player: &mut MainCharacter) -> Result<(), (
         if player.current_state == CharacterState::Jumping
             || player.current_state == CharacterState::Dashing
         {
-            player.update_player(Some(CharacterState::Running));
+            player.update_player(
+                Some(CharacterState::Running),
+                colliders,
+                level_height_offset,
+            );
             return Ok(());
         }
     }
 
+    // Check sideways collisions
+
     // Finally apply the velocity to the player
     player.position += player.velocity;
 
diff --git a/game/src/character/mod.rs b/game/src/character/mod.rs
index 6fe758c..9c1b0d2 100644
--- a/game/src/character/mod.rs
+++ b/game/src/character/mod.rs
@@ -2,7 +2,10 @@ pub mod collisions;
 pub mod render;
 
 use chrono::{DateTime, Utc};
-use raylib::{math::Vector2, texture::Texture2D};
+use raylib::{
+    math::{Rectangle, Vector2},
+    texture::Texture2D,
+};
 
 use crate::utilities::anim_render::AnimatedSpriteSheet;
 
@@ -48,7 +51,12 @@ impl MainCharacter {
         }
     }
 
-    pub fn update_player(&mut self, state: Option<CharacterState>) {
+    pub fn update_player(
+        &mut self,
+        state: Option<CharacterState>,
+        colliders: &Vec<Rectangle>,
+        level_height_offset: f32,
+    ) {
         if let Some(state) = state {
             // Update the internal state
             if state != self.current_state {
@@ -65,6 +73,6 @@ impl MainCharacter {
         }
 
         // Update the player based on the new velocity
-        modify_player_based_on_forces(self).unwrap();
+        modify_player_based_on_forces(self, colliders, level_height_offset).unwrap();
     }
 }
diff --git a/game/src/scenes/ingame_scene/mod.rs b/game/src/scenes/ingame_scene/mod.rs
index 70024d9..cbcb340 100644
--- a/game/src/scenes/ingame_scene/mod.rs
+++ b/game/src/scenes/ingame_scene/mod.rs
@@ -18,7 +18,7 @@ use tracing::{debug, trace};
 mod hud;
 pub mod level;
 mod update;
-mod world;
+pub mod world;
 
 #[derive(Debug)]
 pub struct InGameScreen {
@@ -43,7 +43,7 @@ impl InGameScreen {
                 rotation: 0.0,
                 zoom: 1.0,
             },
-            player: MainCharacter::new(Vector2::new(0.0, -80.0), player_sprite_sheet),
+            player: MainCharacter::new(Vector2::new(0.0, -85.0), player_sprite_sheet),
             world_background: WorldPaintTexture::new(background_texture),
             levels,
             current_level_idx: 0,
@@ -61,7 +61,12 @@ impl Action<Scenes, ScreenError, GameContext> for InGameScreen {
         debug!("Running InGameScreen for the first time");
 
         // Set the player to running
-        self.player.update_player(Some(CharacterState::Running));
+        let cur_level = self.levels.get(self.current_level_idx).unwrap();
+        self.player.update_player(
+            Some(CharacterState::Running),
+            &cur_level.colliders,
+            -cur_level.platform_tex.height as f32,
+        );
 
         Ok(())
     }
diff --git a/game/src/scenes/ingame_scene/update.rs b/game/src/scenes/ingame_scene/update.rs
index 0c98c86..754dbc2 100644
--- a/game/src/scenes/ingame_scene/update.rs
+++ b/game/src/scenes/ingame_scene/update.rs
@@ -17,6 +17,11 @@ impl FrameUpdate for InGameScreen {
         config: &GameConfig,
     ) {
         puffin::profile_function!();
+
+        // Get the current level
+        let cur_level = self.levels.get(self.current_level_idx).unwrap();
+
+
         // Set the camera's offset based on screen size
         self.camera.offset = raylib.get_screen_size().div(Vector2::new(2.0, 1.05));
         self.camera.target = Vector2::new(self.player.position.x, self.camera.target.y);
@@ -28,16 +33,20 @@ impl FrameUpdate for InGameScreen {
             && !(self.player.current_state == CharacterState::Dashing);
 
         if is_jump {
-            self.player.update_player(Some(CharacterState::Jumping));
+            self.player.update_player(Some(CharacterState::Jumping), &cur_level.colliders,
+            -cur_level.platform_tex.height as f32,);
         } else if is_dash {
-            self.player.update_player(Some(CharacterState::Dashing));
+            self.player.update_player(Some(CharacterState::Dashing), &cur_level.colliders,
+            -cur_level.platform_tex.height as f32,);
         } else {
             if self.player.current_state != CharacterState::Jumping
                 && self.player.current_state != CharacterState::Dashing
             {
-                self.player.update_player(Some(CharacterState::Running));
+                self.player.update_player(Some(CharacterState::Running), &cur_level.colliders,
+                -cur_level.platform_tex.height as f32,);
             } else {
-                self.player.update_player(None);
+                self.player.update_player(None, &cur_level.colliders,
+                    -cur_level.platform_tex.height as f32,);
             }
         }
     }
diff --git a/game/src/scenes/ingame_scene/world.rs b/game/src/scenes/ingame_scene/world.rs
index ee10f7e..4e9fd05 100644
--- a/game/src/scenes/ingame_scene/world.rs
+++ b/game/src/scenes/ingame_scene/world.rs
@@ -8,6 +8,8 @@ use crate::{
 };
 use raylib::prelude::*;
 
+pub const WORLD_LEVEL_X_OFFSET: f32 = 200.0;
+
 impl WorldSpaceRender for InGameScreen {
     fn render_world_space(
         &self,
@@ -23,7 +25,7 @@ impl WorldSpaceRender for InGameScreen {
         // self.world_background.render(raylib, Vector2::new(0.0, -1080.0), &self.camera);
 
         // Render the platform layer
-        raylib.draw_texture_v(&cur_level.platform_tex, Vector2::new(-10.0, -cur_level.platform_tex.height as f32), Color::WHITE);
+        raylib.draw_texture_v(&cur_level.platform_tex, Vector2::new(WORLD_LEVEL_X_OFFSET, -cur_level.platform_tex.height as f32), Color::WHITE);
 
         // Render the floor as a line
         let screen_world_zero = raylib.get_screen_to_world2D(Vector2::zero(), self.camera);