From 314c3299ef0c32f8bda921dc4e0a8ab228503daa Mon Sep 17 00:00:00 2001 From: Tao Tien <29749622+taotien@users.noreply.github.com> Date: Tue, 13 Jan 2026 01:08:14 -0800 Subject: [PATCH] render main player's hand --- src/game/hand.rs | 7 ++-- src/game/mod.rs | 25 +++++++++---- src/game/player.rs | 2 +- src/tui/input.rs | 79 ++++++++++++++++++++++++++++++++++++++++ src/tui/menu.rs | 7 +--- src/tui/mod.rs | 57 ++--------------------------- src/tui/render/hand.rs | 47 +++++++++++++----------- src/tui/render/ingame.rs | 7 +++- 8 files changed, 134 insertions(+), 97 deletions(-) create mode 100644 src/tui/input.rs diff --git a/src/game/hand.rs b/src/game/hand.rs index 713ef61..f17b6ba 100644 --- a/src/game/hand.rs +++ b/src/game/hand.rs @@ -1,4 +1,4 @@ -use bevy::prelude::*; +use bevy::{ecs::relationship::RelationshipSourceCollection, prelude::*}; use crate::{ game::{player::Player /* wall::WallTiles */}, @@ -18,12 +18,11 @@ pub struct Hand; pub(crate) fn sort_hands( tiles: Populated<&Tile>, - mut hands: Populated<&mut Children, (With, Changed)>, + mut hands: Populated<&mut Children, (Changed, Without)>, ) -> Result { for mut hand in hands { hand.sort_unstable_by_key(|e| tiles.get(*e).unwrap().suit); - debug!("sorted: {hand:?}") + debug!("sorted: {hand:?}"); } - trace!("sort_hands"); Ok(()) } diff --git a/src/game/mod.rs b/src/game/mod.rs index 09c0e36..8d41908 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -42,7 +42,7 @@ impl Plugin for Riichi { fn shuffle_deal( mut commands: Commands, - tiles: Query>, + tiles: Populated>, players: Populated>, wall_ent: Single>, mut next_gamestate: ResMut>, @@ -50,18 +50,27 @@ fn shuffle_deal( use rand::seq::SliceRandom; let mut rng = rand::rng(); - let mut wall: Vec<_> = tiles.iter().collect(); - wall.shuffle(&mut rng); + let mut walltiles: Vec<_> = tiles.iter().collect(); + walltiles.shuffle(&mut rng); - commands.get_entity(*wall_ent)?.replace_children(&wall); + // commands.get_entity(*wall_ent)?.replace_children(&walltiles); for player_ent in players { - let handtiles = wall.split_off(13); - commands.get_entity(*wall_ent)?.remove_children(&handtiles); - let hand = commands.spawn(Hand).add_children(&handtiles).id(); - commands.get_entity(player_ent)?.replace_children(&[hand]); + 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 + .get_entity(player_ent)? + .replace_children(&[hand_ent]); + + debug!("dealt to player_ent {player_ent:?}"); } + commands.get_entity(*wall_ent)?.replace_children(&walltiles); + next_gamestate.set(GameState::Play); Ok(()) } diff --git a/src/game/player.rs b/src/game/player.rs index 7a928be..c7c3e6c 100644 --- a/src/game/player.rs +++ b/src/game/player.rs @@ -1,6 +1,6 @@ use bevy::prelude::*; -#[derive(Component, Debug)] +#[derive(Component, Debug, PartialEq)] pub struct Player { pub name: String, } diff --git a/src/tui/input.rs b/src/tui/input.rs new file mode 100644 index 0000000..44947c3 --- /dev/null +++ b/src/tui/input.rs @@ -0,0 +1,79 @@ +use bevy::prelude::*; +use bevy_ratatui::event::{KeyMessage, MouseMessage}; + +use jong::game::GameState; + +use crate::tui::{TuiState, console::ConsoleState}; + +#[allow(clippy::too_many_arguments)] +pub(crate) fn kb_input_system( + mut kb_messages: MessageReader, + + curr_tuistate: Res>, + curr_consolestate: Res>, + curr_gamestate: Res>, + + mut next_tuistate: ResMut>, + mut next_consolestate: ResMut>, + mut next_gamestate: ResMut>, + + mut exit: MessageWriter, +) { + use bevy_ratatui::crossterm::event::KeyCode; + + let (ts, cs, gs) = ( + curr_tuistate.get(), + curr_consolestate.get(), + curr_gamestate.get(), + ); + + for message in kb_messages.read() { + if let KeyCode::Char('`') = message.code { + next_consolestate.set(!*curr_consolestate.get()); + continue; + } + + if *cs == ConsoleState::Open { + let mut passthrough = false; + match message.code { + KeyCode::Up => todo!(), + KeyCode::Down => todo!(), + KeyCode::Home => todo!(), + KeyCode::End => todo!(), + KeyCode::PageUp => todo!(), + KeyCode::PageDown => todo!(), + KeyCode::Esc => next_consolestate.set(ConsoleState::Closed), + _ => passthrough = true, + } + if !passthrough { + continue; + } + } + + match ts { + TuiState::MainMenu => match message.code { + KeyCode::Char('p') => { + next_tuistate.set(TuiState::InGame); + next_gamestate.set(GameState::Setup); + } + KeyCode::Char('q') => { + exit.write_default(); + } + _ => {} + }, + TuiState::InGame => match gs { + GameState::Setup => match message.code { + _ => {} + }, + GameState::Play => match message.code { + KeyCode::Char('q') => { + exit.write_default(); + } + _ => {} + }, + _ => todo!(), + _ => unreachable!("TuiState::InGame but GameState invalid"), + }, + } + } +} diff --git a/src/tui/menu.rs b/src/tui/menu.rs index 3ee27e5..104e193 100644 --- a/src/tui/menu.rs +++ b/src/tui/menu.rs @@ -10,13 +10,8 @@ use jong::game::GameState; use crate::tui::TuiState; const MAINMENU_OPTIONS: [&str; 2] = ["(p)lay", "(q)uit"]; -// const MAINMENU_INPUTS: [char;2] = ['p', 'q']; -pub(crate) fn draw_mainmenu( - mut tui_ctx: ResMut, - // mut tui_state: ResMut>, - // mut game_state: ResMut>, -) { +pub(crate) fn draw_mainmenu(mut tui_ctx: ResMut) { let options = MAINMENU_OPTIONS; let layout = Layout::vertical(vec![Constraint::Min(1); options.len()]); diff --git a/src/tui/mod.rs b/src/tui/mod.rs index e3bccf9..f96a68a 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -2,7 +2,6 @@ use std::time::Duration; use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin}; use bevy_ratatui::RatatuiPlugins; -use bevy_ratatui::event::KeyMessage; use ratatui::{text::ToSpan, widgets::Paragraph}; use jong::game::GameState; @@ -13,6 +12,7 @@ use crate::tui::{console::ConsoleState, menu::draw_mainmenu, render::ingame::dra mod console; mod menu; mod render; +mod input; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, States, Default)] pub(crate) enum TuiState { @@ -59,7 +59,7 @@ impl Plugin for RiichiTui { // general setup .init_state::() .add_computed_state::() - .add_systems(Update, input_system) + .add_systems(Update, input::kb_input_system) // main menu .add_systems(Update, menu::draw_mainmenu.run_if(in_state(TuiState::MainMenu))) @@ -67,62 +67,11 @@ impl Plugin for RiichiTui { // gaming .init_resource::() .add_systems(Update, render::ingame::draw_ingame.run_if(in_state(InGame))) - // .add_systems(Update, render::hand::render_changed_hand.run_if(in_state(InGame).and(in_state(GameState::Play)))) + .add_systems(Update, render::hand::render_hand.run_if(in_state(InGame).and(in_state(GameState::Play)))) // semicolon stopper ; } } -#[allow(clippy::too_many_arguments)] -pub(crate) fn input_system( - mut messages: MessageReader, - - curr_tuistate: Res>, - curr_consolestate: Res>, - curr_gamestate: Res>, - - mut next_tuistate: ResMut>, - mut next_consolestate: ResMut>, - mut next_gamestate: ResMut>, - - mut exit: MessageWriter, -) { - use bevy_ratatui::crossterm::event::KeyCode; - - let (ts, cs, gs) = (curr_tuistate.get(), curr_consolestate.get(), curr_gamestate.get()); - - for message in messages.read() { - if let KeyCode::Char('`') = message.code { - next_consolestate.set(!*curr_consolestate.get()); - continue - } - - match ts { - TuiState::MainMenu => match message.code { - KeyCode::Char('p') => { - next_tuistate.set(TuiState::InGame); - next_gamestate.set(GameState::Setup); - } - KeyCode::Char('q') => { - exit.write_default(); - } - _ => {} - }, - TuiState::InGame => match gs { - GameState::Setup => match message.code { - _ => {} - }, - GameState::Play => match message.code { - KeyCode::Char('q') => { - exit.write_default(); - } - _ => {} - }, - _ => todo!(), - _ => unreachable!("TuiState::InGame but GameState invalid") - }, - } - } -} diff --git a/src/tui/render/hand.rs b/src/tui/render/hand.rs index f76e933..a1b5ebc 100644 --- a/src/tui/render/hand.rs +++ b/src/tui/render/hand.rs @@ -1,32 +1,35 @@ -use bevy::prelude::*; +use bevy::{platform::collections::HashMap, prelude::*}; use ratatui::widgets::Paragraph; -// use jong::game::hand::HandTiles; -use jong::tiles::Tile; +use jong::{ + game::{hand::Hand, player::Player}, + tiles::Tile, +}; use crate::tui::render::tiles; #[derive(Resource, Default)] -pub(crate) struct RenderedHand(pub(crate) Vec>>); +pub(crate) struct RenderedHand(pub(crate) HashMap>>); -// pub(crate) fn render_changed_hand( -// hands: Populated<&Children, Changed>, -// tiles: Populated<&Tile>, -// mut target: ResMut, -// ) -> Result { -// let mut rendered = vec![]; +pub(crate) fn render_hand( + tiles: Populated<&Tile>, + player_hands: Populated<(Entity, &Children), (With, Changed)>, + hands: Populated<&Children, (Changed, Without)>, + mut target: ResMut, +) -> Result { + let mut rendered = HashMap::new(); -// for hand in hands { -// let tiles = hand -// .iter() -// .map(|inhand| tiles.get(inhand).map(tiles::draw_tile).unwrap()) -// .collect(); + for (player_ent, hand) in player_hands { + let hand = hand.iter().next().unwrap(); + let tiles = hands + .get(hand)? + .iter() + .map(|it| tiles.get(it).map(tiles::draw_tile).unwrap()) + .collect(); + rendered.insert(player_ent, tiles); + } -// rendered.push(tiles); -// } + target.0 = rendered; -// target.0 = rendered; - -// trace!("render_changed_hand"); -// Ok(()) -// } + Ok(()) +} diff --git a/src/tui/render/ingame.rs b/src/tui/render/ingame.rs index b8e01cc..e573cb9 100644 --- a/src/tui/render/ingame.rs +++ b/src/tui/render/ingame.rs @@ -1,10 +1,12 @@ use bevy::prelude::*; use bevy_ratatui::RatatuiContext; +use jong::game::player::{MainPlayer, Player}; use crate::tui::render::hand; pub(crate) fn draw_ingame( rendered_hand: Res, + main_player: Single, With)>, mut tui_ctx: ResMut, ) -> Result { use ratatui::layout::Flex; @@ -17,8 +19,9 @@ pub(crate) fn draw_ingame( let mut area = frame.area(); area.height = 4; let areas = layout.areas::<13>(area); - if let Some(tiles) = rendered_hand.0.first() { - for (tile, area) in tiles.iter().zip(areas.iter()) { + // if let Some(hand) = rendered_hand.0.get(&*main_player) { + if let Some(hand) = rendered_hand.0.get(&*main_player) { + for (tile, area) in hand.iter().zip(areas.iter()) { frame.render_widget(tile, *area); } }