|
|
|
@ -1,18 +1,36 @@
|
|
|
|
use bevy::prelude::*;
|
|
|
|
use bevy::prelude::*;
|
|
|
|
|
|
|
|
|
|
|
|
use crate::deck::Card;
|
|
|
|
use crate::{deck::Card, GameState};
|
|
|
|
|
|
|
|
|
|
|
|
pub struct PlayPlugin;
|
|
|
|
pub struct PlayPlugin;
|
|
|
|
|
|
|
|
|
|
|
|
impl Plugin for PlayPlugin {
|
|
|
|
impl Plugin for PlayPlugin {
|
|
|
|
fn build(&self, app: &mut App) {
|
|
|
|
fn build(&self, app: &mut App) {
|
|
|
|
app.add_systems(Update, rotate_cards);
|
|
|
|
app.add_systems(OnEnter(GameState::Play), serve_cards)
|
|
|
|
|
|
|
|
.add_systems(Update, rotate_cards);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Marker for cards which the player has selected
|
|
|
|
#[derive(Component)]
|
|
|
|
#[derive(Component)]
|
|
|
|
pub(crate) struct Selected;
|
|
|
|
pub(crate) struct Selected;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Where in the deck a card is
|
|
|
|
|
|
|
|
#[derive(Component)]
|
|
|
|
|
|
|
|
pub(crate) struct DeckOrder(pub u8);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Where on the board/table/play-space a card is
|
|
|
|
|
|
|
|
#[derive(Component)]
|
|
|
|
|
|
|
|
pub(crate) struct PlayLocation {
|
|
|
|
|
|
|
|
pub x: u8,
|
|
|
|
|
|
|
|
pub y: u8,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Which captured set a card is associated with
|
|
|
|
|
|
|
|
#[derive(Component)]
|
|
|
|
|
|
|
|
pub(crate) struct SetNumber(pub u8);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Debug system rotating selected cards for visual flare
|
|
|
|
fn rotate_cards(mut query: Query<&mut Transform, (With<Card>, With<Selected>)>, time: Res<Time>) {
|
|
|
|
fn rotate_cards(mut query: Query<&mut Transform, (With<Card>, With<Selected>)>, time: Res<Time>) {
|
|
|
|
let dt = time.delta().as_secs_f32();
|
|
|
|
let dt = time.delta().as_secs_f32();
|
|
|
|
query.iter_mut().for_each(|mut t| {
|
|
|
|
query.iter_mut().for_each(|mut t| {
|
|
|
|
@ -20,6 +38,7 @@ fn rotate_cards(mut query: Query<&mut Transform, (With<Card>, With<Selected>)>,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Observer system for adding/removing selected components when a card is clicked
|
|
|
|
pub(crate) fn toggle_selected(
|
|
|
|
pub(crate) fn toggle_selected(
|
|
|
|
trigger: Trigger<Pointer<Click>>,
|
|
|
|
trigger: Trigger<Pointer<Click>>,
|
|
|
|
mut commands: Commands,
|
|
|
|
mut commands: Commands,
|
|
|
|
@ -33,6 +52,7 @@ pub(crate) fn toggle_selected(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Observer system for resetting rotation when a card is de-selected
|
|
|
|
pub(crate) fn reset_rotation(
|
|
|
|
pub(crate) fn reset_rotation(
|
|
|
|
trigger: Trigger<OnRemove, Selected>,
|
|
|
|
trigger: Trigger<OnRemove, Selected>,
|
|
|
|
mut transforms: Query<&mut Transform>,
|
|
|
|
mut transforms: Query<&mut Transform>,
|
|
|
|
@ -41,6 +61,7 @@ pub(crate) fn reset_rotation(
|
|
|
|
t.rotation = Quat::default();
|
|
|
|
t.rotation = Quat::default();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Check a set when the "Set" button is clicked
|
|
|
|
pub(crate) fn check_set(
|
|
|
|
pub(crate) fn check_set(
|
|
|
|
_trigger: Trigger<Pointer<Click>>,
|
|
|
|
_trigger: Trigger<Pointer<Click>>,
|
|
|
|
query: Query<(&Card, Entity), With<Selected>>,
|
|
|
|
query: Query<(&Card, Entity), With<Selected>>,
|
|
|
|
@ -66,6 +87,7 @@ pub(crate) fn check_set(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Helper function to determine if three cards constitute a set
|
|
|
|
fn is_set((a, b, c): (&Card, &Card, &Card)) -> bool {
|
|
|
|
fn is_set((a, b, c): (&Card, &Card, &Card)) -> bool {
|
|
|
|
let color = {
|
|
|
|
let color = {
|
|
|
|
((a.color == b.color) && (b.color == c.color) && (c.color == a.color))
|
|
|
|
((a.color == b.color) && (b.color == c.color) && (c.color == a.color))
|
|
|
|
@ -85,3 +107,56 @@ fn is_set((a, b, c): (&Card, &Card, &Card)) -> bool {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
color && number && pattern && shape
|
|
|
|
color && number && pattern && shape
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// When requested, fill in empty spots on the board with cards
|
|
|
|
|
|
|
|
fn serve_cards(
|
|
|
|
|
|
|
|
cards: Query<(Entity, &DeckOrder)>,
|
|
|
|
|
|
|
|
spots: Query<&PlayLocation>,
|
|
|
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
let mut target = (cards.iter().len() - 1) as u8;
|
|
|
|
|
|
|
|
// Iterate over every x, y play location
|
|
|
|
|
|
|
|
for this_x in 0..=2 {
|
|
|
|
|
|
|
|
for this_y in 0..=3 {
|
|
|
|
|
|
|
|
// If this spot does not have a card
|
|
|
|
|
|
|
|
if spots
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.find(|PlayLocation { x, y }| *x == (this_x as u8) && *y == (this_y as u8))
|
|
|
|
|
|
|
|
.is_none()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if let Some((e, _)) = cards.iter().find(|(_, deck_order)| deck_order.0 == target) {
|
|
|
|
|
|
|
|
// Set the selected card to this play location and remove from the deck
|
|
|
|
|
|
|
|
commands
|
|
|
|
|
|
|
|
.entity(e)
|
|
|
|
|
|
|
|
.remove::<DeckOrder>()
|
|
|
|
|
|
|
|
.insert(PlayLocation {
|
|
|
|
|
|
|
|
x: this_x,
|
|
|
|
|
|
|
|
y: this_y,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
target = target - 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// When a card is added to the board, place it on the screen
|
|
|
|
|
|
|
|
pub(crate) fn place_card(
|
|
|
|
|
|
|
|
trigger: Trigger<OnAdd, PlayLocation>,
|
|
|
|
|
|
|
|
mut query: Query<(&PlayLocation, &mut Visibility, &mut Transform)>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
let (PlayLocation { x, y }, mut visibility, mut transform) =
|
|
|
|
|
|
|
|
query.get_mut(trigger.entity()).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set it's transform based on it's placement
|
|
|
|
|
|
|
|
let CARD_SIZE = [100.0, 160.0];
|
|
|
|
|
|
|
|
let offset = Vec2::new(CARD_SIZE[0] * 3.0, CARD_SIZE[1] * 4.0) / 2.0;
|
|
|
|
|
|
|
|
transform.translation = Vec3::new(
|
|
|
|
|
|
|
|
((*x as f32) * CARD_SIZE[0]) - offset.x,
|
|
|
|
|
|
|
|
((*y as f32) * CARD_SIZE[1]) - offset.y,
|
|
|
|
|
|
|
|
0.0,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set it to visible
|
|
|
|
|
|
|
|
*visibility = Visibility::Visible;
|
|
|
|
|
|
|
|
}
|
|
|
|
|