작성자 | SHA1 | 메시지 | 날짜 |
---|---|---|---|
Bergmann89 | a1c55d712b | Implemented ship data depending on ship type and player race | 3 년 전 |
Bergmann89 | ad20e60cde | Merged 'Velocity' and 'Ship' component | 3 년 전 |
@@ -0,0 +1,28 @@ | |||||
x -> needed | |||||
o -> optional | |||||
___________________________________________________________ | |||||
WorldPersistence________________________________________ \ | |||||
Planet_______________________________________________ \ \ | |||||
Asteroid__________________________________________ \ \ \ | |||||
MeetingPoint___________________________________ \ \ \ \ | |||||
Obstacle____________________________________ \ \ \ \ \ | |||||
Shape____________________________________ \ \ \ \ \ \ | |||||
MeetingPointOwned_____________________ \ \ \ \ \ \ \ | |||||
Fleet______________________________ \ \ \ \ \ \ \ \ | |||||
Ship____________________________ \ \ \ \ \ \ \ \ \ | |||||
FleetOwned___________________ \ \ \ \ \ \ \ \ \ \ | |||||
Position__________________ \ \ \ \ \ \ \ \ \ \ \ | |||||
PlayerOwned____________ \ \ \ \ \ \ \ \ \ \ \ \ | |||||
Player______________ \ \ \ \ \ \ \ \ \ \ \ \ \ | |||||
\ \ \ \ \ \ \ \ \ \ \ \ \ \ | |||||
+--------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+ | |||||
| Game Objects | | | | | | | | | | | | | | | |||||
+--------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+ | |||||
| Player | x | | | | | | | | | | | | x | | |||||
| Ship | | x | x | x | x | | | | | | | | x | | |||||
| Fleet | | | | | | x | x | | | | | | x | | |||||
| Asteroid | | o | x | | | | | x | x | x | x | | x | | |||||
| Planet | | o | x | | | | | x | x | x | | x | x | | |||||
| MeetingPoint | | | x | | | | | | | x | | | x | | |||||
+--------------------+---+---+---+---+---+---+---+---+---+---+---+---+---+ |
@@ -1,6 +1,6 @@ | |||||
use glc::vector::Vector4f; | use glc::vector::Vector4f; | ||||
use space_crush_common::{ | use space_crush_common::{ | ||||
components::{Position, Ship, ShipObstacle, Velocity}, | |||||
components::{Player, PlayerOwned, Position, Ship, ShipObstacle}, | |||||
continue_if_none, | continue_if_none, | ||||
}; | }; | ||||
use specs::{prelude::*, ReadStorage, System, World, WriteExpect}; | use specs::{prelude::*, ReadStorage, System, World, WriteExpect}; | ||||
@@ -14,7 +14,8 @@ pub struct Ships; | |||||
pub struct ShipsData<'a> { | pub struct ShipsData<'a> { | ||||
geometry: WriteExpect<'a, Geometry>, | geometry: WriteExpect<'a, Geometry>, | ||||
positions: ReadStorage<'a, Position>, | positions: ReadStorage<'a, Position>, | ||||
velocities: ReadStorage<'a, Velocity>, | |||||
player_owned: ReadStorage<'a, PlayerOwned>, | |||||
players: ReadStorage<'a, Player>, | |||||
ships: ReadStorage<'a, Ship>, | ships: ReadStorage<'a, Ship>, | ||||
} | } | ||||
@@ -25,19 +26,24 @@ impl<'a> System<'a> for Ships { | |||||
let ShipsData { | let ShipsData { | ||||
mut geometry, | mut geometry, | ||||
positions, | positions, | ||||
velocities, | |||||
player_owned, | |||||
players, | |||||
ships, | 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 (position, velocity, ship) in (&positions, &velocities, &ships).join() { | |||||
for (position, player_owned, ship) in (&positions, &player_owned, &ships).join() { | |||||
let ship_pos = position.get(); | let ship_pos = position.get(); | ||||
let type_ = ship.type_(); | |||||
let player_id = player_owned.owner(); | |||||
let player = continue_if_none!(players.get(player_id)); | |||||
let ship_data = player.ship_data(type_); | |||||
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), | ||||
&[*ship_pos, ship_pos + velocity.dir() * velocity.speed()], | |||||
&[*ship_pos, ship_pos + ship.dir() * ship_data.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), | ||||
@@ -12,7 +12,7 @@ use glc::{ | |||||
vertex_array::{DataType, VertexArray}, | vertex_array::{DataType, VertexArray}, | ||||
}; | }; | ||||
use space_crush_common::{ | use space_crush_common::{ | ||||
components::{Player, PlayerOwned, Position, Ship, ShipType, Velocity}, | |||||
components::{Player, PlayerOwned, Position, Ship, ShipType}, | |||||
misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, | misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, | ||||
}; | }; | ||||
use specs::{ | use specs::{ | ||||
@@ -55,7 +55,6 @@ pub struct Ships { | |||||
#[derive(SystemData)] | #[derive(SystemData)] | ||||
pub struct ShipsData<'a> { | pub struct ShipsData<'a> { | ||||
positions: ReadStorage<'a, Position>, | positions: ReadStorage<'a, Position>, | ||||
velocities: ReadStorage<'a, Velocity>, | |||||
players: ReadStorage<'a, Player>, | players: ReadStorage<'a, Player>, | ||||
owned: ReadStorage<'a, PlayerOwned>, | owned: ReadStorage<'a, PlayerOwned>, | ||||
ships: ReadStorage<'a, Ship>, | ships: ReadStorage<'a, Ship>, | ||||
@@ -217,16 +216,15 @@ impl Ships { | |||||
let data = ( | let data = ( | ||||
&ids as &dyn BitSetLike, | &ids as &dyn BitSetLike, | ||||
&d.positions, | &d.positions, | ||||
&d.velocities, | |||||
&d.ships, | &d.ships, | ||||
d.owned.maybe(), | d.owned.maybe(), | ||||
); | ); | ||||
for (id, position, velocity, ship, owned) in data.join() { | |||||
for (id, position, ship, owned) in data.join() { | |||||
let index = self.id_to_index[id as usize]; | let index = self.id_to_index[id as usize]; | ||||
let mut s = &mut buf_ship[index as usize]; | let mut s = &mut buf_ship[index as usize]; | ||||
s.pos = *position.get(); | s.pos = *position.get(); | ||||
s.dir = *velocity.dir(); | |||||
s.dir = *ship.dir(); | |||||
if self.need_init.contains(id) { | if self.need_init.contains(id) { | ||||
s.color = match owned.and_then(|owned| d.players.get(owned.owner())) { | s.color = match owned.and_then(|owned| d.players.get(owned.owner())) { | ||||
@@ -19,7 +19,7 @@ pub struct AsteroidBuilder { | |||||
} | } | ||||
impl AsteroidBuilder { | impl AsteroidBuilder { | ||||
pub fn build(self, world: &mut World) -> Result<Entity, Error> { | |||||
pub fn build(&self, world: &mut World) -> Result<Entity, Error> { | |||||
let type_ = self.type_.ok_or(Error::MissingValue("type"))?; | let type_ = self.type_.ok_or(Error::MissingValue("type"))?; | ||||
let position = self.position.ok_or(Error::MissingValue("position"))?; | let position = self.position.ok_or(Error::MissingValue("position"))?; | ||||
let size = self.size.ok_or(Error::MissingValue("size"))?; | let size = self.size.ok_or(Error::MissingValue("size"))?; | ||||
@@ -13,7 +13,7 @@ pub struct FleetBuilder { | |||||
} | } | ||||
impl FleetBuilder { | impl FleetBuilder { | ||||
pub fn build(self, world: &mut World) -> Result<Entity, Error> { | |||||
pub fn build(&self, world: &mut World) -> Result<Entity, Error> { | |||||
let owner = self.owner.ok_or(Error::MissingValue("owner"))?; | let owner = self.owner.ok_or(Error::MissingValue("owner"))?; | ||||
let meeting_point_owned = MeetingPointOwned::new(owner); | let meeting_point_owned = MeetingPointOwned::new(owner); | ||||
@@ -18,7 +18,7 @@ pub struct PlanetBuilder { | |||||
} | } | ||||
impl PlanetBuilder { | impl PlanetBuilder { | ||||
pub fn build(self, world: &mut World) -> Result<Entity, Error> { | |||||
pub fn build(&self, world: &mut World) -> Result<Entity, Error> { | |||||
let position = self.position.ok_or(Error::MissingValue("position"))?; | let position = self.position.ok_or(Error::MissingValue("position"))?; | ||||
let size = self.size.ok_or(Error::MissingValue("size"))?; | let size = self.size.ok_or(Error::MissingValue("size"))?; | ||||
let (orbit_min, orbit_max) = self.orbit.ok_or(Error::MissingValue("orbit"))?; | let (orbit_min, orbit_max) = self.orbit.ok_or(Error::MissingValue("orbit"))?; | ||||
@@ -3,22 +3,26 @@ use specs::{saveload::MarkedBuilder, Builder, Entity, World, WorldExt}; | |||||
use glc::vector::Vector3f; | use glc::vector::Vector3f; | ||||
use crate::{ | use crate::{ | ||||
components::Player, | |||||
components::{Player, Race}, | |||||
misc::{Persistence, WorldPersistence}, | misc::{Persistence, WorldPersistence}, | ||||
}; | }; | ||||
use super::Error; | use super::Error; | ||||
#[derive(Default, Clone)] | |||||
#[derive(Clone)] | |||||
pub struct PlayerBuilder { | pub struct PlayerBuilder { | ||||
index: usize, | |||||
race: Race, | |||||
color: Option<Vector3f>, | color: Option<Vector3f>, | ||||
} | } | ||||
impl PlayerBuilder { | impl PlayerBuilder { | ||||
pub fn build(self, world: &mut World) -> Result<Entity, Error> { | |||||
let color = self.color.ok_or(Error::MissingValue("color"))?; | |||||
pub fn build(&mut self, world: &mut World) -> Result<Entity, Error> { | |||||
let index = self.index; | |||||
let race = self.race; | |||||
let color = self.color.take().ok_or(Error::MissingValue("color"))?; | |||||
let player = Player::new(color); | |||||
let player = Player::new(index, race, color); | |||||
let entity = world | let entity = world | ||||
.create_entity() | .create_entity() | ||||
@@ -26,6 +30,8 @@ impl PlayerBuilder { | |||||
.with(player) | .with(player) | ||||
.build(); | .build(); | ||||
self.index += 1; | |||||
Ok(entity) | Ok(entity) | ||||
} | } | ||||
@@ -35,3 +41,13 @@ impl PlayerBuilder { | |||||
self | self | ||||
} | } | ||||
} | } | ||||
impl Default for PlayerBuilder { | |||||
fn default() -> Self { | |||||
Self { | |||||
index: 0, | |||||
race: Race::Fighter, | |||||
color: None, | |||||
} | |||||
} | |||||
} |
@@ -3,7 +3,7 @@ use rand::random; | |||||
use specs::{saveload::MarkedBuilder, Builder, Entity, World, WorldExt}; | use specs::{saveload::MarkedBuilder, Builder, Entity, World, WorldExt}; | ||||
use crate::{ | use crate::{ | ||||
components::{FleetOwned, PlayerOwned, Position, Ship, ShipType, Velocity}, | |||||
components::{FleetOwned, PlayerOwned, Position, Ship, ShipType}, | |||||
misc::{Persistence, WorldPersistence}, | misc::{Persistence, WorldPersistence}, | ||||
}; | }; | ||||
@@ -19,19 +19,17 @@ pub struct ShipBuilder { | |||||
} | } | ||||
impl ShipBuilder { | impl ShipBuilder { | ||||
pub fn build(self, world: &mut World) -> Result<Entity, Error> { | |||||
pub fn build(&self, world: &mut World) -> Result<Entity, Error> { | |||||
let player = self.player.ok_or(Error::MissingValue("player"))?; | let player = self.player.ok_or(Error::MissingValue("player"))?; | ||||
let fleet = self.fleet.ok_or(Error::MissingValue("fleet"))?; | let fleet = self.fleet.ok_or(Error::MissingValue("fleet"))?; | ||||
let position = self.position.ok_or(Error::MissingValue("position"))?; | let position = self.position.ok_or(Error::MissingValue("position"))?; | ||||
let type_ = self.type_.ok_or(Error::MissingValue("type"))?; | let type_ = self.type_.ok_or(Error::MissingValue("type"))?; | ||||
let direction = self.direction; | let direction = self.direction; | ||||
let speed = 100.0; | |||||
let player_owned = PlayerOwned::new(player); | let player_owned = PlayerOwned::new(player); | ||||
let fleet_owned = FleetOwned::new(fleet); | let fleet_owned = FleetOwned::new(fleet); | ||||
let position = Position::new(position); | let position = Position::new(position); | ||||
let velocity = Velocity::new(direction, speed); | |||||
let ship = Ship::new(type_); | |||||
let ship = Ship::new(type_, direction); | |||||
let entity = world | let entity = world | ||||
.create_entity() | .create_entity() | ||||
@@ -39,7 +37,6 @@ impl ShipBuilder { | |||||
.with(player_owned) | .with(player_owned) | ||||
.with(fleet_owned) | .with(fleet_owned) | ||||
.with(position) | .with(position) | ||||
.with(velocity) | |||||
.with(ship) | .with(ship) | ||||
.build(); | .build(); | ||||
@@ -81,13 +81,15 @@ impl Component for Fleet { | |||||
/* FleetOwned */ | /* FleetOwned */ | ||||
impl FleetOwned { | impl FleetOwned { | ||||
pub fn new(owner: Entity) -> Self { | |||||
Self { owner } | |||||
} | |||||
pub fn owner(&self) -> Entity { | pub fn owner(&self) -> Entity { | ||||
self.owner | self.owner | ||||
} | } | ||||
} | |||||
impl FleetOwned { | |||||
pub(crate) fn new(owner: Entity) -> Self { | |||||
Self { owner } | |||||
} | |||||
pub(crate) fn set_owner(&mut self, owner: Entity) { | pub(crate) fn set_owner(&mut self, owner: Entity) { | ||||
self.owner = owner; | self.owner = owner; | ||||
@@ -7,15 +7,13 @@ mod player; | |||||
mod position; | mod position; | ||||
mod shape; | mod shape; | ||||
mod ship; | mod ship; | ||||
mod velocity; | |||||
pub use asteroid::{Asteroid, Type as AsteroidType}; | pub use asteroid::{Asteroid, Type as AsteroidType}; | ||||
pub use fleet::{Fleet, FleetOwned}; | pub use fleet::{Fleet, FleetOwned}; | ||||
pub use meeting_point::{MeetingPoint, MeetingPointOwned}; | pub use meeting_point::{MeetingPoint, MeetingPointOwned}; | ||||
pub use obstacle::Obstacle; | pub use obstacle::Obstacle; | ||||
pub use planet::Planet; | pub use planet::Planet; | ||||
pub use player::{Player, PlayerOwned}; | |||||
pub use player::{Player, PlayerOwned, Race}; | |||||
pub use position::Position; | pub use position::Position; | ||||
pub use shape::Shape; | pub use shape::Shape; | ||||
pub use ship::{Count as ShipCount, Obstacle as ShipObstacle, Ship, Type as ShipType}; | |||||
pub use velocity::Velocity; | |||||
pub use ship::{Ship, ShipCount, ShipData, ShipObstacle, ShipType, ShipsData}; |
@@ -6,12 +6,27 @@ use specs::{ | |||||
Component, Entity, HashMapStorage, | Component, Entity, HashMapStorage, | ||||
}; | }; | ||||
use crate::builder::PlayerBuilder; | |||||
use crate::{ | |||||
builder::PlayerBuilder, | |||||
components::{ShipData, ShipType, ShipsData}, | |||||
constants::{SHIPS_DATA_FIGHTER, SHIPS_DATA_RESEARCHER, SHIPS_DATA_TRADER}, | |||||
}; | |||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)] | |||||
#[derive(Clone, Debug, Serialize, Deserialize)] | |||||
pub struct Player { | pub struct Player { | ||||
index: usize, | index: usize, | ||||
race: Race, | |||||
color: Vector3f, | color: Vector3f, | ||||
#[serde(skip)] | |||||
ships_data: ShipsData, | |||||
} | |||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)] | |||||
pub enum Race { | |||||
Fighter, | |||||
Trader, | |||||
Researcher, | |||||
} | } | ||||
#[derive(Copy, Clone, Debug)] | #[derive(Copy, Clone, Debug)] | ||||
@@ -41,14 +56,25 @@ impl Player { | |||||
pub fn color(&self) -> &Vector3f { | pub fn color(&self) -> &Vector3f { | ||||
&self.color | &self.color | ||||
} | } | ||||
#[inline] | |||||
pub fn ship_data(&self, type_: ShipType) -> &ShipData { | |||||
&self.ships_data[type_] | |||||
} | |||||
} | } | ||||
impl Player { | impl Player { | ||||
#[inline] | #[inline] | ||||
pub(crate) fn new(color: Vector3f) -> Self { | |||||
pub(crate) fn new(index: usize, race: Race, color: Vector3f) -> Self { | |||||
Self { | Self { | ||||
index: next_index(), | |||||
index, | |||||
race, | |||||
color, | color, | ||||
ships_data: match race { | |||||
Race::Fighter => SHIPS_DATA_FIGHTER, | |||||
Race::Trader => SHIPS_DATA_TRADER, | |||||
Race::Researcher => SHIPS_DATA_RESEARCHER, | |||||
}, | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -100,11 +126,3 @@ where | |||||
Ok(PlayerOwned { owner }) | Ok(PlayerOwned { owner }) | ||||
} | } | ||||
} | } | ||||
fn next_index() -> usize { | |||||
use std::sync::atomic::{AtomicUsize, Ordering}; | |||||
static NEXT_INDEX: AtomicUsize = AtomicUsize::new(0); | |||||
NEXT_INDEX.fetch_add(1, Ordering::Relaxed) | |||||
} |
@@ -9,10 +9,11 @@ use crate::{builder::ShipBuilder, misc::FlaggedStorage}; | |||||
#[derive(Clone, Debug, Serialize, Deserialize)] | #[derive(Clone, Debug, Serialize, Deserialize)] | ||||
pub struct Ship { | pub struct Ship { | ||||
type_: Type, | |||||
type_: ShipType, | |||||
dir: Vector2f, | |||||
#[serde(skip)] | #[serde(skip)] | ||||
obstacle: Obstacle, | |||||
obstacle: ShipObstacle, | |||||
#[serde(skip)] | #[serde(skip)] | ||||
target_pos: Vector2f, | target_pos: Vector2f, | ||||
@@ -22,21 +23,33 @@ pub struct Ship { | |||||
} | } | ||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)] | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||||
pub enum Obstacle { | |||||
pub enum ShipObstacle { | |||||
Known(Entity), | Known(Entity), | ||||
Search, | Search, | ||||
Done, | Done, | ||||
} | } | ||||
#[derive(Copy, Clone, Debug, Default)] | #[derive(Copy, Clone, Debug, Default)] | ||||
pub struct Count { | |||||
pub struct ShipCount { | |||||
pub fighter: usize, | pub fighter: usize, | ||||
pub bomber: usize, | pub bomber: usize, | ||||
pub transporter: usize, | pub transporter: usize, | ||||
} | } | ||||
#[derive(Clone, Default, Debug)] | |||||
pub struct ShipsData { | |||||
pub fighter: ShipData, | |||||
pub bomber: ShipData, | |||||
pub transporter: ShipData, | |||||
} | |||||
#[derive(Clone, Default, Debug)] | |||||
pub struct ShipData { | |||||
pub speed: f32, | |||||
} | |||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)] | #[derive(Copy, Clone, Debug, Serialize, Deserialize)] | ||||
pub enum Type { | |||||
pub enum ShipType { | |||||
Fighter, | Fighter, | ||||
Bomber, | Bomber, | ||||
Transporter, | Transporter, | ||||
@@ -51,10 +64,15 @@ impl Ship { | |||||
} | } | ||||
#[inline] | #[inline] | ||||
pub fn type_(&self) -> Type { | |||||
pub fn type_(&self) -> ShipType { | |||||
self.type_ | self.type_ | ||||
} | } | ||||
#[inline] | |||||
pub fn dir(&self) -> &Vector2f { | |||||
&self.dir | |||||
} | |||||
#[inline] | #[inline] | ||||
pub fn target_pos(&self) -> &Vector2f { | pub fn target_pos(&self) -> &Vector2f { | ||||
&self.target_pos | &self.target_pos | ||||
@@ -66,16 +84,17 @@ impl Ship { | |||||
} | } | ||||
#[inline] | #[inline] | ||||
pub fn obstacle(&self) -> Obstacle { | |||||
pub fn obstacle(&self) -> ShipObstacle { | |||||
self.obstacle | self.obstacle | ||||
} | } | ||||
} | } | ||||
impl Ship { | impl Ship { | ||||
#[inline] | #[inline] | ||||
pub(crate) fn new(type_: Type) -> Self { | |||||
pub(crate) fn new(type_: ShipType, dir: Vector2f) -> Self { | |||||
Self { | Self { | ||||
type_, | type_, | ||||
dir, | |||||
obstacle: Default::default(), | obstacle: Default::default(), | ||||
target_pos: Default::default(), | target_pos: Default::default(), | ||||
target_dir: Default::default(), | target_dir: Default::default(), | ||||
@@ -89,8 +108,13 @@ impl Ship { | |||||
} | } | ||||
#[inline] | #[inline] | ||||
pub(crate) fn set_obstacle(&mut self, value: Obstacle) { | |||||
self.obstacle = value; | |||||
pub(crate) fn dir_mut(&mut self) -> &mut Vector2f { | |||||
&mut self.dir | |||||
} | |||||
#[inline] | |||||
pub(crate) fn obstacle_mut(&mut self) -> &mut ShipObstacle { | |||||
&mut self.obstacle | |||||
} | } | ||||
} | } | ||||
@@ -100,7 +124,7 @@ impl Component for Ship { | |||||
/* Obstacle */ | /* Obstacle */ | ||||
impl Default for Obstacle { | |||||
impl Default for ShipObstacle { | |||||
fn default() -> Self { | fn default() -> Self { | ||||
Self::Search | Self::Search | ||||
} | } | ||||
@@ -108,7 +132,7 @@ impl Default for Obstacle { | |||||
/* Count */ | /* Count */ | ||||
impl Count { | |||||
impl ShipCount { | |||||
pub fn all() -> Self { | pub fn all() -> Self { | ||||
Self { | Self { | ||||
fighter: usize::MAX, | fighter: usize::MAX, | ||||
@@ -144,7 +168,7 @@ impl Count { | |||||
} | } | ||||
} | } | ||||
impl Index<usize> for Count { | |||||
impl Index<usize> for ShipCount { | |||||
type Output = usize; | type Output = usize; | ||||
fn index(&self, index: usize) -> &Self::Output { | fn index(&self, index: usize) -> &Self::Output { | ||||
@@ -157,7 +181,7 @@ impl Index<usize> for Count { | |||||
} | } | ||||
} | } | ||||
impl IndexMut<usize> for Count { | |||||
impl IndexMut<usize> for ShipCount { | |||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output { | fn index_mut(&mut self, index: usize) -> &mut Self::Output { | ||||
match index { | match index { | ||||
0 => &mut self.fighter, | 0 => &mut self.fighter, | ||||
@@ -168,30 +192,30 @@ impl IndexMut<usize> for Count { | |||||
} | } | ||||
} | } | ||||
impl Index<Type> for Count { | |||||
impl Index<ShipType> for ShipCount { | |||||
type Output = usize; | type Output = usize; | ||||
fn index(&self, index: Type) -> &Self::Output { | |||||
fn index(&self, index: ShipType) -> &Self::Output { | |||||
match index { | match index { | ||||
Type::Fighter => &self.fighter, | |||||
Type::Bomber => &self.bomber, | |||||
Type::Transporter => &self.transporter, | |||||
ShipType::Fighter => &self.fighter, | |||||
ShipType::Bomber => &self.bomber, | |||||
ShipType::Transporter => &self.transporter, | |||||
} | } | ||||
} | } | ||||
} | } | ||||
impl IndexMut<Type> for Count { | |||||
fn index_mut(&mut self, index: Type) -> &mut Self::Output { | |||||
impl IndexMut<ShipType> for ShipCount { | |||||
fn index_mut(&mut self, index: ShipType) -> &mut Self::Output { | |||||
match index { | match index { | ||||
Type::Fighter => &mut self.fighter, | |||||
Type::Bomber => &mut self.bomber, | |||||
Type::Transporter => &mut self.transporter, | |||||
ShipType::Fighter => &mut self.fighter, | |||||
ShipType::Bomber => &mut self.bomber, | |||||
ShipType::Transporter => &mut self.transporter, | |||||
} | } | ||||
} | } | ||||
} | } | ||||
impl Mul<f32> for Count { | |||||
type Output = Count; | |||||
impl Mul<f32> for ShipCount { | |||||
type Output = ShipCount; | |||||
#[allow(unused_assignments)] | #[allow(unused_assignments)] | ||||
fn mul(self, rhs: f32) -> Self::Output { | fn mul(self, rhs: f32) -> Self::Output { | ||||
@@ -219,10 +243,37 @@ impl Mul<f32> for Count { | |||||
actual += 1; | actual += 1; | ||||
} | } | ||||
Count { | |||||
ShipCount { | |||||
fighter, | fighter, | ||||
bomber, | bomber, | ||||
transporter, | transporter, | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* ShipsData */ | |||||
impl Index<usize> for ShipsData { | |||||
type Output = ShipData; | |||||
fn index(&self, index: usize) -> &Self::Output { | |||||
match index { | |||||
0 => &self.fighter, | |||||
1 => &self.bomber, | |||||
2 => &self.transporter, | |||||
x => panic!("Invalid ships data index: {}", x), | |||||
} | |||||
} | |||||
} | |||||
impl Index<ShipType> for ShipsData { | |||||
type Output = ShipData; | |||||
fn index(&self, index: ShipType) -> &Self::Output { | |||||
match index { | |||||
ShipType::Fighter => &self.fighter, | |||||
ShipType::Bomber => &self.bomber, | |||||
ShipType::Transporter => &self.transporter, | |||||
} | |||||
} | |||||
} |
@@ -1,35 +0,0 @@ | |||||
use glc::vector::Vector2f; | |||||
use serde::{Deserialize, Serialize}; | |||||
use specs::{Component, VecStorage}; | |||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)] | |||||
pub struct Velocity { | |||||
dir: Vector2f, | |||||
speed: f32, | |||||
} | |||||
/* Velocity */ | |||||
impl Velocity { | |||||
pub fn dir(&self) -> &Vector2f { | |||||
&self.dir | |||||
} | |||||
pub fn speed(&self) -> f32 { | |||||
self.speed | |||||
} | |||||
} | |||||
impl Velocity { | |||||
pub(crate) fn new(dir: Vector2f, speed: f32) -> Self { | |||||
Self { dir, speed } | |||||
} | |||||
pub(crate) fn dir_mut(&mut self) -> &mut Vector2f { | |||||
&mut self.dir | |||||
} | |||||
} | |||||
impl Component for Velocity { | |||||
type Storage = VecStorage<Self>; | |||||
} |
@@ -1,5 +1,7 @@ | |||||
use glc::{matrix::Angle, vector::Vector2f}; | use glc::{matrix::Angle, vector::Vector2f}; | ||||
use crate::components::{ShipData, ShipsData}; | |||||
/// Distance to orbit before ship is handled as "in orbit" in % | /// Distance to orbit before ship is handled as "in orbit" in % | ||||
pub const SHIP_ORBIT_DISTANCE_MAX: f32 = 1.10; | pub const SHIP_ORBIT_DISTANCE_MAX: f32 = 1.10; | ||||
@@ -13,3 +15,21 @@ pub const SHIP_ORBIT_ANGLE_DELTA_RND: Angle<f32> = Angle::Deg(5000.0); | |||||
pub const SHIP_ORBIT_AGILITY: Angle<f32> = Angle::Deg(90.0); | pub const SHIP_ORBIT_AGILITY: Angle<f32> = Angle::Deg(90.0); | ||||
pub const VECTOR_2F_POS_X: Vector2f = Vector2f::new(1.0, 0.0); | pub const VECTOR_2F_POS_X: Vector2f = Vector2f::new(1.0, 0.0); | ||||
pub const SHIPS_DATA_FIGHTER: ShipsData = ShipsData { | |||||
fighter: ShipData { speed: 120.0 }, | |||||
bomber: ShipData { speed: 80.0 }, | |||||
transporter: ShipData { speed: 100.0 }, | |||||
}; | |||||
pub const SHIPS_DATA_TRADER: ShipsData = ShipsData { | |||||
fighter: ShipData { speed: 100.0 }, | |||||
bomber: ShipData { speed: 70.0 }, | |||||
transporter: ShipData { speed: 120.0 }, | |||||
}; | |||||
pub const SHIPS_DATA_RESEARCHER: ShipsData = ShipsData { | |||||
fighter: ShipData { speed: 90.0 }, | |||||
bomber: ShipData { speed: 60.0 }, | |||||
transporter: ShipData { speed: 100.0 }, | |||||
}; |
@@ -3,7 +3,7 @@ use specs::{Dispatcher as Inner, DispatcherBuilder, World, WorldExt}; | |||||
use crate::{ | use crate::{ | ||||
components::Player, | components::Player, | ||||
resources::Global, | resources::Global, | ||||
systems::{FleetControl, FleetOwnedUpdate, Movement, Process, Ships}, | |||||
systems::{FleetControl, FleetOwnedUpdate, Process, ShipMovement, Ships}, | |||||
Error, | Error, | ||||
}; | }; | ||||
@@ -19,7 +19,7 @@ impl<'a, 'b> Dispatcher<'a, 'b> { | |||||
let mut dispatcher = DispatcherBuilder::new() | let mut dispatcher = DispatcherBuilder::new() | ||||
.with(Process::default(), "process", &[]) | .with(Process::default(), "process", &[]) | ||||
.with(Movement::default(), "movement", &[]) | |||||
.with(ShipMovement::default(), "ship_movement", &[]) | |||||
.with(Ships::new(world), "ships", &[]) | .with(Ships::new(world), "ships", &[]) | ||||
.with(FleetControl::new(world)?, "fleet_control", &[]) | .with(FleetControl::new(world)?, "fleet_control", &[]) | ||||
.with(FleetOwnedUpdate::new(world), "fleet_owned_update", &[]) | .with(FleetOwnedUpdate::new(world), "fleet_owned_update", &[]) | ||||
@@ -8,7 +8,7 @@ use specs::{saveload::SimpleMarker, World}; | |||||
use crate::{ | use crate::{ | ||||
components::{ | components::{ | ||||
Asteroid, MeetingPoint, MeetingPointOwned, Obstacle, Planet, Player, PlayerOwned, Position, | Asteroid, MeetingPoint, MeetingPointOwned, Obstacle, Planet, Player, PlayerOwned, Position, | ||||
Ship, Velocity, | |||||
Ship, | |||||
}, | }, | ||||
Error, | Error, | ||||
}; | }; | ||||
@@ -91,7 +91,6 @@ impl Persistence for WorldPersistence { | |||||
type Marker = SimpleMarker<PersistWorldMarker>; | type Marker = SimpleMarker<PersistWorldMarker>; | ||||
type Components = ( | type Components = ( | ||||
Position, | Position, | ||||
Velocity, | |||||
Player, | Player, | ||||
PlayerOwned, | PlayerOwned, | ||||
MeetingPoint, | MeetingPoint, | ||||
@@ -1,11 +1,11 @@ | |||||
mod fleet_control; | mod fleet_control; | ||||
mod fleet_owned_update; | mod fleet_owned_update; | ||||
mod movement; | |||||
mod process; | mod process; | ||||
mod ship_movement; | |||||
mod ships; | mod ships; | ||||
pub use fleet_control::{FleetControl, FleetControlEvent}; | pub use fleet_control::{FleetControl, FleetControlEvent}; | ||||
pub use fleet_owned_update::FleetOwnedUpdate; | pub use fleet_owned_update::FleetOwnedUpdate; | ||||
pub use movement::Movement; | |||||
pub use process::Process; | pub use process::Process; | ||||
pub use ship_movement::ShipMovement; | |||||
pub use ships::Ships; | pub use ships::Ships; |
@@ -1,39 +0,0 @@ | |||||
#![allow(dead_code)] | |||||
use specs::{prelude::*, ParJoin, Read, ReadStorage, System, WriteStorage}; | |||||
use crate::{ | |||||
components::{Position, Velocity}, | |||||
resources::Global, | |||||
}; | |||||
#[derive(Default)] | |||||
pub struct Movement; | |||||
#[derive(SystemData)] | |||||
pub struct MovementData<'a> { | |||||
position: WriteStorage<'a, Position>, | |||||
velocity: ReadStorage<'a, Velocity>, | |||||
global: Read<'a, Global>, | |||||
} | |||||
impl<'a> System<'a> for Movement { | |||||
type SystemData = MovementData<'a>; | |||||
fn run(&mut self, data: Self::SystemData) { | |||||
let MovementData { | |||||
mut position, | |||||
velocity, | |||||
global, | |||||
} = data; | |||||
(&mut position, &velocity) | |||||
.par_join() | |||||
.for_each(|(position, velocity)| { | |||||
let delta = global.delta * global.world_speed; | |||||
let position = position.get_mut(); | |||||
*position += velocity.dir() * velocity.speed() * delta; | |||||
}); | |||||
} | |||||
} |
@@ -0,0 +1,48 @@ | |||||
#![allow(dead_code)] | |||||
use specs::{prelude::*, ParJoin, Read, ReadStorage, System, WriteStorage}; | |||||
use crate::{ | |||||
components::{Player, PlayerOwned, Position, Ship}, | |||||
resources::Global, | |||||
return_if_none, | |||||
}; | |||||
#[derive(Default)] | |||||
pub struct ShipMovement; | |||||
#[derive(SystemData)] | |||||
pub struct ShipMovementData<'a> { | |||||
positions: WriteStorage<'a, Position>, | |||||
ships: ReadStorage<'a, Ship>, | |||||
player_owned: ReadStorage<'a, PlayerOwned>, | |||||
players: ReadStorage<'a, Player>, | |||||
global: Read<'a, Global>, | |||||
} | |||||
impl<'a> System<'a> for ShipMovement { | |||||
type SystemData = ShipMovementData<'a>; | |||||
fn run(&mut self, data: Self::SystemData) { | |||||
let ShipMovementData { | |||||
mut positions, | |||||
ships, | |||||
player_owned, | |||||
players, | |||||
global, | |||||
} = data; | |||||
(&mut positions, &player_owned, &ships).par_join().for_each( | |||||
|(position, player_owned, ship)| { | |||||
let delta = global.delta * global.world_speed; | |||||
let position = position.get_mut(); | |||||
let type_ = ship.type_(); | |||||
let player_id = player_owned.owner(); | |||||
let player = return_if_none!(players.get(player_id)); | |||||
let ship_data = player.ship_data(type_); | |||||
*position += ship.dir() * ship_data.speed * delta; | |||||
}, | |||||
); | |||||
} | |||||
} |
@@ -13,7 +13,6 @@ use specs::{ | |||||
use crate::{ | use crate::{ | ||||
components::{ | components::{ | ||||
FleetOwned, MeetingPoint, MeetingPointOwned, Obstacle, Position, Shape, Ship, ShipObstacle, | FleetOwned, MeetingPoint, MeetingPointOwned, Obstacle, Position, Shape, 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, | ||||
@@ -34,7 +33,6 @@ pub struct ShipsData<'a> { | |||||
global: Read<'a, Global>, | global: Read<'a, Global>, | ||||
entities: Entities<'a>, | entities: Entities<'a>, | ||||
ships: WriteStorage<'a, Ship>, | ships: WriteStorage<'a, Ship>, | ||||
velocities: WriteStorage<'a, Velocity>, | |||||
fleet_owned: ReadStorage<'a, FleetOwned>, | fleet_owned: ReadStorage<'a, FleetOwned>, | ||||
meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, | meeting_point_owned: ReadStorage<'a, MeetingPointOwned>, | ||||
positions: ReadStorage<'a, Position>, | positions: ReadStorage<'a, Position>, | ||||
@@ -92,7 +90,6 @@ impl<'a> System<'a> for Ships { | |||||
global, | global, | ||||
entities, | entities, | ||||
mut ships, | mut ships, | ||||
mut velocities, | |||||
fleet_owned, | fleet_owned, | ||||
meeting_point_owned, | meeting_point_owned, | ||||
positions, | positions, | ||||
@@ -117,17 +114,11 @@ impl<'a> System<'a> for Ships { | |||||
ships.set_event_emission(false); | ships.set_event_emission(false); | ||||
let data = ( | |||||
positions.mask(), | |||||
&mut ships, | |||||
&mut velocities, | |||||
&positions, | |||||
&fleet_owned, | |||||
); | |||||
let data = (positions.mask(), &mut ships, &positions, &fleet_owned); | |||||
data.par_join() | data.par_join() | ||||
.for_each(|(id, ship, velocity, position, fleet_owned)| { | |||||
processor.progress_ship(id, ship, velocity, position, fleet_owned); | |||||
.for_each(|(id, ship, position, fleet_owned)| { | |||||
processor.progress_ship(id, ship, position, fleet_owned); | |||||
}); | }); | ||||
ships.set_event_emission(true); | ships.set_event_emission(true); | ||||
@@ -139,7 +130,6 @@ impl Processor<'_> { | |||||
&self, | &self, | ||||
id: Index, | id: Index, | ||||
ship: &mut Ship, | ship: &mut Ship, | ||||
velocity: &mut Velocity, | |||||
position: &Position, | position: &Position, | ||||
fleet_owned: &FleetOwned, | fleet_owned: &FleetOwned, | ||||
) { | ) { | ||||
@@ -179,7 +169,7 @@ impl Processor<'_> { | |||||
let target_pos = if ship_in_meeting_point && meeting_point_max > 0.0 { | let target_pos = if ship_in_meeting_point && meeting_point_max > 0.0 { | ||||
let meeting_point_to_ship_vec3 = | let meeting_point_to_ship_vec3 = | ||||
Vector3f::new(meeting_point_to_ship.x, meeting_point_to_ship.y, 0.0); | Vector3f::new(meeting_point_to_ship.x, meeting_point_to_ship.y, 0.0); | ||||
let ship_dir_vec3 = velocity.dir().into_vec3(); | |||||
let ship_dir_vec3 = ship.dir().into_vec3(); | |||||
let dir = if meeting_point_to_ship_vec3.cross(&ship_dir_vec3).z > 0.0 { | let dir = if meeting_point_to_ship_vec3.cross(&ship_dir_vec3).z > 0.0 { | ||||
1.0 | 1.0 | ||||
@@ -201,7 +191,7 @@ impl Processor<'_> { | |||||
meeting_point_pos.y + radius * angle.sin(), | meeting_point_pos.y + radius * angle.sin(), | ||||
) | ) | ||||
} else { | } else { | ||||
ship.set_obstacle(ShipObstacle::Search); | |||||
*ship.obstacle_mut() = ShipObstacle::Search; | |||||
*meeting_point_pos | *meeting_point_pos | ||||
}; | }; | ||||
@@ -213,7 +203,7 @@ impl Processor<'_> { | |||||
/* check if obstacle is still valid */ | /* check if obstacle is still valid */ | ||||
if ship_in_meeting_point { | if ship_in_meeting_point { | ||||
ship.set_obstacle(ShipObstacle::Done); | |||||
*ship.obstacle_mut() = ShipObstacle::Done; | |||||
} else if let ShipObstacle::Known(obstacle) = ship.obstacle() { | } else if let ShipObstacle::Known(obstacle) = ship.obstacle() { | ||||
if let Some(position) = self.positions.get(obstacle) { | if let Some(position) = self.positions.get(obstacle) { | ||||
let obstacle_meeting_point = self.meeting_points.get(obstacle).unwrap(); | let obstacle_meeting_point = self.meeting_points.get(obstacle).unwrap(); | ||||
@@ -230,10 +220,10 @@ impl Processor<'_> { | |||||
if (obstacle_angle > 90.0 && ship_to_obstacle.length_sqr() > meeting_point_sqr) | if (obstacle_angle > 90.0 && ship_to_obstacle.length_sqr() > meeting_point_sqr) | ||||
|| obstacle_angle > 170.0 | || obstacle_angle > 170.0 | ||||
{ | { | ||||
ship.set_obstacle(ShipObstacle::Search); | |||||
*ship.obstacle_mut() = ShipObstacle::Search; | |||||
} | } | ||||
} else { | } else { | ||||
ship.set_obstacle(ShipObstacle::Search); | |||||
*ship.obstacle_mut() = ShipObstacle::Search; | |||||
} | } | ||||
} | } | ||||
@@ -251,13 +241,13 @@ impl Processor<'_> { | |||||
let len_sqr = ship_to_obstacle.length_sqr(); | let len_sqr = ship_to_obstacle.length_sqr(); | ||||
if len_sqr < dist_sqr { | if len_sqr < dist_sqr { | ||||
dist_sqr = len_sqr; | dist_sqr = len_sqr; | ||||
ship.set_obstacle(ShipObstacle::Known(e)); | |||||
*ship.obstacle_mut() = ShipObstacle::Known(e); | |||||
} | } | ||||
} | } | ||||
if let ShipObstacle::Known(e) = ship.obstacle() { | if let ShipObstacle::Known(e) = ship.obstacle() { | ||||
if e == fleet_owned.owner() { | if e == fleet_owned.owner() { | ||||
ship.set_obstacle(ShipObstacle::Done); | |||||
*ship.obstacle_mut() = ShipObstacle::Done; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -296,13 +286,13 @@ impl Processor<'_> { | |||||
} | } | ||||
/* update ship direction */ | /* update ship direction */ | ||||
let angle = expected_dir.angle2(&velocity.dir()); | |||||
let angle = expected_dir.angle2(ship.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 = SHIP_ORBIT_AGILITY; | let agility = SHIP_ORBIT_AGILITY; | ||||
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()); | ||||
*velocity.dir_mut() *= Matrix3f::rotate(rot_speed * -dir * self.delta); | |||||
*ship.dir_mut() *= Matrix3f::rotate(rot_speed * -dir * self.delta); | |||||
} | } | ||||
} | } | ||||
} | } |