From 731a1acf2f67a4fe30c7eb98338bcd76cf622270 Mon Sep 17 00:00:00 2001 From: Evan Pratten Date: Sun, 3 Apr 2022 13:22:03 -0400 Subject: [PATCH] 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);