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, 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, Without)>, enemies_query: Query< (&mut Velocity, &mut Enemy, &mut Gun, &Transform), Without, >, ) { 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 } } } } }