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)), | 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::*, world::Index, 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, | ||||
| @@ -28,16 +29,20 @@ pub struct Ships { | |||||
| #[derive(SystemData)] | #[derive(SystemData)] | ||||
| pub struct ShipsData<'a> { | pub struct ShipsData<'a> { | ||||
| global: Read<'a, Global>, | global: Read<'a, Global>, | ||||
| entities: Entities<'a>, | |||||
| ships: WriteStorage<'a, Ship>, | ships: WriteStorage<'a, Ship>, | ||||
| 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, | ||||
| } | } | ||||
| @@ -85,10 +90,12 @@ impl<'a> System<'a> for Ships { | |||||
| fn run(&mut self, data: Self::SystemData) { | fn run(&mut self, data: Self::SystemData) { | ||||
| let ShipsData { | let ShipsData { | ||||
| global, | global, | ||||
| entities, | |||||
| mut ships, | mut ships, | ||||
| mut velocities, | mut velocities, | ||||
| fleet_owned, | fleet_owned, | ||||
| positions, | positions, | ||||
| obstacles, | |||||
| fleets, | fleets, | ||||
| } = data; | } = data; | ||||
| @@ -97,18 +104,22 @@ 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, | |||||
| }; | }; | ||||
| ( | |||||
| let data = ( | |||||
| positions.mask(), | positions.mask(), | ||||
| &mut ships, | &mut ships, | ||||
| &mut velocities, | &mut velocities, | ||||
| &positions, | &positions, | ||||
| &fleet_owned, | &fleet_owned, | ||||
| ) | |||||
| .par_join() | |||||
| ); | |||||
| data.par_join() | |||||
| .for_each(|(id, ship, velocity, position, fleet_owned)| { | .for_each(|(id, ship, velocity, position, fleet_owned)| { | ||||
| processor.progress_ship(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 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(); | ||||
| @@ -160,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 { | ||||
| @@ -190,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); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||