EventCollision system that takes into account more than one type of collider AND Auto Low ready when gun collider hits object OR when player starts sprinting
This commit is contained in:
parent
1752e21637
commit
f78d4c7f40
|
@ -31,14 +31,18 @@ Multiplayer
|
|||
- [x] High Ready & Low Ready system with state
|
||||
- [x] High ready animation (procedural)
|
||||
- [x] Low ready animation (procedural)
|
||||
- [ ] TODO: Auto Low ready when gun collider hits object OR when player starts sprinting
|
||||
- [x] EventCollision system that takes into account more than one type of collider.
|
||||
- [x] Auto Low ready when gun collider hits object OR when player starts sprinting
|
||||
- [ ] (Not a priority) Collision with wall and attempting to Aim can look very twitchy, maybe add a cooldown of 0.1-0.4s on each change from low ready to high ready
|
||||
- [ ] Optics
|
||||
- [ ] All optics implementing a fn/trait that gives a specific gun offset to use the optic correctly
|
||||
- [ ] Find some way to implement a shader for the optics
|
||||
- [ ] Bobbing
|
||||
- [ ] Gun Bob on run
|
||||
- [ ] Gun Bob on walk
|
||||
- [ ] Reload animation (procedural)
|
||||
- [ ] Real world magazines
|
||||
- [ ] Rewriting bullet physics to use raycasts & kinematic rigidbodies (logic controlled)
|
||||
|
||||
- [ ] Create a Controls struct that holds mappings to all the game keys and replace them in all the game's code
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
use bevy::{ecs::{event::Event, entity::Entity}, transform::components::Transform};
|
||||
|
||||
use super::collision_event_type::CollisionEventType;
|
||||
|
||||
#[derive(Event)]
|
||||
pub struct BulletCollisionEvent {
|
||||
pub bullet: Entity,
|
||||
pub other: Entity,
|
||||
pub at: Transform,
|
||||
pub collision_type: CollisionEventType,
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
pub enum CollisionEventType {
|
||||
Start,
|
||||
End,
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
use bevy::ecs::{event::Event, entity::Entity};
|
||||
|
||||
use super::collision_event_type::CollisionEventType;
|
||||
|
||||
#[derive(Event)]
|
||||
pub struct EquippedGunCollisionEvent {
|
||||
pub gun: Entity,
|
||||
pub other: Entity,
|
||||
pub collision_type: CollisionEventType,
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
//pub mod loot_container;
|
||||
pub mod inventory_changed;
|
||||
pub mod pickup_item;
|
||||
pub mod bullet_collision;
|
||||
pub mod equipped_gun_collision;
|
||||
pub mod collision_event_type;
|
|
@ -1,5 +1,5 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_rapier3d::geometry::Sensor;
|
||||
use bevy_rapier3d::geometry::{Sensor, ActiveEvents};
|
||||
|
||||
use crate::{comps::core::markers::holdable::InPlayerHands, utils::hierarchy::find_child_in_parent_children};
|
||||
|
||||
|
@ -9,14 +9,6 @@ use crate::{comps::core::markers::holdable::InPlayerHands, utils::hierarchy::fin
|
|||
#[reflect(Component)]
|
||||
pub struct GunFirearmCollider;
|
||||
|
||||
|
||||
/*for (gun_firearm_collider_entity, _) in gun_firearm_collider_query.iter() {
|
||||
println!("a");
|
||||
if find_child_in_parent_children(commands, firearm_asset_entity, gun_firearm_collider_entity, &children) {
|
||||
println!("Sensor");
|
||||
commands.entity(gun_firearm_collider_entity).insert(Sensor);
|
||||
}
|
||||
} */
|
||||
pub fn update_gun_collider(
|
||||
mut commands: Commands,
|
||||
gun_firearm_collider_query: Query<Entity, Added<GunFirearmCollider>>,
|
||||
|
@ -27,11 +19,11 @@ pub fn update_gun_collider(
|
|||
let mut found = false;
|
||||
for in_player_hands_entity in in_player_hands_query.iter() {
|
||||
if find_child_in_parent_children(&mut commands, in_player_hands_entity, gun_firearm_collider_entity, &children) {
|
||||
commands.entity(gun_firearm_collider_entity).insert(Sensor);
|
||||
commands.entity(gun_firearm_collider_entity).insert(Sensor).insert(ActiveEvents::COLLISION_EVENTS);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if found { continue; }
|
||||
commands.entity(gun_firearm_collider_entity).remove::<Sensor>();
|
||||
commands.entity(gun_firearm_collider_entity).remove::<Sensor>().remove::<ActiveEvents>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
//!
|
||||
//! The goal of this module is to provide collision hydration to all other systems in the game.
|
||||
//! The reason is, well, rapier does not give a way to read collisions in multiple systems.
|
||||
//! If you read a collision event you automatically starve the systems relying on it.
|
||||
//!
|
||||
//! Have Different collision events for different systems, don't call the system directly, just use events to pass in collisions.
|
||||
//!
|
||||
|
||||
use bevy::{prelude::*, ecs::system::SystemParam};
|
||||
use bevy_rapier3d::{pipeline::CollisionEvent, rapier::geometry::CollisionEventFlags, geometry::Sensor};
|
||||
|
||||
use crate::comps::core::{markers::{bullet::BulletMarker, proxy::weapons::gun_colliders::GunFirearmCollider}, events::{bullet_collision::BulletCollisionEvent, equipped_gun_collision::EquippedGunCollisionEvent, collision_event_type::CollisionEventType}};
|
||||
|
||||
#[derive(SystemParam)]
|
||||
pub struct CollisionHandlerQueryParams<'w, 's> {
|
||||
bullets: Query<'w, 's, (Entity, &'static Transform), With<BulletMarker>>,
|
||||
firearms: Query<'w, 's, Entity, (With<Sensor>, With<GunFirearmCollider>, Without<BulletMarker>)>,
|
||||
}
|
||||
|
||||
#[derive(SystemParam)]
|
||||
pub struct CollisionHandlerEventParams<'w> {
|
||||
bullet_collision_events: EventWriter<'w, BulletCollisionEvent>,
|
||||
equipped_gun_collision_events: EventWriter<'w, EquippedGunCollisionEvent>,
|
||||
}
|
||||
|
||||
pub fn collision_handler(
|
||||
queries: CollisionHandlerQueryParams,
|
||||
mut events: CollisionHandlerEventParams,
|
||||
mut collisions: EventReader<CollisionEvent>,
|
||||
//time: Res<Time>,
|
||||
) {
|
||||
for collision in collisions.read() {
|
||||
let (entity_a, entity_b, flags, collision_type) = match collision {
|
||||
CollisionEvent::Started(entity_a, entity_b, flags) => {
|
||||
(entity_a, entity_b, flags, CollisionEventType::Start)
|
||||
}
|
||||
CollisionEvent::Stopped(entity_a, entity_b, flags) => {
|
||||
(entity_a, entity_b, flags, CollisionEventType::End)
|
||||
}
|
||||
};
|
||||
|
||||
if entity_a == entity_b { continue; } // Avoid inner collisions
|
||||
if flags.contains(CollisionEventFlags::SENSOR) { // Sensor collision event handling
|
||||
println!("Sensor collision");
|
||||
// ######
|
||||
// Equipped Firearm Collisions
|
||||
// ######
|
||||
for gun_collider in queries.firearms.iter() {
|
||||
println!("Gun collider entity detected");
|
||||
if &gun_collider == entity_a {
|
||||
events.equipped_gun_collision_events.send(EquippedGunCollisionEvent {
|
||||
gun: gun_collider,
|
||||
other: *entity_b,
|
||||
collision_type,
|
||||
});
|
||||
} else if &gun_collider == entity_b {
|
||||
events.equipped_gun_collision_events.send(EquippedGunCollisionEvent {
|
||||
gun: gun_collider,
|
||||
other: *entity_a,
|
||||
collision_type,
|
||||
});
|
||||
}
|
||||
}
|
||||
continue; // Continue, as we already handled sensor collisions
|
||||
}
|
||||
// ######
|
||||
// Bullet collisions
|
||||
// ######
|
||||
for (bullet, bullet_transform) in queries.bullets.iter() {
|
||||
if entity_a == &bullet {
|
||||
events.bullet_collision_events.send(BulletCollisionEvent {
|
||||
bullet,
|
||||
other: *entity_b,
|
||||
at: *bullet_transform,
|
||||
collision_type,
|
||||
});
|
||||
} else if entity_b == &bullet {
|
||||
events.bullet_collision_events.send(BulletCollisionEvent {
|
||||
bullet,
|
||||
other: *entity_a,
|
||||
at: *bullet_transform,
|
||||
collision_type,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use crate::comps::core::markers::{bullet::BulletMarker, muzzle_flash::MuzzleFlashMarker};
|
||||
use crate::comps::core::{markers::{bullet::BulletMarker, muzzle_flash::MuzzleFlashMarker}, events::{bullet_collision::BulletCollisionEvent, collision_event_type::CollisionEventType}};
|
||||
use bevy::prelude::*;
|
||||
use bevy_rapier3d::{prelude::*, rapier::geometry::CollisionEventFlags};
|
||||
use bevy_rapier3d::prelude::*;
|
||||
|
||||
pub fn despawn_muzzle_flashes(
|
||||
mut commands: Commands,
|
||||
|
@ -21,59 +21,45 @@ pub fn despawn_stray_bullets(
|
|||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
mut query: Query<(&mut BulletMarker, Entity, &Transform)>,
|
||||
|
||||
mut collisions: EventReader<CollisionEvent>,
|
||||
//res: Res<IntegrationParameters>,
|
||||
mut bullet_collisions: EventReader<BulletCollisionEvent>,
|
||||
time: Res<Time>,
|
||||
) {
|
||||
let collisions_read: Vec<&CollisionEvent> = collisions.read().collect();
|
||||
for (mut bullet, bullet_entity, transform) in query.iter_mut() {
|
||||
bullet.timer.tick(time.delta());
|
||||
for event in collisions_read.iter() {
|
||||
match event {
|
||||
CollisionEvent::Started(entity_a, entity_b, flags) => {
|
||||
if flags.contains(CollisionEventFlags::SENSOR) {
|
||||
continue;
|
||||
}
|
||||
if entity_a == entity_b {
|
||||
// Avoid inner collisions
|
||||
continue;
|
||||
}
|
||||
if entity_a == &bullet_entity || entity_b == &bullet_entity {
|
||||
commands.entity(bullet_entity).remove::<Collider>();
|
||||
//commands.entity(bullet_entity).insert(Sensor);
|
||||
spawn_bullet_hit_marker(
|
||||
&mut commands,
|
||||
transform.translation,
|
||||
&mut meshes,
|
||||
&mut materials,
|
||||
);
|
||||
}
|
||||
}
|
||||
CollisionEvent::Stopped(entity_a, entity_b, flags) => {
|
||||
if flags.contains(CollisionEventFlags::SENSOR) {
|
||||
continue;
|
||||
}
|
||||
if entity_a == entity_b {
|
||||
// Avoid inner collisions
|
||||
continue;
|
||||
}
|
||||
if entity_a == &bullet_entity || entity_b == &bullet_entity {
|
||||
let collisions_read: Vec<&BulletCollisionEvent> = bullet_collisions.read().collect();
|
||||
for event in collisions_read.into_iter() {
|
||||
match event.collision_type {
|
||||
CollisionEventType::Start => {
|
||||
|
||||
commands.entity(event.bullet).remove::<Collider>();
|
||||
//commands.entity(bullet_entity).insert(Sensor);
|
||||
spawn_bullet_hit_marker(
|
||||
&mut commands,
|
||||
event.at.translation,
|
||||
&mut meshes,
|
||||
&mut materials,
|
||||
);
|
||||
},
|
||||
CollisionEventType::End => {
|
||||
for (bullet, bullet_entity, _) in query.iter() {
|
||||
if bullet_entity != event.bullet { continue; }
|
||||
commands
|
||||
.entity(bullet_entity)
|
||||
.entity(event.bullet)
|
||||
.insert(Collider::ball(bullet.caliber.size()));
|
||||
//commands.entity(bullet_entity).remove::<Sensor>();
|
||||
//commands.entity(*entity_b).despawn();
|
||||
spawn_bullet_exit_marker(
|
||||
&mut commands,
|
||||
transform.translation,
|
||||
&mut meshes,
|
||||
&mut materials,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
//commands.entity(bullet_entity).remove::<Sensor>();
|
||||
//commands.entity(*entity_b).despawn();
|
||||
spawn_bullet_exit_marker(
|
||||
&mut commands,
|
||||
event.at.translation,
|
||||
&mut meshes,
|
||||
&mut materials,
|
||||
);
|
||||
continue;
|
||||
} //_ => {}
|
||||
}
|
||||
}
|
||||
for (mut bullet, bullet_entity, transform) in query.iter_mut() {
|
||||
bullet.timer.tick(time.delta());
|
||||
if bullet.timer.finished() {
|
||||
commands.entity(bullet_entity).despawn();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
|
||||
use crate::comps::core::events::{equipped_gun_collision::EquippedGunCollisionEvent, collision_event_type::CollisionEventType};
|
||||
|
||||
use super::player_firing::{PlayerFiringInfo, GunReadyPose};
|
||||
|
||||
pub fn update_gun_position_on_collision(
|
||||
mut query: Query<&mut PlayerFiringInfo>,
|
||||
mut events: EventReader<EquippedGunCollisionEvent>,
|
||||
) {
|
||||
for event in events.read() {
|
||||
println!("Collision");
|
||||
for mut player_firing_info in query.iter_mut() {
|
||||
match event.collision_type {
|
||||
CollisionEventType::Start => {
|
||||
player_firing_info.gun_ready_pose = GunReadyPose::LowReady;
|
||||
player_firing_info.gun_colliding_with_object = true;
|
||||
},
|
||||
CollisionEventType::End => {
|
||||
player_firing_info.gun_colliding_with_object = false;
|
||||
//player_firing_info.gun_ready_pose = GunReadyPose::HighReady;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
pub mod despawn_shots;
|
||||
pub mod player_firing;
|
||||
pub mod shoot;
|
||||
pub mod inspect;
|
||||
pub mod inspect;
|
||||
pub mod equipped_gun_collisions;
|
|
@ -24,6 +24,9 @@ pub struct PlayerFiringInfo {
|
|||
pub is_reloading: bool,
|
||||
pub gun_ready_pose: GunReadyPose,
|
||||
pub is_inspecting: bool,
|
||||
/// This is specifically for situations where the player is holding a gun that is stuck against a wall, and should not be false
|
||||
/// until the gun stops colliding with the wall.
|
||||
pub gun_colliding_with_object: bool,
|
||||
}
|
||||
|
||||
impl Default for PlayerFiringInfo {
|
||||
|
@ -36,6 +39,7 @@ impl Default for PlayerFiringInfo {
|
|||
is_reloading: false,
|
||||
gun_ready_pose: GunReadyPose::LowReady,
|
||||
is_inspecting: false,
|
||||
gun_colliding_with_object: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
pub mod guns;
|
||||
pub mod player;
|
||||
pub mod collisions;
|
|
@ -144,6 +144,7 @@ pub fn capture_hand_usage(
|
|||
} else if !mouse_wheel_events.is_empty() {
|
||||
if player.0.equipment.is_firearm() {
|
||||
for mouse_wheel_event in mouse_wheel_events.read() {
|
||||
if player_firing_info.gun_colliding_with_object { continue; }
|
||||
if mouse_wheel_event.y >= 0.0 {
|
||||
player_firing_info.gun_ready_pose = GunReadyPose::HighReady;
|
||||
} else {
|
||||
|
@ -196,7 +197,7 @@ pub fn capture_hand_usage(
|
|||
}
|
||||
};
|
||||
if resources.mouse_buttons.pressed(MouseButton::Right)
|
||||
&& !resources.game_ui_state.any_window() && !player_linear_xz_state.is_sprinting()
|
||||
&& !resources.game_ui_state.any_window() && !player_linear_xz_state.is_sprinting() && !player_firing_info.gun_colliding_with_object
|
||||
{
|
||||
player_firing_info.gun_ready_pose = GunReadyPose::HighReady;
|
||||
let rotation_lerp_quat = in_hand_transform.rotation.lerp(
|
||||
|
|
|
@ -4,10 +4,10 @@ use crate::{
|
|||
comps::core::{
|
||||
controller::capture_input,
|
||||
inventory::plugin::InventoryPlugin,
|
||||
spawners::{player::player_spawner, spawn::SpawnerPlugin},
|
||||
spawners::{player::player_spawner, spawn::SpawnerPlugin}, events::{bullet_collision::BulletCollisionEvent, equipped_gun_collision::EquippedGunCollisionEvent},
|
||||
},
|
||||
logic::core::{
|
||||
guns::{despawn_shots::{despawn_muzzle_flashes, despawn_stray_bullets}, inspect::inspect_firearm},
|
||||
guns::{despawn_shots::{despawn_muzzle_flashes, despawn_stray_bullets}, inspect::inspect_firearm, equipped_gun_collisions::update_gun_position_on_collision},
|
||||
player::{
|
||||
camera_player_sync::{
|
||||
follow_cursor_with_camera, update_camera_vertical_position, MouseMovementSettings,
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
|||
hands::{capture_hand_usage, interact_action},
|
||||
player_values_state::PlayerValuesState,
|
||||
player_vertical_sync::sync_player_y_state, camera_switching::switch_camera,
|
||||
},
|
||||
}, collisions::collision_handler,
|
||||
},
|
||||
setup::{
|
||||
//animations::{load_animations, AllAnimations},
|
||||
|
@ -60,9 +60,13 @@ pub fn load_scene(application: &mut App) {
|
|||
application.add_systems(Update, change_equipment.before(player_spawner));
|
||||
application.add_systems(Update, (despawn_muzzle_flashes, despawn_stray_bullets));
|
||||
application.add_systems(Update, inspect_firearm);
|
||||
application.add_systems(Update, collision_handler);
|
||||
application.add_systems(Update, update_gun_position_on_collision);
|
||||
|
||||
//application.add_systems(Update, animate_player);
|
||||
//application.add_systems(Update, register_bullet_hits);
|
||||
|
||||
application.add_event::<EquipmentChangeEvent>();
|
||||
application.add_event::<BulletCollisionEvent>();
|
||||
application.add_event::<EquippedGunCollisionEvent>();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue