85 lines
2.3 KiB
Rust
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);
|
|
}
|
|
}
|