| @@ -4,6 +4,10 @@ use lazy_static::lazy_static; | |||
| pub const UNIFORM_BUFFER_INDEX_CAMERA: gl::GLuint = 0; | |||
| pub const UNIFORM_BUFFER_INDEX_UNIFORM: gl::GLuint = 1; | |||
| pub const SHIP_SIZE: f32 = 15.0; | |||
| pub const PLANET_SIZE: f32 = 200.0; | |||
| pub const ASTEROID_SIZE: f32 = 100.0; | |||
| lazy_static! { | |||
| pub static ref PLAYER_COLOR_DEFAULT: Vector4f = Vector4f::new(1.0, 1.0, 1.0, 0.1); | |||
| } | |||
| @@ -5,7 +5,7 @@ use specs::{prelude::*, Entities, ReadExpect, System}; | |||
| use crate::{ | |||
| misc::{Text, TextCache, TextManager}, | |||
| resources::State, | |||
| resources::InputState, | |||
| Error, | |||
| }; | |||
| @@ -55,7 +55,7 @@ impl Summary { | |||
| pub struct SummaryData<'a> { | |||
| entities: Entities<'a>, | |||
| global: ReadExpect<'a, Global>, | |||
| state: ReadExpect<'a, State>, | |||
| input_state: ReadExpect<'a, InputState>, | |||
| } | |||
| impl<'a> System<'a> for Summary { | |||
| @@ -65,7 +65,7 @@ impl<'a> System<'a> for Summary { | |||
| let SummaryData { | |||
| entities, | |||
| global, | |||
| state, | |||
| input_state, | |||
| } = data; | |||
| let entity_count = entities.par_join().count(); | |||
| @@ -82,14 +82,14 @@ impl<'a> System<'a> for Summary { | |||
| &mut self.text, | |||
| 4, | |||
| &mut self.resolution, | |||
| &state.resolution, | |||
| &input_state.resolution, | |||
| |(w, h)| format!("{} | {}", w, h), | |||
| ); | |||
| update_text( | |||
| &mut self.text, | |||
| 6, | |||
| &mut self.mouse_pos, | |||
| &state.mouse_pos, | |||
| &input_state.mouse_pos, | |||
| |(x, y)| format!("{:.2} | {:.2}", x, y), | |||
| ); | |||
| update_text( | |||
| @@ -14,7 +14,7 @@ pub use error::Error; | |||
| use debug::{Fleets as DebugFleets, Ships as DebugShips, Summary as DebugSummary}; | |||
| use misc::{Events, TextManager, Window}; | |||
| use render::{Asteroids, Init, Planets, Ships}; | |||
| use resources::{Camera, Config, Geometry, PlayerState, State, Uniform}; | |||
| use resources::{Camera, Config, Geometry, InputState, PlayerState, Uniform}; | |||
| use systems::{FleetInfoUpdate, StateUpdate}; | |||
| pub struct App<'a, 'b> { | |||
| @@ -30,24 +30,24 @@ impl<'a, 'b> App<'a, 'b> { | |||
| let events = Events::new(world)?; | |||
| let window = Window::new(events.handle(), &config)?; | |||
| let state = State::default(); | |||
| let camera = Camera::new()?; | |||
| let uniform = Uniform::new()?; | |||
| let geometry = Geometry::new(world)?; | |||
| let input_state = InputState::default(); | |||
| let player_state = PlayerState::new(player_id); | |||
| world.insert(state); | |||
| world.insert(config); | |||
| world.insert(camera); | |||
| world.insert(uniform); | |||
| world.insert(geometry); | |||
| world.insert(input_state); | |||
| world.insert(player_state); | |||
| let text_manager = TextManager::new(world)?; | |||
| let mut dispatcher = DispatcherBuilder::new() | |||
| .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(Planets::new(world)?) | |||
| .with_thread_local(Asteroids::new(world)?) | |||
| @@ -76,7 +76,7 @@ impl<'a, 'b> App<'a, 'b> { | |||
| self.window.swap_buffers()?; | |||
| self.is_running = !world.fetch::<State>().close_requested; | |||
| self.is_running = !world.fetch::<InputState>().close_requested; | |||
| Ok(()) | |||
| } | |||
| @@ -60,8 +60,8 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
| use space_crush_app::components::FleetInfo; | |||
| use space_crush_common::{ | |||
| components::{ | |||
| Asteroid, AsteroidType, Fleet, FleetOwned, Planet, Player, PlayerOwned, Position, Ship, | |||
| ShipType, Velocity, | |||
| Asteroid, AsteroidType, Fleet, FleetOwned, Planet, Player, PlayerOwned, Position, | |||
| Shape, Ship, ShipType, Velocity, | |||
| }, | |||
| misc::{PersistWorld, Persistence}, | |||
| }; | |||
| @@ -84,7 +84,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
| .marked::<<PersistWorld as Persistence>::Marker>() | |||
| .with(Position { | |||
| pos: Vector2f::new(500.0, -500.0), | |||
| size: 100.0, | |||
| shape: Shape::Circle(100.0), | |||
| }) | |||
| .with(Fleet { | |||
| orbit_min: 125.0, | |||
| @@ -101,7 +101,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
| .marked::<<PersistWorld as Persistence>::Marker>() | |||
| .with(Position { | |||
| pos: Vector2f::new(500.0, 500.0), | |||
| size: 100.0, | |||
| shape: Shape::Circle(100.0), | |||
| }) | |||
| .with(Fleet { | |||
| orbit_min: 125.0, | |||
| @@ -119,7 +119,7 @@ fn create_world(world: &mut World, player_id: Entity) { | |||
| .with(PlayerOwned { owner: player_id }) | |||
| .with(Position { | |||
| pos: Vector2f::default(), | |||
| size: 250.0, | |||
| shape: Shape::Circle(250.0), | |||
| }) | |||
| .with(Fleet { | |||
| orbit_min: 325.0, | |||
| @@ -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, | |||
| ), | |||
| size: 15.0, | |||
| shape: Shape::Dot, | |||
| }) | |||
| .with(Velocity { | |||
| 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 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, | |||
| resources::Geometry, | |||
| Error, | |||
| @@ -85,7 +88,7 @@ impl<'a> System<'a> for Asteroids { | |||
| for (position, asteroid, owned) in (&position, &asteroid, owned.maybe()).join() { | |||
| let p_x = position.pos.x; | |||
| let p_y = position.pos.y; | |||
| let s = position.size; | |||
| let s = position.shape.circle().unwrap_or(ASTEROID_SIZE); | |||
| let _guard = match asteroid.type_ { | |||
| AsteroidType::Metal => BindGuard::new(&self.texture_metal), | |||
| @@ -14,7 +14,7 @@ use specs::{prelude::*, ReadExpect, System, World, WriteExpect}; | |||
| use crate::{ | |||
| constants::{UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||
| misc::{ControlEvent, MouseButton, MouseEvent, WorldHelper}, | |||
| resources::{Camera, Config, Geometry, State, Uniform}, | |||
| resources::{Camera, Config, Geometry, InputState, Uniform}, | |||
| Error, | |||
| }; | |||
| @@ -54,10 +54,10 @@ pub struct InitData<'a> { | |||
| uniform: WriteExpect<'a, Uniform>, | |||
| control_events: WriteExpect<'a, EventChannel<ControlEvent>>, | |||
| state: ReadExpect<'a, State>, | |||
| global: ReadExpect<'a, Global>, | |||
| config: ReadExpect<'a, Config>, | |||
| geometry: ReadExpect<'a, Geometry>, | |||
| input_state: ReadExpect<'a, InputState>, | |||
| mouse_events: ReadExpect<'a, EventChannel<MouseEvent>>, | |||
| } | |||
| @@ -69,16 +69,16 @@ impl<'a> System<'a> for Init { | |||
| mut camera, | |||
| mut uniform, | |||
| mut control_events, | |||
| state, | |||
| global, | |||
| config, | |||
| geometry, | |||
| input_state, | |||
| mouse_events, | |||
| } = data; | |||
| /* screen size */ | |||
| if self.resolution != state.resolution { | |||
| self.resolution = state.resolution; | |||
| if self.resolution != input_state.resolution { | |||
| self.resolution = input_state.resolution; | |||
| gl::viewport(0, 0, self.resolution.0 as _, self.resolution.1 as _); | |||
| @@ -88,21 +88,22 @@ impl<'a> System<'a> for Init { | |||
| } | |||
| /* zoom */ | |||
| let mouse_pos = &input_state.mouse_pos; | |||
| let events = mouse_events.read(&mut self.mouse_event_id); | |||
| for event in events { | |||
| match event { | |||
| MouseEvent::ScrollY(delta) => { | |||
| let s = config.input.camera_zoom_speed; | |||
| let z = s / (s - delta); | |||
| let m = Matrix4f::translate((state.mouse_pos.0, state.mouse_pos.1, 0.0).into()) | |||
| let m = Matrix4f::translate((mouse_pos.0, mouse_pos.1, 0.0).into()) | |||
| * Matrix4f::scale(z.into()) | |||
| * Matrix4f::translate((-state.mouse_pos.0, -state.mouse_pos.1, 0.0).into()); | |||
| * Matrix4f::translate((-mouse_pos.0, -mouse_pos.1, 0.0).into()); | |||
| camera | |||
| .update_with(move |v| m * v) | |||
| .error("Error while zooming camera"); | |||
| } | |||
| MouseEvent::Delta(x, y) if state.button_state(&[MouseButton::Right]) => { | |||
| MouseEvent::Delta(x, y) if input_state.button_state(&[MouseButton::Right]) => { | |||
| let m = Matrix4f::translate((*x, -*y, 0.0).into()); | |||
| camera | |||
| @@ -120,10 +121,10 @@ impl<'a> System<'a> for Init { | |||
| } | |||
| /* move camera */ | |||
| let up = state.key_state(&config.input.camera_move_key_up); | |||
| let down = state.key_state(&config.input.camera_move_key_down); | |||
| let left = state.key_state(&config.input.camera_move_key_left); | |||
| let right = state.key_state(&config.input.camera_move_key_right); | |||
| let up = input_state.key_state(&config.input.camera_move_key_up); | |||
| let down = input_state.key_state(&config.input.camera_move_key_down); | |||
| let left = input_state.key_state(&config.input.camera_move_key_left); | |||
| let right = input_state.key_state(&config.input.camera_move_key_right); | |||
| if up || down || left || right { | |||
| let s = config.input.camera_move_speed * global.delta; | |||
| @@ -12,7 +12,10 @@ use space_crush_common::{ | |||
| use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | |||
| 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, | |||
| resources::Geometry, | |||
| Error, | |||
| @@ -83,7 +86,7 @@ impl<'a> System<'a> for Planets { | |||
| for (p, _, owned) in (&position, &planet, owned.maybe()).join() { | |||
| let p_x = p.pos.x; | |||
| 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)) { | |||
| Some(pv) => &pv.color, | |||
| @@ -12,7 +12,9 @@ use space_crush_common::{ | |||
| use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | |||
| 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, | |||
| resources::Geometry, | |||
| Error, | |||
| @@ -103,7 +105,7 @@ impl<'a> System<'a> for Ships { | |||
| let p_y = p.pos.y; | |||
| let d_x = v.dir.x; | |||
| let d_y = v.dir.y; | |||
| let s = p.size; | |||
| let s = SHIP_SIZE; | |||
| let m = Matrix4f::new( | |||
| Vector4f::new(-s * d_y, s * d_x, 0.0, 0.0), | |||
| @@ -6,7 +6,7 @@ use std::iter::IntoIterator; | |||
| use crate::misc::{MouseButton, VirtualKeyCode}; | |||
| #[derive(Default)] | |||
| pub struct State { | |||
| pub struct InputState { | |||
| pub mouse_pos: (f32, f32), | |||
| pub resolution: (u32, u32), | |||
| pub close_requested: bool, | |||
| @@ -14,7 +14,7 @@ pub struct State { | |||
| pub button_states: HashSet<MouseButton>, | |||
| } | |||
| impl State { | |||
| impl InputState { | |||
| pub fn key_state<'a, I>(&self, codes: I) -> bool | |||
| where | |||
| I: IntoIterator<Item = &'a VirtualKeyCode>, | |||
| @@ -1,13 +1,13 @@ | |||
| mod camera; | |||
| mod config; | |||
| mod geometry; | |||
| mod input_state; | |||
| mod player_state; | |||
| mod state; | |||
| mod uniform; | |||
| pub use camera::Camera; | |||
| pub use config::Config; | |||
| pub use geometry::Geometry; | |||
| pub use input_state::InputState; | |||
| pub use player_state::PlayerState; | |||
| pub use state::State; | |||
| pub use uniform::Uniform; | |||
| @@ -10,7 +10,7 @@ use specs::{ | |||
| World, WriteStorage, | |||
| }; | |||
| use crate::{components::FleetInfo, resources::PlayerState, Error}; | |||
| use crate::{components::FleetInfo, resources::PlayerState}; | |||
| pub struct FleetInfoUpdate { | |||
| modified: HashMap<Index, Modified>, | |||
| @@ -26,7 +26,7 @@ struct Modified { | |||
| } | |||
| impl FleetInfoUpdate { | |||
| pub fn new(world: &mut World) -> Result<Self, Error> { | |||
| pub fn new(world: &mut World) -> Self { | |||
| let modified = HashMap::new(); | |||
| let need_update = BitSet::new(); | |||
| @@ -50,12 +50,12 @@ impl FleetInfoUpdate { | |||
| .register_reader() | |||
| }; | |||
| Ok(Self { | |||
| Self { | |||
| modified, | |||
| need_update, | |||
| fleet_owned_id, | |||
| player_owned_id, | |||
| }) | |||
| } | |||
| } | |||
| } | |||
| @@ -4,7 +4,7 @@ use specs::{prelude::*, ReadExpect, System, World, Write}; | |||
| use crate::{ | |||
| misc::{KeyboardEvent, MouseEvent, WindowEvent}, | |||
| resources::State, | |||
| resources::InputState, | |||
| Error, | |||
| }; | |||
| @@ -30,7 +30,7 @@ impl StateUpdate { | |||
| #[derive(SystemData)] | |||
| pub struct StateUpdateData<'a> { | |||
| state: Write<'a, State>, | |||
| input_state: Write<'a, InputState>, | |||
| mouse_events: ReadExpect<'a, EventChannel<MouseEvent>>, | |||
| window_events: ReadExpect<'a, EventChannel<WindowEvent>>, | |||
| keyboard_events: ReadExpect<'a, EventChannel<KeyboardEvent>>, | |||
| @@ -41,7 +41,7 @@ impl<'a> System<'a> for StateUpdate { | |||
| fn run(&mut self, data: Self::SystemData) { | |||
| let StateUpdateData { | |||
| mut state, | |||
| mut input_state, | |||
| mouse_events, | |||
| window_events, | |||
| keyboard_events, | |||
| @@ -51,13 +51,13 @@ impl<'a> System<'a> for StateUpdate { | |||
| for event in events { | |||
| match event { | |||
| MouseEvent::Move(x, y) => { | |||
| let x = *x - state.resolution.0 as f32 / 2.0; | |||
| let y = state.resolution.1 as f32 / 2.0 - *y; | |||
| let x = *x - input_state.resolution.0 as f32 / 2.0; | |||
| let y = input_state.resolution.1 as f32 / 2.0 - *y; | |||
| state.mouse_pos = (x, y); | |||
| input_state.mouse_pos = (x, y); | |||
| } | |||
| MouseEvent::ButtonUp(button) => state.set_button_state(*button, false), | |||
| MouseEvent::ButtonDown(button) => state.set_button_state(*button, true), | |||
| MouseEvent::ButtonUp(button) => input_state.set_button_state(*button, false), | |||
| MouseEvent::ButtonDown(button) => input_state.set_button_state(*button, true), | |||
| _ => (), | |||
| } | |||
| } | |||
| @@ -66,10 +66,10 @@ impl<'a> System<'a> for StateUpdate { | |||
| for event in events { | |||
| match event { | |||
| WindowEvent::Resize(w, h) => { | |||
| state.resolution = (*w, *h); | |||
| input_state.resolution = (*w, *h); | |||
| } | |||
| WindowEvent::Close => { | |||
| state.close_requested = true; | |||
| input_state.close_requested = true; | |||
| } | |||
| } | |||
| } | |||
| @@ -77,8 +77,8 @@ impl<'a> System<'a> for StateUpdate { | |||
| let events = keyboard_events.read(&mut self.keyboard_events_id); | |||
| for event in events { | |||
| match event { | |||
| KeyboardEvent::KeyUp(code) => state.set_key_state(*code, false), | |||
| KeyboardEvent::KeyDown(code) => state.set_key_state(*code, true), | |||
| KeyboardEvent::KeyUp(code) => input_state.set_key_state(*code, false), | |||
| KeyboardEvent::KeyDown(code) => input_state.set_key_state(*code, true), | |||
| _ => (), | |||
| } | |||
| } | |||
| @@ -10,6 +10,6 @@ pub use asteroid::{Asteroid, Type as AsteroidType}; | |||
| pub use fleet::{Fleet, Owned as FleetOwned}; | |||
| pub use planet::Planet; | |||
| 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 velocity::Velocity; | |||
| @@ -5,9 +5,31 @@ use specs::{Component, VecStorage}; | |||
| #[derive(Clone, Debug, Default, Serialize, Deserialize)] | |||
| pub struct Position { | |||
| pub pos: Vector2f, | |||
| pub size: f32, | |||
| pub shape: Shape, | |||
| } | |||
| #[derive(Clone, Debug, Serialize, Deserialize)] | |||
| pub enum Shape { | |||
| Dot, | |||
| Circle(f32), | |||
| } | |||
| impl Component for Position { | |||
| type Storage = 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 | |||
| } | |||
| } | |||