pub fn projectile_system(projectiles: Query<(Ref<Projectile>, Ref<EntityId>, Ref<Timer>, Ref<Velocity>, Ref<Collider>, Ref<Transform>)>, player_query: Query<(Ref<Transform>, Ref<Player>, Ref<Collider>, Ref<Velocity>)>, enemies: Query<(Ref<Transform>, Ref<Enemy>, Ref<Collider>, Ref<Velocity>)>, engine: Ref<Engine>, frame_constants: Ref<FrameConstants>) {
for (projectile, entity_id, timer, velocity, collider, transform) in projectiles.iter() {
if timer.time_remaining <= 0.0 || projectile.number_of_hits >= projectile.max_number_of_hits.unwrap_or(0) {
//TODO: apply on death effects
engine.despawn(*entity_id);
}
let (can_hit_enemies, can_hit_player) = match projectile.valid_targets {
Faction::Enemy => (true, false),
Faction::Player => (false, true),
Faction::All => (true, true),
};
let projectile_mm = Mat4::from_translation(transform.position.extend(0.)).into();
let options = ShapeCastOptions {
max_time_of_impact: frame_constants.delta_time,
..Default::default()
};
if can_hit_enemies {
let collider_radius = match *collider {
Collider::Sphere { radius } => radius,
Collider::Box { size } => (size[0] + size[1]) / 2.0,
Collider::Capsule { radius, height } => (radius + height) / 2.0,
};
let check_range = 2.0 * collider_radius
+ velocity.current_velocity.length() * frame_constants.delta_time * 10.0;
for (enemy_transform, _, enemy_collider, enemy_velocity) in enemies.iter() {
let distance = transform.position.distance_squared(enemy_transform.position);
// Check if enemey is close enoough to even consider
if distance <= check_range * check_range {
let enemy_mm = Mat4::from_translation(enemy_transform.position.extend(0.)).into();
if physics::cast_shapes(
&collider.clone(),
&projectile_mm,
&velocity.current_velocity,
&enemy_collider,
&enemy_mm,
&enemy_velocity.current_velocity,
options).is_some() {
println!("Hit enemy");
engine.despawn(*entity_id);
}
}
}
}
if can_hit_player {
for (player_transform, _, player_collider, player_velocity) in player_query.iter() {
let player_mm = Mat4::from_translation(player_transform.position.extend(0.)).into();
if physics::cast_shapes(
&collider.clone(),
&projectile_mm,
&velocity.current_velocity,
&player_collider,
&player_mm,
&player_velocity.current_velocity,
options,
).is_some() {
println!("Hit player");
engine.despawn(*entity_id);
}
}
}
}
}