From d506a25716848ae396aa1f8aa457b08d90660484 Mon Sep 17 00:00:00 2001 From: Tao Tien <29749622+taotien@users.noreply.github.com> Date: Fri, 9 Jan 2026 23:14:29 -0800 Subject: [PATCH] render some tiles --- src/game/mod.rs | 4 +-- src/game/wall.rs | 17 +++++++------ src/main.rs | 17 ++++++++++--- src/tiles.rs | 9 ++++--- src/tui/console.rs | 2 +- src/tui/mod.rs | 55 +++++++++-------------------------------- src/tui/render.rs | 55 +++++++++++++++++++++++++++++++++++++++++ src/tui/render/tiles.rs | 30 ++++++++++++++++++++++ 8 files changed, 129 insertions(+), 60 deletions(-) create mode 100644 src/tui/render.rs create mode 100644 src/tui/render/tiles.rs diff --git a/src/game/mod.rs b/src/game/mod.rs index 577e397..7f65cd7 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -1,4 +1,5 @@ use bevy::prelude::*; +use tracing::instrument; use crate::tiles::{self, *}; @@ -11,8 +12,7 @@ impl Plugin for Riichi { fn build(&self, app: &mut App) { app.init_resource::() .add_systems(Startup, init_match) - .add_systems(Startup, tiles::init_tiles) - .add_systems(Update, wall::build_wall) + .add_systems(Startup, (tiles::init_tiles, wall::build_wall).chain()) // semicolon stopper ; } diff --git a/src/game/wall.rs b/src/game/wall.rs index 4de0558..ce54ec5 100644 --- a/src/game/wall.rs +++ b/src/game/wall.rs @@ -6,19 +6,22 @@ use crate::game::InWall; use crate::tiles::Tile; #[derive(Component)] -#[relationship_target(relationship = InWall)] -pub struct Wall(Vec); +#[relationship_target(relationship = InWall, linked_spawn)] +pub struct WallTiles(Vec); + +#[derive(Component)] +pub struct Wall; -#[instrument(level = "trace", skip_all)] pub(crate) fn build_wall(mut commands: Commands, tiles: Query>) -> Result { let mut rng = rand::rng(); - let mut wall = commands.spawn(Wall(vec![])); - - let mut shuffled = tiles.iter().collect::>(); + let mut shuffled = tiles + .iter() + .inspect(|e| debug!("{e:?}")) + .collect::>(); shuffled.shuffle(&mut rng); - wall.replace_children(&shuffled); + let mut wall = commands.spawn((Wall, WallTiles(shuffled))); Ok(()) } diff --git a/src/main.rs b/src/main.rs index 5c8cbe2..1a8dd9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ #![allow(unused)] -use bevy::prelude::*; +use bevy::{log::LogPlugin, prelude::*}; use clap::{Parser, Subcommand}; +use tracing::Level; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; mod gui; @@ -19,18 +20,28 @@ enum Mode { RunTui, } +const FILTERSTRING: &str = "warn,jong=trace"; + fn main() { let args = Args::parse(); let mut app = App::new(); let app = match args.mode { - Mode::RunGui => app.add_plugins(DefaultPlugins), + Mode::RunGui => { + app.add_plugins(DefaultPlugins.set(LogPlugin { + filter: FILTERSTRING.into(), + level: Level::TRACE, + // custom_layer: todo!(), + // fmt_layer: todo!(), + ..Default::default() + })) + } Mode::RunTui => { tracing_subscriber::registry() .with(tui_logger::TuiTracingSubscriberLayer) .init(); tui_logger::init_logger(tui_logger::LevelFilter::Trace).unwrap(); - tui_logger::set_env_filter_from_string("warn,jong=trace"); + tui_logger::set_env_filter_from_string(FILTERSTRING); app.add_plugins(tui::RiichiTui) } diff --git a/src/tiles.rs b/src/tiles.rs index 7716df0..4c6eb3c 100644 --- a/src/tiles.rs +++ b/src/tiles.rs @@ -1,10 +1,11 @@ use bevy::{ecs::entity::MapEntities, prelude::*}; use strum::FromRepr; +use tracing::instrument; -use crate::game::wall::Wall; +use crate::game::wall::WallTiles; #[derive(Component)] -#[relationship(relationship_target = Wall)] +#[relationship(relationship_target = WallTiles)] pub struct InWall(pub Entity); // #[derive(Component)] @@ -13,7 +14,7 @@ pub struct InWall(pub Entity); #[derive(Component, Debug)] pub struct Tile { - suit: Suit, + pub suit: Suit, } #[derive(MapEntities, Debug)] @@ -26,7 +27,7 @@ pub enum Suit { } #[derive(Deref, DerefMut, Debug)] -pub struct Rank(u8); +pub struct Rank(pub u8); #[derive(FromRepr, Debug)] pub enum Wind { diff --git a/src/tui/console.rs b/src/tui/console.rs index 97b346c..8112010 100644 --- a/src/tui/console.rs +++ b/src/tui/console.rs @@ -6,8 +6,8 @@ use tui_logger::TuiLoggerWidget; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)] pub(crate) enum ConsoleState { #[default] - Open, Closed, + Open, } impl std::ops::Not for ConsoleState { diff --git a/src/tui/mod.rs b/src/tui/mod.rs index d960f2e..6b10813 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -1,11 +1,13 @@ use std::time::Duration; use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin}; -use bevy_ratatui::{RatatuiContext, RatatuiPlugins}; -use jong::{game::wall::Wall, tiles::Tile}; -use ratatui::widgets::Paragraph; +use bevy_ratatui::RatatuiPlugins; +use jong::tiles::InWall; +use ratatui::{text::ToSpan, widgets::Paragraph}; + mod console; mod input; +mod render; pub struct RiichiTui; @@ -26,50 +28,17 @@ impl Plugin for RiichiTui { .init_state::() .add_systems(Update, console::toggle_console) .add_systems(Update, console::draw_console.run_if(in_state(console::ConsoleState::Open))) + .init_state::() .add_systems(Update, input::keyboard_input_system) - .add_systems(Update, draw_system) + .add_systems(Update, render::draw_ingame.run_if(in_state(TuiState::InGame))) // semicolon stopper ; } } -// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, States)] -// enum TuiState { -// MainMenu, -// InGame, -// } - -pub(crate) fn draw_system( - // mut commands: Commands, - wall: Option>, - tiles: Option>, - mut tui_ctx: ResMut, -) -> Result { - let title = ratatui::text::Text::raw("tiny riichi"); - let wall = if let Some(wall) = wall { - let text = (*wall) - .iter() - .map(|c| { - tiles - .as_ref() - .unwrap() - .get(c) - .map(|tile| format!("{tile:?}")) - }) - .collect::>()?; - - Some(Paragraph::new(text)) - } else { - None - }; - - tui_ctx.draw(|frame| { - frame.render_widget(title, frame.area()); - - if let Some(wall) = wall { - frame.render_widget(wall, frame.area()); - } - })?; - - Ok(()) +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, States, Default)] +enum TuiState { + MainMenu, + #[default] + InGame, } diff --git a/src/tui/render.rs b/src/tui/render.rs new file mode 100644 index 0000000..a7bece1 --- /dev/null +++ b/src/tui/render.rs @@ -0,0 +1,55 @@ +use std::marker::PhantomData; + +use bevy::ecs::system::SystemParam; +use bevy::prelude::*; +use bevy_ratatui::RatatuiContext; +use ratatui::widgets::Paragraph; + +use jong::game::wall::Wall; +use jong::game::wall::WallTiles; +use jong::tiles::Tile; + +mod tiles; + +pub(crate) fn draw_ingame( + tiles: Query<&Tile>, + wall: Option>>, + mut tui_ctx: ResMut, +) -> Result { + use ratatui::layout::Flex; + use ratatui::prelude::*; + + let title = ratatui::text::Text::raw("tiny riichi"); + + let wall = if let Some(wall) = wall { + let wall = wall + .iter() + .map(|inwall| -> Result<_> { Ok(tiles.get(inwall).map(tiles::draw_tile)?) }) + .collect::>>()?; + + // let paragraph = Paragraph::new(wall.join(", ")).wrap(ratatui::widgets::Wrap { trim: true }); + Some(wall) + } else { + None + }; + + tui_ctx.draw(|frame| { + // frame.render_widget(title, frame.area()); + debug!("{}", frame.area()); + + if let Some(wall) = wall { + // let tile_area = Rect::new(0, 0, 5, 4); + let layout = Layout::horizontal(vec![Constraint::Max(5); 13]).flex(Flex::Start); + let mut area = frame.area(); + area.height = 4; + let areas = layout.areas::<13>(area); + // debug!("wall.len(): {}, areas.len(): {}", wall.len(), areas.len()); + for (tile, rect) in wall.iter().zip(areas.iter()) { + // debug!("{rect:?}"); + frame.render_widget(tile, *rect); + } + } + })?; + + Ok(()) +} diff --git a/src/tui/render/tiles.rs b/src/tui/render/tiles.rs new file mode 100644 index 0000000..802b38d --- /dev/null +++ b/src/tui/render/tiles.rs @@ -0,0 +1,30 @@ +use ratatui::widgets::Paragraph; + +use jong::tiles::Tile; + +pub(crate) fn draw_tile(tile: &Tile) -> Paragraph<'_> { + use ratatui::prelude::*; + + let block = ratatui::widgets::Block::bordered(); + + Paragraph::new(match &tile.suit { + jong::tiles::Suit::Pin(rank) => format!("{}\np", rank.0), + jong::tiles::Suit::Sou(rank) => format!("{}\ns", rank.0), + jong::tiles::Suit::Man(rank) => format!("{}\nm", rank.0), + jong::tiles::Suit::Wind(wind) => (match wind { + jong::tiles::Wind::Ton => "e\nw", + jong::tiles::Wind::Nan => "s\nw", + jong::tiles::Wind::Shaa => "w\nw", + jong::tiles::Wind::Pei => "n\nw", + }) + .into(), + jong::tiles::Suit::Dragon(dragon) => (match dragon { + jong::tiles::Dragon::Haku => "w\nd", + jong::tiles::Dragon::Hatsu => "g\nd", + jong::tiles::Dragon::Chun => "r\nd", + }) + .into(), + }) + .block(block) + .centered() +}