Skip to content

Commit 1cf67f4

Browse files
committed
refactor: kinematic controller plugin
1 parent 11047dd commit 1cf67f4

File tree

12 files changed

+134
-152
lines changed

12 files changed

+134
-152
lines changed

src/enemy/ai/mod.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ use bevy::prelude::*;
33
use crate::{
44
enemy::{
55
ai::systems::{
6-
apply_gravity_over_time, check_if_enemy_can_see_player,
7-
check_if_enemy_reached_target, handle_chasing_enemies,
8-
set_zero_velocity_if_not_chasing, update_enemy_on_ground,
6+
check_if_enemy_can_see_player, check_if_enemy_reached_target,
7+
handle_chasing_enemies, set_zero_velocity_if_not_chasing,
98
},
109
shooting::systems::enemy_shoot_player,
1110
},
@@ -36,8 +35,6 @@ impl Plugin for EnemyAiPlugin {
3635
// needs to run after enemy_shoot_player, so we can include all enemy bullets in
3736
// the SpatialQueryFilter
3837
check_if_enemy_can_see_player.after(enemy_shoot_player),
39-
update_enemy_on_ground,
40-
apply_gravity_over_time,
4138
check_if_enemy_reached_target,
4239
set_zero_velocity_if_not_chasing,
4340
)

src/enemy/ai/systems.rs

Lines changed: 6 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,12 @@ use bevy::prelude::*;
33
use bevy_landmass::{AgentState, AgentTarget3d, Velocity3d};
44

55
use crate::{
6-
GRAVITY,
76
enemy::{
87
Enemy, ai::EnemyState, shooting::components::EnemyBullet,
98
spawn::AgentEnemyEntityPointer,
109
},
1110
game_flow::states::InGameState,
12-
player::{
13-
Player,
14-
spawn::{PLAYER_CAPSULE_LENGTH, PLAYER_CAPSULE_RADIUS},
15-
},
11+
player::Player,
1612
};
1713

1814
/// This system iterates over each enemy, and with a raycast, determines whether the enemy can see
@@ -127,11 +123,13 @@ pub fn set_zero_velocity_if_not_chasing(
127123
enemy_query: Query<(&Enemy, &mut LinearVelocity)>,
128124
) {
129125
for (enemy, mut velocity) in enemy_query {
130-
if enemy.state != EnemyState::ChasingPlayer && velocity.0 != Vec3::ZERO
126+
if enemy.state != EnemyState::ChasingPlayer
127+
&& velocity.x != 0.0
128+
&& velocity.z != 0.0
131129
{
132-
info!("current velocity: {}", velocity.0);
133130
info!("Enemy no longer chasing player, zeoring velocity!");
134-
velocity.0 = Vec3::ZERO;
131+
velocity.z = 0.0;
132+
velocity.x = 0.0
135133
}
136134
}
137135
}
@@ -167,49 +165,3 @@ pub fn handle_chasing_enemies(
167165
velocity.0 = agent_velocity.velocity;
168166
}
169167
}
170-
171-
pub fn update_enemy_on_ground(
172-
enemies: Query<(&mut Enemy, &Transform, Entity, &mut LinearVelocity)>,
173-
spatial_query: SpatialQuery,
174-
) {
175-
for (mut enemy, transform, player_entity, mut player_velocity) in enemies {
176-
let on_ground = spatial_query
177-
.cast_shape(
178-
&Collider::capsule(
179-
PLAYER_CAPSULE_RADIUS,
180-
PLAYER_CAPSULE_LENGTH,
181-
),
182-
transform.translation,
183-
transform.rotation,
184-
Dir3::NEG_Y,
185-
&ShapeCastConfig {
186-
max_distance: 0.1,
187-
..default()
188-
},
189-
&SpatialQueryFilter::default()
190-
.with_excluded_entities([player_entity]),
191-
)
192-
.is_some();
193-
if enemy.on_ground != on_ground {
194-
enemy.on_ground = on_ground;
195-
}
196-
197-
if on_ground {
198-
if player_velocity.y <= 0.0 {
199-
player_velocity.y = 0.0;
200-
}
201-
}
202-
}
203-
}
204-
205-
pub fn apply_gravity_over_time(
206-
mut enemy_query: Single<(&Enemy, &mut LinearVelocity)>,
207-
time: Res<Time>,
208-
) {
209-
let enemy = enemy_query.0;
210-
let enemy_velocity = &mut enemy_query.1;
211-
212-
if !enemy.on_ground && enemy_velocity.y > 0.0 {
213-
enemy_velocity.y -= GRAVITY * time.delta_secs();
214-
}
215-
}

