From e6157067ed5f20975e532965c4bfbcd3df90a9e0 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Sat, 2 Apr 2022 21:39:44 -0400 Subject: [PATCH 1/3] Can no longer run off the map --- .../env/env_testObject/env_testObject.json | 5 +- game/dist/map_gameMap.objects.json | 9 ++- .../src/rendering/utilities/map_render.rs | 65 +++++++++++++++++++ .../src/scenes/player_interaction.rs | 54 ++++++++------- 4 files changed, 104 insertions(+), 29 deletions(-) diff --git a/game/dist/assets/env/env_testObject/env_testObject.json b/game/dist/assets/env/env_testObject/env_testObject.json index 0655307a..37414a10 100644 --- a/game/dist/assets/env/env_testObject/env_testObject.json +++ b/game/dist/assets/env/env_testObject/env_testObject.json @@ -6,7 +6,7 @@ "top_texture": { "file_path": "assets/env/env_testObject/env_testObjectTop.png" }, - "footprint_radius": 128.0, + "footprint_radius": 256.0, "physics_colliders": [ { "position": [ @@ -16,7 +16,8 @@ "size": [ 230, 127 - ] + ], + "radius": 128.0 } ], "temperature": 5.0 diff --git a/game/dist/map_gameMap.objects.json b/game/dist/map_gameMap.objects.json index e5bb13c2..80a5a2b5 100644 --- a/game/dist/map_gameMap.objects.json +++ b/game/dist/map_gameMap.objects.json @@ -1,8 +1,11 @@ [ { - "type":"env", - "name":"env_testObject", - "position": [0,0], + "type": "env", + "name": "env_testObject", + "position": [ + 0, + 0 + ], "rotation_radians": 0.5 } ] \ No newline at end of file diff --git a/game/game_logic/src/rendering/utilities/map_render.rs b/game/game_logic/src/rendering/utilities/map_render.rs index 4f3cc3b2..e246fcf3 100644 --- a/game/game_logic/src/rendering/utilities/map_render.rs +++ b/game/game_logic/src/rendering/utilities/map_render.rs @@ -460,4 +460,69 @@ impl MapRenderer { } } } + + /// Used to modify the player's velocity based on the effects of the world + pub fn effect_velocity_with_collisions( + &self, + player_position: na::Vector2, + player_velocity: na::Vector2, + ) -> na::Vector2 { + // If the player is not moving, we don't need to do anything + if player_velocity.norm() == 0.0 { + return player_velocity; + } + + // Get the velocity unit vector + let player_velocity_unit_vector = player_velocity.normalize(); + + // Find the position 1 pixel infront of the player + let player_position_1_pixel_infront = player_position + player_velocity_unit_vector; + + // Check if this is in the collision zone of any objects + for obj_ref in &self.world_objects.object_references { + // Filter out anything more than 1000 pixels away + if (obj_ref.position - player_position).norm() > 1000.0 { + continue; + } + + // Get the object definition + let object_key = format!("{}:{}", obj_ref.kind, obj_ref.name); + let obj_def = self + .world_objects + .object_definitions + .get(&object_key) + .unwrap(); + + // Check if the player is about to be in a collision zone + for collider in &obj_def.physics_colliders { + // Handle a radius collider vs a size collider + if let Some(radius) = collider.radius { + // if (player_position_1_pixel_infront - obj_ref.position).norm() <= radius { + // // We are in a collision zone. Only allow the player to move away from the object + // let player_to_object_vector = obj_ref.position - player_position; + // } + } else if let Some(size) = collider.size { + } + } + } + + // Check if the player is about to leave the map + let next_player_position = player_position + player_velocity; + let mut player_velocity = player_velocity; + if next_player_position.x < 0.0 { + player_velocity.x = 0.0; + } + else if next_player_position.x > self.map.width as f32 * 128.0 { + player_velocity.x = 0.0; + } + if next_player_position.y > 0.0 { + player_velocity.y = 0.0; + } + else if next_player_position.y < self.map.height as f32 * -128.0 { + player_velocity.y = 0.0; + } + + // If we got here, the player is not in a collision zone + player_velocity + } } diff --git a/game/game_logic/src/scenes/player_interaction.rs b/game/game_logic/src/scenes/player_interaction.rs index dfcb9708..79be0d78 100644 --- a/game/game_logic/src/scenes/player_interaction.rs +++ b/game/game_logic/src/scenes/player_interaction.rs @@ -44,17 +44,14 @@ impl PlayableScene { Self { has_updated_discord_rpc: false, - player: Player::new(na::Vector2::new(10.0 * constants.tile_size as f32, -10.0 * constants.tile_size as f32)), + player: Player::new(na::Vector2::new( + 10.0 * constants.tile_size as f32, + -10.0 * constants.tile_size as f32, + )), world_map: map_renderer, camera: raylib::camera::Camera2D { - target: raylib::math::Vector2 { - x: 0.0, - y: 0.0, - }, - offset: raylib::math::Vector2 { - x: 0.0, - y: 0.0 - }, + target: raylib::math::Vector2 { x: 0.0, y: 0.0 }, + offset: raylib::math::Vector2 { x: 0.0, y: 0.0 }, rotation: 0.0, zoom: 1.0, }, @@ -191,38 +188,47 @@ impl PlayableScene { .set_magnitude((constants.player.max_velocity * constants.tile_size) as f32); } - player.position += &player.velocity * delta_time; + let velocity_modifier = &player.velocity * delta_time; + + // Handle the player colliding with the world + let velocity_modifier = self + .world_map + .effect_velocity_with_collisions(player.position, velocity_modifier); + + player.position += velocity_modifier; self.update_camera(raylib); } // Update the camera - pub fn update_camera( - &mut self, - raylib: & raylib::RaylibHandle, - ) { - + pub fn update_camera(&mut self, raylib: &raylib::RaylibHandle) { // Bounding box let bbox = na::Vector2::new(0.2, 0.2); // Get bounding box dimensions on the screen - let bbox_screen_min: raylib::math::Vector2 = (((na::Vector2::new(1.0, 1.0) - bbox) * 0.5).component_mul( - &na::Vector2::new(raylib.get_screen_width() as f32, raylib.get_screen_height() as f32) - )).into(); - let bbox_screen_max: raylib::math::Vector2 = (((na::Vector2::new(1.0, 1.0) + bbox) * 0.5).component_mul( - &na::Vector2::new(raylib.get_screen_width() as f32, raylib.get_screen_height() as f32) - )).into(); + let bbox_screen_min: raylib::math::Vector2 = (((na::Vector2::new(1.0, 1.0) - bbox) * 0.5) + .component_mul(&na::Vector2::new( + raylib.get_screen_width() as f32, + raylib.get_screen_height() as f32, + ))) + .into(); + let bbox_screen_max: raylib::math::Vector2 = (((na::Vector2::new(1.0, 1.0) + bbox) * 0.5) + .component_mul(&na::Vector2::new( + raylib.get_screen_width() as f32, + raylib.get_screen_height() as f32, + ))) + .into(); // Get bounding box in world space let mut bbox_world_min = raylib.get_screen_to_world2D(bbox_screen_min, self.camera); let mut bbox_world_max = raylib.get_screen_to_world2D(bbox_screen_max, self.camera); - // Invert y + // Invert y bbox_world_min.y *= -1.0; bbox_world_max.y *= -1.0; self.camera.offset = bbox_screen_min; - + if self.player.position.x < bbox_world_min.x { self.camera.target.x = self.player.position.x; } @@ -234,7 +240,7 @@ impl PlayableScene { if self.player.position.x > bbox_world_max.x { self.camera.target.x = bbox_world_min.x + (self.player.position.x - bbox_world_max.x); } - + if self.player.position.y < bbox_world_max.y { self.camera.target.y = bbox_world_max.y - (self.player.position.y + bbox_world_min.y); } From 56ed7622ac8b6e3328dfcb64ba8d2d43464219d4 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Sat, 2 Apr 2022 21:59:18 -0400 Subject: [PATCH 2/3] kinda works? --- .../src/rendering/utilities/map_render.rs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/game/game_logic/src/rendering/utilities/map_render.rs b/game/game_logic/src/rendering/utilities/map_render.rs index e246fcf3..0b6f9187 100644 --- a/game/game_logic/src/rendering/utilities/map_render.rs +++ b/game/game_logic/src/rendering/utilities/map_render.rs @@ -477,6 +477,7 @@ impl MapRenderer { // Find the position 1 pixel infront of the player let player_position_1_pixel_infront = player_position + player_velocity_unit_vector; + let next_player_position = player_position + player_velocity; // Check if this is in the collision zone of any objects for obj_ref in &self.world_objects.object_references { @@ -497,28 +498,32 @@ impl MapRenderer { for collider in &obj_def.physics_colliders { // Handle a radius collider vs a size collider if let Some(radius) = collider.radius { - // if (player_position_1_pixel_infront - obj_ref.position).norm() <= radius { - // // We are in a collision zone. Only allow the player to move away from the object - // let player_to_object_vector = obj_ref.position - player_position; - // } + // Check if we are about to collide with the circle + if (next_player_position - obj_ref.position).norm() < radius { + // Get the angle from the player to the center of the collider + let angle_to_center = + (obj_ref.position - player_position).angle(&na::Vector2::new(0.0, 0.0)); + if angle_to_center.abs() <= std::f32::consts::FRAC_PI_2 { + // Apply the inverse of the velocity to the player + return na::Vector2::zeros(); + } + } } else if let Some(size) = collider.size { + // TODO: make this work for regular and rotated objects } } } // Check if the player is about to leave the map - let next_player_position = player_position + player_velocity; let mut player_velocity = player_velocity; if next_player_position.x < 0.0 { player_velocity.x = 0.0; - } - else if next_player_position.x > self.map.width as f32 * 128.0 { + } else if next_player_position.x > self.map.width as f32 * 128.0 { player_velocity.x = 0.0; } if next_player_position.y > 0.0 { player_velocity.y = 0.0; - } - else if next_player_position.y < self.map.height as f32 * -128.0 { + } else if next_player_position.y < self.map.height as f32 * -128.0 { player_velocity.y = 0.0; } From 731a1acf2f67a4fe30c7eb98338bcd76cf622270 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Sun, 3 Apr 2022 13:22:03 -0400 Subject: [PATCH 3/3] World colission querying --- .../env/env_testObject/env_testObject.json | 17 +- game/game_logic/src/model/world_object.rs | 13 +- .../src/model/world_object_package.rs | 21 ++- .../src/rendering/utilities/map_render.rs | 155 ++++++++++-------- .../src/scenes/player_interaction.rs | 20 +-- 5 files changed, 137 insertions(+), 89 deletions(-) diff --git a/game/dist/assets/env/env_testObject/env_testObject.json b/game/dist/assets/env/env_testObject/env_testObject.json index 37414a10..7339f1b1 100644 --- a/game/dist/assets/env/env_testObject/env_testObject.json +++ b/game/dist/assets/env/env_testObject/env_testObject.json @@ -6,7 +6,19 @@ "top_texture": { "file_path": "assets/env/env_testObject/env_testObjectTop.png" }, - "footprint_radius": 256.0, + "footprint":[ + { + "position": [ + -128, + -128 + ], + "size": [ + 256, + 256 + ] + } + ], + "visualization_radius": 256.0, "physics_colliders": [ { "position": [ @@ -16,8 +28,7 @@ "size": [ 230, 127 - ], - "radius": 128.0 + ] } ], "temperature": 5.0 diff --git a/game/game_logic/src/model/world_object.rs b/game/game_logic/src/model/world_object.rs index 2a540451..1d1bb029 100644 --- a/game/game_logic/src/model/world_object.rs +++ b/game/game_logic/src/model/world_object.rs @@ -23,10 +23,12 @@ pub struct ObjectCollider { pub position: na::Vector2, /// Possible sizing pub size: Option>, - /// Possible radius - pub radius: Option, } +// Handy aliases +pub type ObjectSpaceObjectCollider = ObjectCollider; +pub type WorldSpaceObjectCollider = ObjectCollider; + /// Definition of an object. Only one of these should exist *per object*, and they will be GPU instanced. #[derive(Debug, Clone, Deserialize)] pub struct WorldObject { @@ -37,10 +39,11 @@ pub struct WorldObject { /// The object's top texture pub top_texture: Option, /// colliders describing the object's footprint - // pub footprint: Vec, - pub footprint_radius: Option, + pub footprint: Vec, + /// A "sphere of influence" for the object. This is used for showing under the roof + pub visualization_radius: Option, /// Colliders for physics - pub physics_colliders: Vec, + pub physics_colliders: Vec, /// Temperature pub temperature: Option, /// Friction diff --git a/game/game_logic/src/model/world_object_package.rs b/game/game_logic/src/model/world_object_package.rs index 8f8cd245..153c2bd7 100644 --- a/game/game_logic/src/model/world_object_package.rs +++ b/game/game_logic/src/model/world_object_package.rs @@ -7,7 +7,7 @@ use crate::{ rendering::utilities::anim_texture::AnimatedTexture, }; -use super::world_object::{WorldObject, WorldObjectRef}; +use super::world_object::{WorldObject, WorldObjectRef, WorldSpaceObjectCollider}; #[derive(Debug, thiserror::Error)] pub enum WorldObjectPackageLoadError { @@ -32,6 +32,8 @@ pub struct WorldObjectPackage { pub bottom_animated_textures: HashMap, /// Top animated textures pub top_animated_textures: HashMap, + /// A list of colliders in the world. We pre-solve these to make comput happy :) + pub world_space_colliders: Vec, } impl WorldObjectPackage { @@ -49,6 +51,7 @@ impl WorldObjectPackage { let mut top_static_textures = HashMap::new(); let mut bottom_animated_textures = HashMap::new(); let mut top_animated_textures = HashMap::new(); + let mut world_space_colliders: Vec = Vec::new(); for reference in &object_references { // If this is a new object, load it. let object_key = format!("{}:{}", reference.kind, reference.name); @@ -94,6 +97,21 @@ impl WorldObjectPackage { } } + // Keep track of all the colliders in the world + for collider in &object_definition.physics_colliders { + // Get the object's position + let object_position = reference.position; + + // Convert the collider's position to world space + let world_space_collider = WorldSpaceObjectCollider { + position: object_position + collider.position, + size: collider.size, + }; + + // Add the collider to the list + world_space_colliders.push(world_space_collider); + } + // Store the object definition object_definitions.insert(object_key.to_string(), object_definition); } @@ -106,6 +124,7 @@ impl WorldObjectPackage { top_static_textures, bottom_animated_textures, top_animated_textures, + world_space_colliders, }) } } diff --git a/game/game_logic/src/rendering/utilities/map_render.rs b/game/game_logic/src/rendering/utilities/map_render.rs index 0b6f9187..b447c6b3 100644 --- a/game/game_logic/src/rendering/utilities/map_render.rs +++ b/game/game_logic/src/rendering/utilities/map_render.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, path::PathBuf, sync::Arc}; use crate::{ asset_manager::{load_texture_from_internal_data, InternalData}, - model::world_object_package::WorldObjectPackage, + model::{world_object_package::WorldObjectPackage, world_object::WorldSpaceObjectCollider}, }; use nalgebra as na; use raylib::{ @@ -131,6 +131,14 @@ impl MapRenderer { }) } + /// Gets the map size + pub fn get_map_size(&self) -> na::Vector2 { + na::Vector2::new( + self.map.width as f32 * 128.0, + self.map.height as f32 * 128.0, + ) + } + pub fn sample_friction_at(&self, world_position: na::Vector2) -> Option { // Convert to a tile position let tile_position = na::Vector2::new( @@ -376,7 +384,7 @@ impl MapRenderer { // We need to detect if the player is in the footprint of the object let mut tint = Color::WHITE; if let Some(footprint_radius) = - obj_def.footprint_radius + obj_def.visualization_radius { let player_dist_to_object = (obj_ref.position - player_position).norm(); @@ -461,73 +469,80 @@ impl MapRenderer { } } - /// Used to modify the player's velocity based on the effects of the world - pub fn effect_velocity_with_collisions( - &self, - player_position: na::Vector2, - player_velocity: na::Vector2, - ) -> na::Vector2 { - // If the player is not moving, we don't need to do anything - if player_velocity.norm() == 0.0 { - return player_velocity; - } - - // Get the velocity unit vector - let player_velocity_unit_vector = player_velocity.normalize(); - - // Find the position 1 pixel infront of the player - let player_position_1_pixel_infront = player_position + player_velocity_unit_vector; - let next_player_position = player_position + player_velocity; - - // Check if this is in the collision zone of any objects - for obj_ref in &self.world_objects.object_references { - // Filter out anything more than 1000 pixels away - if (obj_ref.position - player_position).norm() > 1000.0 { - continue; - } - - // Get the object definition - let object_key = format!("{}:{}", obj_ref.kind, obj_ref.name); - let obj_def = self - .world_objects - .object_definitions - .get(&object_key) - .unwrap(); - - // Check if the player is about to be in a collision zone - for collider in &obj_def.physics_colliders { - // Handle a radius collider vs a size collider - if let Some(radius) = collider.radius { - // Check if we are about to collide with the circle - if (next_player_position - obj_ref.position).norm() < radius { - // Get the angle from the player to the center of the collider - let angle_to_center = - (obj_ref.position - player_position).angle(&na::Vector2::new(0.0, 0.0)); - if angle_to_center.abs() <= std::f32::consts::FRAC_PI_2 { - // Apply the inverse of the velocity to the player - return na::Vector2::zeros(); - } - } - } else if let Some(size) = collider.size { - // TODO: make this work for regular and rotated objects - } - } - } - - // Check if the player is about to leave the map - let mut player_velocity = player_velocity; - if next_player_position.x < 0.0 { - player_velocity.x = 0.0; - } else if next_player_position.x > self.map.width as f32 * 128.0 { - player_velocity.x = 0.0; - } - if next_player_position.y > 0.0 { - player_velocity.y = 0.0; - } else if next_player_position.y < self.map.height as f32 * -128.0 { - player_velocity.y = 0.0; - } - - // If we got here, the player is not in a collision zone - player_velocity + /// Get the list of world colliders + pub fn get_world_colliders(&self) -> Vec { + self.world_objects.world_space_colliders.clone() } + + // /// Used to modify the player's velocity based on the effects of the world + // pub fn effect_velocity_with_collisions( + // &self, + // player_position: na::Vector2, + // player_velocity: na::Vector2, + // ) -> na::Vector2 { + // // If the player is not moving, we don't need to do anything + // if player_velocity.norm() == 0.0 { + // return player_velocity; + // } + + // // Get the velocity unit vector + // let player_velocity_unit_vector = player_velocity.normalize(); + + // // Find the position 1 pixel infront of the player + // let player_position_1_pixel_infront = player_position + player_velocity_unit_vector; + // let next_player_position = player_position + player_velocity; + + // // Check if this is in the collision zone of any objects + // for obj_ref in &self.world_objects.object_references { + // // Filter out anything more than 1000 pixels away + // if (obj_ref.position - player_position).norm() > 1000.0 { + // continue; + // } + + // // Get the object definition + // let object_key = format!("{}:{}", obj_ref.kind, obj_ref.name); + // let obj_def = self + // .world_objects + // .object_definitions + // .get(&object_key) + // .unwrap(); + + // // Check if the player is about to be in a collision zone + // for collider in &obj_def.physics_colliders { + // // Handle a radius collider vs a size collider + // if let Some(radius) = collider.radius { + // // Check if we are about to collide with the circle + // if (next_player_position - obj_ref.position).norm() < radius { + // // Get the angle from the player to the center of the collider + // let angle_to_center = + // (obj_ref.position - player_position).angle(&na::Vector2::new(0.0, 0.0)); + // if angle_to_center.abs() <= std::f32::consts::FRAC_PI_2 { + // // Apply the inverse of the velocity to the player + // return na::Vector2::zeros(); + // } + // } + // } else if let Some(size) = collider.size { + // // TODO: make this work for regular and rotated objects + // } + // } + // } + + // // Check if the player is about to leave the map + // let mut player_velocity = player_velocity; + // if next_player_position.x < 0.0 { + // player_velocity.x = 0.0; + // } else if next_player_position.x > self.map.width as f32 * 128.0 { + // player_velocity.x = 0.0; + // } + // if next_player_position.y > 0.0 { + // player_velocity.y = 0.0; + // } else if next_player_position.y < self.map.height as f32 * -128.0 { + // player_velocity.y = 0.0; + // } + + // // If we got here, the player is not in a collision zone + // player_velocity + // } + + } diff --git a/game/game_logic/src/scenes/player_interaction.rs b/game/game_logic/src/scenes/player_interaction.rs index 79be0d78..bff9ca0a 100644 --- a/game/game_logic/src/scenes/player_interaction.rs +++ b/game/game_logic/src/scenes/player_interaction.rs @@ -8,7 +8,7 @@ use crate::{ asset_manager::{load_music_from_internal_data, load_sound_from_internal_data}, discord::{DiscordChannel, DiscordRpcSignal}, global_resource_package::GlobalResources, - model::player::Player, + model::{player::Player, world_object::WorldSpaceObjectCollider}, project_constants::ProjectConstants, rendering::utilities::{anim_texture::AnimatedTexture, map_render::MapRenderer}, }; @@ -21,6 +21,7 @@ pub struct PlayableScene { camera: raylib::camera::Camera2D, last_update: SystemTime, game_soundtrack: Music, + world_colliders: Vec, } impl PlayableScene { @@ -37,6 +38,7 @@ impl PlayableScene { thread, ) .unwrap(); + let world_colliders = map_renderer.get_world_colliders(); // Load the game music let game_soundtrack = @@ -57,6 +59,7 @@ impl PlayableScene { }, last_update: SystemTime::UNIX_EPOCH, game_soundtrack, + world_colliders, } } @@ -113,10 +116,6 @@ impl PlayableScene { self.world_map .render_map(&mut ctx2d, &self.camera, true, self.player.position); - // NOTE: This is how to check friction and temperature - let current_friction = self.world_map.sample_friction_at(self.player.position); - let current_temperature = self.world_map.sample_temperature_at(self.player.position); - let player_size = (constants.tile_size as f32 * constants.player.start_size * self.player.size) as i32; @@ -156,6 +155,12 @@ impl PlayableScene { let player = &mut self.player; + // NOTE: This is how to check friction and temperature + let current_friction = self.world_map.sample_friction_at(player.position); + let current_temperature = self.world_map.sample_temperature_at(player.position); + let map_size = self.world_map.get_map_size(); + // TODO: You can access the colission list with: self.world_colliders + // Get input direction components let h_axis = raylib.is_key_down(KeyboardKey::KEY_D) as i8 - raylib.is_key_down(KeyboardKey::KEY_A) as i8; @@ -190,11 +195,6 @@ impl PlayableScene { let velocity_modifier = &player.velocity * delta_time; - // Handle the player colliding with the world - let velocity_modifier = self - .world_map - .effect_velocity_with_collisions(player.position, velocity_modifier); - player.position += velocity_modifier; self.update_camera(raylib);