|
|
|
@ -8,10 +8,7 @@ use bevy::{
|
|
|
|
/// TODO: Custom Asset: SpriteSheetAtlas Mapper
|
|
|
|
/// TODO: Custom Asset: SpriteSheetAtlas Mapper
|
|
|
|
/// TODO: Handle Cursor!
|
|
|
|
/// TODO: Handle Cursor!
|
|
|
|
///
|
|
|
|
///
|
|
|
|
use crate::{
|
|
|
|
use crate::{game::*, prelude::*};
|
|
|
|
game::{ActiveTile, Board, BoardIndex, Piece, Side, Tile},
|
|
|
|
|
|
|
|
prelude::*,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const SCALE: f32 = 4.0;
|
|
|
|
const SCALE: f32 = 4.0;
|
|
|
|
const TILE_SIZE: f32 = 16.0;
|
|
|
|
const TILE_SIZE: f32 = 16.0;
|
|
|
|
@ -26,25 +23,19 @@ impl Plugin for Display2dPlugin {
|
|
|
|
.add_systems(
|
|
|
|
.add_systems(
|
|
|
|
Update,
|
|
|
|
Update,
|
|
|
|
(
|
|
|
|
(
|
|
|
|
active_tile.run_if(in_state(GameState::Display2d)),
|
|
|
|
|
|
|
|
menu::exit_to_menu.run_if(in_state(GameState::Display2d)),
|
|
|
|
menu::exit_to_menu.run_if(in_state(GameState::Display2d)),
|
|
|
|
select_piece.run_if(in_state(GameState::Display2d)),
|
|
|
|
select_2d.run_if(on_event::<MouseButtonInput>()),
|
|
|
|
move_piece
|
|
|
|
move_piece
|
|
|
|
.run_if(in_state(GameState::Display2d))
|
|
|
|
.run_if(in_state(GameState::Display2d))
|
|
|
|
.run_if(any_with_component::<game::Selected>()),
|
|
|
|
.run_if(any_with_component::<game::Selected>()),
|
|
|
|
place_piece
|
|
|
|
place_piece
|
|
|
|
.run_if(in_state(GameState::Display2d))
|
|
|
|
.run_if(in_state(GameState::Display2d))
|
|
|
|
.run_if(any_with_component::<game::Selected>()),
|
|
|
|
.run_if(any_with_component::<game::Selected>()),
|
|
|
|
cancel_place
|
|
|
|
|
|
|
|
.run_if(in_state(GameState::Display2d))
|
|
|
|
|
|
|
|
.run_if(on_event::<MouseButtonInput>()),
|
|
|
|
|
|
|
|
snap_back_cancel
|
|
|
|
|
|
|
|
.run_if(in_state(GameState::Display2d))
|
|
|
|
|
|
|
|
.run_if(any_component_removed::<game::Selected>()),
|
|
|
|
|
|
|
|
update_background.run_if(on_event::<WindowResized>()),
|
|
|
|
update_background.run_if(on_event::<WindowResized>()),
|
|
|
|
set_transform
|
|
|
|
set_2d_transform
|
|
|
|
.after(game::update_board::<Display2d>)
|
|
|
|
.run_if(any_component_changed::<BoardIndex>)
|
|
|
|
.run_if(any_component_changed::<BoardIndex>),
|
|
|
|
.before(game::update_board::<Display2d>)
|
|
|
|
|
|
|
|
.after(game::manage_piece),
|
|
|
|
set_piece_sprite.run_if(any_component_changed::<Side>),
|
|
|
|
set_piece_sprite.run_if(any_component_changed::<Side>),
|
|
|
|
set_tile_sprite.run_if(any_component_added::<game::Tile>),
|
|
|
|
set_tile_sprite.run_if(any_component_added::<game::Tile>),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
@ -232,91 +223,99 @@ fn set_tile_sprite(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Sets a piece location given it's board index
|
|
|
|
/// Sets a piece location given it's board index
|
|
|
|
fn set_transform(
|
|
|
|
fn set_2d_transform(
|
|
|
|
mut events: Query<
|
|
|
|
mut events: Query<
|
|
|
|
(&mut Transform, &BoardIndex),
|
|
|
|
(Entity, &mut Transform, &BoardIndex),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
With<Display2d>,
|
|
|
|
With<Display2d>,
|
|
|
|
Or<(Changed<BoardIndex>, Added<BoardIndex>)>,
|
|
|
|
Or<(Changed<BoardIndex>, Added<BoardIndex>)>,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
>,
|
|
|
|
>,
|
|
|
|
|
|
|
|
pieces: Query<Entity, (With<game::Piece>, With<Display2d>)>,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
events.iter_mut().for_each(|(mut t, i)| {
|
|
|
|
events.iter_mut().for_each(|(e, mut t, i)| {
|
|
|
|
let x = SCALE * 16.0 * ((i.x as f32) - 3.5);
|
|
|
|
let x = SCALE * 16.0 * ((i.x as f32) - 3.5);
|
|
|
|
let y = SCALE * 16.0 * ((i.y as f32) - 1.5);
|
|
|
|
let y = SCALE * 16.0 * ((i.y as f32) - 1.5);
|
|
|
|
*t = Transform::from_scale(Vec3::splat(SCALE)).with_translation(Vec3::new(x, y, 0.0));
|
|
|
|
let z = if pieces.contains(e) { 1.0 } else { 0.0 };
|
|
|
|
|
|
|
|
*t = Transform::from_scale(Vec3::splat(SCALE)).with_translation(Vec3::new(x, y, z));
|
|
|
|
debug!("setting position of {:?} to {:?}", i, t);
|
|
|
|
debug!("setting position of {:?} to {:?}", i, t);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn active_tile(
|
|
|
|
fn select_2d(
|
|
|
|
mut events: EventReader<CursorMoved>,
|
|
|
|
|
|
|
|
sprite_q: Query<(
|
|
|
|
|
|
|
|
&TextureAtlasSprite,
|
|
|
|
|
|
|
|
&Handle<TextureAtlas>,
|
|
|
|
|
|
|
|
&GlobalTransform,
|
|
|
|
|
|
|
|
&BoardIndex,
|
|
|
|
|
|
|
|
)>,
|
|
|
|
|
|
|
|
camera_q: Query<(&Camera, &GlobalTransform), With<Display2d>>,
|
|
|
|
|
|
|
|
atlases: Res<Assets<TextureAtlas>>,
|
|
|
|
|
|
|
|
mut active: ResMut<ActiveTile>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
events.iter().for_each(|CursorMoved { position, .. }| {
|
|
|
|
|
|
|
|
if let Some(position) = camera_q
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.find_map(|(camera, transform)| camera.viewport_to_world_2d(transform, *position))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let idx = sprite_q.iter().find_map(
|
|
|
|
|
|
|
|
|(TextureAtlasSprite { index, anchor, .. }, handle, transform, board_index)| {
|
|
|
|
|
|
|
|
// Implementation credit goes to the sprite bevy_mod_picking backend
|
|
|
|
|
|
|
|
// TODO: Upstream changes
|
|
|
|
|
|
|
|
let pos = transform.translation();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let size = {
|
|
|
|
|
|
|
|
let sprite_size = atlases
|
|
|
|
|
|
|
|
.get(handle)
|
|
|
|
|
|
|
|
.map(|atlas| atlas.textures.get(*index).expect("Get this rect texture"))
|
|
|
|
|
|
|
|
.expect("get this rect")
|
|
|
|
|
|
|
|
.size();
|
|
|
|
|
|
|
|
let (transform_scale, _, _) = transform.to_scale_rotation_translation();
|
|
|
|
|
|
|
|
sprite_size * transform_scale.truncate()
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let center = pos.truncate() - (anchor.as_vec() * size);
|
|
|
|
|
|
|
|
let rect = Rect::from_center_half_size(center, size / 2.0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rect.contains(position).then_some(board_index)
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
if active.idx != idx.cloned() {
|
|
|
|
|
|
|
|
active.idx = idx.cloned();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn select_piece(
|
|
|
|
|
|
|
|
mut events: EventReader<MouseButtonInput>,
|
|
|
|
mut events: EventReader<MouseButtonInput>,
|
|
|
|
pieces: Query<(Entity, &BoardIndex), (With<game::Piece>, With<Display2d>)>,
|
|
|
|
sprite_q: Query<
|
|
|
|
active: Res<ActiveTile>,
|
|
|
|
(
|
|
|
|
mut commands: Commands,
|
|
|
|
Entity,
|
|
|
|
|
|
|
|
&TextureAtlasSprite,
|
|
|
|
|
|
|
|
&Handle<TextureAtlas>,
|
|
|
|
|
|
|
|
&GlobalTransform,
|
|
|
|
|
|
|
|
&BoardIndex,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
(Without<game::Selected>, With<Display2d>),
|
|
|
|
|
|
|
|
>,
|
|
|
|
|
|
|
|
cameras: Query<(&Camera, &GlobalTransform), With<Display2d>>,
|
|
|
|
|
|
|
|
atlases: Res<Assets<TextureAtlas>>,
|
|
|
|
|
|
|
|
windows: Query<&Window, With<PrimaryWindow>>,
|
|
|
|
mut writer: EventWriter<game::GameEvent>,
|
|
|
|
mut writer: EventWriter<game::GameEvent>,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
events
|
|
|
|
events
|
|
|
|
.iter()
|
|
|
|
.iter()
|
|
|
|
.filter_map(|MouseButtonInput { button, state, .. }| {
|
|
|
|
.filter(|ev| ev.state == ButtonState::Pressed)
|
|
|
|
active.idx.as_ref().and_then(|index| {
|
|
|
|
.for_each(|_| {
|
|
|
|
pieces.iter().find_map(|(entity, board_idx)| {
|
|
|
|
windows
|
|
|
|
(board_idx == index).then_some((entity, button, state))
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.filter_map(|window| window.cursor_position())
|
|
|
|
|
|
|
|
.find_map(|position| {
|
|
|
|
|
|
|
|
cameras
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.filter_map(|(camera, gt)| camera.viewport_to_world_2d(gt, position))
|
|
|
|
|
|
|
|
.find_map(|pos| {
|
|
|
|
|
|
|
|
// TODO: Sort by Z-Index
|
|
|
|
|
|
|
|
sprite_q
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.filter_map(
|
|
|
|
|
|
|
|
|(
|
|
|
|
|
|
|
|
entity,
|
|
|
|
|
|
|
|
TextureAtlasSprite { index, anchor, .. },
|
|
|
|
|
|
|
|
handle,
|
|
|
|
|
|
|
|
transform,
|
|
|
|
|
|
|
|
board_index,
|
|
|
|
|
|
|
|
)| {
|
|
|
|
|
|
|
|
// Implementation credit goes to the sprite bevy_mod_picking backend
|
|
|
|
|
|
|
|
// TODO: Upstream changes (related to sprite atlas correct behavior)
|
|
|
|
|
|
|
|
let p = transform.translation();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let size = {
|
|
|
|
|
|
|
|
let sprite_size = atlases
|
|
|
|
|
|
|
|
.get(handle)
|
|
|
|
|
|
|
|
.map(|atlas| {
|
|
|
|
|
|
|
|
atlas
|
|
|
|
|
|
|
|
.textures
|
|
|
|
|
|
|
|
.get(*index)
|
|
|
|
|
|
|
|
.expect("Get this rect texture")
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.expect("get this rect")
|
|
|
|
|
|
|
|
.size();
|
|
|
|
|
|
|
|
let (transform_scale, _, _) =
|
|
|
|
|
|
|
|
transform.to_scale_rotation_translation();
|
|
|
|
|
|
|
|
sprite_size * transform_scale.truncate()
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let center = p.truncate() - (anchor.as_vec() * size);
|
|
|
|
|
|
|
|
let rect = Rect::from_center_half_size(center, size / 2.0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rect.contains(pos).then_some((entity, board_index, p.z))
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.max_by_key(|(_, _, z)| z.round() as usize)
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.iter()
|
|
|
|
})
|
|
|
|
.for_each(|(e, &ref i, _)| {
|
|
|
|
.filter_map(|(entity, button, state)| {
|
|
|
|
info!("Select piece in 2d {:?} {:?}", e, i);
|
|
|
|
((*button, *state) == (MouseButton::Left, ButtonState::Pressed)).then_some(entity)
|
|
|
|
writer.send(game::GameEvent::Select(*e, i.clone()));
|
|
|
|
})
|
|
|
|
});
|
|
|
|
.for_each(|entity| {
|
|
|
|
|
|
|
|
commands.entity(entity).insert(game::Selected);
|
|
|
|
|
|
|
|
writer.send(game::GameEvent::SelectPiece);
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -339,86 +338,48 @@ fn move_piece(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// TODO: Only place piece if spot is valid move for the selected entity
|
|
|
|
/// 2D Placement Logic
|
|
|
|
///
|
|
|
|
///
|
|
|
|
fn place_piece(
|
|
|
|
fn place_piece(
|
|
|
|
mut events: EventReader<MouseButtonInput>,
|
|
|
|
mut events: EventReader<MouseButtonInput>,
|
|
|
|
current: Query<
|
|
|
|
active_piece: Query<
|
|
|
|
(Entity, &BoardIndex),
|
|
|
|
(Entity, &BoardIndex),
|
|
|
|
(With<game::Selected>, With<game::Piece>, With<Display2d>),
|
|
|
|
(With<game::Piece>, With<game::Selected>, With<Display2d>),
|
|
|
|
>,
|
|
|
|
>,
|
|
|
|
pieces: Query<&BoardIndex, (Without<game::Selected>, With<game::Piece>, With<Display2d>)>,
|
|
|
|
active_tile: Query<&BoardIndex, (With<game::Tile>, With<game::Selected>, With<Display2d>)>,
|
|
|
|
active: Res<ActiveTile>,
|
|
|
|
|
|
|
|
mut board: ResMut<Board>,
|
|
|
|
mut board: ResMut<Board>,
|
|
|
|
mut commands: Commands,
|
|
|
|
|
|
|
|
mut game_events: EventWriter<game::GameEvent>,
|
|
|
|
mut game_events: EventWriter<game::GameEvent>,
|
|
|
|
mut move_events: EventWriter<game::Move>,
|
|
|
|
mut move_events: EventWriter<game::Move>,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
events
|
|
|
|
events
|
|
|
|
.iter()
|
|
|
|
.iter()
|
|
|
|
.filter_map(|MouseButtonInput { button, state, .. }| {
|
|
|
|
.filter_map(|event| match event {
|
|
|
|
if (*button, *state) == (MouseButton::Left, ButtonState::Pressed) {
|
|
|
|
MouseButtonInput {
|
|
|
|
active.idx.as_ref()
|
|
|
|
button: MouseButton::Left,
|
|
|
|
} else {
|
|
|
|
state: ButtonState::Pressed,
|
|
|
|
None
|
|
|
|
..
|
|
|
|
}
|
|
|
|
} => active_tile.get_single().ok(),
|
|
|
|
|
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.filter_map(|idx| {
|
|
|
|
.filter_map(|to| {
|
|
|
|
if !current.is_empty() {
|
|
|
|
active_piece
|
|
|
|
(!pieces.iter().any(|board_index| board_index == idx)).then_some((
|
|
|
|
.get_single()
|
|
|
|
current.single().0,
|
|
|
|
.map(|(entity, from)| (entity, from, to))
|
|
|
|
current.single().1,
|
|
|
|
.ok()
|
|
|
|
idx,
|
|
|
|
|
|
|
|
))
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
None
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.for_each(|(entity, from, to)| match board.move_piece(from, to) {
|
|
|
|
.for_each(|(entity, from, to)| match board.move_piece(from, to) {
|
|
|
|
Ok(moves) => {
|
|
|
|
Ok(moves) => {
|
|
|
|
commands.entity(entity).remove::<game::Selected>();
|
|
|
|
info!("Moving piece {:?} {:?} -> {:?}", entity, from, to);
|
|
|
|
moves.iter().for_each(|m| {
|
|
|
|
moves.iter().for_each(|m| {
|
|
|
|
move_events.send(m.clone());
|
|
|
|
move_events.send(m.clone());
|
|
|
|
});
|
|
|
|
});
|
|
|
|
game_events.send(game::GameEvent::PlacePiece);
|
|
|
|
game_events.send(game::GameEvent::Place(entity, to.clone()));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(game::GameError::NullMove) => {
|
|
|
|
|
|
|
|
warn!("Null move!");
|
|
|
|
|
|
|
|
game_events.send(game::GameEvent::Place(entity, from.clone()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(game::GameError::NullMove) => game_events.send(game::GameEvent::PlacePiece),
|
|
|
|
|
|
|
|
Err(game::GameError::InvalidMove) => warn!("Invalid move!"),
|
|
|
|
Err(game::GameError::InvalidMove) => warn!("Invalid move!"),
|
|
|
|
Err(game::GameError::InvalidIndex) => warn!("Invalid index!"),
|
|
|
|
Err(game::GameError::InvalidIndex) => warn!("Invalid index!"),
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn cancel_place(
|
|
|
|
|
|
|
|
mut events: EventReader<MouseButtonInput>,
|
|
|
|
|
|
|
|
current: Query<Entity, (With<game::Selected>, With<game::Piece>, With<Display2d>)>,
|
|
|
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
|
|
|
mut writer: EventWriter<game::GameEvent>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
events
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.filter(|MouseButtonInput { button, state, .. }| {
|
|
|
|
|
|
|
|
(*button, *state) == (MouseButton::Right, ButtonState::Pressed)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.for_each(|_| {
|
|
|
|
|
|
|
|
if let Ok(entity) = current.get_single() {
|
|
|
|
|
|
|
|
commands.entity(entity).remove::<game::Selected>();
|
|
|
|
|
|
|
|
writer.send(game::GameEvent::PlacePiece);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn snap_back_cancel(
|
|
|
|
|
|
|
|
mut events: RemovedComponents<game::Selected>,
|
|
|
|
|
|
|
|
query: Query<&game::BoardIndex, (With<game::Piece>, With<Display2d>)>,
|
|
|
|
|
|
|
|
mut move_events: EventWriter<game::Move>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
events.iter().for_each(|entity| {
|
|
|
|
|
|
|
|
if let Ok(idx) = query.get(entity) {
|
|
|
|
|
|
|
|
move_events.send(game::Move {
|
|
|
|
|
|
|
|
epoch: 0,
|
|
|
|
|
|
|
|
from: idx.clone(),
|
|
|
|
|
|
|
|
to: Some(idx.clone()),
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|