use cgmath::{Deg, InnerSpace}; use crate::ShipBehavior; use galactica_content as content; use galactica_physics::{util, Physics, ShipHandle}; pub struct Point { handle: ShipHandle, } impl Point { pub fn new(handle: ShipHandle) -> Box { 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 = (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; } }