use cgmath::{Deg, InnerSpace}; use crate::{ content, inputstatus::InputStatus, physics::{util, Physics, ShipHandle}, }; pub trait ShipBehavior where Self: Send, { fn update_controls( &mut self, physics: &mut Physics, input: &InputStatus, content: &content::Content, ); fn get_handle(&self) -> ShipHandle; } pub struct Dummy { _handle: ShipHandle, } impl Dummy { pub fn new(handle: ShipHandle) -> Box { Box::new(Self { _handle: handle }) } } impl ShipBehavior for Dummy { fn update_controls( &mut self, _physics: &mut Physics, _input: &InputStatus, _content: &content::Content, ) { } fn get_handle(&self) -> ShipHandle { return self._handle; } } pub struct Player { handle: ShipHandle, } impl Player { pub fn new(handle: ShipHandle) -> Box { Box::new(Self { handle }) } } impl ShipBehavior for Player { fn update_controls( &mut self, physics: &mut Physics, input: &InputStatus, _content: &content::Content, ) { let s = physics.get_ship_mut(&self.handle).unwrap(); s.controls.left = input.key_left; s.controls.right = input.key_right; s.controls.guns = input.key_guns; s.controls.thrust = input.key_thrust; } fn get_handle(&self) -> ShipHandle { return self.handle; } } 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, _input: &InputStatus, 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; } }