2024-01-01 12:01:29 -08:00

81 lines
2.1 KiB
Rust

use cgmath::{Deg, InnerSpace};
use crate::ShipBehavior;
use galactica_content as content;
use galactica_physics::{util, Physics, ShipHandle};
/// "Point" ship behavior.
/// Point and shoot towards the nearest enemy.
pub struct Point {
handle: ShipHandle,
}
impl Point {
/// Create a new ship controller
pub fn new(handle: ShipHandle) -> Box<Self> {
Box::new(Self { handle })
}
}
impl ShipBehavior for Point {
fn update_controls(&mut self, physics: &mut Physics, content: &content::Content) {
// Turn off all controls
let s = physics.get_ship_mut(&self.handle).unwrap();
s.controls.left = false;
s.controls.right = false;
s.controls.guns = false;
s.controls.thrust = false;
let (my_s, my_r) = physics.get_ship_body(&self.handle).unwrap();
let my_position = util::rigidbody_position(my_r);
let my_rotation = util::rigidbody_rotation(my_r);
let my_angvel = my_r.angvel();
let my_faction = content.get_faction(my_s.faction);
// Iterate all possible targets
let mut it = physics
.iter_ship_body()
.filter(|(s, _)| match my_faction.relationships[&s.faction] {
content::Relationship::Hostile => true,
_ => false,
})
.map(|(_, r)| r);
// Find the closest target
let mut closest_enemy_position = match it.next() {
Some(c) => util::rigidbody_position(c),
None => return, // Do nothing if no targets are available
};
let mut d = (my_position - closest_enemy_position).magnitude();
for r in it {
let p = util::rigidbody_position(r);
let new_d = (my_position - p).magnitude();
if new_d < d {
d = new_d;
closest_enemy_position = p;
}
}
let angle_delta: Deg<f32> = (my_rotation)
.angle(closest_enemy_position - my_position)
.into();
let s = physics.get_ship_mut(&self.handle).unwrap();
s.controls.left = false;
s.controls.right = false;
if angle_delta < Deg(0.0) && my_angvel > -0.3 {
s.controls.right = true;
} else if angle_delta > Deg(0.0) && my_angvel < 0.3 {
s.controls.left = true;
}
s.controls.guns = true;
s.controls.thrust = false;
}
fn get_handle(&self) -> ShipHandle {
return self.handle;
}
}