Plantes and asteroids are now recognized as obstacles for ships.master
@@ -323,6 +323,20 @@ where | |||
Vector3::new(mul!(2, 0), mul!(2, 1), mul!(2, 2)), | |||
) | |||
} | |||
#[inline] | |||
pub fn transform<V: Into<Vector2<T>>>(&self, v: V) -> Vector2<T> { | |||
let m = self; | |||
let v = V::into(v); | |||
macro_rules! mul { | |||
($i:tt) => { | |||
m[0][$i] * v[0] + m[1][$i] * v[1] + m[2][$i] * T::one() | |||
}; | |||
} | |||
Vector2::new(mul!(0), mul!(1)) | |||
} | |||
} | |||
impl<T> Matrix3<T> | |||
@@ -5,7 +5,7 @@ use glc::vector::Vector4f; | |||
pub const UNIFORM_BUFFER_INDEX_CAMERA: gl::GLuint = 0; | |||
pub const UNIFORM_BUFFER_INDEX_UNIFORM: gl::GLuint = 1; | |||
pub const SHIP_SIZE: f32 = 15.0; | |||
pub const SHIP_SIZE: f32 = 25.0; | |||
pub const PLANET_SIZE: f32 = 200.0; | |||
pub const ASTEROID_SIZE: f32 = 100.0; | |||
@@ -1,5 +1,8 @@ | |||
use glc::vector::Vector4f; | |||
use space_crush_common::components::{Position, Ship, Velocity}; | |||
use space_crush_common::{ | |||
components::{Position, Ship, ShipObstacle, Velocity}, | |||
continue_if_none, | |||
}; | |||
use specs::{prelude::*, ReadStorage, System, World, WriteExpect}; | |||
use crate::resources::Geometry; | |||
@@ -10,9 +13,9 @@ pub struct Ships; | |||
#[derive(SystemData)] | |||
pub struct ShipsData<'a> { | |||
geometry: WriteExpect<'a, Geometry>, | |||
position: ReadStorage<'a, Position>, | |||
velocity: ReadStorage<'a, Velocity>, | |||
ship: ReadStorage<'a, Ship>, | |||
positions: ReadStorage<'a, Position>, | |||
velocities: ReadStorage<'a, Velocity>, | |||
ships: ReadStorage<'a, Ship>, | |||
} | |||
impl<'a> System<'a> for Ships { | |||
@@ -21,24 +24,35 @@ impl<'a> System<'a> for Ships { | |||
fn run(&mut self, data: Self::SystemData) { | |||
let ShipsData { | |||
mut geometry, | |||
position, | |||
velocity, | |||
ship, | |||
positions, | |||
velocities, | |||
ships, | |||
} = data; | |||
gl::enable(gl::BLEND); | |||
gl::blend_func(gl::SRC_ALPHA, gl::ONE); | |||
for (p, v, s) in (&position, &velocity, &ship).join() { | |||
for (position, velocity, ship) in (&positions, &velocities, &ships).join() { | |||
let ship_pos = position.pos; | |||
geometry.render_lines( | |||
Vector4f::new(0.0, 0.0, 1.0, 0.2), | |||
&[p.pos, p.pos + v.dir * v.speed], | |||
&[ship_pos, ship_pos + velocity.dir * velocity.speed], | |||
); | |||
geometry.render_lines( | |||
Vector4f::new(1.0, 0.0, 0.0, 0.2), | |||
&[p.pos, p.pos + s.target_dir * 100.0], | |||
&[ship_pos, ship_pos + ship.target_dir * 100.0], | |||
); | |||
geometry.render_lines( | |||
Vector4f::new(1.0, 1.0, 1.0, 0.2), | |||
&[ship_pos, ship.target_pos], | |||
); | |||
geometry.render_lines(Vector4f::new(1.0, 1.0, 1.0, 0.2), &[p.pos, s.target_pos]); | |||
if let ShipObstacle::Known(obstacle) = ship.obstacle { | |||
let obstacle_pos = continue_if_none!(positions.get(obstacle)).pos; | |||
geometry.render_lines(Vector4f::new(0.0, 1.0, 0.0, 0.2), &[ship_pos, obstacle_pos]); | |||
} | |||
} | |||
gl::disable(gl::BLEND); | |||
@@ -7,6 +7,7 @@ pub mod render; | |||
pub mod resources; | |||
pub mod systems; | |||
use glc::matrix::Matrix4f; | |||
use specs::{Dispatcher, DispatcherBuilder, Entity, World}; | |||
pub use error::Error; | |||
@@ -30,12 +31,14 @@ impl<'a, 'b> App<'a, 'b> { | |||
let events = Events::new(world)?; | |||
let window = Window::new(events.handle(), &config)?; | |||
let camera = Camera::new()?; | |||
let mut camera = Camera::new()?; | |||
let uniform = Uniform::new()?; | |||
let geometry = Geometry::new(world)?; | |||
let input_state = InputState::default(); | |||
let player_state = PlayerState::new(player_id); | |||
camera.update(Matrix4f::scale(0.25))?; | |||
world.insert(config); | |||
world.insert(camera); | |||
world.insert(uniform); | |||
@@ -60,8 +60,8 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
use space_crush_app::components::FleetInfo; | |||
use space_crush_common::{ | |||
components::{ | |||
Asteroid, AsteroidType, Fleet, FleetOwned, Planet, Player, PlayerOwned, Position, | |||
Shape, Ship, ShipType, Velocity, | |||
Asteroid, AsteroidType, Fleet, FleetOwned, Obstacle, Planet, Player, PlayerOwned, | |||
Position, Shape, Ship, ShipType, Velocity, | |||
}, | |||
misc::{PersistWorld, Persistence}, | |||
}; | |||
@@ -79,88 +79,80 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
) | |||
.unwrap(); | |||
let planet = world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(PlayerOwned { owner: player_id }) | |||
.with(Position { | |||
pos: Vector2f::default(), | |||
shape: Shape::Circle(250.0), | |||
let planets = (0..3) | |||
.map(|i| { | |||
let x = 2000.0 * (i as f32 - 1.0); | |||
let y = 0.0; | |||
world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(PlayerOwned { owner: player_id }) | |||
.with(Position { | |||
pos: Vector2f::new(x, y), | |||
shape: Shape::Circle(250.0), | |||
}) | |||
.with(Fleet { | |||
orbit_min: 325.0, | |||
orbit_max: 425.0, | |||
}) | |||
.with(FleetInfo::default()) | |||
.with(Obstacle {}) | |||
.with(Planet {}) | |||
.build() | |||
}) | |||
.with(Fleet { | |||
orbit_min: 325.0, | |||
orbit_max: 425.0, | |||
}) | |||
.with(FleetInfo::default()) | |||
.with(Planet {}) | |||
.build(); | |||
.collect::<Vec<_>>(); | |||
world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(Position { | |||
pos: Vector2f::new(2000.0, 0.0), | |||
shape: Shape::Circle(250.0), | |||
}) | |||
.with(Fleet { | |||
orbit_min: 325.0, | |||
orbit_max: 425.0, | |||
}) | |||
.with(FleetInfo::default()) | |||
.with(Planet {}) | |||
.build(); | |||
for i in 0..4 { | |||
let i_x: isize = if i & 1 == 0 { -1 } else { 1 }; | |||
let i_y: isize = if i & 2 == 0 { -1 } else { 1 }; | |||
world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(Position { | |||
pos: Vector2f::new(1000.0, -1000.0), | |||
shape: Shape::Circle(100.0), | |||
}) | |||
.with(Fleet { | |||
orbit_min: 125.0, | |||
orbit_max: 175.0, | |||
}) | |||
.with(FleetInfo::default()) | |||
.with(Asteroid { | |||
type_: AsteroidType::Metal, | |||
}) | |||
.build(); | |||
let x = 1000.0 * i_x as f32; | |||
let y = 1000.0 * i_y as f32; | |||
world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(Position { | |||
pos: Vector2f::new(1000.0, 1000.0), | |||
shape: Shape::Circle(100.0), | |||
}) | |||
.with(Fleet { | |||
orbit_min: 125.0, | |||
orbit_max: 175.0, | |||
}) | |||
.with(FleetInfo::default()) | |||
.with(Asteroid { | |||
type_: AsteroidType::Crystal, | |||
}) | |||
.build(); | |||
world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(Position { | |||
pos: Vector2f::new(x, y), | |||
shape: Shape::Circle(100.0), | |||
}) | |||
.with(Fleet { | |||
orbit_min: 125.0, | |||
orbit_max: 175.0, | |||
}) | |||
.with(FleetInfo::default()) | |||
.with(Obstacle {}) | |||
.with(Asteroid { | |||
type_: match i_x * i_y { | |||
-1 => AsteroidType::Metal, | |||
1 => AsteroidType::Crystal, | |||
_ => unreachable!(), | |||
}, | |||
}) | |||
.build(); | |||
} | |||
for i in 0..999 { | |||
let r = 325.0 + 100.0 * random::<f32>(); | |||
let a = Angle::Deg(360.0 * random::<f32>()); | |||
let x = r * a.cos(); | |||
let y = r * a.sin(); | |||
for i in 0..30 { | |||
world | |||
.create_entity() | |||
.marked::<<PersistWorld as Persistence>::Marker>() | |||
.with(PlayerOwned { owner: player_id }) | |||
.with(Position { | |||
pos: Vector2f::new( | |||
500.0 * random::<f32>() - 250.0, | |||
500.0 * random::<f32>() - 250.0, | |||
), | |||
pos: Vector2f::new(x, y), | |||
shape: Shape::Dot, | |||
}) | |||
.with(Velocity { | |||
dir: Vector2f::new(random::<f32>() - 0.5, random::<f32>() - 0.5).normalize(), | |||
speed: 100.0, | |||
}) | |||
.with(FleetOwned { owner: planet }) | |||
.with(FleetOwned { owner: planets[1] }) | |||
.with(Ship { | |||
type_: match i % 3 { | |||
0 => ShipType::Fighter, | |||
@@ -171,6 +163,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
agility: Angle::Deg(360.0), | |||
target_pos: Default::default(), | |||
target_dir: Default::default(), | |||
obstacle: Default::default(), | |||
}) | |||
.build(); | |||
} | |||
@@ -267,7 +267,7 @@ impl FleetSelect { | |||
self.marker = d.camera.view_to_world(self.mouse_pos) - position.pos; | |||
self.zoom = d.camera.view().axis_x.as_vec3().length(); | |||
self.shape_size = position.shape.radius().unwrap_or(0.0); | |||
self.shape_size = position.shape.radius(); | |||
self.ring0 = self.shape_size + FLEET_SELECT_OFFSET / self.zoom; | |||
self.ring1 = self.ring0 + FLEET_SELECT_WIDTH / self.zoom; | |||
@@ -1,5 +1,6 @@ | |||
mod asteroid; | |||
mod fleet; | |||
mod obstacle; | |||
mod planet; | |||
mod player; | |||
mod position; | |||
@@ -8,8 +9,9 @@ mod velocity; | |||
pub use asteroid::{Asteroid, Type as AsteroidType}; | |||
pub use fleet::{Fleet, Owned as FleetOwned}; | |||
pub use obstacle::Obstacle; | |||
pub use planet::Planet; | |||
pub use player::{Owned as PlayerOwned, Player}; | |||
pub use position::{Position, Shape}; | |||
pub use ship::{Count as ShipCount, Ship, Type as ShipType}; | |||
pub use ship::{Count as ShipCount, Obstacle as ShipObstacle, Ship, Type as ShipType}; | |||
pub use velocity::Velocity; |
@@ -0,0 +1,9 @@ | |||
use serde::{Deserialize, Serialize}; | |||
use specs::{Component, NullStorage}; | |||
#[derive(Clone, Debug, Default, Serialize, Deserialize)] | |||
pub struct Obstacle {} | |||
impl Component for Obstacle { | |||
type Storage = NullStorage<Self>; | |||
} |
@@ -19,10 +19,10 @@ impl Component for Position { | |||
} | |||
impl Shape { | |||
pub fn radius(&self) -> Option<f32> { | |||
pub fn radius(&self) -> f32 { | |||
match self { | |||
Self::Dot => Some(0.0), | |||
Self::Circle(r) => Some(*r), | |||
Self::Dot => 0.0, | |||
Self::Circle(r) => *r, | |||
} | |||
} | |||
@@ -3,7 +3,7 @@ use std::ops::{Index, IndexMut, Mul}; | |||
use glc::{matrix::Angle, vector::Vector2f}; | |||
use serde::{Deserialize, Serialize}; | |||
use specs::{Component, VecStorage}; | |||
use specs::{Component, Entity, VecStorage}; | |||
#[derive(Clone, Debug, Serialize, Deserialize)] | |||
pub struct Ship { | |||
@@ -11,6 +11,15 @@ pub struct Ship { | |||
pub agility: Angle<f32>, | |||
pub target_pos: Vector2f, | |||
pub target_dir: Vector2f, | |||
#[serde(skip)] | |||
pub obstacle: Obstacle, | |||
} | |||
#[derive(Copy, Clone, Debug, PartialEq, Eq)] | |||
pub enum Obstacle { | |||
Known(Entity), | |||
Search, | |||
Done, | |||
} | |||
#[derive(Copy, Clone, Debug, Default)] | |||
@@ -31,6 +40,12 @@ impl Component for Ship { | |||
type Storage = VecStorage<Self>; | |||
} | |||
impl Default for Obstacle { | |||
fn default() -> Self { | |||
Self::Search | |||
} | |||
} | |||
impl Count { | |||
pub fn all() -> Self { | |||
Self { | |||
@@ -4,10 +4,10 @@ use glc::{matrix::Angle, vector::Vector2f}; | |||
pub const SHIP_ORBIT_DISTANCE_MAX: f32 = 1.10; | |||
/// Minimum angle between old and new target position in orbit | |||
pub const SHIP_ORBIT_ANGLE_DELTA_MIN: Angle<f32> = Angle::Deg(7000.0); | |||
pub const SHIP_ORBIT_ANGLE_DELTA_MIN: Angle<f32> = Angle::Deg(5000.0); | |||
/// Random angle between old and new target position in orbit | |||
pub const SHIP_ORBIT_ANGLE_DELTA_RND: Angle<f32> = Angle::Deg(4000.0); | |||
pub const SHIP_ORBIT_ANGLE_DELTA_RND: Angle<f32> = Angle::Deg(5000.0); | |||
/// Agility of ships inside orbit | |||
pub const SHIP_ORBIT_AGILITY: Angle<f32> = Angle::Deg(90.0); | |||
@@ -17,3 +17,13 @@ macro_rules! break_if_none { | |||
} | |||
}; | |||
} | |||
#[macro_export] | |||
macro_rules! continue_if_none { | |||
($value:expr) => { | |||
match $value { | |||
Some(value) => value, | |||
None => continue, | |||
} | |||
}; | |||
} |
@@ -1,5 +1,15 @@ | |||
#[derive(Default)] | |||
pub struct Global { | |||
pub fps: usize, | |||
pub delta: f32, | |||
pub world_speed: f32, | |||
} | |||
impl Default for Global { | |||
fn default() -> Self { | |||
Self { | |||
fps: 0, | |||
delta: 0.0, | |||
world_speed: 1.0, | |||
} | |||
} | |||
} |
@@ -30,7 +30,9 @@ impl<'a> System<'a> for Movement { | |||
(&mut position, &velocity) | |||
.par_join() | |||
.for_each(|(position, velocity)| { | |||
position.pos = position.pos + velocity.dir * velocity.speed * global.delta; | |||
let delta = global.delta * global.world_speed; | |||
position.pos = position.pos + velocity.dir * velocity.speed * delta; | |||
}); | |||
} | |||
} |
@@ -1,16 +1,17 @@ | |||
use glc::{ | |||
math::{linear_step, sqr}, | |||
matrix::Matrix3f, | |||
vector::{Vector2f, Vector3f}, | |||
vector::{Angle, Vector2f, Vector3f}, | |||
}; | |||
use rand::random; | |||
use shrev::ReaderId; | |||
use specs::{ | |||
hibitset::BitSet, prelude::*, world::Index, ParJoin, Read, ReadStorage, System, WriteStorage, | |||
hibitset::BitSet, prelude::*, world::Index, Entities, ParJoin, Read, ReadStorage, System, | |||
WriteStorage, | |||
}; | |||
use crate::{ | |||
components::{Fleet, FleetOwned, Position, Ship, Velocity}, | |||
components::{Fleet, FleetOwned, Obstacle, Position, Ship, ShipObstacle, Velocity}, | |||
constants::{ | |||
SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND, | |||
SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X, | |||
@@ -28,16 +29,20 @@ pub struct Ships { | |||
#[derive(SystemData)] | |||
pub struct ShipsData<'a> { | |||
global: Read<'a, Global>, | |||
entities: Entities<'a>, | |||
ships: WriteStorage<'a, Ship>, | |||
velocities: WriteStorage<'a, Velocity>, | |||
fleet_owned: ReadStorage<'a, FleetOwned>, | |||
positions: ReadStorage<'a, Position>, | |||
obstacles: ReadStorage<'a, Obstacle>, | |||
fleets: ReadStorage<'a, Fleet>, | |||
} | |||
struct Processor<'a> { | |||
need_update: &'a BitSet, | |||
entities: &'a Entities<'a>, | |||
positions: &'a ReadStorage<'a, Position>, | |||
obstacles: &'a ReadStorage<'a, Obstacle>, | |||
fleets: &'a ReadStorage<'a, Fleet>, | |||
delta: f32, | |||
} | |||
@@ -85,10 +90,12 @@ impl<'a> System<'a> for Ships { | |||
fn run(&mut self, data: Self::SystemData) { | |||
let ShipsData { | |||
global, | |||
entities, | |||
mut ships, | |||
mut velocities, | |||
fleet_owned, | |||
positions, | |||
obstacles, | |||
fleets, | |||
} = data; | |||
@@ -97,18 +104,22 @@ impl<'a> System<'a> for Ships { | |||
/* update ships */ | |||
let processor = Processor { | |||
need_update: &self.need_update, | |||
entities: &entities, | |||
positions: &positions, | |||
obstacles: &obstacles, | |||
fleets: &fleets, | |||
delta: global.delta, | |||
delta: global.delta * global.world_speed, | |||
}; | |||
( | |||
let data = ( | |||
positions.mask(), | |||
&mut ships, | |||
&mut velocities, | |||
&positions, | |||
&fleet_owned, | |||
) | |||
.par_join() | |||
); | |||
data.par_join() | |||
.for_each(|(id, ship, velocity, position, fleet_owned)| { | |||
processor.progress_ship(id, ship, velocity, position, fleet_owned); | |||
}); | |||
@@ -132,8 +143,8 @@ impl Processor<'_> { | |||
let target_dir = ship.target_dir; | |||
let orbit_to_target = target_pos - orbit_pos; | |||
let orbit_to_ship = position.pos - orbit_pos; | |||
let ship_to_target = target_pos - position.pos; | |||
let orbit_to_ship = ship_pos - orbit_pos; | |||
let mut ship_to_target = target_pos - position.pos; | |||
let r_ship = orbit_to_ship.length_sqr(); | |||
let r_target = orbit_to_target.length_sqr(); | |||
@@ -160,27 +171,110 @@ impl Processor<'_> { | |||
-1.0 | |||
}; | |||
let add = SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random(); | |||
let angle = orbit_to_ship.angle2(&VECTOR_2F_POS_X); | |||
let angle = angle | |||
+ (SHIP_ORBIT_ANGLE_DELTA_MIN + SHIP_ORBIT_ANGLE_DELTA_RND * random()) * dir | |||
/ fleet.orbit_max; | |||
let radius = | |||
fleet.orbit_min + (fleet.orbit_max - fleet.orbit_min) * random::<f32>(); | |||
let angle = angle + add * dir / orbit_max; | |||
let radius = orbit_min + (orbit_max - orbit_min) * random::<f32>(); | |||
Vector2f::new( | |||
orbit_pos.x + radius * angle.cos(), | |||
orbit_pos.y + radius * angle.sin(), | |||
) | |||
} else { | |||
ship.obstacle = ShipObstacle::Search; | |||
orbit_pos | |||
}; | |||
ship.target_pos = target_pos; | |||
ship.target_dir = (target_pos - ship_pos).normalize(); | |||
ship_to_target = target_pos - ship_pos; | |||
} | |||
/* check if obstacle is still valid */ | |||
if ship_in_orbit { | |||
ship.obstacle = ShipObstacle::Done; | |||
} else if let ShipObstacle::Known(obstacle) = ship.obstacle { | |||
if let Some(position) = self.positions.get(obstacle) { | |||
let obstacle_fleet = self.fleets.get(obstacle).unwrap(); | |||
let obstacle_pos = position.pos; | |||
let ship_to_obstacle = obstacle_pos - ship_pos; | |||
let obstacle_angle = ship_to_target | |||
.angle2(&ship_to_obstacle) | |||
.into_deg() | |||
.into_inner() | |||
.abs(); | |||
let orbit_sqr = obstacle_fleet.orbit_max * obstacle_fleet.orbit_max; | |||
if (obstacle_angle > 90.0 && ship_to_obstacle.length_sqr() > orbit_sqr) | |||
|| obstacle_angle > 170.0 | |||
{ | |||
ship.obstacle = ShipObstacle::Search; | |||
} | |||
} else { | |||
ship.obstacle = ShipObstacle::Search; | |||
} | |||
} | |||
/* find obstacle */ | |||
if !ship_in_orbit && ship.obstacle == ShipObstacle::Search { | |||
let mut dist_sqr = f32::MAX; | |||
for (e, position, _) in (self.entities, self.positions, self.obstacles).join() { | |||
let obstacle_pos = position.pos; | |||
let ship_to_obstacle = obstacle_pos - ship_pos; | |||
if ship_to_target * ship_to_obstacle < 0.0 { | |||
continue; // obstacle is behind the ship | |||
} | |||
let len_sqr = ship_to_obstacle.length_sqr(); | |||
if len_sqr < dist_sqr { | |||
dist_sqr = len_sqr; | |||
ship.obstacle = ShipObstacle::Known(e); | |||
} | |||
} | |||
if let ShipObstacle::Known(e) = ship.obstacle { | |||
if e == fleet_owned.owner { | |||
ship.obstacle = ShipObstacle::Done; | |||
} | |||
} | |||
} | |||
/* check the obstacle */ | |||
let mut expected_dir = ship_to_target; | |||
if let ShipObstacle::Known(obstacle) = ship.obstacle { | |||
let obstacle_pos = self.positions.get(obstacle).unwrap(); | |||
let obstacle_fleet = self.fleets.get(obstacle).unwrap(); | |||
let ship_to_obstacle = obstacle_pos.pos - ship_pos; | |||
let orbit = ship_to_obstacle.length(); | |||
if orbit < obstacle_fleet.orbit_max { | |||
let orbit_min = obstacle_fleet.orbit_min; | |||
let orbit_max = obstacle_fleet.orbit_max; | |||
let mut tangent = Vector2f::new(-ship_to_obstacle.y, ship_to_obstacle.x); | |||
let radius = obstacle_pos.shape.radius(); | |||
let mut adjust_low = linear_step(orbit_min, radius, orbit); | |||
let adjust_high = 1.0 - linear_step(orbit_max, orbit_min, orbit); | |||
if ship_to_target * tangent < 0.0 { | |||
tangent = -tangent; | |||
} else { | |||
adjust_low = -adjust_low; | |||
} | |||
let a_low = Angle::Deg(45.0); | |||
let a_high = tangent.angle2(&ship_to_target); | |||
let mat = Matrix3f::rotate(a_low * adjust_low + a_high * adjust_high); | |||
expected_dir = mat.transform(tangent); | |||
} | |||
} | |||
/* update ship direction */ | |||
let angle = ship_to_target.angle2(&velocity.dir); | |||
let angle = expected_dir.angle2(&velocity.dir); | |||
if angle.into_inner().abs() > 0.0001 { | |||
let dir = angle.into_inner() / angle.abs().into_inner(); | |||
let agility = if ship_in_orbit { | |||
@@ -190,14 +284,7 @@ impl Processor<'_> { | |||
}; | |||
let rot_speed = agility * linear_step(0.0, 45.0, angle.abs().into_deg().into_inner()); | |||
let m = Matrix3f::new( | |||
Vector3f::new(velocity.dir.y, -velocity.dir.x, 0.0), | |||
Vector3f::new(velocity.dir.x, velocity.dir.y, 0.0), | |||
Vector3f::new(0.0, 0.0, 1.0), | |||
); | |||
let m = m * Matrix3f::rotate(rot_speed * -dir * self.delta); | |||
velocity.dir = Vector2f::new(m.axis_y.x, m.axis_y.y); | |||
velocity.dir = Matrix3f::rotate(rot_speed * -dir * self.delta).transform(velocity.dir); | |||
} | |||
} | |||
} |