From abb0198a2baba5ea20de0b8ace2d5069d1aa39fc Mon Sep 17 00:00:00 2001 From: Rendo Date: Mon, 17 Nov 2025 16:42:15 +0500 Subject: [PATCH] Enemy AI --- src/ships/enemy.rs | 91 ++++++++++++++++++++++++++++++++++++++++++--- src/ships/mod.rs | 1 + src/ships/player.rs | 6 +-- 3 files changed, 88 insertions(+), 10 deletions(-) diff --git a/src/ships/enemy.rs b/src/ships/enemy.rs index c4a5788..c5cf156 100644 --- a/src/ships/enemy.rs +++ b/src/ships/enemy.rs @@ -3,22 +3,101 @@ use bevy::prelude::*; use crate::{ collision::Collider, damagable::Damagable, - ships::{Factions, gun::Gun}, - velocity::Velocity, + ships::{Factions, gun::Gun, player::PlayerMovement}, + velocity::{self, Velocity}, }; #[derive(Component)] -pub struct Enemy; +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, - Gun::new(5, f32::to_radians(15.), 0.2), + 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::stopped(500., f32::to_radians(360.)), + Velocity::moving(256., f32::to_radians(360.)), Sprite::from(sprite), Transform::from_xyz(at.x, at.y, 0.), Damagable::new(100), Factions::EnemyFaction, )); } + +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; + gun.shoot = false; + continue; + } + } + EnemyState::Distancing => { + if distance_to_player > enemy.return_radius * enemy.return_radius { + enemy.state = EnemyState::Approaching; + continue; + } + if direction.angle_between(dir_to_player) > f32::to_radians(90.) { + enemy_velocity.rotation_speed = 0.; + 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 + } + } + } + } +} diff --git a/src/ships/mod.rs b/src/ships/mod.rs index f4adc6e..96edd2e 100644 --- a/src/ships/mod.rs +++ b/src/ships/mod.rs @@ -39,6 +39,7 @@ impl Plugin for ShipsPlugin { player::player_movement_system.run_if(in_state(GameState::Game)), player::player_shooting_system.run_if(in_state(GameState::Game)), gun::gun_shooting_system.run_if(in_state(GameState::Game)), + enemy::enemy_ai_system, ), ); } diff --git a/src/ships/player.rs b/src/ships/player.rs index c01e9c6..7f6655b 100644 --- a/src/ships/player.rs +++ b/src/ships/player.rs @@ -1,12 +1,10 @@ use crate::{ collision::Collider, damagable::Damagable, - projectile::ProjectileSprite, - ships::{Factions, gun::Gun}, + ships::{Factions, enemy::Enemy, gun::Gun}, velocity::Velocity, }; use bevy::prelude::*; -use rand::random_range; #[derive(Component)] #[require(Velocity)] @@ -92,7 +90,7 @@ pub(super) fn player_movement_system( pub fn player_shooting_system( keyboard_input: Res>, - query: Single<&mut Gun, With>, + query: Single<&mut Gun, (With, Without)>, ) { let mut gun = query.into_inner(); gun.shoot = keyboard_input.pressed(KeyCode::Space);