Add rustdoc and inline comments throughout; update CLAUDE.md style guide

All public types, fields, and functions in game.rs and map_file.rs now
have /// doc comments. main.rs has /// on App and draw_glyph plus inline
comments explaining the input/render pipeline. CLAUDE.md records the
expectation that generated code includes comments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-17 12:48:52 -05:00
parent 176c70de6b
commit 453c7baf4e
4 changed files with 237 additions and 1 deletions
+38
View File
@@ -5,13 +5,20 @@ mod game;
mod map_file;
use game::{GameState, Glyph};
/// Width of one board cell in pixels.
const CELL_W: f32 = 14.0;
/// Height of one board cell in pixels.
const CELL_H: f32 = 20.0;
/// Approximate height of the egui menu bar in pixels, used for window sizing.
const MENU_H: f32 = 24.0;
/// Default inner margin that egui's CentralPanel adds on all sides, in pixels.
/// The minimum window size accounts for this so the board fits without clipping.
const PANEL_MARGIN: f32 = 8.0;
fn main() -> eframe::Result<()> {
// Load the board before creating the window so its dimensions can drive
// the initial and minimum window size.
let board = map_file::load("maps/start.toml").expect("failed to load maps/start.toml");
let board_px_w = board.width as f32 * CELL_W + 2.0 * PANEL_MARGIN;
let board_px_h = board.height as f32 * CELL_H + MENU_H + 2.0 * PANEL_MARGIN;
@@ -29,6 +36,10 @@ fn main() -> eframe::Result<()> {
)
}
/// The eframe application. Owns the game state and drives the frame loop.
///
/// eframe calls [`App::update`] every frame. All input handling, game logic
/// updates, and rendering happen there. There is no separate game loop thread.
struct App {
state: GameState,
}
@@ -41,6 +52,9 @@ impl App {
impl eframe::App for App {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
// --- Input ---
// Arrow keys are read before any panel is drawn. egui accumulates
// key events between frames; key_pressed returns true once per press.
ctx.input(|i| {
if i.key_pressed(Key::ArrowUp) { self.state.try_move( 0, -1); }
if i.key_pressed(Key::ArrowDown) { self.state.try_move( 0, 1); }
@@ -48,6 +62,7 @@ impl eframe::App for App {
if i.key_pressed(Key::ArrowRight) { self.state.try_move( 1, 0); }
});
// --- Menu bar ---
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
egui::MenuBar::new().ui(ui, |ui| {
ui.menu_button("File", |ui| {
@@ -58,14 +73,23 @@ impl eframe::App for App {
});
});
// --- Board rendering ---
// The board is drawn using the egui Painter API (direct 2D drawing),
// not egui widgets. This gives pixel-level control over placement.
egui::CentralPanel::default().show(ctx, |ui| {
let board = &self.state.board;
let available = ui.available_rect_before_wrap();
// Center the board within the panel. If the window is at minimum
// size the offset is zero; if the window is larger the board floats
// in the middle.
let board_px = vec2(board.width as f32 * CELL_W, board.height as f32 * CELL_H);
let offset = ((available.size() - board_px) / 2.0).max(egui::Vec2::ZERO);
let origin = available.min + offset;
let painter = ui.painter();
// Draw each board cell: filled background rect, then the character.
for y in 0..board.height {
for x in 0..board.width {
let (glyph, _) = board.get(x, y);
@@ -73,6 +97,9 @@ impl eframe::App for App {
}
}
// Draw the player on top of the board. The player is not stored as
// a board cell, so it is rendered as a separate overlay. This will
// change once the player becomes a scripted object.
let player_glyph = Glyph::player();
draw_glyph(
painter,
@@ -83,10 +110,21 @@ impl eframe::App for App {
);
});
// Force a repaint every frame so input is processed continuously.
// Remove this if the game becomes purely event-driven.
ctx.request_repaint();
}
}
/// Draws a single cell at grid position `(x, y)` using the given glyph.
///
/// Each cell is rendered as two layers:
/// 1. A filled rectangle in `glyph.bg` covering the full cell area.
/// 2. A monospace character (`glyph.ch`) in `glyph.fg`, centered in the cell.
///
/// `origin` is the pixel position of cell `(0, 0)` — the top-left corner of
/// the board within the panel. Cell positions are computed from `origin` using
/// [`CELL_W`] and [`CELL_H`].
fn draw_glyph(painter: &egui::Painter, origin: Pos2, x: usize, y: usize, glyph: &Glyph) {
let tl = origin + vec2(x as f32 * CELL_W, y as f32 * CELL_H);
let rect = Rect::from_min_size(tl, vec2(CELL_W, CELL_H));