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, this_ship: ColliderHandle, ) -> Option { 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 = (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); } }