@@ -4,6 +4,10 @@ use lazy_static::lazy_static; | |||||
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 PLANET_SIZE: f32 = 200.0; | |||||
pub const ASTEROID_SIZE: f32 = 100.0; | |||||
lazy_static! { | lazy_static! { | ||||
pub static ref PLAYER_COLOR_DEFAULT: Vector4f = Vector4f::new(1.0, 1.0, 1.0, 0.1); | pub static ref PLAYER_COLOR_DEFAULT: Vector4f = Vector4f::new(1.0, 1.0, 1.0, 0.1); | ||||
} | } |
@@ -1,7 +1,9 @@ | |||||
mod fleets; | mod fleets; | ||||
mod raster; | |||||
mod ships; | mod ships; | ||||
mod summary; | mod summary; | ||||
pub use fleets::Fleets; | pub use fleets::Fleets; | ||||
pub use raster::Raster; | |||||
pub use ships::Ships; | pub use ships::Ships; | ||||
pub use summary::Summary; | pub use summary::Summary; |
@@ -0,0 +1,52 @@ | |||||
use glc::vector::{Vector2f, Vector4f}; | |||||
use space_crush_common::resources::Raster as RasterResource; | |||||
use specs::{prelude::*, ReadExpect, System, World, WriteExpect}; | |||||
use crate::resources::Geometry; | |||||
#[derive(Default)] | |||||
pub struct Raster; | |||||
#[derive(SystemData)] | |||||
pub struct FleetData<'a> { | |||||
geometry: WriteExpect<'a, Geometry>, | |||||
raster: ReadExpect<'a, RasterResource>, | |||||
} | |||||
impl<'a> System<'a> for Raster { | |||||
type SystemData = FleetData<'a>; | |||||
fn run(&mut self, data: Self::SystemData) { | |||||
let FleetData { | |||||
mut geometry, | |||||
raster, | |||||
} = data; | |||||
let s = raster.size(); | |||||
gl::enable(gl::BLEND); | |||||
gl::blend_func(gl::SRC_ALPHA, gl::ONE); | |||||
for (x, y, q) in raster.quads() { | |||||
let a = if q.is_empty() { 0.05 } else { 0.5 }; | |||||
geometry.render_lines( | |||||
Vector4f::new(1.0, 1.0, 1.0, a), | |||||
&create_quad(x as _, y as _, s), | |||||
); | |||||
} | |||||
gl::disable(gl::BLEND); | |||||
} | |||||
} | |||||
fn create_quad(x: f32, y: f32, s: f32) -> Vec<Vector2f> { | |||||
let f = s / 2.0; | |||||
vec![ | |||||
Vector2f::new(x * s + f, y * s + f), | |||||
Vector2f::new(x * s + f, y * s - f), | |||||
Vector2f::new(x * s - f, y * s - f), | |||||
Vector2f::new(x * s - f, y * s + f), | |||||
Vector2f::new(x * s + f, y * s + f), | |||||
] | |||||
} |
@@ -11,7 +11,9 @@ use specs::{Dispatcher, DispatcherBuilder, Entity, World}; | |||||
pub use error::Error; | pub use error::Error; | ||||
use debug::{Fleets as DebugFleets, Ships as DebugShips, Summary as DebugSummary}; | |||||
use debug::{ | |||||
Fleets as DebugFleets, Raster as RasterDebug, Ships as DebugShips, Summary as DebugSummary, | |||||
}; | |||||
use misc::{Events, TextManager, Window}; | use misc::{Events, TextManager, Window}; | ||||
use render::{Asteroids, Init, Planets, Ships}; | use render::{Asteroids, Init, Planets, Ships}; | ||||
use resources::{Camera, Config, Geometry, PlayerState, State, Uniform}; | use resources::{Camera, Config, Geometry, PlayerState, State, Uniform}; | ||||
@@ -47,11 +49,12 @@ impl<'a, 'b> App<'a, 'b> { | |||||
let mut dispatcher = DispatcherBuilder::new() | let mut dispatcher = DispatcherBuilder::new() | ||||
.with(StateUpdate::new(world)?, "state_update", &[]) | .with(StateUpdate::new(world)?, "state_update", &[]) | ||||
.with(FleetInfoUpdate::new(world)?, "fleet_info_update", &[]) | |||||
.with(FleetInfoUpdate::new(world), "fleet_info_update", &[]) | |||||
.with_thread_local(Init::new(world)?) | .with_thread_local(Init::new(world)?) | ||||
.with_thread_local(Planets::new(world)?) | .with_thread_local(Planets::new(world)?) | ||||
.with_thread_local(Asteroids::new(world)?) | .with_thread_local(Asteroids::new(world)?) | ||||
.with_thread_local(Ships::new(world)?) | .with_thread_local(Ships::new(world)?) | ||||
.with_thread_local(RasterDebug::default()) | |||||
.with_thread_local(DebugShips::default()) | .with_thread_local(DebugShips::default()) | ||||
.with_thread_local(DebugFleets::default()) | .with_thread_local(DebugFleets::default()) | ||||
.with_thread_local(DebugSummary::new(&text_manager)?) | .with_thread_local(DebugSummary::new(&text_manager)?) | ||||
@@ -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, Ship, | |||||
ShipType, Velocity, | |||||
Asteroid, AsteroidType, Fleet, FleetOwned, Planet, Player, PlayerOwned, Position, | |||||
Shape, Ship, ShipType, Velocity, | |||||
}, | }, | ||||
misc::{PersistWorld, Persistence}, | misc::{PersistWorld, Persistence}, | ||||
}; | }; | ||||
@@ -84,7 +84,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
.marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
.with(Position { | .with(Position { | ||||
pos: Vector2f::new(500.0, -500.0), | pos: Vector2f::new(500.0, -500.0), | ||||
size: 100.0, | |||||
shape: Shape::Circle(100.0), | |||||
}) | }) | ||||
.with(Fleet { | .with(Fleet { | ||||
orbit_min: 125.0, | orbit_min: 125.0, | ||||
@@ -101,7 +101,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
.marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
.with(Position { | .with(Position { | ||||
pos: Vector2f::new(500.0, 500.0), | pos: Vector2f::new(500.0, 500.0), | ||||
size: 100.0, | |||||
shape: Shape::Circle(100.0), | |||||
}) | }) | ||||
.with(Fleet { | .with(Fleet { | ||||
orbit_min: 125.0, | orbit_min: 125.0, | ||||
@@ -119,7 +119,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
.with(PlayerOwned { owner: player_id }) | .with(PlayerOwned { owner: player_id }) | ||||
.with(Position { | .with(Position { | ||||
pos: Vector2f::default(), | pos: Vector2f::default(), | ||||
size: 250.0, | |||||
shape: Shape::Circle(250.0), | |||||
}) | }) | ||||
.with(Fleet { | .with(Fleet { | ||||
orbit_min: 325.0, | orbit_min: 325.0, | ||||
@@ -129,7 +129,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
.with(Planet {}) | .with(Planet {}) | ||||
.build(); | .build(); | ||||
for i in 0..10 { | |||||
for i in 0..100 { | |||||
world | world | ||||
.create_entity() | .create_entity() | ||||
.marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
@@ -139,7 +139,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
500.0 * random::<f32>() - 250.0, | 500.0 * random::<f32>() - 250.0, | ||||
500.0 * random::<f32>() - 250.0, | 500.0 * random::<f32>() - 250.0, | ||||
), | ), | ||||
size: 15.0, | |||||
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(), | ||||
@@ -12,7 +12,10 @@ use space_crush_common::{ | |||||
use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | ||||
use crate::{ | use crate::{ | ||||
constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||||
constants::{ | |||||
ASTEROID_SIZE, PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, | |||||
UNIFORM_BUFFER_INDEX_UNIFORM, | |||||
}, | |||||
misc::WorldHelper, | misc::WorldHelper, | ||||
resources::Geometry, | resources::Geometry, | ||||
Error, | Error, | ||||
@@ -85,7 +88,7 @@ impl<'a> System<'a> for Asteroids { | |||||
for (position, asteroid, owned) in (&position, &asteroid, owned.maybe()).join() { | for (position, asteroid, owned) in (&position, &asteroid, owned.maybe()).join() { | ||||
let p_x = position.pos.x; | let p_x = position.pos.x; | ||||
let p_y = position.pos.y; | let p_y = position.pos.y; | ||||
let s = position.size; | |||||
let s = position.shape.circle().unwrap_or(ASTEROID_SIZE); | |||||
let _guard = match asteroid.type_ { | let _guard = match asteroid.type_ { | ||||
AsteroidType::Metal => BindGuard::new(&self.texture_metal), | AsteroidType::Metal => BindGuard::new(&self.texture_metal), | ||||
@@ -12,7 +12,10 @@ use space_crush_common::{ | |||||
use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | ||||
use crate::{ | use crate::{ | ||||
constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||||
constants::{ | |||||
PLANET_SIZE, PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, | |||||
UNIFORM_BUFFER_INDEX_UNIFORM, | |||||
}, | |||||
misc::WorldHelper, | misc::WorldHelper, | ||||
resources::Geometry, | resources::Geometry, | ||||
Error, | Error, | ||||
@@ -83,7 +86,7 @@ impl<'a> System<'a> for Planets { | |||||
for (p, _, owned) in (&position, &planet, owned.maybe()).join() { | for (p, _, owned) in (&position, &planet, owned.maybe()).join() { | ||||
let p_x = p.pos.x; | let p_x = p.pos.x; | ||||
let p_y = p.pos.y; | let p_y = p.pos.y; | ||||
let s = p.size; | |||||
let s = p.shape.circle().unwrap_or(PLANET_SIZE); | |||||
let c = match owned.and_then(|owned| player.get(owned.owner)) { | let c = match owned.and_then(|owned| player.get(owned.owner)) { | ||||
Some(pv) => &pv.color, | Some(pv) => &pv.color, | ||||
@@ -12,7 +12,9 @@ use space_crush_common::{ | |||||
use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | ||||
use crate::{ | use crate::{ | ||||
constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||||
constants::{ | |||||
PLAYER_COLOR_DEFAULT, SHIP_SIZE, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM, | |||||
}, | |||||
misc::WorldHelper, | misc::WorldHelper, | ||||
resources::Geometry, | resources::Geometry, | ||||
Error, | Error, | ||||
@@ -103,7 +105,7 @@ impl<'a> System<'a> for Ships { | |||||
let p_y = p.pos.y; | let p_y = p.pos.y; | ||||
let d_x = v.dir.x; | let d_x = v.dir.x; | ||||
let d_y = v.dir.y; | let d_y = v.dir.y; | ||||
let s = p.size; | |||||
let s = SHIP_SIZE; | |||||
let m = Matrix4f::new( | let m = Matrix4f::new( | ||||
Vector4f::new(-s * d_y, s * d_x, 0.0, 0.0), | Vector4f::new(-s * d_y, s * d_x, 0.0, 0.0), | ||||
@@ -10,7 +10,7 @@ use specs::{ | |||||
World, WriteStorage, | World, WriteStorage, | ||||
}; | }; | ||||
use crate::{components::FleetInfo, resources::PlayerState, Error}; | |||||
use crate::{components::FleetInfo, resources::PlayerState}; | |||||
pub struct FleetInfoUpdate { | pub struct FleetInfoUpdate { | ||||
modified: HashMap<Index, Modified>, | modified: HashMap<Index, Modified>, | ||||
@@ -26,7 +26,7 @@ struct Modified { | |||||
} | } | ||||
impl FleetInfoUpdate { | impl FleetInfoUpdate { | ||||
pub fn new(world: &mut World) -> Result<Self, Error> { | |||||
pub fn new(world: &mut World) -> Self { | |||||
let modified = HashMap::new(); | let modified = HashMap::new(); | ||||
let need_update = BitSet::new(); | let need_update = BitSet::new(); | ||||
@@ -50,12 +50,12 @@ impl FleetInfoUpdate { | |||||
.register_reader() | .register_reader() | ||||
}; | }; | ||||
Ok(Self { | |||||
Self { | |||||
modified, | modified, | ||||
need_update, | need_update, | ||||
fleet_owned_id, | fleet_owned_id, | ||||
player_owned_id, | player_owned_id, | ||||
}) | |||||
} | |||||
} | } | ||||
} | } | ||||
@@ -10,6 +10,6 @@ pub use asteroid::{Asteroid, Type as AsteroidType}; | |||||
pub use fleet::{Fleet, Owned as FleetOwned}; | pub use fleet::{Fleet, Owned as FleetOwned}; | ||||
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; | |||||
pub use position::{Position, Shape}; | |||||
pub use ship::{Count as ShipCount, Ship, Type as ShipType}; | pub use ship::{Count as ShipCount, Ship, Type as ShipType}; | ||||
pub use velocity::Velocity; | pub use velocity::Velocity; |
@@ -2,12 +2,36 @@ use glc::vector::Vector2f; | |||||
use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||
use specs::{Component, VecStorage}; | use specs::{Component, VecStorage}; | ||||
use crate::misc::FlaggedStorage; | |||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, Default, Serialize, Deserialize)] | ||||
pub struct Position { | pub struct Position { | ||||
pub pos: Vector2f, | pub pos: Vector2f, | ||||
pub size: f32, | |||||
pub shape: Shape, | |||||
} | |||||
#[derive(Clone, Debug, Serialize, Deserialize)] | |||||
pub enum Shape { | |||||
Dot, | |||||
Circle(f32), | |||||
} | } | ||||
impl Component for Position { | impl Component for Position { | ||||
type Storage = VecStorage<Self>; | |||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>; | |||||
} | |||||
impl Shape { | |||||
pub fn circle(&self) -> Option<f32> { | |||||
if let Self::Circle(r) = &self { | |||||
Some(*r) | |||||
} else { | |||||
None | |||||
} | |||||
} | |||||
} | |||||
impl Default for Shape { | |||||
fn default() -> Self { | |||||
Self::Dot | |||||
} | |||||
} | } |
@@ -2,8 +2,8 @@ use specs::{Dispatcher as Inner, DispatcherBuilder, World, WorldExt}; | |||||
use crate::{ | use crate::{ | ||||
components::Player, | components::Player, | ||||
resources::Global, | |||||
systems::{Fleets, Movement, Process}, | |||||
resources::{Global, Raster}, | |||||
systems::{Fleets, Movement, Process, RasterUpdate}, | |||||
}; | }; | ||||
pub struct Dispatcher<'a, 'b> { | pub struct Dispatcher<'a, 'b> { | ||||
@@ -13,6 +13,7 @@ pub struct Dispatcher<'a, 'b> { | |||||
impl<'a, 'b> Dispatcher<'a, 'b> { | impl<'a, 'b> Dispatcher<'a, 'b> { | ||||
pub fn new(world: &mut World) -> Self { | pub fn new(world: &mut World) -> Self { | ||||
world.insert(Global::default()); | world.insert(Global::default()); | ||||
world.insert(Raster::new(250.0)); | |||||
world.register::<Player>(); | world.register::<Player>(); | ||||
@@ -20,6 +21,7 @@ impl<'a, 'b> Dispatcher<'a, 'b> { | |||||
.with(Process::default(), "process", &[]) | .with(Process::default(), "process", &[]) | ||||
.with(Movement::default(), "movement", &[]) | .with(Movement::default(), "movement", &[]) | ||||
.with(Fleets::default(), "fleets", &[]) | .with(Fleets::default(), "fleets", &[]) | ||||
.with(RasterUpdate::new(world), "raster_update", &[]) | |||||
.build(); | .build(); | ||||
dispatcher.setup(world); | dispatcher.setup(world); | ||||
@@ -1,3 +1,5 @@ | |||||
mod global; | mod global; | ||||
mod raster; | |||||
pub use global::Global; | pub use global::Global; | ||||
pub use raster::Raster; |
@@ -0,0 +1,210 @@ | |||||
#![allow(dead_code)] | |||||
use std::collections::HashSet; | |||||
use glc::vector::Vector2f; | |||||
use specs::world::Index; | |||||
use crate::components::{Position, Shape}; | |||||
pub struct Raster { | |||||
size: f32, | |||||
quads: OffsetVec<OffsetVec<Quad>>, | |||||
} | |||||
#[derive(Default)] | |||||
struct OffsetVec<T> | |||||
where | |||||
T: Default, | |||||
{ | |||||
origin: usize, | |||||
data: Vec<T>, | |||||
} | |||||
#[derive(Default)] | |||||
pub struct Quad { | |||||
entities: HashSet<Index>, | |||||
} | |||||
impl Raster { | |||||
pub fn new(size: f32) -> Self { | |||||
Self { | |||||
size, | |||||
quads: OffsetVec::new(), | |||||
} | |||||
} | |||||
pub fn size(&self) -> f32 { | |||||
self.size | |||||
} | |||||
pub fn insert(&mut self, id: Index, position: &Position) -> bool { | |||||
self.update_quads(position, |q| { | |||||
q.entities.insert(id); | |||||
}) | |||||
} | |||||
pub fn remove(&mut self, id: &Index, position: &Position) -> bool { | |||||
self.update_quads(position, |q| { | |||||
q.entities.remove(id); | |||||
}) | |||||
} | |||||
pub fn quads(&self) -> impl Iterator<Item = (isize, isize, &Quad)> { | |||||
self.quads.data.iter().enumerate().flat_map(move |(x, vy)| { | |||||
vy.data.iter().enumerate().map(move |(y, q)| { | |||||
( | |||||
x as isize - self.quads.origin as isize, | |||||
y as isize - vy.origin as isize, | |||||
q, | |||||
) | |||||
}) | |||||
}) | |||||
} | |||||
fn update_quads<F>(&mut self, position: &Position, mut f: F) -> bool | |||||
where | |||||
F: FnMut(&mut Quad), | |||||
{ | |||||
let p = position.pos; | |||||
match position.shape { | |||||
Shape::Dot => { | |||||
let x = (p.x / self.size).round() as isize; | |||||
let y = (p.y / self.size).round() as isize; | |||||
f(self.quads.get_mut(x).get_mut(y)); | |||||
true | |||||
} | |||||
Shape::Circle(r) => { | |||||
let s = self.size; | |||||
let min_x = ((p.x - r) / s).round() as isize - 1; | |||||
let max_x = ((p.x + r) / s).round() as isize + 1; | |||||
let min_y = ((p.y - r) / s).round() as isize - 1; | |||||
let max_y = ((p.y + r) / s).round() as isize + 1; | |||||
let sr = r * r; | |||||
let s = self.size / 2.0; | |||||
let mut ret = false; | |||||
for x in min_x..=max_x { | |||||
for y in min_y..=max_y { | |||||
let fx = x as f32 * self.size; | |||||
let fy = y as f32 * self.size; | |||||
let quad = self.quads.get_mut(x).get_mut(y); | |||||
if (Vector2f::new(fx - s, fy - s) - p).length_sqr() < sr | |||||
|| (Vector2f::new(fx + s, fy - s) - p).length_sqr() < sr | |||||
|| (Vector2f::new(fx - s, fy + s) - p).length_sqr() < sr | |||||
|| (Vector2f::new(fx + s, fy + s) - p).length_sqr() < sr | |||||
{ | |||||
f(quad); | |||||
ret = true; | |||||
} | |||||
} | |||||
} | |||||
ret | |||||
} | |||||
} | |||||
} | |||||
fn get_quad(&self, x: isize, y: isize) -> Option<&Quad> { | |||||
let row = self.quads.get(x)?; | |||||
let quad = row.get(y)?; | |||||
Some(quad) | |||||
} | |||||
fn get_quad_mut(&mut self, x: isize, y: isize) -> &mut Quad { | |||||
self.quads.get_mut(x).get_mut(y) | |||||
} | |||||
} | |||||
impl<T> OffsetVec<T> | |||||
where | |||||
T: Default, | |||||
{ | |||||
pub fn new() -> Self { | |||||
Self { | |||||
origin: 0, | |||||
data: Vec::new(), | |||||
} | |||||
} | |||||
pub fn get(&self, i: isize) -> Option<&T> { | |||||
let low = (0usize - self.origin) as isize; | |||||
let high = (self.data.len() - self.origin) as isize - 1; | |||||
if i < low || i > high { | |||||
None | |||||
} else { | |||||
Some(&self.data[(i - low) as usize]) | |||||
} | |||||
} | |||||
pub fn get_mut(&mut self, i: isize) -> &mut T { | |||||
let low = 0isize - self.origin as isize; | |||||
let high = (self.data.len() - self.origin) as isize - 1; | |||||
if i > high { | |||||
let add = (i - low + 1) as usize; | |||||
self.data.resize_with(add, Default::default); | |||||
} else if i < low { | |||||
let add = (low - i) as usize; | |||||
let mut prefix = Vec::new(); | |||||
prefix.resize_with(add, Default::default); | |||||
prefix.append(&mut self.data); | |||||
self.data = prefix; | |||||
self.origin += add; | |||||
} | |||||
&mut self.data[(i + self.origin as isize) as usize] | |||||
} | |||||
} | |||||
impl Quad { | |||||
pub fn is_empty(&self) -> bool { | |||||
self.entities.is_empty() | |||||
} | |||||
} | |||||
#[cfg(test)] | |||||
mod tests { | |||||
use super::*; | |||||
#[test] | |||||
fn vec_get_mut() { | |||||
let mut vec = OffsetVec::<usize>::new(); | |||||
assert_eq!(vec.origin, 0); | |||||
assert_eq!(vec.data, Vec::<usize>::new()); | |||||
*vec.get_mut(0) = 100; | |||||
assert_eq!(vec.origin, 0); | |||||
assert_eq!(vec.data, vec![100]); | |||||
*vec.get_mut(1) = 101; | |||||
assert_eq!(vec.origin, 0); | |||||
assert_eq!(vec.data, vec![100, 101]); | |||||
*vec.get_mut(-2) = 98; | |||||
assert_eq!(vec.origin, 2); | |||||
assert_eq!(vec.data, vec![98, 0, 100, 101]); | |||||
*vec.get_mut(4) = 104; | |||||
assert_eq!(vec.origin, 2); | |||||
assert_eq!(vec.data, vec![98, 0, 100, 101, 0, 0, 104]); | |||||
*vec.get_mut(-4) = 96; | |||||
assert_eq!(vec.origin, 4); | |||||
assert_eq!(vec.data, vec![96, 0, 98, 0, 100, 101, 0, 0, 104]); | |||||
} | |||||
} |
@@ -1,7 +1,9 @@ | |||||
mod fleets; | mod fleets; | ||||
mod movement; | mod movement; | ||||
mod process; | mod process; | ||||
mod raster_update; | |||||
pub use fleets::Fleets; | pub use fleets::Fleets; | ||||
pub use movement::Movement; | pub use movement::Movement; | ||||
pub use process::Process; | pub use process::Process; | ||||
pub use raster_update::RasterUpdate; |
@@ -1,6 +1,6 @@ | |||||
#![allow(dead_code)] | #![allow(dead_code)] | ||||
use specs::{prelude::*, ParJoin, Read, ReadStorage, System, WriteStorage}; | |||||
use specs::{prelude::*, Read, ReadStorage, System, WriteStorage}; | |||||
use crate::{ | use crate::{ | ||||
components::{Position, Velocity}, | components::{Position, Velocity}, | ||||
@@ -27,10 +27,8 @@ impl<'a> System<'a> for Movement { | |||||
global, | global, | ||||
} = data; | } = data; | ||||
(&mut position, &velocity) | |||||
.par_join() | |||||
.for_each(|(position, velocity)| { | |||||
position.pos = position.pos + velocity.dir * velocity.speed * global.delta; | |||||
}); | |||||
for (position, velocity) in (&mut position, &velocity).join() { | |||||
position.pos = position.pos + velocity.dir * velocity.speed * global.delta; | |||||
} | |||||
} | } | ||||
} | } |
@@ -0,0 +1,74 @@ | |||||
use shrev::ReaderId; | |||||
use specs::{hibitset::BitSetLike, prelude::*, Entities, ReadStorage, System, World, WriteStorage}; | |||||
use crate::{components::Position, misc::ComponentEvent, resources::Raster}; | |||||
pub struct RasterUpdate { | |||||
need_update: BitSet, | |||||
position_id: ReaderId<ComponentEvent<Position>>, | |||||
} | |||||
impl RasterUpdate { | |||||
pub fn new(world: &mut World) -> Self { | |||||
let need_update = BitSet::new(); | |||||
let position_id = unsafe { | |||||
WriteStorage::<Position>::setup(world); | |||||
let mut position = world.write_component::<Position>(); | |||||
position | |||||
.unprotected_storage_mut() | |||||
.channel_mut() | |||||
.register_reader() | |||||
}; | |||||
Self { | |||||
need_update, | |||||
position_id, | |||||
} | |||||
} | |||||
} | |||||
#[derive(SystemData)] | |||||
pub struct RasterUpdateData<'a> { | |||||
raster: WriteExpect<'a, Raster>, | |||||
entities: Entities<'a>, | |||||
positions: ReadStorage<'a, Position>, | |||||
} | |||||
impl<'a> System<'a> for RasterUpdate { | |||||
type SystemData = RasterUpdateData<'a>; | |||||
fn run(&mut self, data: Self::SystemData) { | |||||
let RasterUpdateData { | |||||
mut raster, | |||||
entities, | |||||
positions, | |||||
} = data; | |||||
self.need_update.clear(); | |||||
let events = positions | |||||
.unprotected_storage() | |||||
.channel() | |||||
.read(&mut self.position_id); | |||||
for event in events { | |||||
match event { | |||||
ComponentEvent::Inserted(id) => { | |||||
self.need_update.add(*id); | |||||
} | |||||
ComponentEvent::Modified(id, position) | ComponentEvent::Removed(id, position) => { | |||||
self.need_update.add(*id); | |||||
raster.remove(id, position); | |||||
} | |||||
} | |||||
} | |||||
if self.need_update.is_empty() { | |||||
return; | |||||
} | |||||
for (e, position) in (&entities, &positions).join() { | |||||
raster.insert(e.id(), position); | |||||
} | |||||
} | |||||
} |