M client/src/plugins/game/mod.rs => client/src/plugins/game/mod.rs +2 -0
@@ 17,6 17,7 @@ use super::GameDetailsCallEvent;
mod ui;
mod card;
+mod supply;
pub struct GamePlugin;
@@ 25,6 26,7 @@ impl Plugin for GamePlugin {
app.insert_resource(GameData::default())
.add_plugin(ui::GameUIPlugin)
.add_plugin(card::CardPlugin)
+ .add_plugin(supply::SupplyPlugin)
.add_system(game_setup.in_schedule(OnEnter(AppState::InGame)));
}
}
A client/src/plugins/game/supply/mod.rs => client/src/plugins/game/supply/mod.rs +83 -0
@@ 0,0 1,83 @@
+/*
+ * This file is part of laurelin_client
+ * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
+ *
+ * Licensed under GPL-3.0-only.
+ * See LICENSE for licensing information.
+ */
+
+use bevy::prelude::*;
+use bevy_rapier3d::prelude::*;
+
+use super::{GameData, card::{VisualCardBundle, VisualCard, visual_card_kind}};
+
+pub struct SupplyPlugin;
+
+impl Plugin for SupplyPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_event::<SpawnSupplyPilesEvent>()
+ .add_event::<PositionSupplyPilesEvent>()
+ .add_system(spawn_supply_piles.run_if(on_event::<SpawnSupplyPilesEvent>()))
+ .add_system(position_supply_piles.run_if(on_event::<PositionSupplyPilesEvent>()));
+ }
+}
+
+pub struct SpawnSupplyPilesEvent;
+
+fn spawn_supply_piles(
+ mut commands: Commands,
+ game_data: Res<GameData>,
+ mut psp_ev_w: EventWriter<PositionSupplyPilesEvent>,
+) {
+ let Some(status) = &game_data.game_status else {
+ warn!("game_status was none");
+ return;
+ };
+
+ for (index, pile) in status.supply_piles.iter().enumerate() {
+ commands.spawn(VisualCardBundle {
+ visual_card: VisualCard {
+ card: pile.card.clone(),
+ },
+ rigid_body: RigidBody::Fixed,
+ ..Default::default()
+ }).insert(visual_card_kind::Supply(index));
+ }
+
+ psp_ev_w.send(PositionSupplyPilesEvent);
+}
+
+pub struct PositionSupplyPilesEvent;
+
+fn position_supply_piles(
+ mut pile_query: Query<(&VisualCard, &mut Transform), With<visual_card_kind::Supply>>,
+) {
+ let mut piles: Vec<(&VisualCard, Mut<Transform>)> = pile_query.iter_mut()
+ .collect::<Vec<_>>();
+
+ piles.sort_by_key(|(vc, _t)| vc.card.name.clone());
+ piles.sort_by_key(|(vc, _t)| vc.card.cost);
+
+ // split piles into top and bottom row
+ let mid = piles.len() / 2;
+ let (p1, p2) = piles.split_at_mut(mid);
+
+ // keep track of offset between cards
+ let mut offset = 0.;
+
+ // top row
+ for (_, t) in p1 {
+ t.translation.x += offset;
+ offset += 1.0;
+ }
+
+ // reset offset when changing rows
+ offset = 0.;
+
+ // bottom row
+ for (_, t) in p2 {
+ t.translation.z += 1.5;
+ t.translation.x += offset;
+ offset += 1.0;
+ }
+}
M client/src/plugins/game/ui/mod.rs => client/src/plugins/game/ui/mod.rs +6 -1
@@ 11,7 11,7 @@ use bevy_egui::{egui, EguiContexts};
use crate::{plugins::{GameDetailsCallEvent, GameActionCreateCallEvent}, Global, api::game::{Action, Command, Game}, game_status::{Card, PlayerState}, AppState};
-use super::GameData;
+use super::{GameData, supply::SpawnSupplyPilesEvent};
pub struct GameUIPlugin;
@@ 27,6 27,7 @@ pub fn details_ui(
game_data: Res<GameData>,
mut details_ev_w: EventWriter<GameDetailsCallEvent>,
mut create_action_ev_w: EventWriter<GameActionCreateCallEvent>,
+ mut ssp_ev_w: EventWriter<SpawnSupplyPilesEvent>,
) {
egui::Window::new("Game Details")
.show(contexts.ctx_mut(), |ui| {
@@ 57,6 58,10 @@ pub fn details_ui(
}
}
+ if ui.button("spawn things").clicked() {
+ ssp_ev_w.send(SpawnSupplyPilesEvent);
+ }
+
ui.separator();
egui::CollapsingHeader::new("Game")