Drawing pieces on the board!

Also states: 2d state, skeleton 3d state, menu state, loading state.

Really leaning into the bevy system scheduling.
selection-refactor
Elijah Voigt 2 years ago
parent 21f5bded8a
commit 5f255275e0

@ -96,13 +96,15 @@ fn initialize_board(sprite_sheet: Option<Res<SpriteSheet>>, mut commands: Comman
let index = BoardIndex { x, y }; let index = BoardIndex { x, y };
// Rectangle // Rectangle
parent.spawn(SpriteSheetBundle { parent.spawn((
SpriteSheetBundle {
texture_atlas, texture_atlas,
sprite, sprite,
transform, transform,
index,
..default() ..default()
}); },
index,
));
} }
}); });
} }

@ -4,21 +4,17 @@ pub struct DebugPlugin;
impl Plugin for DebugPlugin { impl Plugin for DebugPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(PostStartup, display_board); app.add_systems(
Update,
display_board.run_if(resource_exists::<DebugEnabled>()),
);
} }
} }
fn display_board(board: Res<crate::game::Board>, pieces: Query<&crate::game::Piece>) { /// Marker resource used to enable Debug mode when present
board.inner.iter().for_each(|row| { #[derive(Debug, Resource)]
print!("+--+--+--+--+--+--+--+--+\n"); struct DebugEnabled;
print!("|");
row.iter() fn display_board(board: Res<crate::game::Board>) {
.map(|piece| piece.and_then(|p| pieces.get(p).ok())) info!("{}", *board);
.for_each(|piece| match piece {
Some(p) => print!("{} |", p),
None => print!(" |"),
});
print!("\n");
});
print!("+--+--+--+--+--+--+--+--+\n");
} }

@ -1,9 +1,170 @@
use crate::prelude::*; use crate::{
game::{Board, BoardIndex, Piece},
prelude::*,
};
const SCALE: f32 = 80.0;
pub struct Display2dPlugin; pub struct Display2dPlugin;
impl Plugin for Display2dPlugin { impl Plugin for Display2dPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
todo!() app.add_systems(
Startup,
(initialize_camera, load_spritesheet).run_if(in_state(GameState::Loading)),
)
.add_systems(
Update,
(
initialize_board.run_if(resource_added::<SpriteSheet>()),
draw_board
.run_if(resource_exists::<SpriteSheet>())
.run_if(resource_changed::<Board>()) // TODO: run_if(in_state(Display2d))
.run_if(any_with_component::<BoardIndex>()),
),
)
.add_systems(OnEnter(GameState::Display2d), (activate, draw_board));
} }
} }
/// Sprite sheet Resource for later reference
#[derive(Debug, Resource)]
struct SpriteSheet {
handle: Handle<TextureAtlas>,
}
/// Marker component for the 2d board entity
#[derive(Debug, Component)]
struct Board2d;
/// Marker for 2d piece entities
#[derive(Debug, Component)]
struct Piece2d;
/// STARTUP: Initialize 2d gameplay Camera
fn initialize_camera(mut commands: Commands) {
commands.spawn(Camera2dBundle {
camera: Camera {
is_active: false,
..default()
},
..default()
});
}
/// STARTUP: Load sprite sheet and insert texture atlas
fn load_spritesheet(
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
server: Res<AssetServer>,
mut commands: Commands,
) {
let atlas = TextureAtlas::from_grid(
server.load("sprites.png"),
Vec2::new(16.0, 16.0),
5,
1,
None,
None,
);
commands.insert_resource(SpriteSheet {
handle: texture_atlases.add(atlas),
});
}
/// STARTUP: Initialize the board for representation
fn initialize_board(sprite_sheet: Option<Res<SpriteSheet>>, mut commands: Commands) {
if let Some(sprite_sheet) = sprite_sheet {
commands
.spawn((
SpatialBundle {
transform: Transform::from_xyz(-SCALE * 3.5, -SCALE * 1.5, 0.0),
..default()
},
Board2d,
))
.with_children(|parent| {
for i in 0..32 {
let x = i % 8;
let y = i / 8;
let s = (x % 2) ^ (y % 2);
let transform = Transform::from_scale(Vec3::splat(5.0))
.with_translation(Vec3::new(SCALE * x as f32, SCALE * y as f32, 0.0));
let sprite = TextureAtlasSprite::new(s);
let texture_atlas = sprite_sheet.handle.clone();
let index = BoardIndex { x, y };
// Rectangle
parent.spawn((
SpriteSheetBundle {
texture_atlas,
sprite,
transform,
..default()
},
index,
));
}
});
}
}
fn draw_board(
board: Option<Res<Board>>,
mut commands: Commands,
tiles: Query<(&Transform, &BoardIndex)>,
pieces: Query<Entity, With<Piece2d>>,
root: Query<Entity, With<Board2d>>,
sprite_sheet: Option<Res<SpriteSheet>>,
) {
if let (Some(board), Some(sprite_sheet)) = (board, sprite_sheet) {
commands.entity(root.single()).with_children(|parent| {
info!("Board and sprite sheet ready, drawing board");
board
.pieces()
.iter()
.filter_map(|(board_index, piece)| {
tiles.iter().find_map(|(transform, this_index)| {
(*this_index == *board_index).then(|| (piece, transform))
})
})
.for_each(|(piece, transform)| {
let texture_atlas = sprite_sheet.handle.clone();
let s = match piece {
Piece::Queen => 2,
Piece::Drone => 3,
Piece::Pawn => 4,
};
let sprite = TextureAtlasSprite::new(s);
// TODO: transform is slightly different, set sprite
parent.spawn((
piece.clone(),
SpriteSheetBundle {
texture_atlas,
sprite,
transform: Transform {
..transform.clone()
},
..default()
},
Piece2d,
));
});
});
}
}
fn activate(
mut cameras: Query<&mut Camera, With<Camera2d>>,
mut boards: Query<&mut Visibility, With<Board2d>>,
) {
cameras.iter_mut().for_each(|mut camera| {
camera.is_active = true;
});
boards.iter_mut().for_each(|mut visibility| {
*visibility = Visibility::Visible;
});
}

