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);