refactor entites to reduce complexity and crashes, switch to Querys
This commit is contained in:
parent
3182916832
commit
c7200b1fd3
8 changed files with 95 additions and 89 deletions
|
|
@ -25,9 +25,6 @@ tracing = "0.1.44"
|
|||
tracing-subscriber = "0.3.22"
|
||||
tui-logger = { version = "0.18.0", features = ["tracing-support", "crossterm"] }
|
||||
|
||||
[dev-dependencies]
|
||||
bevy = { version = "0.17.3", features = ["track_location"] }
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
|
||||
|
|
|
|||
11
src/game.rs
11
src/game.rs
|
|
@ -1,10 +1,10 @@
|
|||
use bevy::{ecs::query::QueryData, prelude::*};
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::{
|
||||
game::{
|
||||
hand::Hand,
|
||||
player::MainPlayer,
|
||||
round::{CurrentPlayer, TurnState, Wind},
|
||||
player::{CurrentPlayer, MainPlayer},
|
||||
round::{TurnState, Wind},
|
||||
wall::Wall,
|
||||
},
|
||||
tile::{self},
|
||||
|
|
@ -60,7 +60,6 @@ pub(crate) fn setup(
|
|||
matchsettings: Res<round::MatchSettings>,
|
||||
// mut compass: ResMut<Compass>
|
||||
// tiles: Query<Entity, With<Tile>>,
|
||||
curr_gamestate: Res<State<GameState>>,
|
||||
mut next_gamestate: ResMut<NextState<GameState>>,
|
||||
) {
|
||||
for i in 1..=matchsettings.player_count {
|
||||
|
|
@ -77,8 +76,8 @@ pub(crate) fn setup(
|
|||
);
|
||||
|
||||
if i == 1 {
|
||||
let player = commands.spawn((bundle, MainPlayer)).id();
|
||||
commands.insert_resource(CurrentPlayer(player));
|
||||
let player = commands.spawn((bundle, MainPlayer, CurrentPlayer)).id();
|
||||
// commands.insert_resource(CurrentPlayer(player));
|
||||
} else {
|
||||
commands.spawn(bundle);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ use crate::{
|
|||
#[derive(Component)]
|
||||
pub struct Hand;
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
pub struct DrawnTile(pub Entity);
|
||||
#[derive(Component)]
|
||||
pub struct Drawn;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct DiscardedTile(pub Entity);
|
||||
pub struct Discarded;
|
||||
|
||||
// #[derive(Component, Default)]
|
||||
// enum SortHand {
|
||||
|
|
@ -48,19 +48,16 @@ pub(crate) fn shuffle_deal(
|
|||
let mut walltiles: Vec<_> = tiles.iter().collect();
|
||||
walltiles.shuffle(&mut rng);
|
||||
|
||||
// commands.get_entity(*wall_ent)?.replace_children(&walltiles);
|
||||
|
||||
for player_ent in players {
|
||||
debug!("deal to player_ent {player_ent:?}");
|
||||
let handtiles = walltiles.split_off(walltiles.len() - 13);
|
||||
// commands.get_entity(*wall_ent)?.remove_children(&handtiles);
|
||||
|
||||
let hand_ent = commands.spawn(Hand).add_children(&handtiles).id();
|
||||
debug!("hand_ent: {hand_ent:?}");
|
||||
|
||||
commands.entity(player_ent).replace_children(&[hand_ent]);
|
||||
commands.entity(player_ent).add_child(hand_ent);
|
||||
debug!("deal to player_ent {player_ent:?} {hand_ent:?}");
|
||||
}
|
||||
|
||||
// don't need to remove hands from wall if we don't insert to wall to begin with
|
||||
// TODO probably do this later on when animating the draw
|
||||
debug!("shuffled: {walltiles:?}");
|
||||
commands.entity(*wall_ent).replace_children(&walltiles);
|
||||
|
||||
next_gamestate.set(GameState::Play);
|
||||
|
|
|
|||
|
|
@ -11,8 +11,11 @@ pub struct Points(pub isize);
|
|||
#[derive(Component)]
|
||||
pub struct MainPlayer;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct CurrentPlayer;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct Dealer;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct Tsumo(pub Entity);
|
||||
pub struct Tsumo;
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ use crate::{
|
|||
EnumNextCycle,
|
||||
game::{
|
||||
GameMessage, GameState,
|
||||
hand::{DiscardedTile, DrawnTile, Hand},
|
||||
player::Player,
|
||||
hand::{Discarded, Drawn, Hand},
|
||||
player::{CurrentPlayer, Player},
|
||||
wall::Wall,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct CurrentPlayer(pub Entity);
|
||||
// #[derive(Resource)]
|
||||
// pub struct CurrentPlayer(pub Entity);
|
||||
|
||||
#[derive(Resource)]
|
||||
pub(crate) struct MatchSettings {
|
||||
|
|
@ -58,9 +58,6 @@ pub(crate) enum TurnState {
|
|||
End,
|
||||
}
|
||||
|
||||
#[derive(EntityEvent)]
|
||||
pub struct Discard(pub Entity);
|
||||
|
||||
impl Default for MatchSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
|
@ -116,22 +113,22 @@ impl EnumNextCycle for TurnState {
|
|||
|
||||
pub(crate) fn tsumo(
|
||||
mut commands: Commands,
|
||||
curr_player: Res<CurrentPlayer>,
|
||||
// players: Populated<Entity, With<Player>>,
|
||||
wall_ent: Single<Entity, With<Wall>>,
|
||||
|
||||
// curr_player: Res<CurrentPlayer>,
|
||||
curr_player: Single<Entity, With<CurrentPlayer>>,
|
||||
wall: Single<Entity, With<Wall>>,
|
||||
walltiles: Single<&Children, With<Wall>>,
|
||||
|
||||
curr_turnstate: Res<State<TurnState>>,
|
||||
mut next_turnstate: ResMut<NextState<TurnState>>,
|
||||
) {
|
||||
debug!("tsumo for: {:?}", curr_player.0);
|
||||
|
||||
let drawn = walltiles.last().unwrap();
|
||||
commands.entity(*wall_ent).remove_child(*drawn);
|
||||
let drawn_ent = commands.spawn(DrawnTile(*drawn)).id();
|
||||
commands.entity(curr_player.0).add_child(drawn_ent);
|
||||
commands.entity(*wall).remove_child(*drawn);
|
||||
|
||||
debug!("drew: ent: {drawn_ent:?} tile_ent: {:?}", drawn);
|
||||
let drawn = commands.entity(*drawn).insert(Drawn).id();
|
||||
commands.entity(*curr_player).add_child(drawn);
|
||||
|
||||
debug!("tsumo for: {:?}, tile: {:?}", *curr_player, drawn);
|
||||
next_turnstate.set(curr_turnstate.next());
|
||||
}
|
||||
|
||||
|
|
@ -156,39 +153,43 @@ pub(crate) fn discard(
|
|||
mut commands: Commands,
|
||||
mut reader: MessageReader<GameMessage>,
|
||||
|
||||
currplayer: Res<CurrentPlayer>,
|
||||
drawntile: Single<(&DrawnTile, Entity), With<DrawnTile>>,
|
||||
player_hands: Populated<(&Player, &Children), With<Hand>>,
|
||||
hands: Populated<&Children, (With<Hand>, Without<Player>)>,
|
||||
curr_player: Single<Entity, With<CurrentPlayer>>,
|
||||
players: Query<&Children, With<Player>>,
|
||||
mut hands: Query<(&Children, Entity), (With<Hand>, Without<Player>)>,
|
||||
drawn: Single<Entity, With<Drawn>>,
|
||||
|
||||
curr_turnstate: Res<State<TurnState>>,
|
||||
mut next_turnstate: ResMut<NextState<TurnState>>,
|
||||
) {
|
||||
let curr = currplayer.0;
|
||||
let hand = player_hands.get(curr).unwrap().1.iter().next().unwrap();
|
||||
let handtiles = hands.get(hand).unwrap();
|
||||
let (drawntile, drawn_ent) = *drawntile;
|
||||
|
||||
// debug!("discard turn for: {curr:?}");
|
||||
) -> Result {
|
||||
// trace!("discard");
|
||||
let curr_hand = hands.get_mut(players.get(*curr_player)?.iter().next().unwrap())?;
|
||||
|
||||
let mut done = false;
|
||||
while let Some(message) = reader.read().next() {
|
||||
if let GameMessage::Discarded(entity) = message {
|
||||
debug!("{curr:?} discarded: {entity:?}");
|
||||
// commands.entity(drawn_ent).despawn();
|
||||
if *entity == drawntile.0 {
|
||||
} else if handtiles.contains(entity) {
|
||||
if let GameMessage::Discarded(discarded) = message {
|
||||
if *discarded == *drawn {
|
||||
} else if curr_hand.0.contains(discarded) {
|
||||
commands
|
||||
.entity(hand)
|
||||
.remove_child(*entity)
|
||||
.add_child(drawntile.0);
|
||||
.entity(curr_hand.1)
|
||||
.remove_child(*discarded)
|
||||
.add_child(*drawn);
|
||||
} else {
|
||||
panic!("discarded illegal player tile?")
|
||||
panic!("current hand nor drawn tile contains discarded tile")
|
||||
}
|
||||
commands.spawn(DiscardedTile(*entity));
|
||||
next_turnstate.set(curr_turnstate.next());
|
||||
commands
|
||||
.entity(*discarded)
|
||||
.remove::<Drawn>()
|
||||
.insert(Discarded);
|
||||
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if done {
|
||||
next_turnstate.set(curr_turnstate.next());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn ron_chi_pon_kan(
|
||||
|
|
|
|||
26
src/tui.rs
26
src/tui.rs
|
|
@ -1,13 +1,13 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin};
|
||||
use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin, time::TimePlugin};
|
||||
use bevy_ratatui::RatatuiPlugins;
|
||||
use jong::game::{
|
||||
GameMessage, GameState,
|
||||
hand::{DrawnTile, Hand},
|
||||
player::{MainPlayer, Player},
|
||||
round::{CurrentPlayer, Discard},
|
||||
hand::{Drawn, Hand},
|
||||
player::{CurrentPlayer, Player},
|
||||
};
|
||||
use tracing::instrument;
|
||||
use tui_logger::TuiWidgetState;
|
||||
|
||||
use crate::tui::{input::ConfirmSelect, states::ConsoleWidget};
|
||||
|
|
@ -72,17 +72,25 @@ impl Plugin for TuiPlugin {
|
|||
fn discard_tile(
|
||||
mut writer: MessageWriter<GameMessage>,
|
||||
mut selected: MessageReader<ConfirmSelect>,
|
||||
drawntile: Single<Entity, With<DrawnTile>>,
|
||||
currplayer: Res<CurrentPlayer>,
|
||||
|
||||
drawn: Single<Entity, With<Drawn>>,
|
||||
curr_player: Single<Entity, With<CurrentPlayer>>,
|
||||
player_hands: Populated<(&Player, &Children), With<Hand>>,
|
||||
hands: Populated<&Children, (With<Hand>, Without<Player>)>,
|
||||
) {
|
||||
let curr = currplayer.0;
|
||||
let hand_ent = player_hands.get(curr).unwrap().1.iter().next().unwrap();
|
||||
// trace!("discard_tile");
|
||||
|
||||
let hand_ent = player_hands
|
||||
.get(*curr_player)
|
||||
.unwrap()
|
||||
.1
|
||||
.iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
let hand = hands.get(hand_ent).unwrap();
|
||||
|
||||
while let Some(message) = selected.read().next()
|
||||
&& (message.0 == *drawntile || hand.contains(&message.0))
|
||||
&& (message.0 == *drawn || hand.contains(&message.0))
|
||||
{
|
||||
writer.write(GameMessage::Discarded(message.0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,5 +12,5 @@ pub(crate) struct Hovered;
|
|||
#[derive(Component)]
|
||||
pub(crate) struct StartSelect;
|
||||
|
||||
#[derive(Message)]
|
||||
#[derive(Message, Debug)]
|
||||
pub(crate) struct ConfirmSelect(pub(crate) Entity);
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
use std::io::Write as _;
|
||||
use std::ops::Sub;
|
||||
|
||||
use bevy::platform::collections::HashSet;
|
||||
use bevy::prelude::*;
|
||||
use bevy_ratatui::RatatuiContext;
|
||||
use ratatui::layout::{Constraint, Flex, Layout, Offset, Rect, Size};
|
||||
use ratatui::style::{Modifier, Style, Stylize};
|
||||
use ratatui::style::{Modifier, Stylize};
|
||||
use ratatui::widgets::{Block, Borders, Clear, Paragraph};
|
||||
|
||||
use jong::game::hand::{DrawnTile, Hand};
|
||||
use jong::game::player::{MainPlayer, Player};
|
||||
use jong::game::hand::{Drawn, Hand};
|
||||
use jong::game::player::{CurrentPlayer, MainPlayer, Player};
|
||||
use jong::game::round::Wind;
|
||||
use jong::tile::Tile;
|
||||
|
||||
|
|
@ -22,7 +20,7 @@ pub(crate) struct PickRegion {
|
|||
pub(crate) area: Rect,
|
||||
}
|
||||
|
||||
fn render_tile(tile: &Tile, hovered: bool) -> (Paragraph<'_>) {
|
||||
fn render_tile(tile: &Tile, hovered: bool) -> Paragraph<'_> {
|
||||
let block = ratatui::widgets::Block::bordered();
|
||||
let mut widget = Paragraph::new(match &tile.suit {
|
||||
jong::tile::Suit::Pin(rank) => format!("{}\np", rank.0),
|
||||
|
|
@ -99,32 +97,35 @@ pub(crate) fn render(
|
|||
pub(crate) fn render_hands(
|
||||
mut commands: Commands,
|
||||
mut tui: ResMut<RatatuiContext>,
|
||||
|
||||
hovered: Query<Entity, With<Hovered>>,
|
||||
layouts: Res<HandLayouts>,
|
||||
mainplayer: Single<(&Player, &Wind), With<MainPlayer>>,
|
||||
players: Populated<(&Player, /* &Wind, */ &Children)>,
|
||||
hands: Populated<&Children, (With<Hand>, Without<Player>)>,
|
||||
tiles: Populated<&Tile>,
|
||||
drawn_tile: Option<Single<(&Player, &DrawnTile, Entity)>>,
|
||||
|
||||
tiles: Query<&Tile>,
|
||||
main_player: Single<(&Player, &Wind), With<MainPlayer>>,
|
||||
curr_player: Single<Entity, With<CurrentPlayer>>,
|
||||
players: Query<(&Player, &Children)>,
|
||||
hands: Query<(&Children, Entity), (With<Hand>, Without<Player>)>,
|
||||
drawn_tile: Option<Single<(&Player, Entity), With<Drawn>>>,
|
||||
) -> Result {
|
||||
let mut frame = tui.get_frame();
|
||||
debug_blocks(*layouts, &mut frame);
|
||||
|
||||
for (player, /* wind, */ hand_ent) in players {
|
||||
let hand = hand_ent.iter().next().unwrap();
|
||||
let hand: Vec<_> = hands
|
||||
.get(hand)?
|
||||
for (hand, hand_ent) in hands {
|
||||
// debug!("{hand:?}");
|
||||
let (player, _) = players.iter().find(|(_, c)| c.contains(&hand_ent)).unwrap();
|
||||
let hand: Vec<_> = hand
|
||||
.iter()
|
||||
.map(|entity| -> Result<_> {
|
||||
let tile = tiles.get(entity)?;
|
||||
// let paragraph = render_tile(tile,);
|
||||
let tile = tiles.get(entity).unwrap_or_else(|_| panic!("{entity:?}"));
|
||||
let hovered = hovered.contains(entity);
|
||||
let widget = render_tile(tile, hovered);
|
||||
|
||||
Ok((entity, widget, hovered))
|
||||
})
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
if player == mainplayer.0 {
|
||||
if player == main_player.0 {
|
||||
// split main box into thirds
|
||||
let mut this_hand = layouts.this_hand;
|
||||
let this_drawer = drawn_tile.as_ref().is_some_and(|dt| dt.0 == player);
|
||||
|
|
@ -169,14 +170,14 @@ pub(crate) fn render_hands(
|
|||
|
||||
// tsumo tile
|
||||
if this_drawer {
|
||||
let (_, tile, entity) = **drawn_tile.as_ref().unwrap();
|
||||
let (_, entity) = **drawn_tile.as_ref().unwrap();
|
||||
let mut area = drawn_area.resize(Size {
|
||||
width: 5,
|
||||
height: 4,
|
||||
});
|
||||
area = area.offset(Offset { x: 2, y: 0 });
|
||||
let hovered = hovered.contains(entity);
|
||||
let widget = render_tile(tiles.get(tile.0)?, hovered);
|
||||
let widget = render_tile(tiles.get(entity)?, hovered);
|
||||
if hovered {
|
||||
area = area.offset(Offset { x: 0, y: -1 });
|
||||
let mut hitbox = area.as_size();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue