105 lines
3.7 KiB
Rust
105 lines
3.7 KiB
Rust
use crate::{GameObject, velocity::Velocity};
|
|
use bevy::prelude::*;
|
|
|
|
use crate::{
|
|
collision::Collider,
|
|
damagable::Damagable,
|
|
ships::{Factions, gun::Gun, player::PlayerMovement},
|
|
};
|
|
|
|
#[derive(Component)]
|
|
pub struct Enemy {
|
|
state: EnemyState,
|
|
return_radius: f32,
|
|
search_arc: f32,
|
|
}
|
|
|
|
#[derive(PartialEq)]
|
|
enum EnemyState {
|
|
Approaching,
|
|
OriginalViolence,
|
|
Distancing,
|
|
}
|
|
|
|
pub fn spawn_enemy(commands: &mut Commands, sprite: Handle<Image>, at: Vec2) {
|
|
commands.spawn((
|
|
Enemy {
|
|
state: EnemyState::Approaching,
|
|
return_radius: 128.0,
|
|
search_arc: f32::to_radians(5.),
|
|
},
|
|
Gun::new(2, f32::to_radians(15.), 0.2),
|
|
Collider::new(8.),
|
|
Velocity::moving(256., f32::to_radians(180.)),
|
|
Sprite::from(sprite),
|
|
Transform::from_xyz(at.x, at.y, 0.),
|
|
Damagable::new(20),
|
|
Factions::EnemyFaction,
|
|
GameObject,
|
|
));
|
|
}
|
|
|
|
pub fn enemy_ai_system(
|
|
player_query: Single<&Transform, (With<PlayerMovement>, Without<Enemy>)>,
|
|
enemies_query: Query<
|
|
(&mut Velocity, &mut Enemy, &mut Gun, &Transform),
|
|
Without<PlayerMovement>,
|
|
>,
|
|
) {
|
|
let player_transform = player_query.into_inner();
|
|
for (mut enemy_velocity, mut enemy, mut gun, enemy_transform) in enemies_query {
|
|
let direction = enemy_transform.rotation * Vec3::X;
|
|
let left_side = enemy_transform.rotation * Vec3::Y;
|
|
let dir_to_player = player_transform.translation - enemy_transform.translation;
|
|
let distance_to_player = enemy_transform
|
|
.translation
|
|
.distance_squared(player_transform.translation);
|
|
match enemy.state {
|
|
EnemyState::Approaching => {
|
|
if direction.angle_between(dir_to_player) <= enemy.search_arc {
|
|
enemy_velocity.rotation_speed = 0.;
|
|
gun.shoot = true;
|
|
enemy.state = EnemyState::OriginalViolence;
|
|
enemy_velocity.linear_speed = enemy_velocity.max_linear_speed / 2.0;
|
|
continue;
|
|
}
|
|
|
|
enemy_velocity.rotation_speed =
|
|
enemy_velocity.max_rotation_speed * (left_side.dot(dir_to_player)).signum();
|
|
}
|
|
EnemyState::OriginalViolence => {
|
|
gun.shoot = true;
|
|
if direction.angle_between(dir_to_player) > enemy.search_arc {
|
|
enemy_velocity.linear_speed = enemy_velocity.max_linear_speed;
|
|
enemy.state = EnemyState::Approaching;
|
|
gun.shoot = false;
|
|
continue;
|
|
}
|
|
if distance_to_player <= enemy.return_radius * enemy.return_radius {
|
|
enemy_velocity.linear_speed = enemy_velocity.max_linear_speed;
|
|
enemy.state = EnemyState::Distancing;
|
|
continue;
|
|
}
|
|
}
|
|
EnemyState::Distancing => {
|
|
if distance_to_player > enemy.return_radius * enemy.return_radius {
|
|
enemy.state = EnemyState::Approaching;
|
|
gun.shoot = false;
|
|
continue;
|
|
}
|
|
if direction.angle_between(dir_to_player) > f32::to_radians(90.) {
|
|
enemy_velocity.rotation_speed = 0.;
|
|
gun.shoot = false;
|
|
continue;
|
|
}
|
|
|
|
let angle_to_left = direction.angle_between(left_side);
|
|
if angle_to_left <= f32::to_radians(90.) {
|
|
enemy_velocity.rotation_speed = -enemy_velocity.max_rotation_speed
|
|
} else {
|
|
enemy_velocity.rotation_speed = enemy_velocity.max_rotation_speed
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|