New bullet system #1
|
@ -47,7 +47,7 @@ Multiplayer
|
||||||
- [ ] Gun Bob on walk
|
- [ ] Gun Bob on walk
|
||||||
- [ ] Reload animation (procedural)
|
- [ ] Reload animation (procedural)
|
||||||
- [ ] Real world magazines
|
- [ ] Real world magazines
|
||||||
- [ ] Rewriting bullet physics to use raycasts & kinematic rigidbodies (logic controlled)
|
- [x] Rewriting bullet physics to use raycasts & kinematic rigidbodies (logic controlled)
|
||||||
- [x] Create a Controls struct that holds mappings to all the game keys and replace them in all the game's code
|
- [x] Create a Controls struct that holds mappings to all the game keys and replace them in all the game's code
|
||||||
- [x] Gun dropping drops on only one side of player
|
- [x] Gun dropping drops on only one side of player
|
||||||
- [x] Gun dropping does not apply impulse for some reason...
|
- [x] Gun dropping does not apply impulse for some reason...
|
||||||
|
|
|
@ -1,14 +1,23 @@
|
||||||
use bevy::{
|
use bevy::{
|
||||||
prelude::{Component, Vec3},
|
prelude::{Component, Vec3},
|
||||||
reflect::Reflect,
|
reflect::Reflect,
|
||||||
time::Timer,
|
time::Timer, ecs::{reflect::ReflectComponent, entity::Entity},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::comps::core::weapons::caliber::Caliber;
|
use crate::comps::core::weapons::caliber::Caliber;
|
||||||
|
|
||||||
#[derive(Component, Reflect)]
|
#[derive(PartialEq, Clone, Reflect)]
|
||||||
|
pub struct BulletHit {
|
||||||
|
pub entity: Entity,
|
||||||
|
pub position: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Reflect, Default)]
|
||||||
|
#[reflect(Component)]
|
||||||
pub struct BulletMarker {
|
pub struct BulletMarker {
|
||||||
pub caliber: Caliber,
|
pub caliber: Caliber,
|
||||||
pub starting_point: Vec3,
|
pub starting_point: Vec3,
|
||||||
pub timer: Timer,
|
pub timer: Timer,
|
||||||
|
pub current_velocity: Vec3,
|
||||||
|
pub hits: Vec<BulletHit>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
use bevy::reflect::Reflect;
|
use bevy::reflect::Reflect;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Clone, Reflect)]
|
#[derive(Clone, Reflect, Default)]
|
||||||
pub enum Caliber {
|
pub enum Caliber {
|
||||||
/// 5.56x45mm
|
/// 5.56x45mm
|
||||||
NATO556,
|
NATO556,
|
||||||
/// 9x19mm
|
/// 9x19mm
|
||||||
|
#[default]
|
||||||
Parabellum9mm,
|
Parabellum9mm,
|
||||||
/// 5.45x39mm
|
/// 5.45x39mm (7N6M)
|
||||||
|
/// Reference: [Wikipedia](https://en.wikipedia.org/wiki/5.45%C3%9739mm)
|
||||||
RU545
|
RU545
|
||||||
}
|
}
|
||||||
impl Caliber {
|
impl Caliber {
|
||||||
|
@ -32,11 +34,12 @@ impl Caliber {
|
||||||
Caliber::RU545 => 75.0,
|
Caliber::RU545 => 75.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Unit = kg
|
||||||
pub fn mass(&self) -> f32 {
|
pub fn mass(&self) -> f32 {
|
||||||
match self {
|
match self {
|
||||||
Caliber::NATO556 => 0.1,
|
Caliber::NATO556 => 0.00402,
|
||||||
Caliber::Parabellum9mm => 0.05,
|
Caliber::Parabellum9mm => 0.05,
|
||||||
Caliber::RU545 => 0.07,
|
Caliber::RU545 => 0.00343,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn linear_damping(&self) -> f32 {
|
pub fn linear_damping(&self) -> f32 {
|
||||||
|
@ -60,4 +63,20 @@ impl Caliber {
|
||||||
Caliber::RU545 => 0.06
|
Caliber::RU545 => 0.06
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Unit = m/s
|
||||||
|
pub fn muzzle_velocity(&self) -> f32 {
|
||||||
|
match self {
|
||||||
|
Caliber::NATO556 => 991.0,
|
||||||
|
Caliber::Parabellum9mm => todo!(),
|
||||||
|
Caliber::RU545 => 880.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Unit = m/s
|
||||||
|
pub fn velocity_shed(&self) -> f32 {
|
||||||
|
match self {
|
||||||
|
Caliber::NATO556 => todo!(),
|
||||||
|
Caliber::Parabellum9mm => todo!(),
|
||||||
|
Caliber::RU545 => 120.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ pub fn despawn_stray_bullets(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_bullet_hit_marker(
|
pub fn spawn_bullet_hit_marker(
|
||||||
commands: &mut Commands,
|
commands: &mut Commands,
|
||||||
at: Vec3,
|
at: Vec3,
|
||||||
meshes: &mut ResMut<Assets<Mesh>>,
|
meshes: &mut ResMut<Assets<Mesh>>,
|
||||||
|
|
|
@ -10,7 +10,6 @@ pub fn update_gun_position_on_collision(
|
||||||
mut events: EventReader<EquippedGunCollisionEvent>,
|
mut events: EventReader<EquippedGunCollisionEvent>,
|
||||||
) {
|
) {
|
||||||
for event in events.read() {
|
for event in events.read() {
|
||||||
println!("Collision");
|
|
||||||
for mut player_firing_info in query.iter_mut() {
|
for mut player_firing_info in query.iter_mut() {
|
||||||
match event.collision_type {
|
match event.collision_type {
|
||||||
CollisionEventType::Start => {
|
CollisionEventType::Start => {
|
||||||
|
@ -19,7 +18,6 @@ pub fn update_gun_position_on_collision(
|
||||||
},
|
},
|
||||||
CollisionEventType::End => {
|
CollisionEventType::End => {
|
||||||
player_firing_info.gun_colliding_with_object = false;
|
player_firing_info.gun_colliding_with_object = false;
|
||||||
//player_firing_info.gun_ready_pose = GunReadyPose::HighReady;
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,3 +3,4 @@ pub mod player_firing;
|
||||||
pub mod shoot;
|
pub mod shoot;
|
||||||
pub mod inspect;
|
pub mod inspect;
|
||||||
pub mod equipped_gun_collisions;
|
pub mod equipped_gun_collisions;
|
||||||
|
pub mod update_bullet;
|
|
@ -1,9 +1,9 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use bevy::{prelude::*, render::render_resource::PrimitiveTopology};
|
use bevy::prelude::*;
|
||||||
use bevy_rapier3d::prelude::*;
|
use bevy_rapier3d::prelude::*;
|
||||||
|
|
||||||
use crate::{comps::core::{markers::{bullet::BulletMarker, muzzle_flash::MuzzleFlashMarker, collider_flags::ColliderFlags}, weapons::caliber::Caliber}, logic::core::player::player_settings::PlayerSettings};
|
use crate::comps::core::{markers::{bullet::BulletMarker, muzzle_flash::MuzzleFlashMarker, collider_flags::ColliderFlags}, weapons::caliber::Caliber};
|
||||||
|
|
||||||
|
|
||||||
pub fn shoot_bullet(
|
pub fn shoot_bullet(
|
||||||
|
@ -14,7 +14,6 @@ pub fn shoot_bullet(
|
||||||
forward: Vec3,
|
forward: Vec3,
|
||||||
up: Vec3,
|
up: Vec3,
|
||||||
caliber: Caliber,
|
caliber: Caliber,
|
||||||
player_settings: &Res<PlayerSettings>
|
|
||||||
) {
|
) {
|
||||||
// Spawn muzzle flash LIGHT
|
// Spawn muzzle flash LIGHT
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
|
@ -40,7 +39,7 @@ pub fn shoot_bullet(
|
||||||
));
|
));
|
||||||
|
|
||||||
// Spawn Line
|
// Spawn Line
|
||||||
if player_settings.shot_lines_enabled {
|
/*if player_settings.shot_lines_enabled {
|
||||||
commands.spawn(
|
commands.spawn(
|
||||||
MaterialMeshBundle {
|
MaterialMeshBundle {
|
||||||
mesh: {
|
mesh: {
|
||||||
|
@ -57,15 +56,15 @@ pub fn shoot_bullet(
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
spawn_bullet(
|
spawn_bullet(
|
||||||
commands,
|
commands,
|
||||||
meshes,
|
meshes,
|
||||||
materials,
|
materials,
|
||||||
firing_point,
|
firing_point,
|
||||||
forward,
|
|
||||||
up,
|
up,
|
||||||
|
forward,
|
||||||
caliber,
|
caliber,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -75,8 +74,8 @@ pub fn spawn_bullet(
|
||||||
meshes: &mut ResMut<Assets<Mesh>>,
|
meshes: &mut ResMut<Assets<Mesh>>,
|
||||||
materials: &mut ResMut<Assets<StandardMaterial>>,
|
materials: &mut ResMut<Assets<StandardMaterial>>,
|
||||||
firing_point: Transform,
|
firing_point: Transform,
|
||||||
forward: Vec3,
|
|
||||||
_up: Vec3,
|
_up: Vec3,
|
||||||
|
forward: Vec3,
|
||||||
caliber: Caliber,
|
caliber: Caliber,
|
||||||
) {
|
) {
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
|
@ -88,6 +87,8 @@ pub fn spawn_bullet(
|
||||||
Duration::from_secs_f32(caliber.max_airtime_secs()),
|
Duration::from_secs_f32(caliber.max_airtime_secs()),
|
||||||
TimerMode::Once,
|
TimerMode::Once,
|
||||||
),
|
),
|
||||||
|
current_velocity: forward * caliber.muzzle_velocity(),
|
||||||
|
hits: Vec::new()
|
||||||
},
|
},
|
||||||
MaterialMeshBundle {
|
MaterialMeshBundle {
|
||||||
mesh: {
|
mesh: {
|
||||||
|
@ -113,21 +114,8 @@ pub fn spawn_bullet(
|
||||||
transform: firing_point,
|
transform: firing_point,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
RigidBody::Dynamic,
|
RigidBody::KinematicPositionBased,
|
||||||
GravityScale(4.0),
|
|
||||||
Collider::ball(caliber.size()),
|
|
||||||
Velocity::zero(),
|
|
||||||
Damping {
|
|
||||||
linear_damping: caliber.linear_damping(),
|
|
||||||
angular_damping: caliber.angular_damping(),
|
|
||||||
},
|
|
||||||
ColliderMassProperties::Mass(caliber.mass()),
|
|
||||||
ExternalImpulse {
|
|
||||||
impulse: forward * caliber.impulse(),
|
|
||||||
torque_impulse: Vec3::ZERO,
|
|
||||||
},
|
|
||||||
ActiveEvents::COLLISION_EVENTS,
|
ActiveEvents::COLLISION_EVENTS,
|
||||||
CollisionGroups::new(Group::from_bits_retain(ColliderFlags::BULLETS.bits()), Group::from_bits_retain((ColliderFlags::SOLIDS | ColliderFlags::FLOOR).bits())),
|
CollisionGroups::new(Group::from_bits_retain(ColliderFlags::BULLETS.bits()), Group::from_bits_retain((ColliderFlags::SOLIDS | ColliderFlags::FLOOR).bits())),
|
||||||
Ccd::enabled(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
use bevy::{prelude::*, render::render_resource::PrimitiveTopology, ecs::system::SystemParam};
|
||||||
|
use bevy_rapier3d::prelude::*;
|
||||||
|
|
||||||
|
use crate::{comps::core::{markers::{bullet::{BulletMarker, BulletHit}, proxy::weapons::gun_colliders::GunFirearmCollider}, events::{bullet_collision::BulletCollisionEvent, collision_event_type::CollisionEventType}}, logic::core::player::player_settings::PlayerSettings};
|
||||||
|
|
||||||
|
#[derive(SystemParam)]
|
||||||
|
pub struct UpdateBulletQueryParams<'w, 's> {
|
||||||
|
bullets: Query<'w, 's, (Entity, &'static mut BulletMarker, &'static mut Transform)>,
|
||||||
|
firearm_colliders: Query<'w, 's, Entity, With<GunFirearmCollider>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_bullet(
|
||||||
|
mut commands: Commands,
|
||||||
|
time: Res<Time>,
|
||||||
|
rapier_context: Res<RapierContext>,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
player_settings: Res<PlayerSettings>,
|
||||||
|
mut query: UpdateBulletQueryParams,
|
||||||
|
mut bullet_collision_event: EventWriter<BulletCollisionEvent>,
|
||||||
|
) {
|
||||||
|
for (bullet, mut marker, mut transform) in query.bullets.iter_mut() {
|
||||||
|
let future_frame_pos = (marker.current_velocity * time.delta_seconds()) + (Vec3 { x: 0.0, y: -9.81, z: 0.0 } * time.delta_seconds() * marker.caliber.mass());
|
||||||
|
|
||||||
|
let max_toi = transform.translation.distance(future_frame_pos + transform.translation);
|
||||||
|
|
||||||
|
let mut query_filter = QueryFilter::default();
|
||||||
|
for firearm_collider in query.firearm_colliders.iter() {
|
||||||
|
query_filter = query_filter.exclude_collider(firearm_collider);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(bullet_hit) = raycast_until_destination(&rapier_context, query_filter, transform.translation, future_frame_pos, max_toi) {
|
||||||
|
if marker.hits.iter().find(|hit| hit.entity == bullet_hit.entity).is_none() {
|
||||||
|
marker.hits.push(bullet_hit.clone());
|
||||||
|
bullet_collision_event.send(BulletCollisionEvent { bullet, other: bullet_hit.entity, at: Transform::from_translation(bullet_hit.position), collision_type: CollisionEventType::Start })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if player_settings.shot_lines_enabled {
|
||||||
|
commands.spawn(
|
||||||
|
MaterialMeshBundle {
|
||||||
|
mesh: {
|
||||||
|
let mut mesh = Mesh::new(PrimitiveTopology::LineStrip);
|
||||||
|
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, Vec::from([Vec3::ZERO, (future_frame_pos.normalize_or_zero() * max_toi)]));
|
||||||
|
meshes.add(mesh)
|
||||||
|
},
|
||||||
|
material: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::RED,
|
||||||
|
emissive: Color::RED,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
visibility: Visibility::Visible,
|
||||||
|
transform: *transform,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raycast to future frame pos
|
||||||
|
transform.translation += future_frame_pos;
|
||||||
|
let vel_shed = marker.caliber.velocity_shed() * marker.current_velocity.normalize() * time.delta_seconds();
|
||||||
|
marker.current_velocity -= vel_shed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn raycast_until_destination(
|
||||||
|
rapier_context: &RapierContext,
|
||||||
|
query_filter: QueryFilter<'_>,
|
||||||
|
origin: Vec3,
|
||||||
|
dir: Vec3,
|
||||||
|
max_toi: f32,
|
||||||
|
) -> Option<BulletHit> {
|
||||||
|
if let Some((entity, toi)) = rapier_context.cast_ray(
|
||||||
|
origin,
|
||||||
|
dir,
|
||||||
|
max_toi,
|
||||||
|
true,
|
||||||
|
query_filter,
|
||||||
|
) {
|
||||||
|
return Some(BulletHit { entity, position: origin + dir * toi });
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
|
@ -266,7 +266,6 @@ pub fn capture_hand_usage(
|
||||||
forward,
|
forward,
|
||||||
up,
|
up,
|
||||||
firearm_data.caliber.clone(),
|
firearm_data.caliber.clone(),
|
||||||
&resources.player_settings
|
|
||||||
);
|
);
|
||||||
// Increment indexes and timers
|
// Increment indexes and timers
|
||||||
player_firing_info.current_round_index += 1;
|
player_firing_info.current_round_index += 1;
|
||||||
|
@ -336,7 +335,7 @@ pub fn interact_action(
|
||||||
for player_entity in query.player_query.iter() {
|
for player_entity in query.player_query.iter() {
|
||||||
for global_transform in query.camera_query.iter() {
|
for global_transform in query.camera_query.iter() {
|
||||||
let ray_pos = global_transform.translation();
|
let ray_pos = global_transform.translation();
|
||||||
let ray_dir = global_transform.forward() * 2.0; // TODO: Move this into global Resource state
|
let ray_dir = global_transform.forward() * 3.0; // TODO: Move this into global Resource state
|
||||||
let max_toi = 4.0;
|
let max_toi = 4.0;
|
||||||
let solid = true;
|
let solid = true;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
spawners::{player::player_spawner, spawn::SpawnerPlugin}, events::{bullet_collision::BulletCollisionEvent, equipped_gun_collision::EquippedGunCollisionEvent},
|
spawners::{player::player_spawner, spawn::SpawnerPlugin}, events::{bullet_collision::BulletCollisionEvent, equipped_gun_collision::EquippedGunCollisionEvent},
|
||||||
},
|
},
|
||||||
logic::core::{
|
logic::core::{
|
||||||
guns::{despawn_shots::{despawn_muzzle_flashes, despawn_stray_bullets}, inspect::inspect_firearm, equipped_gun_collisions::update_gun_position_on_collision},
|
guns::{despawn_shots::{despawn_muzzle_flashes, despawn_stray_bullets}, inspect::inspect_firearm, equipped_gun_collisions::update_gun_position_on_collision, update_bullet::update_bullet},
|
||||||
player::{
|
player::{
|
||||||
camera_player_sync::{
|
camera_player_sync::{
|
||||||
follow_cursor_with_camera, update_camera_vertical_position, MouseMovementSettings,
|
follow_cursor_with_camera, update_camera_vertical_position, MouseMovementSettings,
|
||||||
|
@ -62,6 +62,7 @@ pub fn load_scene(application: &mut App) {
|
||||||
application.add_systems(Update, inspect_firearm);
|
application.add_systems(Update, inspect_firearm);
|
||||||
application.add_systems(Update, collision_handler);
|
application.add_systems(Update, collision_handler);
|
||||||
application.add_systems(Update, update_gun_position_on_collision);
|
application.add_systems(Update, update_gun_position_on_collision);
|
||||||
|
application.add_systems(Update, update_bullet);
|
||||||
|
|
||||||
//application.add_systems(Update, animate_player);
|
//application.add_systems(Update, animate_player);
|
||||||
//application.add_systems(Update, register_bullet_hits);
|
//application.add_systems(Update, register_bullet_hits);
|
||||||
|
|
|
@ -5,7 +5,7 @@ use bevy_inspector_egui::bevy_egui::EguiPlugin;
|
||||||
use crate::{
|
use crate::{
|
||||||
comps::core::{markers::{
|
comps::core::{markers::{
|
||||||
holdable::{HoldableObjectData, InPlayerHands},
|
holdable::{HoldableObjectData, InPlayerHands},
|
||||||
player::{Player, PlayerData, PlayerHand}, inspect_screen::InspectScreenSlotUiMarker,
|
player::{Player, PlayerData, PlayerHand}, inspect_screen::InspectScreenSlotUiMarker, bullet::BulletMarker,
|
||||||
}, weapons::{firearm_data::FirearmData, magazine_data::MagazineData, caliber::Caliber, firearm::Firearm, spray_pattern::FirearmSprayPattern, firearm_state::FirearmState}},
|
}, weapons::{firearm_data::FirearmData, magazine_data::MagazineData, caliber::Caliber, firearm::Firearm, spray_pattern::FirearmSprayPattern, firearm_state::FirearmState}},
|
||||||
logic::core::{
|
logic::core::{
|
||||||
guns::player_firing::PlayerFiringInfo,
|
guns::player_firing::PlayerFiringInfo,
|
||||||
|
@ -39,6 +39,7 @@ impl Plugin for MainEditorUiPlugin {
|
||||||
.register_type::<PlayerValuesState>()
|
.register_type::<PlayerValuesState>()
|
||||||
.register_type::<FirearmData>()
|
.register_type::<FirearmData>()
|
||||||
.register_type::<MagazineData>()
|
.register_type::<MagazineData>()
|
||||||
|
.register_type::<BulletMarker>()
|
||||||
.register_type::<HoldableObjectData>()
|
.register_type::<HoldableObjectData>()
|
||||||
.register_type::<InPlayerHands>()
|
.register_type::<InPlayerHands>()
|
||||||
.register_type::<PlayerData>()
|
.register_type::<PlayerData>()
|
||||||
|
|
Loading…
Reference in New Issue