Автор | SHA1 | Сообщение | Дата |
---|---|---|---|
Bergmann89 | 9fb731b856 |
Implemented ship obstacles
Plantes and asteroids are now recognized as obstacles for ships. |
3 лет назад |
Bergmann89 | 5a52cc04c4 | Remove unneded system data from ships system | 3 лет назад |
@@ -323,6 +323,20 @@ where | |||||
Vector3::new(mul!(2, 0), mul!(2, 1), mul!(2, 2)), | 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> | 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_CAMERA: gl::GLuint = 0; | ||||
pub const UNIFORM_BUFFER_INDEX_UNIFORM: gl::GLuint = 1; | 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 PLANET_SIZE: f32 = 200.0; | ||||
pub const ASTEROID_SIZE: f32 = 100.0; | pub const ASTEROID_SIZE: f32 = 100.0; | ||||
@@ -1,5 +1,8 @@ | |||||
use glc::vector::Vector4f; | 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 specs::{prelude::*, ReadStorage, System, World, WriteExpect}; | ||||
use crate::resources::Geometry; | use crate::resources::Geometry; | ||||
@@ -10,9 +13,9 @@ pub struct Ships; | |||||
#[derive(SystemData)] | #[derive(SystemData)] | ||||
pub struct ShipsData<'a> { | pub struct ShipsData<'a> { | ||||
geometry: WriteExpect<'a, Geometry>, | 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 { | impl<'a> System<'a> for Ships { | ||||
@@ -21,24 +24,35 @@ impl<'a> System<'a> for Ships { | |||||
fn run(&mut self, data: Self::SystemData) { | fn run(&mut self, data: Self::SystemData) { | ||||
let ShipsData { | let ShipsData { | ||||
mut geometry, | mut geometry, | ||||
position, | |||||
velocity, | |||||
ship, | |||||
positions, | |||||
velocities, | |||||
ships, | |||||
} = data; | } = data; | ||||
gl::enable(gl::BLEND); | gl::enable(gl::BLEND); | ||||
gl::blend_func(gl::SRC_ALPHA, gl::ONE); | 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( | geometry.render_lines( | ||||
Vector4f::new(0.0, 0.0, 1.0, 0.2), | 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( | geometry.render_lines( | ||||
Vector4f::new(1.0, 0.0, 0.0, 0.2), | 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); | gl::disable(gl::BLEND); | ||||
@@ -7,6 +7,7 @@ pub mod render; | |||||
pub mod resources; | pub mod resources; | ||||
pub mod systems; | pub mod systems; | ||||
use glc::matrix::Matrix4f; | |||||
use specs::{Dispatcher, DispatcherBuilder, Entity, World}; | use specs::{Dispatcher, DispatcherBuilder, Entity, World}; | ||||
pub use error::Error; | pub use error::Error; | ||||
@@ -30,12 +31,14 @@ impl<'a, 'b> App<'a, 'b> { | |||||
let events = Events::new(world)?; | let events = Events::new(world)?; | ||||
let window = Window::new(events.handle(), &config)?; | let window = Window::new(events.handle(), &config)?; | ||||
let camera = Camera::new()?; | |||||
let mut camera = Camera::new()?; | |||||
let uniform = Uniform::new()?; | let uniform = Uniform::new()?; | ||||
let geometry = Geometry::new(world)?; | let geometry = Geometry::new(world)?; | ||||
let input_state = InputState::default(); | let input_state = InputState::default(); | ||||
let player_state = PlayerState::new(player_id); | let player_state = PlayerState::new(player_id); | ||||
camera.update(Matrix4f::scale(0.25))?; | |||||
world.insert(config); | world.insert(config); | ||||
world.insert(camera); | world.insert(camera); | ||||
world.insert(uniform); | 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_app::components::FleetInfo; | ||||
use space_crush_common::{ | use space_crush_common::{ | ||||
components::{ | 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}, | misc::{PersistWorld, Persistence}, | ||||
}; | }; | ||||
@@ -79,88 +79,80 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
) | ) | ||||
.unwrap(); | .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 | world | ||||
.create_entity() | .create_entity() | ||||
.marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
.with(PlayerOwned { owner: player_id }) | .with(PlayerOwned { owner: player_id }) | ||||
.with(Position { | .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, | shape: Shape::Dot, | ||||
}) | }) | ||||
.with(Velocity { | .with(Velocity { | ||||
dir: Vector2f::new(random::<f32>() - 0.5, random::<f32>() - 0.5).normalize(), | dir: Vector2f::new(random::<f32>() - 0.5, random::<f32>() - 0.5).normalize(), | ||||
speed: 100.0, | speed: 100.0, | ||||
}) | }) | ||||
.with(FleetOwned { owner: planet }) | |||||
.with(FleetOwned { owner: planets[1] }) | |||||
.with(Ship { | .with(Ship { | ||||
type_: match i % 3 { | type_: match i % 3 { | ||||
0 => ShipType::Fighter, | 0 => ShipType::Fighter, | ||||
@@ -171,6 +163,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
agility: Angle::Deg(360.0), | agility: Angle::Deg(360.0), | ||||
target_pos: Default::default(), | target_pos: Default::default(), | ||||
target_dir: Default::default(), | target_dir: Default::default(), | ||||
obstacle: Default::default(), | |||||
}) | }) | ||||
.build(); | .build(); | ||||
} | } | ||||
@@ -267,7 +267,7 @@ impl FleetSelect { | |||||
self.marker = d.camera.view_to_world(self.mouse_pos) - position.pos; | self.marker = d.camera.view_to_world(self.mouse_pos) - position.pos; | ||||
self.zoom = d.camera.view().axis_x.as_vec3().length(); | 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.ring0 = self.shape_size + FLEET_SELECT_OFFSET / self.zoom; | ||||
self.ring1 = self.ring0 + FLEET_SELECT_WIDTH / self.zoom; | self.ring1 = self.ring0 + FLEET_SELECT_WIDTH / self.zoom; | ||||
@@ -1,5 +1,6 @@ | |||||
mod asteroid; | mod asteroid; | ||||
mod fleet; | mod fleet; | ||||
mod obstacle; | |||||
mod planet; | mod planet; | ||||
mod player; | mod player; | ||||
mod position; | mod position; | ||||
@@ -8,8 +9,9 @@ mod velocity; | |||||
pub use asteroid::{Asteroid, Type as AsteroidType}; | pub use asteroid::{Asteroid, Type as AsteroidType}; | ||||
pub use fleet::{Fleet, Owned as FleetOwned}; | pub use fleet::{Fleet, Owned as FleetOwned}; | ||||
pub use obstacle::Obstacle; | |||||
pub use planet::Planet; | pub use planet::Planet; | ||||
pub use player::{Owned as PlayerOwned, Player}; | pub use player::{Owned as PlayerOwned, Player}; | ||||
pub use position::{Position, Shape}; | 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; | 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 { | impl Shape { | ||||
pub fn radius(&self) -> Option<f32> { | |||||
pub fn radius(&self) -> f32 { | |||||
match self { | 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 glc::{matrix::Angle, vector::Vector2f}; | ||||
use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||
use specs::{Component, VecStorage}; | |||||
use specs::{Component, Entity, VecStorage}; | |||||
#[derive(Clone, Debug, Serialize, Deserialize)] | #[derive(Clone, Debug, Serialize, Deserialize)] | ||||
pub struct Ship { | pub struct Ship { | ||||
@@ -11,6 +11,15 @@ pub struct Ship { | |||||
pub agility: Angle<f32>, | pub agility: Angle<f32>, | ||||
pub target_pos: Vector2f, | pub target_pos: Vector2f, | ||||
pub target_dir: 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)] | #[derive(Copy, Clone, Debug, Default)] | ||||
@@ -31,6 +40,12 @@ impl Component for Ship { | |||||
type Storage = VecStorage<Self>; | type Storage = VecStorage<Self>; | ||||
} | } | ||||
impl Default for Obstacle { | |||||
fn default() -> Self { | |||||
Self::Search | |||||
} | |||||
} | |||||
impl Count { | impl Count { | ||||
pub fn all() -> Self { | pub fn all() -> Self { | ||||
Self { | Self { | ||||
@@ -4,10 +4,10 @@ use glc::{matrix::Angle, vector::Vector2f}; | |||||
pub const SHIP_ORBIT_DISTANCE_MAX: f32 = 1.10; | pub const SHIP_ORBIT_DISTANCE_MAX: f32 = 1.10; | ||||
/// Minimum angle between old and new target position in orbit | /// 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 | /// 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 | /// Agility of ships inside orbit | ||||
pub const SHIP_ORBIT_AGILITY: Angle<f32> = Angle::Deg(90.0); | 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 struct Global { | ||||
pub fps: usize, | pub fps: usize, | ||||
pub delta: f32, | 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) | (&mut position, &velocity) | ||||
.par_join() | .par_join() | ||||
.for_each(|(position, velocity)| { | .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::{ | use glc::{ | ||||
math::{linear_step, sqr}, | math::{linear_step, sqr}, | ||||
matrix::Matrix3f, | matrix::Matrix3f, | ||||
vector::{Vector2f, Vector3f}, | |||||
vector::{Angle, Vector2f, Vector3f}, | |||||
}; | }; | ||||
use rand::random; | use rand::random; | ||||
use shrev::ReaderId; | use shrev::ReaderId; | ||||
use specs::{ | use specs::{ | ||||
hibitset::BitSet, prelude::*, Entities, ParJoin, Read, ReadStorage, System, WriteStorage, | |||||
hibitset::BitSet, prelude::*, world::Index, Entities, ParJoin, Read, ReadStorage, System, | |||||
WriteStorage, | |||||
}; | }; | ||||
use crate::{ | use crate::{ | ||||
components::{Fleet, FleetOwned, Position, Ship, Velocity}, | |||||
components::{Fleet, FleetOwned, Obstacle, Position, Ship, ShipObstacle, Velocity}, | |||||
constants::{ | constants::{ | ||||
SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND, | SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND, | ||||
SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X, | SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X, | ||||
@@ -33,12 +34,15 @@ pub struct ShipsData<'a> { | |||||
velocities: WriteStorage<'a, Velocity>, | velocities: WriteStorage<'a, Velocity>, | ||||
fleet_owned: ReadStorage<'a, FleetOwned>, | fleet_owned: ReadStorage<'a, FleetOwned>, | ||||
positions: ReadStorage<'a, Position>, | positions: ReadStorage<'a, Position>, | ||||
obstacles: ReadStorage<'a, Obstacle>, | |||||
fleets: ReadStorage<'a, Fleet>, | fleets: ReadStorage<'a, Fleet>, | ||||
} | } | ||||
struct Processor<'a> { | struct Processor<'a> { | ||||
need_update: &'a BitSet, | need_update: &'a BitSet, | ||||
entities: &'a Entities<'a>, | |||||
positions: &'a ReadStorage<'a, Position>, | positions: &'a ReadStorage<'a, Position>, | ||||
obstacles: &'a ReadStorage<'a, Obstacle>, | |||||
fleets: &'a ReadStorage<'a, Fleet>, | fleets: &'a ReadStorage<'a, Fleet>, | ||||
delta: f32, | delta: f32, | ||||
} | } | ||||
@@ -91,6 +95,7 @@ impl<'a> System<'a> for Ships { | |||||
mut velocities, | mut velocities, | ||||
fleet_owned, | fleet_owned, | ||||
positions, | positions, | ||||
obstacles, | |||||
fleets, | fleets, | ||||
} = data; | } = data; | ||||
@@ -99,20 +104,24 @@ impl<'a> System<'a> for Ships { | |||||
/* update ships */ | /* update ships */ | ||||
let processor = Processor { | let processor = Processor { | ||||
need_update: &self.need_update, | need_update: &self.need_update, | ||||
entities: &entities, | |||||
positions: &positions, | positions: &positions, | ||||
obstacles: &obstacles, | |||||
fleets: &fleets, | fleets: &fleets, | ||||
delta: global.delta, | |||||
delta: global.delta * global.world_speed, | |||||
}; | }; | ||||
( | |||||
&entities, | |||||
let data = ( | |||||
positions.mask(), | |||||
&mut ships, | &mut ships, | ||||
&mut velocities, | &mut velocities, | ||||
&positions, | &positions, | ||||
&fleet_owned, | &fleet_owned, | ||||
) | |||||
.par_join() | |||||
.for_each(|(entity, ship, velocity, position, fleet_owned)| { | |||||
processor.progress_ship(entity, ship, velocity, position, fleet_owned); | |||||
); | |||||
data.par_join() | |||||
.for_each(|(id, ship, velocity, position, fleet_owned)| { | |||||
processor.progress_ship(id, ship, velocity, position, fleet_owned); | |||||
}); | }); | ||||
} | } | ||||
} | } | ||||
@@ -120,7 +129,7 @@ impl<'a> System<'a> for Ships { | |||||
impl Processor<'_> { | impl Processor<'_> { | ||||
fn progress_ship( | fn progress_ship( | ||||
&self, | &self, | ||||
entity: Entity, | |||||
id: Index, | |||||
ship: &mut Ship, | ship: &mut Ship, | ||||
velocity: &mut Velocity, | velocity: &mut Velocity, | ||||
position: &Position, | position: &Position, | ||||
@@ -134,8 +143,8 @@ impl Processor<'_> { | |||||
let target_dir = ship.target_dir; | let target_dir = ship.target_dir; | ||||
let orbit_to_target = target_pos - orbit_pos; | 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_ship = orbit_to_ship.length_sqr(); | ||||
let r_target = orbit_to_target.length_sqr(); | let r_target = orbit_to_target.length_sqr(); | ||||
@@ -146,7 +155,7 @@ impl Processor<'_> { | |||||
let target_in_orbit = (r_target <= sqr(fleet.orbit_max)) && (r_target >= sqr(orbit_min)); | let target_in_orbit = (r_target <= sqr(fleet.orbit_max)) && (r_target >= sqr(orbit_min)); | ||||
let ship_in_orbit = r_ship < sqr(SHIP_ORBIT_DISTANCE_MAX * orbit_max); | let ship_in_orbit = r_ship < sqr(SHIP_ORBIT_DISTANCE_MAX * orbit_max); | ||||
let need_update = self.need_update.contains(entity.id()); | |||||
let need_update = self.need_update.contains(id); | |||||
let has_target = target_dir.length_sqr() != 0.0; | let has_target = target_dir.length_sqr() != 0.0; | ||||
let passed_target = target_dir * ship_to_target <= 0.0; | let passed_target = target_dir * ship_to_target <= 0.0; | ||||
@@ -162,27 +171,110 @@ impl Processor<'_> { | |||||
-1.0 | -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 = 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( | Vector2f::new( | ||||
orbit_pos.x + radius * angle.cos(), | orbit_pos.x + radius * angle.cos(), | ||||
orbit_pos.y + radius * angle.sin(), | orbit_pos.y + radius * angle.sin(), | ||||
) | ) | ||||
} else { | } else { | ||||
ship.obstacle = ShipObstacle::Search; | |||||
orbit_pos | orbit_pos | ||||
}; | }; | ||||
ship.target_pos = target_pos; | ship.target_pos = target_pos; | ||||
ship.target_dir = (target_pos - ship_pos).normalize(); | 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 */ | /* 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 { | if angle.into_inner().abs() > 0.0001 { | ||||
let dir = angle.into_inner() / angle.abs().into_inner(); | let dir = angle.into_inner() / angle.abs().into_inner(); | ||||
let agility = if ship_in_orbit { | let agility = if ship_in_orbit { | ||||
@@ -192,14 +284,7 @@ impl Processor<'_> { | |||||
}; | }; | ||||
let rot_speed = agility * linear_step(0.0, 45.0, angle.abs().into_deg().into_inner()); | 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); | |||||
} | } | ||||
} | } | ||||
} | } |