@@ -1,8 +1,9 @@ | |||||
use space_crush_common::components::ShipCount; | use space_crush_common::components::ShipCount; | ||||
use specs::{Component, HashMapStorage}; | |||||
use specs::{hibitset::BitSet, Component, HashMapStorage}; | |||||
#[derive(Default, Debug)] | #[derive(Default, Debug)] | ||||
pub struct FleetInfo { | pub struct FleetInfo { | ||||
pub owned: BitSet, | |||||
pub count: ShipCount, | pub count: ShipCount, | ||||
} | } | ||||
@@ -15,7 +15,7 @@ use debug::{Fleets as DebugFleets, Ships as DebugShips, Summary as DebugSummary} | |||||
use misc::{Events, TextManager, Window}; | use misc::{Events, TextManager, Window}; | ||||
use render::{Asteroids, FleetSelect, Init, Planets, Ships}; | use render::{Asteroids, FleetSelect, Init, Planets, Ships}; | ||||
use resources::{Camera, Config, Geometry, InputState, PlayerState, Uniform}; | use resources::{Camera, Config, Geometry, InputState, PlayerState, Uniform}; | ||||
use systems::{FleetInfoUpdate, StateUpdate}; | |||||
use systems::{FleetControl, FleetInfoUpdate, StateUpdate}; | |||||
pub struct App<'a, 'b> { | pub struct App<'a, 'b> { | ||||
is_running: bool, | is_running: bool, | ||||
@@ -48,6 +48,7 @@ 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(FleetControl::new(world)?, "fleet_control", &[]) | |||||
.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)?) | ||||
@@ -79,69 +79,69 @@ fn create_world(world: &mut World, player_id: Entity) { | |||||
) | ) | ||||
.unwrap(); | .unwrap(); | ||||
world | |||||
let planet = world | |||||
.create_entity() | .create_entity() | ||||
.marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
.with(PlayerOwned { owner: player_id }) | |||||
.with(Position { | .with(Position { | ||||
pos: Vector2f::new(1000.0, -1000.0), | |||||
shape: Shape::Circle(100.0), | |||||
pos: Vector2f::default(), | |||||
shape: Shape::Circle(250.0), | |||||
}) | }) | ||||
.with(Fleet { | .with(Fleet { | ||||
orbit_min: 125.0, | |||||
orbit_max: 175.0, | |||||
orbit_min: 325.0, | |||||
orbit_max: 425.0, | |||||
}) | }) | ||||
.with(FleetInfo::default()) | .with(FleetInfo::default()) | ||||
.with(Asteroid { | |||||
type_: AsteroidType::Metal, | |||||
}) | |||||
.with(Planet {}) | |||||
.build(); | .build(); | ||||
world | world | ||||
.create_entity() | .create_entity() | ||||
.marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
.with(Position { | .with(Position { | ||||
pos: Vector2f::new(1000.0, 1000.0), | |||||
shape: Shape::Circle(100.0), | |||||
pos: Vector2f::new(2000.0, 0.0), | |||||
shape: Shape::Circle(250.0), | |||||
}) | }) | ||||
.with(Fleet { | .with(Fleet { | ||||
orbit_min: 125.0, | |||||
orbit_max: 175.0, | |||||
orbit_min: 325.0, | |||||
orbit_max: 425.0, | |||||
}) | }) | ||||
.with(FleetInfo::default()) | .with(FleetInfo::default()) | ||||
.with(Asteroid { | |||||
type_: AsteroidType::Crystal, | |||||
}) | |||||
.with(Planet {}) | |||||
.build(); | .build(); | ||||
let planet = world | |||||
world | |||||
.create_entity() | .create_entity() | ||||
.marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
.with(PlayerOwned { owner: player_id }) | |||||
.with(Position { | .with(Position { | ||||
pos: Vector2f::default(), | |||||
shape: Shape::Circle(250.0), | |||||
pos: Vector2f::new(1000.0, -1000.0), | |||||
shape: Shape::Circle(100.0), | |||||
}) | }) | ||||
.with(Fleet { | .with(Fleet { | ||||
orbit_min: 325.0, | |||||
orbit_max: 425.0, | |||||
orbit_min: 125.0, | |||||
orbit_max: 175.0, | |||||
}) | }) | ||||
.with(FleetInfo::default()) | .with(FleetInfo::default()) | ||||
.with(Planet {}) | |||||
.with(Asteroid { | |||||
type_: AsteroidType::Metal, | |||||
}) | |||||
.build(); | .build(); | ||||
world | world | ||||
.create_entity() | .create_entity() | ||||
.marked::<<PersistWorld as Persistence>::Marker>() | .marked::<<PersistWorld as Persistence>::Marker>() | ||||
.with(Position { | .with(Position { | ||||
pos: Vector2f::new(2000.0, 0.0), | |||||
shape: Shape::Circle(250.0), | |||||
pos: Vector2f::new(1000.0, 1000.0), | |||||
shape: Shape::Circle(100.0), | |||||
}) | }) | ||||
.with(Fleet { | .with(Fleet { | ||||
orbit_min: 325.0, | |||||
orbit_max: 425.0, | |||||
orbit_min: 125.0, | |||||
orbit_max: 175.0, | |||||
}) | }) | ||||
.with(FleetInfo::default()) | .with(FleetInfo::default()) | ||||
.with(Planet {}) | |||||
.with(Asteroid { | |||||
type_: AsteroidType::Crystal, | |||||
}) | |||||
.build(); | .build(); | ||||
for i in 0..30 { | for i in 0..30 { | ||||
@@ -46,6 +46,8 @@ pub struct Input { | |||||
pub camera_move_button: MouseButton, | pub camera_move_button: MouseButton, | ||||
#[serde(default = "defaults::fleet_select_button")] | #[serde(default = "defaults::fleet_select_button")] | ||||
pub fleet_select_button: MouseButton, | pub fleet_select_button: MouseButton, | ||||
#[serde(default = "defaults::fleet_move_button")] | |||||
pub fleet_move_button: MouseButton, | |||||
#[serde(default = "defaults::camera_move_speed")] | #[serde(default = "defaults::camera_move_speed")] | ||||
pub camera_move_speed: f32, | pub camera_move_speed: f32, | ||||
@@ -95,6 +97,7 @@ impl Default for Input { | |||||
camera_move_button: defaults::camera_move_button(), | camera_move_button: defaults::camera_move_button(), | ||||
fleet_select_button: defaults::fleet_select_button(), | fleet_select_button: defaults::fleet_select_button(), | ||||
fleet_move_button: defaults::fleet_move_button(), | |||||
camera_move_speed: defaults::camera_move_speed(), | camera_move_speed: defaults::camera_move_speed(), | ||||
camera_zoom_speed: defaults::camera_zoom_speed(), | camera_zoom_speed: defaults::camera_zoom_speed(), | ||||
@@ -145,6 +148,10 @@ mod defaults { | |||||
MouseButton::Left | MouseButton::Left | ||||
} | } | ||||
pub fn fleet_move_button() -> MouseButton { | |||||
MouseButton::Right | |||||
} | |||||
pub fn camera_move_speed() -> f32 { | pub fn camera_move_speed() -> f32 { | ||||
500.0 | 500.0 | ||||
} | } | ||||
@@ -0,0 +1,113 @@ | |||||
use shrev::{EventChannel, ReaderId}; | |||||
use space_crush_common::{ | |||||
components::{Fleet, FleetOwned, Position, Ship, ShipType}, | |||||
misc::WorldHelper, | |||||
return_if_none, | |||||
}; | |||||
use specs::{prelude::*, Entities, Entity, ReadStorage, System, World, WriteStorage}; | |||||
use crate::{ | |||||
components::FleetInfo, | |||||
misc::MouseEvent, | |||||
resources::{Camera, Config, InputState, PlayerState}, | |||||
Error, | |||||
}; | |||||
pub struct FleetControl { | |||||
mouse_event_id: ReaderId<MouseEvent>, | |||||
target_fleet: Option<Entity>, | |||||
} | |||||
#[derive(SystemData)] | |||||
pub struct FleetControlData<'a> { | |||||
player_state: WriteExpect<'a, PlayerState>, | |||||
mouse_events: ReadExpect<'a, EventChannel<MouseEvent>>, | |||||
input_state: ReadExpect<'a, InputState>, | |||||
camera: ReadExpect<'a, Camera>, | |||||
config: ReadExpect<'a, Config>, | |||||
entities: Entities<'a>, | |||||
ships: ReadStorage<'a, Ship>, | |||||
fleet_owned: WriteStorage<'a, FleetOwned>, | |||||
positions: ReadStorage<'a, Position>, | |||||
fleet_infos: ReadStorage<'a, FleetInfo>, | |||||
fleets: ReadStorage<'a, Fleet>, | |||||
} | |||||
impl FleetControl { | |||||
pub fn new(world: &mut World) -> Result<Self, Error> { | |||||
let mouse_event_id = world.register_event_reader::<MouseEvent>()?; | |||||
let target_fleet = None; | |||||
Ok(Self { | |||||
mouse_event_id, | |||||
target_fleet, | |||||
}) | |||||
} | |||||
} | |||||
impl<'a> System<'a> for FleetControl { | |||||
type SystemData = FleetControlData<'a>; | |||||
fn run(&mut self, data: Self::SystemData) { | |||||
let FleetControlData { | |||||
mut player_state, | |||||
mouse_events, | |||||
input_state, | |||||
camera, | |||||
config, | |||||
entities, | |||||
ships, | |||||
mut fleet_owned, | |||||
positions, | |||||
fleet_infos, | |||||
fleets, | |||||
} = data; | |||||
let events = mouse_events.read(&mut self.mouse_event_id); | |||||
for event in events { | |||||
match event { | |||||
MouseEvent::ButtonDown(button) if button == &config.input.fleet_move_button => { | |||||
let pos = camera.view_to_world(input_state.mouse_pos); | |||||
for (id, position, fleet) in (&entities, &positions, &fleets).join() { | |||||
let r = fleet.orbit_max * fleet.orbit_max; | |||||
if (position.pos - pos).length_sqr() <= r { | |||||
self.target_fleet = Some(id); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
MouseEvent::ButtonUp(button) if button == &config.input.fleet_move_button => { | |||||
let selection = player_state.selection.take(); | |||||
let target_fleet = return_if_none!(self.target_fleet.take()); | |||||
let mut selection = return_if_none!(selection); | |||||
let fleet_info = return_if_none!(fleet_infos.get(selection.fleet)); | |||||
for (ship, fleet_owned, _) in | |||||
(&ships, &mut fleet_owned, &fleet_info.owned).join() | |||||
{ | |||||
match &ship.type_ { | |||||
ShipType::Fighter if selection.count.fighter > 0 => { | |||||
fleet_owned.owner = target_fleet; | |||||
selection.count.fighter -= 1; | |||||
} | |||||
ShipType::Bomber if selection.count.bomber > 0 => { | |||||
fleet_owned.owner = target_fleet; | |||||
selection.count.bomber -= 1; | |||||
} | |||||
ShipType::Transporter if selection.count.transporter > 0 => { | |||||
fleet_owned.owner = target_fleet; | |||||
selection.count.transporter -= 1; | |||||
} | |||||
_ => (), | |||||
} | |||||
} | |||||
} | |||||
MouseEvent::Move(_, _) => { | |||||
self.target_fleet = None; | |||||
} | |||||
_ => (), | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -155,8 +155,10 @@ impl<'a> System<'a> for FleetInfoUpdate { | |||||
}; | }; | ||||
if old_match && !new_match { | if old_match && !new_match { | ||||
fleet_info.owned.remove(ship_id.id()); | |||||
fleet_info.count[ship.type_] = fleet_info.count[ship.type_].saturating_sub(1); | fleet_info.count[ship.type_] = fleet_info.count[ship.type_].saturating_sub(1); | ||||
} else if !old_match && new_match { | } else if !old_match && new_match { | ||||
fleet_info.owned.add(ship_id.id()); | |||||
fleet_info.count[ship.type_] += 1; | fleet_info.count[ship.type_] += 1; | ||||
} | } | ||||
} | } | ||||
@@ -1,5 +1,7 @@ | |||||
mod fleet_control; | |||||
mod fleet_info_update; | mod fleet_info_update; | ||||
mod state_update; | mod state_update; | ||||
pub use fleet_control::FleetControl; | |||||
pub use fleet_info_update::FleetInfoUpdate; | pub use fleet_info_update::FleetInfoUpdate; | ||||
pub use state_update::StateUpdate; | pub use state_update::StateUpdate; |