@ -4,6 +4,62 @@ pub struct Display3dPlugin;
impl Plugin for Display3dPlugin { impl Plugin for Display3dPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
todo!() app.add_systems(
Startup,
(initialize_camera, load_models).run_if(in_state(GameState::Loading)),
)
.add_systems(
Update,
initialize_board.run_if(resource_added::<ModelMap>()),
)
.add_systems(OnEnter(GameState::Display3d), activate);
} }
} }
#[derive(Debug, Component)]
struct Board3d;
#[derive(Debug, Resource)]
struct ModelMap;
fn initialize_camera(mut commands: Commands) {
commands.spawn(Camera3dBundle {
camera: Camera {
is_active: false,
..default()
},
..default()
});
}
fn load_models(server: Res<AssetServer>, mut commands: Commands) {
warn!("TODO: Load models");
commands.insert_resource(ModelMap);
}
fn initialize_board(mut commands: Commands, model_map: Option<Res<ModelMap>>) {
if let Some(models) = model_map {
warn!("TODO: Intialize 3D Board!");
commands.spawn((
SpatialBundle {
visibility: Visibility::Hidden,
..default()
},
Board3d,
));
}
}
fn activate(
mut cameras: Query<&mut Camera, With<Camera3d>>,
mut boards: Query<&mut Visibility, With<Board3d>>,
) {
cameras.iter_mut().for_each(|mut camera| {
camera.is_active = true;
});
boards.iter_mut().for_each(|mut visibility| {
*visibility = Visibility::Visible;
});
}

@ -8,7 +8,7 @@ impl Plugin for GamePlugin {
} }
} }
#[derive(Debug, Component)] #[derive(Debug, Component, Clone)]
pub(crate) enum Piece { pub(crate) enum Piece {
Pawn, Pawn,
Drone, Drone,
@ -41,65 +41,55 @@ impl std::fmt::Display for Piece {
/// ```` /// ````
#[derive(Debug, Resource)] #[derive(Debug, Resource)]
pub(crate) struct Board { pub(crate) struct Board {
pub inner: Vec<Vec<Option<Entity>>>, inner: Vec<Vec<Option<Piece>>>,
} }
fn setup_board(mut commands: Commands) { #[derive(Debug, Component, PartialEq)]
let a5d = commands pub(crate) struct BoardIndex {
.spawn((SpatialBundle { ..default() }, Piece::Drone)) pub x: usize,
.id(); pub y: usize,
let a6q = commands }
.spawn((SpatialBundle { ..default() }, Piece::Queen))
.id(); impl Board {
let a7q = commands /// Returns the piece at the given location
.spawn((SpatialBundle { ..default() }, Piece::Queen)) pub(crate) fn _at(&self, (_x, _y): (usize, usize)) -> Option<Piece> {
.id(); todo!("return piece at location")
let b0d = commands }
.spawn((SpatialBundle { ..default() }, Piece::Drone))
.id(); /// Returns a list of all pieces on the board with their location
let b1p = commands pub(crate) fn pieces(&self) -> Vec<(BoardIndex, Piece)> {
.spawn((SpatialBundle { ..default() }, Piece::Pawn)) self.inner
.id(); .iter()
let b2p = commands .enumerate()
.spawn((SpatialBundle { ..default() }, Piece::Pawn)) .flat_map(|(y, nested)| {
.id(); nested.iter().enumerate().filter_map(move |(x, p)| {
let c5p = commands p.as_ref().map(|val| (BoardIndex { x, y }, val.clone()))
.spawn((SpatialBundle { ..default() }, Piece::Pawn)) })
.id(); })
let b5p = commands .collect()
.spawn((SpatialBundle { ..default() }, Piece::Pawn)) }
.id(); }
let b6d = commands
.spawn((SpatialBundle { ..default() }, Piece::Drone))
.id();
let b7q = commands
.spawn((SpatialBundle { ..default() }, Piece::Queen))
.id();
let c0q = commands
.spawn((SpatialBundle { ..default() }, Piece::Queen))
.id();
let c1d = commands
.spawn((SpatialBundle { ..default() }, Piece::Drone))
.id();
let c2p = commands
.spawn((SpatialBundle { ..default() }, Piece::Pawn))
.id();
let c6p = commands
.spawn((SpatialBundle { ..default() }, Piece::Pawn))
.id();
let c7d = commands
.spawn((SpatialBundle { ..default() }, Piece::Drone))
.id();
let d0q = commands
.spawn((SpatialBundle { ..default() }, Piece::Queen))
.id();
let d1q = commands
.spawn((SpatialBundle { ..default() }, Piece::Queen))
.id();
let d2d = commands
.spawn((SpatialBundle { ..default() }, Piece::Drone))
.id();
impl std::fmt::Display for Board {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let _ = write!(f, "\n");
self.inner.iter().for_each(|row| {
let _ = write!(f, "+--+--+--+--+--+--+--+--+\n");
let _ = write!(f, "|");
row.iter().for_each(|piece| {
let _ = match piece {
Some(p) => write!(f, "{} |", p),
None => write!(f, " |"),
};
});
let _ = write!(f, "\n");
});
let _ = write!(f, "+--+--+--+--+--+--+--+--+\n");
Ok(())
}
}
fn setup_board(mut commands: Commands) {
commands.insert_resource(Board { commands.insert_resource(Board {
inner: vec![ inner: vec![
vec![ vec![
@ -108,34 +98,34 @@ fn setup_board(mut commands: Commands) {
None, None,
None, None,
None, None,
Some(a5d), Some(Piece::Drone),
Some(a6q), Some(Piece::Queen),
Some(a7q), Some(Piece::Queen),
], ],
vec![ vec![
Some(b0d), Some(Piece::Drone),
Some(b1p), Some(Piece::Pawn),
Some(b2p), Some(Piece::Pawn),
None, None,
None, None,
Some(b5p), Some(Piece::Pawn),
Some(b6d), Some(Piece::Drone),
Some(b7q), Some(Piece::Queen),
], ],
vec![ vec![
Some(c0q), Some(Piece::Queen),
Some(c1d), Some(Piece::Drone),
Some(c2p), Some(Piece::Pawn),
None, None,
None, None,
Some(c5p), Some(Piece::Pawn),
Some(c6p), Some(Piece::Pawn),
Some(c7d), Some(Piece::Drone),
], ],
vec![ vec![
Some(d0q), Some(Piece::Queen),
Some(d1q), Some(Piece::Queen),
Some(d2d), Some(Piece::Drone),
None, None,
None, None,
None, None,

@ -9,8 +9,11 @@ use crate::prelude::*;
fn main() { fn main() {
App::new() App::new()
.add_state::<GameState>()
.add_systems(Update, state)
.add_systems(Update, loading.run_if(in_state(GameState::Loading)))
.add_plugins(( .add_plugins((
DefaultPlugins, DefaultPlugins.set(ImagePlugin::default_nearest()),
audio::AudioPlugin, audio::AudioPlugin,
debug::DebugPlugin, debug::DebugPlugin,
display2d::Display2dPlugin, display2d::Display2dPlugin,
@ -19,3 +22,33 @@ fn main() {
)) ))
.run(); .run();
} }
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)]
pub enum GameState {
#[default]
Loading,
Menu,
Display2d,
Display3d,
}
fn loading(
server: Res<AssetServer>,
sprites: Res<Assets<Image>>,
mut next_state: ResMut<NextState<GameState>>,
) {
let items = { sprites.ids() };
let states = server.get_group_load_state(items);
match states {
LoadState::Loaded | LoadState::NotLoaded => next_state.set(GameState::Display2d),
_ => (),
}
}
fn state(state: Option<Res<State<GameState>>>) {
state.map(|s| {
if s.is_added() || s.is_changed() {
info!("Updated state is {:?}", s);
}
});
}

@ -1,2 +1,6 @@
pub use crate::*;
pub use bevy::asset::LoadState;
pub use bevy::gltf::Gltf;
pub use bevy::prelude::*; pub use bevy::prelude::*;
pub use bevy_fmod::prelude::AudioSource;
pub use bevy_fmod::prelude::*; pub use bevy_fmod::prelude::*;

Loading…
Cancel
Save