1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
//! Player and editor input types.
use std::array;
use bones_framework::input::PlayerControls;
use crate::{prelude::*, MAX_PLAYERS};
pub fn install(session: &mut Session) {
session.world.init_resource::<MatchInputs>();
}
/// The inputs for each player in this simulation frame.
#[derive(Clone, Debug, HasSchema)]
pub struct MatchInputs {
pub players: [PlayerInput; MAX_PLAYERS as usize],
}
impl Default for MatchInputs {
fn default() -> Self {
Self {
players: array::from_fn(|_| default()),
}
}
}
impl PlayerControls<'_, PlayerControl> for MatchInputs {
type ControlSource = ControlSource;
type ControlMapping = PlayerControlMapping;
type InputCollector = PlayerInputCollector;
fn update_controls(&mut self, collector: &mut PlayerInputCollector) {
(0..MAX_PLAYERS as usize).for_each(|i| {
let player_input = &mut self.players[i];
if let Some(source) = &player_input.control_source {
player_input.control = *collector.get_control(i, *source);
}
});
}
fn get_control_source(&self, player_idx: usize) -> Option<ControlSource> {
self.players.get(player_idx).unwrap().control_source
}
fn get_control(&self, player_idx: usize) -> &PlayerControl {
&self.players.get(player_idx).unwrap().control
}
fn get_control_mut(&mut self, player_idx: usize) -> &mut PlayerControl {
&mut self.players.get_mut(player_idx).unwrap().control
}
}
/// Player input, not just controls, but also other status that comes from the player, such as the
/// selected player and whether the player is actually active.
#[derive(Default, Clone, Debug, HasSchema)]
pub struct PlayerInput {
/// Whether or not the player is present.
pub active: bool,
/// The selected player skin.
pub selected_player: Handle<PlayerMeta>,
/// The selected player hat.
pub selected_hat: Option<Handle<HatMeta>>,
/// The player control input
pub control: PlayerControl,
/// The editor inputs the player is making, if any.
pub editor_input: Option<EditorInput>,
/// If this is [`None`] it means the player is an AI, or remote player in networked game.
pub control_source: Option<ControlSource>,
/// Whether or not this is an AI player.
pub is_ai: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct LocatedTileLayer {
pub layer_index: u32,
pub located_tiles: Vec<(UVec2, u32, TileCollisionKind)>,
}
#[derive(Clone, HasSchema, Default, Debug)]
pub struct ElementLayer {
pub layer_index: u32,
pub located_elements: Vec<(Vec2, Handle<ElementMeta>)>,
}
/// The editor inputs that a player may make.
#[derive(Clone, Debug)]
pub enum EditorInput {
/// Spawn an element onto the map.
SpawnElement {
/// The handle to the element that is being spawned.
handle: Handle<ElementMeta>,
/// The translation to spawn the element with.
translation: Vec2,
/// The map layer index to spawn the element on.
layer: u8,
},
MoveEntity {
/// The entity to move.
entity: Entity,
/// The amount to move the entity.
pos: Vec2,
},
DeleteEntity {
/// The entity to delete.
entity: Entity,
},
/// Create a new layer
CreateLayer {
/// The name of the layer.
id: String,
},
/// Rename a map layer.
RenameLayer {
/// The index of the layer to rename.
layer: u8,
/// The new name of the layer.
name: String,
},
DeleteLayer {
layer: u8,
},
/// Move a layer up or down.
MoveLayer {
/// The layer to move
layer: u8,
/// Whether or not to move the layer down. If false, move the layer up.
down: bool,
},
/// Update the tilemap of a layer.
SetTilemap {
/// The layer index of the layer to update.
layer: u8,
/// The handle to the tilemap to use or [`None`] to clear the tilemap.
handle: Option<Handle<Atlas>>,
},
SetTile {
/// The layer index of the layer to update
layer: u8,
/// The position of the tile to set
pos: UVec2,
/// The index in the tilemap to set the tile, or [`None`] to delete the tile.
tilemap_tile_idx: Option<u32>,
/// The tile collision kind
collision: TileCollisionKind,
},
RenameMap {
name: String,
},
RandomizeTiles {
tile_layers: Vec<LocatedTileLayer>,
element_layers: Vec<ElementLayer>,
tile_size: Vec2,
},
}