Skip to content

Commit af249d2

Browse files
committed
feat: make character controller usable for the enemy too
1 parent 5d2c1d6 commit af249d2

File tree

5 files changed

+92
-77
lines changed

5 files changed

+92
-77
lines changed

src/character_controller/mod.rs

Lines changed: 75 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use bevy::prelude::*;
33

44
use crate::{
55
GRAVITY,
6-
enemy::Enemy,
76
game_flow::states::InGameState,
87
player::{Player, camera::components::ViewModelCamera},
98
};
@@ -32,7 +31,12 @@ pub enum MovementStateEnum {
3231
}
3332

3433
#[derive(Message)]
35-
pub enum MovementAction {
34+
pub struct MovementAction {
35+
pub direction: MovementDirection,
36+
pub character_controller_entity: Entity,
37+
}
38+
39+
pub enum MovementDirection {
3640
// TODO: should be possible to just have Vec2
3741
Move(Vec3),
3842
Jump,
@@ -73,7 +77,7 @@ impl Default for CharacterControllerBundle {
7377
Quaternion::default(),
7478
Dir3::NEG_Y,
7579
)
76-
.with_max_distance(0.2),
80+
.with_max_distance(0.1),
7781
}
7882
}
7983
}
@@ -98,8 +102,7 @@ impl Plugin for CharacterControllerPlugin {
98102
update_on_ground,
99103
apply_gravity_over_time,
100104
handle_keyboard_input_for_player,
101-
handle_movement_actions_for_player,
102-
debug_remove_grounded_from_enemies,
105+
handle_movement_actions_for_character_controllers,
103106
)
104107
.run_if(in_state(InGameState::Playing)),
105108
)
@@ -120,9 +123,14 @@ fn handle_player_dead_velocity(
120123
fn handle_keyboard_input_for_player(
121124
keyboard_input: Res<ButtonInput<KeyCode>>,
122125
mut movement_action_writer: MessageWriter<MovementAction>,
123-
player_query: Single<(&Transform, &mut MovementState), With<Player>>,
126+
player_query: Single<
127+
(&Transform, &mut MovementState, Entity),
128+
With<Player>,
129+
>,
124130
) {
125-
let (player_transform, mut movement_state) = player_query.into_inner();
131+
let (player_transform, mut movement_state, player_entity) =
132+
player_query.into_inner();
133+
126134
let speed = if keyboard_input.pressed(KeyCode::ShiftLeft) {
127135
RUN_VELOCITY
128136
} else {
@@ -146,7 +154,11 @@ fn handle_keyboard_input_for_player(
146154

147155
let world_velocity = player_transform.rotation * local_velocity;
148156

149-
movement_action_writer.write(MovementAction::Move(world_velocity));
157+
movement_action_writer.write(MovementAction {
158+
direction: MovementDirection::Move(world_velocity),
159+
character_controller_entity: player_entity,
160+
});
161+
150162
if local_velocity.x == 0.0 && local_velocity.z == 0.0 {
151163
if movement_state.0 != MovementStateEnum::Idle {
152164
movement_state.0 = MovementStateEnum::Idle;
@@ -162,59 +174,78 @@ fn handle_keyboard_input_for_player(
162174
}
163175

164176
if keyboard_input.just_pressed(KeyCode::Space) {
165-
movement_action_writer.write(MovementAction::Jump);
177+
movement_action_writer.write(MovementAction {
178+
direction: MovementDirection::Jump,
179+
character_controller_entity: player_entity,
180+
});
166181
}
167182
}
168183

169-
fn handle_movement_actions_for_player(
184+
fn handle_movement_actions_for_character_controllers(
170185
mut movement_action_reader: MessageReader<MovementAction>,
171-
player_query: Single<
172-
(&mut LinearVelocity, &Grounded, &Transform, Entity),
173-
With<Player>,
174-
>,
186+
mut character_controller_query: Query<(
187+
&mut LinearVelocity,
188+
&Grounded,
189+
&Transform,
190+
Entity,
191+
)>,
192+
// TODO: i dont want this here
175193
player_camera_entity: Single<Entity, With<ViewModelCamera>>,
176194
spatial_query: SpatialQuery,
177195
time: Res<Time>,
178196
) {
179-
let (mut player_velocity, player_grounded, player_transform, player_entity) =
180-
player_query.into_inner();
181197
for movement_action in movement_action_reader.read() {
182-
match movement_action {
183-
MovementAction::Jump => {
184-
if player_grounded.0 {
185-
player_velocity.y = JUMP_VELOCITY;
198+
let direction = &movement_action.direction;
199+
let character_controller_entity =
200+
movement_action.character_controller_entity;
201+
let Ok((mut velocity, grounded, transform, entity)) =
202+
character_controller_query.get_mut(character_controller_entity)
203+
else {
204+
// FIXME
205+
warn!("lkjdsflkjdsf");
206+
continue;
207+
};
208+
209+
match *direction {
210+
MovementDirection::Jump => {
211+
if grounded.0 {
212+
velocity.y = JUMP_VELOCITY;
186213
}
187214
}
188215
// TODO: should probably move the content of this block elsewhere
189-
MovementAction::Move(world_velocity) => {
216+
MovementDirection::Move(world_velocity) => {
190217
let Ok(direction_from_world_velocity) =
191-
Dir3::new(*world_velocity)
218+
Dir3::new(world_velocity)
192219
else {
193-
player_velocity.x = 0.0;
194-
player_velocity.z = 0.0;
220+
velocity.x = 0.0;
221+
velocity.z = 0.0;
195222
return;
196223
};
197224

198-
let ray_origin = player_transform.translation
225+
let ray_origin = transform.translation
199226
- direction_from_world_velocity.as_vec3() * 0.025;
200227
let max_distance = 0.3;
201228

229+
let spatial_query_filter = &SpatialQueryFilter::default()
230+
.with_excluded_entities([
231+
entity,
232+
// TODO: should only be excluded when we have player
233+
*player_camera_entity,
234+
]);
235+
202236
if let Some(hit_ahead) = spatial_query.cast_shape(
203237
&Collider::capsule(
204238
CHARACTER_CAPSULE_RADIUS,
205239
CHARACTER_CAPSULE_LENGTH,
206240
),
207241
ray_origin,
208-
player_transform.rotation,
242+
transform.rotation,
209243
direction_from_world_velocity,
210244
&ShapeCastConfig {
211245
max_distance,
212246
..default()
213247
},
214-
&SpatialQueryFilter::default().with_excluded_entities([
215-
player_entity,
216-
*player_camera_entity,
217-
]),
248+
spatial_query_filter,
218249
) {
219250
// obstacle in the way, check if we can slimb it
220251
// a normal is just a direction something is facing
@@ -226,12 +257,12 @@ fn handle_movement_actions_for_player(
226257
debug!("MOVEMENT: Climable slope!");
227258
// this is the most important part to make the slope climbing possible.
228259
// instead of trying to go straight, we slide along the ground
229-
player_velocity.0 =
260+
velocity.0 =
230261
world_velocity.reject_from_normalized(normal);
231262

232263
// slope snapping
233264
let ray_down_origin =
234-
player_transform.translation + Vec3::Y * 0.5;
265+
transform.translation + Vec3::Y * 0.5;
235266
let ray_down_direction = Dir3::NEG_Y;
236267
let max_down_distance = 1.0;
237268

@@ -240,21 +271,16 @@ fn handle_movement_actions_for_player(
240271
ray_down_direction,
241272
max_down_distance,
242273
true,
243-
&SpatialQueryFilter::default()
244-
.with_excluded_entities([
245-
player_entity,
246-
*player_camera_entity,
247-
]),
274+
spatial_query_filter,
248275
) {
249276
let hit_down_point = ray_down_origin
250277
+ ray_down_direction * hit_down.distance;
251278
let hit_down_y = hit_down_point.y;
252-
let player_y = player_transform.translation.y;
279+
let player_y = transform.translation.y;
253280
let difference_y = hit_down_y - player_y;
254281
if difference_y.abs() < 0.3 {
255-
info!("Snapping player to slope");
256-
player_velocity.y =
257-
difference_y / time.delta_secs();
282+
info!("Snapping character controller to slope");
283+
velocity.y = difference_y / time.delta_secs();
258284
}
259285
}
260286
} else {
@@ -267,14 +293,14 @@ fn handle_movement_actions_for_player(
267293
// want to climb up
268294
let impulse =
269295
world_velocity.reject_from_normalized(normal);
270-
player_velocity.x = impulse.x;
271-
player_velocity.z = impulse.z
296+
velocity.x = impulse.x;
297+
velocity.z = impulse.z
272298
}
273299
} else {
274300
debug!("MOVEMENT: No obstacle ahead, free movement");
275301
// no obstacle ahead, free movement
276-
player_velocity.x = world_velocity.x;
277-
player_velocity.z = world_velocity.z;
302+
velocity.x = world_velocity.x;
303+
velocity.z = world_velocity.z;
278304
}
279305
}
280306
}
@@ -283,20 +309,11 @@ fn handle_movement_actions_for_player(
283309

284310
/// Updates the [`Grounded`] status for character controllers.
285311
fn update_on_ground(
286-
mut query: Query<(
287-
&ShapeHits,
288-
&Rotation,
289-
&mut Grounded,
290-
&mut LinearVelocity,
291-
)>,
312+
mut query: Query<(&ShapeHits, &mut Grounded, &mut LinearVelocity)>,
292313
) {
293-
for (hits, rotation, mut grounded, mut velocity) in &mut query {
294-
// The character is grounded if the shape caster has a hit with a normal
295-
// that isn't too steep.
296-
let on_ground = hits.iter().any(|hit| {
297-
(rotation * -hit.normal2).angle_between(Vec3::Y).abs()
298-
<= MAX_SLOPE_ANGLE
299-
});
314+
for (hits, mut grounded, mut velocity) in &mut query {
315+
let on_ground = hits.0.len() > 0;
316+
300317
if grounded.0 != on_ground {
301318
grounded.0 = on_ground;
302319
}
@@ -318,15 +335,3 @@ fn apply_gravity_over_time(
318335
}
319336
}
320337
}
321-
322-
fn debug_remove_grounded_from_enemies(
323-
mut commands: Commands,
324-
keyboard_input: Res<ButtonInput<KeyCode>>,
325-
enemy_query: Query<Entity, With<Enemy>>,
326-
) {
327-
if keyboard_input.just_pressed(KeyCode::KeyU) {
328-
for enemy in enemy_query {
329-
commands.entity(enemy).remove::<Grounded>();
330-
}
331-
}
332-
}

src/enemy/ai/systems.rs

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

55
use crate::{
6+
character_controller::{MovementAction, MovementDirection},
67
enemy::{
78
Enemy, ai::EnemyState, shooting::components::EnemyBullet,
89
spawn::AgentEnemyEntityPointer,
@@ -135,12 +136,13 @@ pub fn set_zero_velocity_if_not_chasing(
135136
}
136137

137138
pub fn handle_chasing_enemies(
138-
mut enemy_query: Query<(&Enemy, &mut LinearVelocity)>,
139+
mut enemy_query: Query<(&Enemy, Entity, &mut LinearVelocity)>,
139140
enemy_agents_query: Query<(&Velocity3d, &AgentEnemyEntityPointer)>,
140141
current_in_game_state: Res<State<InGameState>>,
142+
mut movement_action_writer: MessageWriter<MovementAction>,
141143
) {
142144
for (agent_velocity, agent_enemy_entity_pointer) in enemy_agents_query {
143-
let Ok((enemy, mut velocity)) =
145+
let Ok((enemy, entity, mut velocity)) =
144146
enemy_query.get_mut(agent_enemy_entity_pointer.0)
145147
else {
146148
warn!(
@@ -162,7 +164,9 @@ pub fn handle_chasing_enemies(
162164
continue;
163165
}
164166

165-
debug!("Applying agent velocity to actual velocity of enemy");
166-
velocity.0 = agent_velocity.velocity;
167+
movement_action_writer.write(MovementAction {
168+
direction: MovementDirection::Move(agent_velocity.velocity),
169+
character_controller_entity: entity,
170+
});
167171
}
168172
}

src/enemy/spawn/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::{
22
character_controller::{
33
CHARACTER_CAPSULE_LENGTH, CHARACTER_CAPSULE_RADIUS, Grounded,
4+
RUN_VELOCITY, WALK_VELOCITY,
45
},
56
enemy::{
67
animate::ENEMY_MODEL_PATH,

src/main.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
use avian3d::prelude::*;
2-
use bevy::{prelude::*, window::PresentMode};
2+
use bevy::{
3+
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
4+
prelude::*,
5+
window::PresentMode,
6+
};
37
use bevy_hanabi::HanabiPlugin;
48
use bevy_inspector_egui::{
59
bevy_egui::{self, EguiPlugin},
@@ -55,8 +59,8 @@ fn main() {
5559
..default()
5660
}),
5761
);
58-
// app.add_plugins(FrameTimeDiagnosticsPlugin::default());
59-
// app.add_plugins(LogDiagnosticsPlugin::default());
62+
app.add_plugins(FrameTimeDiagnosticsPlugin::default());
63+
app.add_plugins(LogDiagnosticsPlugin::default());
6064

6165
// External plugins
6266
app.add_plugins(PhysicsPlugins::default())

src/nav_mesh_pathfinding/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ fn update_agent_velocity(
8989
}
9090
}
9191

92+
// FIXME: dont need this anymore
9293
fn snap_agent_to_floor(
9394
query: Query<
9495
(Entity, &Transform, &mut LinearVelocity, &ShapeHits),

0 commit comments

Comments
 (0)