2024-01-11 22:28:02 -08:00

85 lines
2.3 KiB
Rust

use cgmath::{Deg, InnerSpace};
use galactica_content::Relationship;
use rapier2d::{dynamics::RigidBodySet, geometry::ColliderHandle};
use std::collections::HashMap;
use super::{
super::{
objects::{PhysSimShip, ShipControls},
util, PhysStepResources,
},
ShipControllerStruct,
};
/// "Point" ship controller.
/// Point and shoot towards the nearest enemy.
#[derive(Debug, Clone)]
pub struct PointShipController {}
impl PointShipController {
/// Create a new ship controller
pub fn new() -> Self {
Self {}
}
}
impl ShipControllerStruct for PointShipController {
fn update_controls(
&mut self,
res: &PhysStepResources,
rigid_bodies: &RigidBodySet,
ships: &HashMap<ColliderHandle, PhysSimShip>,
this_ship: ColliderHandle,
) -> Option<ShipControls> {
let mut controls = ShipControls::new();
let my_ship = ships.get(&this_ship).unwrap();
let this_rigidbody = rigid_bodies.get(my_ship.rigid_body).unwrap();
let my_position = util::rigidbody_position(this_rigidbody);
let my_rotation = util::rigidbody_rotation(this_rigidbody);
let my_angvel = this_rigidbody.angvel();
let my_faction = res.ct.get_faction(my_ship.data.get_faction());
// Iterate all possible targets
let mut hostile_ships = ships
.values()
.filter(
// Target only flying ships we're hostile towards
|s| match my_faction.relationships.get(&s.data.get_faction()).unwrap() {
Relationship::Hostile => s.data.get_state().is_flying(),
_ => false,
},
)
.map(|s| rigid_bodies.get(s.rigid_body).unwrap());
// Find the closest target
let mut closest_enemy_position = match hostile_ships.next() {
Some(c) => util::rigidbody_position(c),
None => return Some(controls), // Do nothing if no targets are available
};
let mut d = (my_position - closest_enemy_position).magnitude();
for r in hostile_ships {
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();
if angle_delta < Deg(0.0) && my_angvel > -0.3 {
controls.right = true;
} else if angle_delta > Deg(0.0) && my_angvel < 0.3 {
controls.left = true;
}
controls.guns = true;
return Some(controls);
}
}