src/enemy/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,4 @@ impl Plugin for EnemyPlugin {
3030
pub struct Enemy {
3131
state: EnemyState,
3232
pub health: f32,
33-
on_ground: bool,
3433
}

src/enemy/shooting/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ impl Plugin for EnemyShootingPlugin {
2222
app.add_message::<EnemyKilledMessage>().add_systems(
2323
Update,
2424
(
25-
// enemy_shoot_player,
25+
enemy_shoot_player,
2626
tick_enemy_shoot_player_cooldown_timer,
2727
detect_player_bullet_collision_with_enemy,
2828
handle_enemy_killed_message,

src/enemy/spawn/mod.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ use crate::{
33
animate::ENEMY_MODEL_PATH,
44
shooting::components::EnemyShootPlayerCooldownTimer,
55
},
6+
kinematic_controller::KinematicController,
67
nav_mesh_pathfinding::{ArchipelagoRef, ENEMY_AGENT_RADIUS},
78
player::spawn::{PLAYER_CAPSULE_LENGTH, PLAYER_CAPSULE_RADIUS},
89
};
9-
use avian3d::{math::PI, prelude::*};
10+
use avian3d::math::PI;
1011
use bevy::prelude::*;
1112
use bevy_landmass::{
1213
Agent, Agent3dBundle, AgentSettings, AgentTarget3d, ArchipelagoRef3d,
@@ -130,23 +131,12 @@ fn handle_spawn_enemies_at_enemy_spawn_locations_message(
130131
health: 100.0,
131132
..default()
132133
},
133-
RigidBody::Kinematic,
134-
LockedAxes::new()
135-
.lock_rotation_x()
136-
.lock_rotation_y()
137-
.lock_rotation_z(),
138-
Collider::capsule(
139-
PLAYER_CAPSULE_RADIUS,
140-
PLAYER_CAPSULE_LENGTH,
141-
),
142-
AngularVelocity::ZERO,
143-
LinearVelocity::ZERO,
134+
KinematicController::default(),
144135
EnemyShootPlayerCooldownTimer(Timer::from_seconds(
145136
0.5,
146137
TimerMode::Repeating,
147138
)),
148139
Visibility::Visible,
149-
CollidingEntities::default(),
150140
))
151141
.with_child((
152142
Transform {

src/kinematic_controller/mod.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
use avian3d::prelude::*;
2+
use bevy::prelude::*;
3+
4+
use crate::GRAVITY;
5+
6+
// so total length is 1.9m = 1.4 + 0.25 * 2
7+
const CAPSULE_RADIUS: f32 = 0.25;
8+
const CAPSULE_LENGTH: f32 = 1.4;
9+
10+
#[derive(Component)]
11+
pub struct KinematicController {
12+
pub on_ground: bool,
13+
}
14+
15+
impl Default for KinematicController {
16+
fn default() -> Self {
17+
Self { on_ground: true }
18+
}
19+
}
20+
21+
pub struct KinematicControllerPlugin;
22+
23+
impl Plugin for KinematicControllerPlugin {
24+
fn build(&self, app: &mut App) {
25+
app.add_systems(
26+
Update,
27+
(
28+
add_required_components_for_kinematic_controllers,
29+
update_on_ground,
30+
apply_gravity_over_time,
31+
),
32+
);
33+
}
34+
}
35+
36+
fn add_required_components_for_kinematic_controllers(
37+
mut commands: Commands,
38+
query: Query<Entity, Added<KinematicController>>,
39+
) {
40+
for entity in query {
41+
commands.entity(entity).insert((
42+
RigidBody::Kinematic,
43+
LockedAxes::new()
44+
.lock_rotation_x()
45+
.lock_rotation_y()
46+
.lock_rotation_z(),
47+
Collider::capsule(CAPSULE_RADIUS, CAPSULE_LENGTH),
48+
LinearVelocity::ZERO,
49+
CollidingEntities::default(),
50+
));
51+
}
52+
}
53+
54+
fn update_on_ground(
55+
query: Query<(
56+
&Transform,
57+
Entity,
58+
&mut LinearVelocity,
59+
&mut KinematicController,
60+
)>,
61+
spatial_query: SpatialQuery,
62+
) {
63+
for (transform, entity, mut velocity, mut kinematic_controller) in query {
64+
let on_ground = spatial_query
65+
.cast_shape(
66+
&Collider::capsule(CAPSULE_RADIUS, CAPSULE_LENGTH),
67+
transform.translation,
68+
transform.rotation,
69+
Dir3::NEG_Y,
70+
&ShapeCastConfig {
71+
max_distance: 0.1,
72+
..default()
73+
},
74+
&SpatialQueryFilter::default().with_excluded_entities([entity]),
75+
)
76+
.is_some();
77+
if kinematic_controller.on_ground != on_ground {
78+
kinematic_controller.on_ground = on_ground;
79+
}
80+
81+
if on_ground && velocity.y <= 0.0 {
82+
velocity.y = 0.0;
83+
}
84+
}
85+
}
86+
87+
fn apply_gravity_over_time(
88+
query: Query<(&KinematicController, &mut LinearVelocity)>,
89+
time: Res<Time>,
90+
) {
91+
for (kinematic_controller, mut velocity) in query {
92+
if !kinematic_controller.on_ground {
93+
velocity.y -= GRAVITY * time.delta_secs();
94+
}
95+
}
96+
}

src/main.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ use bevy_inspector_egui::{
88
use bevy_skein::SkeinPlugin;
99

1010
use crate::{
11-
enemy::EnemyPlugin, game_flow::GameFlowPlugin, music::MusicPlugin,
11+
enemy::EnemyPlugin, game_flow::GameFlowPlugin,
12+
kinematic_controller::KinematicControllerPlugin, music::MusicPlugin,
1213
nav_mesh_pathfinding::NavMeshPathfindingPlugin, particles::ParticlesPlugin,
1314
player::PlayerPlugin, shared::CommonPlugin,
1415
user_interface::UserInterfacePlugin, world::WorldPlugin,
1516
};
1617

1718
mod enemy;
1819
mod game_flow;
20+
mod kinematic_controller;
1921
mod music;
2022
mod nav_mesh_pathfinding;
2123
mod particles;
@@ -61,9 +63,14 @@ fn main() {
6163
.add_plugins(PhysicsDebugPlugin::default())
6264
.insert_resource(Gravity(Vec3::NEG_Y * GRAVITY));
6365
app.add_plugins(SkeinPlugin::default());
66+
app.add_plugins(HanabiPlugin);
67+
6468
app.add_plugins(EguiPlugin::default())
6569
.add_plugins(WorldInspectorPlugin::new());
66-
app.add_plugins(HanabiPlugin);
70+
app.insert_resource(bevy_egui::EguiGlobalSettings {
71+
auto_create_primary_context: false,
72+
..default()
73+
});
6774

6875
// own plugins
6976
app.add_plugins(PlayerPlugin)
@@ -74,12 +81,8 @@ fn main() {
7481
.add_plugins(UserInterfacePlugin)
7582
.add_plugins(ParticlesPlugin)
7683
.add_plugins(MusicPlugin)
77-
.add_plugins(NavMeshPathfindingPlugin);
78-
79-
app.insert_resource(bevy_egui::EguiGlobalSettings {
80-
auto_create_primary_context: false,
81-
..default()
82-
});
84+
.add_plugins(NavMeshPathfindingPlugin)
85+
.add_plugins(KinematicControllerPlugin);
8386

8487
app.run();
8588
}

src/player/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ pub mod spawn;
1919
#[derive(Component, Debug)]
2020
pub struct Player {
2121
pub health: f32,
22-
pub on_ground: bool,
2322
// TODO: get rid of me or move me somewhere else
2423
pub camera_state: PlayerCameraState,
2524
}
@@ -28,7 +27,6 @@ impl Default for Player {
2827
fn default() -> Self {
2928
Player {
3029
health: 100.0,
31-
on_ground: true,
3230
camera_state: PlayerCameraState::Normal,
3331
}
3432
}

0 commit comments

Comments
 (0)