churn debugging bullet physics
This commit is contained in:
parent
14e383864d
commit
5ea8392068
@ -1,60 +0,0 @@
|
|||||||
|
|
||||||
use bevy::prelude::*;
|
|
||||||
use avian3d::prelude::*;
|
|
||||||
|
|
||||||
mod target_wall;
|
|
||||||
|
|
||||||
pub struct LevelPlugin;
|
|
||||||
|
|
||||||
impl Plugin for LevelPlugin
|
|
||||||
{
|
|
||||||
fn build(&self, app: &mut App)
|
|
||||||
{
|
|
||||||
app.add_plugins(target_wall::TargetWallPlugin);
|
|
||||||
app.add_systems(Startup, setup_level);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_level(
|
|
||||||
mut commands: Commands,
|
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
||||||
) {
|
|
||||||
const GROUND_SIZE: f32 = 100.0;
|
|
||||||
|
|
||||||
// spawn the ground plane
|
|
||||||
commands.spawn((
|
|
||||||
Mesh3d(meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(GROUND_SIZE * 0.5)))),
|
|
||||||
MeshMaterial3d(materials.add(StandardMaterial {
|
|
||||||
base_color: Color::srgb(0.761, 0.698, 0.502),
|
|
||||||
..default()
|
|
||||||
})),
|
|
||||||
Transform::IDENTITY,
|
|
||||||
Collider::cuboid(GROUND_SIZE, 0.0, GROUND_SIZE),
|
|
||||||
RigidBody::Static,
|
|
||||||
));
|
|
||||||
|
|
||||||
// spawn a box
|
|
||||||
commands.spawn((
|
|
||||||
Mesh3d(meshes.add(Cuboid::from_corners(
|
|
||||||
Vec3::new(-0.5, -0.5, -0.5), Vec3::new(0.5, 0.5, 0.5)
|
|
||||||
))),
|
|
||||||
MeshMaterial3d(materials.add(StandardMaterial {
|
|
||||||
base_color: Color::srgb(0.7, 0.1, 0.1),
|
|
||||||
..default()
|
|
||||||
})),
|
|
||||||
Transform::from_xyz(2.0, 0.5, -5.0),
|
|
||||||
Collider::cuboid(1.0, 1.0, 1.0),
|
|
||||||
RigidBody::Dynamic,
|
|
||||||
));
|
|
||||||
|
|
||||||
// spawn a light source
|
|
||||||
commands.spawn((
|
|
||||||
DirectionalLight {
|
|
||||||
illuminance: light_consts::lux::AMBIENT_DAYLIGHT,
|
|
||||||
shadows_enabled: true,
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
Transform::from_xyz(100.0, 200.0, 100.0).looking_at(Vec3::ZERO, Vec3::Y),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
100
src/game/mod.rs
100
src/game/mod.rs
@ -1,8 +1,15 @@
|
|||||||
|
|
||||||
|
use bevy::input::ButtonState;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use bevy::input::mouse::MouseButtonInput;
|
||||||
|
use avian3d::prelude::*;
|
||||||
|
|
||||||
mod player;
|
use crate::physics::BulletFiredEvent;
|
||||||
mod level;
|
use crate::ui::camera::CameraController;
|
||||||
|
use crate::ui::cursor::CursorGrabState;
|
||||||
|
|
||||||
|
mod target_wall;
|
||||||
|
use target_wall::TargetWallPlugin;
|
||||||
|
|
||||||
pub struct GamePlugin;
|
pub struct GamePlugin;
|
||||||
|
|
||||||
@ -10,7 +17,92 @@ impl Plugin for GamePlugin
|
|||||||
{
|
{
|
||||||
fn build(&self, app: &mut App)
|
fn build(&self, app: &mut App)
|
||||||
{
|
{
|
||||||
app.add_plugins(player::PlayerPlugin);
|
app.add_plugins(TargetWallPlugin);
|
||||||
app.add_plugins(level::LevelPlugin);
|
|
||||||
|
app.add_systems(Startup, setup_level);
|
||||||
|
|
||||||
|
app.add_systems(Update, do_shoot_on_left_click
|
||||||
|
.run_if(in_state(CursorGrabState(true)))
|
||||||
|
.run_if(on_event::<MouseButtonInput>))
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setup_level(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
) {
|
||||||
|
const GROUND_SIZE: f32 = 100.0;
|
||||||
|
|
||||||
|
// spawn the camera
|
||||||
|
commands.spawn((
|
||||||
|
CameraController {
|
||||||
|
sensitivity: Vec2::new(0.0007, 0.0007),
|
||||||
|
},
|
||||||
|
Camera3d::default(),
|
||||||
|
Transform::from_xyz(0.0, 1.75, 2.0),
|
||||||
|
));
|
||||||
|
|
||||||
|
// spawn the ground plane
|
||||||
|
commands.spawn((
|
||||||
|
Mesh3d(meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(GROUND_SIZE * 0.5)))),
|
||||||
|
MeshMaterial3d(materials.add(StandardMaterial {
|
||||||
|
base_color: Color::srgb(0.761, 0.698, 0.502),
|
||||||
|
..default()
|
||||||
|
})),
|
||||||
|
Transform::IDENTITY,
|
||||||
|
Collider::cuboid(GROUND_SIZE, 0.0, GROUND_SIZE),
|
||||||
|
RigidBody::Static,
|
||||||
|
));
|
||||||
|
|
||||||
|
// spawn some boxes to shoot at
|
||||||
|
for x in [0.0, 1.5, 3.0]
|
||||||
|
{
|
||||||
|
commands.spawn((
|
||||||
|
Mesh3d(meshes.add(Cuboid::from_corners(
|
||||||
|
Vec3::ZERO, Vec3::ONE,
|
||||||
|
))),
|
||||||
|
MeshMaterial3d(materials.add(StandardMaterial {
|
||||||
|
base_color: Color::srgb(0.7, 0.1, 0.1),
|
||||||
|
..default()
|
||||||
|
})),
|
||||||
|
Transform::from_xyz(x, 0.5, -2.0),
|
||||||
|
Collider::cuboid(1.0, 1.0, 1.0),
|
||||||
|
RigidBody::Dynamic,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// spawn a light source
|
||||||
|
commands.spawn((
|
||||||
|
DirectionalLight {
|
||||||
|
illuminance: light_consts::lux::AMBIENT_DAYLIGHT,
|
||||||
|
shadows_enabled: true,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
Transform::from_xyz(100.0, 200.0, 100.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_shoot_on_left_click(
|
||||||
|
camera_query: Single<&GlobalTransform, With<Camera>>,
|
||||||
|
mut mouse_events: EventReader<MouseButtonInput>,
|
||||||
|
mut bullet_events: EventWriter<BulletFiredEvent>,
|
||||||
|
) {
|
||||||
|
let camera_transform = camera_query.into_inner();
|
||||||
|
|
||||||
|
let bullet_fired_event = BulletFiredEvent {
|
||||||
|
position: camera_transform.translation() + Dir3::NEG_X * 2.0,
|
||||||
|
direction: camera_transform.forward(),
|
||||||
|
speed: 200.0,
|
||||||
|
radius: 0.008,
|
||||||
|
density: 11.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
bullet_events.send_batch(mouse_events.read()
|
||||||
|
.filter(|event| event.button == MouseButton::Left)
|
||||||
|
.filter(|event| event.state == ButtonState::Pressed)
|
||||||
|
.map(|_| bullet_fired_event)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,68 +0,0 @@
|
|||||||
|
|
||||||
use bevy::prelude::*;
|
|
||||||
use bevy::input::{mouse::MouseButtonInput, ButtonState};
|
|
||||||
use avian3d::prelude::*;
|
|
||||||
|
|
||||||
use crate::physics::BulletFiredEvent;
|
|
||||||
use crate::ui::camera::CameraController;
|
|
||||||
use crate::ui::cursor::CursorGrabState;
|
|
||||||
|
|
||||||
pub struct PlayerPlugin;
|
|
||||||
|
|
||||||
impl Plugin for PlayerPlugin
|
|
||||||
{
|
|
||||||
fn build(&self, app: &mut App)
|
|
||||||
{
|
|
||||||
app.add_systems(Startup, setup_player);
|
|
||||||
app.add_systems(Update, do_shoot_on_left_click
|
|
||||||
.run_if(in_state(CursorGrabState(true)))
|
|
||||||
.run_if(on_event::<MouseButtonInput>)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
pub struct Player;
|
|
||||||
|
|
||||||
fn setup_player(
|
|
||||||
mut commands: Commands,
|
|
||||||
) {
|
|
||||||
commands
|
|
||||||
.spawn((
|
|
||||||
Player,
|
|
||||||
Transform::from_xyz(0.0, 1.0, 0.0),
|
|
||||||
Collider::capsule(0.5, 1.0),
|
|
||||||
RigidBody::Kinematic,
|
|
||||||
Dominance(32),
|
|
||||||
Visibility::default(),
|
|
||||||
))
|
|
||||||
.with_child((
|
|
||||||
CameraController {
|
|
||||||
sensitivity: Vec2::new(0.0007, 0.0007),
|
|
||||||
},
|
|
||||||
Camera3d::default(),
|
|
||||||
Transform::from_xyz(0.0, 0.75, 0.0),
|
|
||||||
))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_shoot_on_left_click(
|
|
||||||
query: Single<&GlobalTransform, With<Camera>>,
|
|
||||||
mut mouse_events: EventReader<MouseButtonInput>,
|
|
||||||
mut bullet_events: EventWriter<BulletFiredEvent>,
|
|
||||||
) {
|
|
||||||
let transform = query.into_inner();
|
|
||||||
|
|
||||||
for _ in mouse_events.read()
|
|
||||||
.filter(|event| event.button == MouseButton::Left)
|
|
||||||
.filter(|event| event.state == ButtonState::Pressed)
|
|
||||||
{
|
|
||||||
bullet_events.send(BulletFiredEvent {
|
|
||||||
position: transform.translation() + transform.forward() * 0.5,
|
|
||||||
direction: transform.forward(),
|
|
||||||
radius: 0.008,
|
|
||||||
density: 11.0,
|
|
||||||
velocity: 910.0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -150,6 +150,7 @@ fn setup_target_wall(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_targets_shot(
|
fn on_targets_shot(
|
||||||
|
mut commands: Commands,
|
||||||
mut collision_events: EventReader<CollisionEnded>,
|
mut collision_events: EventReader<CollisionEnded>,
|
||||||
mut query_set: ParamSet<(
|
mut query_set: ParamSet<(
|
||||||
Query<Entity, With<Bullet>>,
|
Query<Entity, With<Bullet>>,
|
||||||
@ -163,7 +164,7 @@ fn on_targets_shot(
|
|||||||
// between a bullet and a target
|
// between a bullet and a target
|
||||||
//
|
//
|
||||||
let bullet_query = &mut query_set.p0();
|
let bullet_query = &mut query_set.p0();
|
||||||
let Ok(_) = collision.query_unique(bullet_query) else {
|
let Ok(bullet_entity) = collision.query_unique(bullet_query) else {
|
||||||
continue; // the collision doesn't involve a bullet
|
continue; // the collision doesn't involve a bullet
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
@ -174,5 +175,9 @@ fn on_targets_shot(
|
|||||||
|
|
||||||
// move the target
|
// move the target
|
||||||
*target_transform = target_resources.random_transform(target_handle);
|
*target_transform = target_resources.random_transform(target_handle);
|
||||||
|
|
||||||
|
// despawn the bullet
|
||||||
|
// TODO: this should be handled by the projectiles system
|
||||||
|
commands.entity(bullet_entity).despawn_recursive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -12,14 +12,14 @@ pub struct PhysicsPlugins;
|
|||||||
|
|
||||||
impl PluginGroup for PhysicsPlugins
|
impl PluginGroup for PhysicsPlugins
|
||||||
{
|
{
|
||||||
fn build(self) -> bevy::app::PluginGroupBuilder
|
fn build(self) -> PluginGroupBuilder
|
||||||
{
|
{
|
||||||
PluginGroupBuilder::start::<Self>()
|
PluginGroupBuilder::start::<Self>()
|
||||||
|
|
||||||
.add_group(avian3d::PhysicsPlugins::default())
|
.add_group(avian3d::PhysicsPlugins::default())
|
||||||
.add(avian3d::debug_render::PhysicsDebugPlugin::default())
|
.add(avian3d::debug_render::PhysicsDebugPlugin::default())
|
||||||
|
|
||||||
.add(WorldBoundsPlugin)
|
|
||||||
.add(ProjectilesPlugin)
|
.add(ProjectilesPlugin)
|
||||||
|
.add(WorldBoundsPlugin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use avian3d::prelude::*;
|
use avian3d::prelude::*;
|
||||||
|
|
||||||
|
use crate::util::ecs::PathTracer;
|
||||||
|
|
||||||
pub struct ProjectilesPlugin;
|
pub struct ProjectilesPlugin;
|
||||||
|
|
||||||
impl Plugin for ProjectilesPlugin
|
impl Plugin for ProjectilesPlugin
|
||||||
@ -38,14 +40,14 @@ fn setup_projectiles(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Event, Debug)]
|
#[derive(Event, Copy, Clone, PartialEq, Debug)]
|
||||||
pub struct BulletFiredEvent
|
pub struct BulletFiredEvent
|
||||||
{
|
{
|
||||||
pub position: Vec3,
|
pub position: Vec3,
|
||||||
pub direction: Dir3,
|
pub direction: Dir3,
|
||||||
|
pub speed: f32,
|
||||||
pub radius: f32,
|
pub radius: f32,
|
||||||
pub density: f32,
|
pub density: f32,
|
||||||
pub velocity: f32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
@ -71,9 +73,10 @@ fn on_bullet_fired_event(
|
|||||||
transform,
|
transform,
|
||||||
RigidBody::Dynamic,
|
RigidBody::Dynamic,
|
||||||
ColliderDensity(event.density),
|
ColliderDensity(event.density),
|
||||||
LinearVelocity(event.velocity * event.direction),
|
SpeculativeMargin(event.radius),
|
||||||
SpeculativeMargin(0.0),
|
|
||||||
SweptCcd::LINEAR,
|
SweptCcd::LINEAR,
|
||||||
|
LinearVelocity(event.speed * event.direction),
|
||||||
|
PathTracer::default(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
30
src/util/ecs/despawn_timer.rs
Normal file
30
src/util/ecs/despawn_timer.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
pub struct DespawnTimerPlugin;
|
||||||
|
|
||||||
|
impl Plugin for DespawnTimerPlugin
|
||||||
|
{
|
||||||
|
fn build(&self, app: &mut App)
|
||||||
|
{
|
||||||
|
app.add_systems(Update, do_despawn_timer_tick_and_despawn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct DespawnTimer(pub Timer);
|
||||||
|
|
||||||
|
fn do_despawn_timer_tick_and_despawn(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut query: Query<(Entity, &mut DespawnTimer)>,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
for (entity, mut timer) in query.iter_mut()
|
||||||
|
{
|
||||||
|
timer.0.tick(time.delta());
|
||||||
|
|
||||||
|
if timer.0.finished() {
|
||||||
|
commands.entity(entity).despawn_recursive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/util/ecs/mod.rs
Normal file
20
src/util/ecs/mod.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
mod despawn_timer;
|
||||||
|
pub use despawn_timer::*;
|
||||||
|
|
||||||
|
mod path_tracer;
|
||||||
|
pub use path_tracer::*;
|
||||||
|
|
||||||
|
use bevy::app::{PluginGroup, PluginGroupBuilder};
|
||||||
|
|
||||||
|
pub struct UtilEcsPlugins;
|
||||||
|
|
||||||
|
impl PluginGroup for UtilEcsPlugins
|
||||||
|
{
|
||||||
|
fn build(self) -> bevy::app::PluginGroupBuilder
|
||||||
|
{
|
||||||
|
PluginGroupBuilder::start::<Self>()
|
||||||
|
.add(DespawnTimerPlugin)
|
||||||
|
.add(EntityPathTracerPlugin)
|
||||||
|
}
|
||||||
|
}
|
||||||
156
src/util/ecs/path_tracer.rs
Normal file
156
src/util/ecs/path_tracer.rs
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use avian3d::prelude::*;
|
||||||
|
|
||||||
|
use crate::util::physics::CollisionQuery;
|
||||||
|
|
||||||
|
const TRACER_PATH_COLOR: Color = Color::srgb(0.1, 0.7, 0.1);
|
||||||
|
const TRACER_HIT_COLOR_X: Color = Color::srgb(0.7, 0.0, 0.0);
|
||||||
|
const TRACER_HIT_COLOR_Y: Color = Color::srgb(0.0, 0.7, 0.0);
|
||||||
|
const TRACER_HIT_COLOR_Z: Color = Color::srgb(0.0, 0.0, 0.7);
|
||||||
|
const TRACER_HIT_RADIUS: f32 = 0.33;
|
||||||
|
|
||||||
|
pub struct EntityPathTracerPlugin;
|
||||||
|
|
||||||
|
impl Plugin for EntityPathTracerPlugin
|
||||||
|
{
|
||||||
|
fn build(&self, app: &mut App)
|
||||||
|
{
|
||||||
|
app.insert_resource(PathTracerResources {
|
||||||
|
tracers: HashMap::new(),
|
||||||
|
});
|
||||||
|
|
||||||
|
app.add_systems(PhysicsSchedule, do_tracer_log_path.in_set(SolverSet::PreSubstep));
|
||||||
|
app.add_systems(PostProcessCollisions, do_tracer_log_collisions);
|
||||||
|
app.add_systems(Last, do_draw_tracers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
struct PathTracerResources
|
||||||
|
{
|
||||||
|
tracers: HashMap<Entity,PathTraceData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone, PartialEq)]
|
||||||
|
pub struct PathTraceData
|
||||||
|
{
|
||||||
|
path: Vec<Vec3>,
|
||||||
|
collisions: Vec<Isometry3d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PathTraceData
|
||||||
|
{
|
||||||
|
fn log_position(&mut self, isometry: Isometry3d)
|
||||||
|
{
|
||||||
|
self.path.push(isometry.translation.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log_collision(&mut self, isometry: Isometry3d)
|
||||||
|
{
|
||||||
|
self.collisions.push(isometry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Clone, PartialEq)]
|
||||||
|
#[allow(unused)]
|
||||||
|
pub enum PathTracer
|
||||||
|
{
|
||||||
|
Transient(PathTraceData),
|
||||||
|
Persistent,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PathTracer
|
||||||
|
{
|
||||||
|
fn default() -> Self
|
||||||
|
{
|
||||||
|
PathTracer::Transient(PathTraceData {
|
||||||
|
path: Vec::new(),
|
||||||
|
collisions: Vec::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PathTracer
|
||||||
|
{
|
||||||
|
fn mut_trace_data<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
entity: &Entity,
|
||||||
|
resources: &'a mut ResMut<PathTracerResources>
|
||||||
|
) -> &'a mut PathTraceData
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
PathTracer::Transient(trace_data) => trace_data,
|
||||||
|
PathTracer::Persistent => resources.tracers.get_mut(entity).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_trace_data<'a>(
|
||||||
|
&'a self,
|
||||||
|
entity: &Entity,
|
||||||
|
resources: &'a Res<PathTracerResources>
|
||||||
|
) -> &'a PathTraceData
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
PathTracer::Transient(trace_data) => trace_data,
|
||||||
|
PathTracer::Persistent => resources.tracers.get(entity).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_tracer_log_path(
|
||||||
|
mut query: Query<(Entity, &mut PathTracer, &GlobalTransform)>,
|
||||||
|
mut resources: ResMut<PathTracerResources>,
|
||||||
|
) {
|
||||||
|
for (entity, mut tracer, transform) in query.iter_mut()
|
||||||
|
{
|
||||||
|
let trace_data = tracer.mut_trace_data(&entity, &mut resources);
|
||||||
|
trace_data.log_position(transform.compute_transform().to_isometry());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_tracer_log_collisions(
|
||||||
|
mut query: Query<(Entity, &mut PathTracer, &GlobalTransform)>,
|
||||||
|
mut collision_events: EventReader<CollisionStarted>,
|
||||||
|
mut resources: ResMut<PathTracerResources>,
|
||||||
|
) {
|
||||||
|
for collision in collision_events.read()
|
||||||
|
{
|
||||||
|
let Ok((entity, mut tracer, transform)) = collision.query_unique(&mut query) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let trace_data = tracer.mut_trace_data(&entity, &mut resources);
|
||||||
|
trace_data.log_collision(transform.compute_transform().to_isometry());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_draw_tracers(
|
||||||
|
query: Query<(Entity, &PathTracer)>,
|
||||||
|
resources: Res<PathTracerResources>,
|
||||||
|
mut gizmos: Gizmos,
|
||||||
|
) {
|
||||||
|
use std::f32::consts::FRAC_PI_2;
|
||||||
|
let isometry_x = Isometry3d::from_rotation(Quat::from_rotation_x(FRAC_PI_2));
|
||||||
|
let isometry_y = Isometry3d::from_rotation(Quat::from_rotation_y(FRAC_PI_2));
|
||||||
|
let isometry_z = Isometry3d::from_rotation(Quat::from_rotation_z(FRAC_PI_2));
|
||||||
|
|
||||||
|
for (entity, tracer) in query.iter()
|
||||||
|
{
|
||||||
|
let trace_data = tracer.get_trace_data(&entity, &resources);
|
||||||
|
|
||||||
|
for window in trace_data.path.windows(2)
|
||||||
|
{
|
||||||
|
gizmos.line(window[0], window[1], TRACER_PATH_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
for isometry in trace_data.collisions.iter()
|
||||||
|
{
|
||||||
|
gizmos.circle(*isometry * isometry_x, TRACER_HIT_RADIUS, TRACER_HIT_COLOR_X);
|
||||||
|
gizmos.circle(*isometry * isometry_y, TRACER_HIT_RADIUS, TRACER_HIT_COLOR_Y);
|
||||||
|
gizmos.circle(*isometry * isometry_z, TRACER_HIT_RADIUS, TRACER_HIT_COLOR_Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +1,21 @@
|
|||||||
|
|
||||||
|
use bevy::app::{PluginGroup, PluginGroupBuilder};
|
||||||
|
|
||||||
|
pub mod ecs;
|
||||||
|
use ecs::UtilEcsPlugins;
|
||||||
|
|
||||||
pub mod physics;
|
pub mod physics;
|
||||||
|
use physics::UtilPhysicsPlugins;
|
||||||
|
|
||||||
|
pub struct UtilPlugins;
|
||||||
|
|
||||||
|
impl PluginGroup for UtilPlugins
|
||||||
|
{
|
||||||
|
fn build(self) -> bevy::app::PluginGroupBuilder
|
||||||
|
{
|
||||||
|
PluginGroupBuilder::start::<Self>()
|
||||||
|
|
||||||
|
.add_group(UtilEcsPlugins)
|
||||||
|
.add_group(UtilPhysicsPlugins)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,3 +1,15 @@
|
|||||||
|
|
||||||
|
use bevy::app::{PluginGroup, PluginGroupBuilder};
|
||||||
|
|
||||||
mod collision_query;
|
mod collision_query;
|
||||||
pub use collision_query::*;
|
pub use collision_query::*;
|
||||||
|
|
||||||
|
pub struct UtilPhysicsPlugins;
|
||||||
|
|
||||||
|
impl PluginGroup for UtilPhysicsPlugins
|
||||||
|
{
|
||||||
|
fn build(self) -> PluginGroupBuilder
|
||||||
|
{
|
||||||
|
PluginGroupBuilder::start::<Self>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user