World colission querying

This commit is contained in:
Evan Pratten 2022-04-03 13:22:03 -04:00
parent 3a37d7b715
commit 731a1acf2f
5 changed files with 137 additions and 89 deletions

View File

@ -6,7 +6,19 @@
"top_texture": { "top_texture": {
"file_path": "assets/env/env_testObject/env_testObjectTop.png" "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": [ "physics_colliders": [
{ {
"position": [ "position": [
@ -16,8 +28,7 @@
"size": [ "size": [
230, 230,
127 127
], ]
"radius": 128.0
} }
], ],
"temperature": 5.0 "temperature": 5.0

View File

@ -23,10 +23,12 @@ pub struct ObjectCollider {
pub position: na::Vector2<f32>, pub position: na::Vector2<f32>,
/// Possible sizing /// Possible sizing
pub size: Option<na::Vector2<f32>>, pub size: Option<na::Vector2<f32>>,
/// Possible radius
pub radius: Option<f32>,
} }
// 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. /// Definition of an object. Only one of these should exist *per object*, and they will be GPU instanced.
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct WorldObject { pub struct WorldObject {
@ -37,10 +39,11 @@ pub struct WorldObject {
/// The object's top texture /// The object's top texture
pub top_texture: Option<PossiblyAnimatedTexture>, pub top_texture: Option<PossiblyAnimatedTexture>,
/// colliders describing the object's footprint /// colliders describing the object's footprint
// pub footprint: Vec<ObjectCollider>, pub footprint: Vec<ObjectSpaceObjectCollider>,
pub footprint_radius: Option<f32>, /// A "sphere of influence" for the object. This is used for showing under the roof
pub visualization_radius: Option<f32>,
/// Colliders for physics /// Colliders for physics
pub physics_colliders: Vec<ObjectCollider>, pub physics_colliders: Vec<ObjectSpaceObjectCollider>,
/// Temperature /// Temperature
pub temperature: Option<f32>, pub temperature: Option<f32>,
/// Friction /// Friction

View File

@ -7,7 +7,7 @@ use crate::{
rendering::utilities::anim_texture::AnimatedTexture, rendering::utilities::anim_texture::AnimatedTexture,
}; };
use super::world_object::{WorldObject, WorldObjectRef}; use super::world_object::{WorldObject, WorldObjectRef, WorldSpaceObjectCollider};
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum WorldObjectPackageLoadError { pub enum WorldObjectPackageLoadError {
@ -32,6 +32,8 @@ pub struct WorldObjectPackage {
pub bottom_animated_textures: HashMap<String, AnimatedTexture>, pub bottom_animated_textures: HashMap<String, AnimatedTexture>,
/// Top animated textures /// Top animated textures
pub top_animated_textures: HashMap<String, AnimatedTexture>, pub top_animated_textures: HashMap<String, AnimatedTexture>,
/// A list of colliders in the world. We pre-solve these to make comput happy :)
pub world_space_colliders: Vec<WorldSpaceObjectCollider>,
} }
impl WorldObjectPackage { impl WorldObjectPackage {
@ -49,6 +51,7 @@ impl WorldObjectPackage {
let mut top_static_textures = HashMap::new(); let mut top_static_textures = HashMap::new();
let mut bottom_animated_textures = HashMap::new(); let mut bottom_animated_textures = HashMap::new();
let mut top_animated_textures = HashMap::new(); let mut top_animated_textures = HashMap::new();
let mut world_space_colliders: Vec<WorldSpaceObjectCollider> = Vec::new();
for reference in &object_references { for reference in &object_references {
// If this is a new object, load it. // If this is a new object, load it.
let object_key = format!("{}:{}", reference.kind, reference.name); 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 // Store the object definition
object_definitions.insert(object_key.to_string(), object_definition); object_definitions.insert(object_key.to_string(), object_definition);
} }
@ -106,6 +124,7 @@ impl WorldObjectPackage {
top_static_textures, top_static_textures,
bottom_animated_textures, bottom_animated_textures,
top_animated_textures, top_animated_textures,
world_space_colliders,
}) })
} }
} }

View File

@ -2,7 +2,7 @@ use std::{collections::HashMap, path::PathBuf, sync::Arc};
use crate::{ use crate::{
asset_manager::{load_texture_from_internal_data, InternalData}, 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 nalgebra as na;
use raylib::{ use raylib::{
@ -131,6 +131,14 @@ impl MapRenderer {
}) })
} }
/// Gets the map size
pub fn get_map_size(&self) -> na::Vector2<f32> {
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<f32>) -> Option<f32> { pub fn sample_friction_at(&self, world_position: na::Vector2<f32>) -> Option<f32> {
// Convert to a tile position // Convert to a tile position
let tile_position = na::Vector2::new( 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 // We need to detect if the player is in the footprint of the object
let mut tint = Color::WHITE; let mut tint = Color::WHITE;
if let Some(footprint_radius) = if let Some(footprint_radius) =
obj_def.footprint_radius obj_def.visualization_radius
{ {
let player_dist_to_object = let player_dist_to_object =
(obj_ref.position - player_position).norm(); (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 /// Get the list of world colliders
pub fn effect_velocity_with_collisions( pub fn get_world_colliders(&self) -> Vec<WorldSpaceObjectCollider> {
&self, self.world_objects.world_space_colliders.clone()
player_position: na::Vector2<f32>,
player_velocity: na::Vector2<f32>,
) -> na::Vector2<f32> {
// 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 // /// Used to modify the player's velocity based on the effects of the world
let player_velocity_unit_vector = player_velocity.normalize(); // pub fn effect_velocity_with_collisions(
// &self,
// player_position: na::Vector2<f32>,
// player_velocity: na::Vector2<f32>,
// ) -> na::Vector2<f32> {
// // If the player is not moving, we don't need to do anything
// if player_velocity.norm() == 0.0 {
// return player_velocity;
// }
// Find the position 1 pixel infront of the player // // Get the velocity unit vector
let player_position_1_pixel_infront = player_position + player_velocity_unit_vector; // let player_velocity_unit_vector = player_velocity.normalize();
let next_player_position = player_position + player_velocity;
// Check if this is in the collision zone of any objects // // Find the position 1 pixel infront of the player
for obj_ref in &self.world_objects.object_references { // let player_position_1_pixel_infront = player_position + player_velocity_unit_vector;
// Filter out anything more than 1000 pixels away // let next_player_position = player_position + player_velocity;
if (obj_ref.position - player_position).norm() > 1000.0 {
continue;
}
// Get the object definition // // Check if this is in the collision zone of any objects
let object_key = format!("{}:{}", obj_ref.kind, obj_ref.name); // for obj_ref in &self.world_objects.object_references {
let obj_def = self // // Filter out anything more than 1000 pixels away
.world_objects // if (obj_ref.position - player_position).norm() > 1000.0 {
.object_definitions // continue;
.get(&object_key) // }
.unwrap();
// Check if the player is about to be in a collision zone // // Get the object definition
for collider in &obj_def.physics_colliders { // let object_key = format!("{}:{}", obj_ref.kind, obj_ref.name);
// Handle a radius collider vs a size collider // let obj_def = self
if let Some(radius) = collider.radius { // .world_objects
// Check if we are about to collide with the circle // .object_definitions
if (next_player_position - obj_ref.position).norm() < radius { // .get(&object_key)
// Get the angle from the player to the center of the collider // .unwrap();
let angle_to_center =
(obj_ref.position - player_position).angle(&na::Vector2::new(0.0, 0.0)); // // Check if the player is about to be in a collision zone
if angle_to_center.abs() <= std::f32::consts::FRAC_PI_2 { // for collider in &obj_def.physics_colliders {
// Apply the inverse of the velocity to the player // // Handle a radius collider vs a size collider
return na::Vector2::zeros(); // 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 {
} else if let Some(size) = collider.size { // // Get the angle from the player to the center of the collider
// TODO: make this work for regular and rotated objects // 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
// }
// 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
}
} }

View File

@ -8,7 +8,7 @@ use crate::{
asset_manager::{load_music_from_internal_data, load_sound_from_internal_data}, asset_manager::{load_music_from_internal_data, load_sound_from_internal_data},
discord::{DiscordChannel, DiscordRpcSignal}, discord::{DiscordChannel, DiscordRpcSignal},
global_resource_package::GlobalResources, global_resource_package::GlobalResources,
model::player::Player, model::{player::Player, world_object::WorldSpaceObjectCollider},
project_constants::ProjectConstants, project_constants::ProjectConstants,
rendering::utilities::{anim_texture::AnimatedTexture, map_render::MapRenderer}, rendering::utilities::{anim_texture::AnimatedTexture, map_render::MapRenderer},
}; };
@ -21,6 +21,7 @@ pub struct PlayableScene {
camera: raylib::camera::Camera2D, camera: raylib::camera::Camera2D,
last_update: SystemTime, last_update: SystemTime,
game_soundtrack: Music, game_soundtrack: Music,
world_colliders: Vec<WorldSpaceObjectCollider>,
} }
impl PlayableScene { impl PlayableScene {
@ -37,6 +38,7 @@ impl PlayableScene {
thread, thread,
) )
.unwrap(); .unwrap();
let world_colliders = map_renderer.get_world_colliders();
// Load the game music // Load the game music
let game_soundtrack = let game_soundtrack =
@ -57,6 +59,7 @@ impl PlayableScene {
}, },
last_update: SystemTime::UNIX_EPOCH, last_update: SystemTime::UNIX_EPOCH,
game_soundtrack, game_soundtrack,
world_colliders,
} }
} }
@ -113,10 +116,6 @@ impl PlayableScene {
self.world_map self.world_map
.render_map(&mut ctx2d, &self.camera, true, self.player.position); .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 = let player_size =
(constants.tile_size as f32 * constants.player.start_size * self.player.size) as i32; (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; 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 // Get input direction components
let h_axis = raylib.is_key_down(KeyboardKey::KEY_D) as i8 let h_axis = raylib.is_key_down(KeyboardKey::KEY_D) as i8
- raylib.is_key_down(KeyboardKey::KEY_A) as i8; - raylib.is_key_down(KeyboardKey::KEY_A) as i8;
@ -190,11 +195,6 @@ impl PlayableScene {
let velocity_modifier = &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; player.position += velocity_modifier;
self.update_camera(raylib); self.update_camera(raylib);