spacorium/src/ships/enemy.rs
2025-11-18 00:21:40 +05:00

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
}
}
}
}
}