animations
This commit is contained in:
+28
-20
@@ -7,6 +7,7 @@
|
||||
//! Rendering is text-based: kiln's bitmap-font tile indices are reinterpreted
|
||||
//! as characters (see [`cp437`]) and drawn with each cell's RGB colors.
|
||||
|
||||
mod animation;
|
||||
mod cp437;
|
||||
mod log;
|
||||
mod render;
|
||||
@@ -34,11 +35,11 @@ use std::io;
|
||||
use std::process::ExitCode;
|
||||
use std::time::{Duration, Instant};
|
||||
use term::TerminalCaps;
|
||||
use crate::animation::{AnimationLayer, AnimWidget};
|
||||
use crate::input::{current_input_mode, handle_board_input, handle_scroll_input, InputMode};
|
||||
use crate::log::{log_preview_line, LogWidget};
|
||||
use crate::scroll_overlay::ScrollOverlayWidget;
|
||||
use crate::speech::SpeechBubblesWidget;
|
||||
use crate::transition::TransitionAnimation;
|
||||
use crate::ui::Ui;
|
||||
|
||||
/// Entry point: parse the map path, load the board, then run the play loop with
|
||||
@@ -136,11 +137,10 @@ fn run(
|
||||
if handle_board_input(event, ui.log.open, terminal_h, game, ui) {
|
||||
return Ok(());
|
||||
}
|
||||
ui.post_transition_wait = false;
|
||||
}
|
||||
InputMode::Scroll => handle_scroll_input(event, game, ui),
|
||||
// Wipe is running — discard all events.
|
||||
InputMode::Transition => {}
|
||||
// Animation running — discard all events.
|
||||
InputMode::Animating => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ fn run(
|
||||
/// Render a single frame: the board in a bordered block, and — when open — a log
|
||||
/// panel across the bottom. When the panel is closed the latest log message is
|
||||
/// previewed in the board's bottom-left border after a `[l]og:` label.
|
||||
/// A scroll overlay is drawn on top of everything when active.
|
||||
/// A scroll overlay or overlay animation is drawn on top of everything when active.
|
||||
fn draw(frame: &mut Frame, game: &GameState, ui: &mut Ui) {
|
||||
// Borrow the board for the duration of the frame (no script runs during draw).
|
||||
let board = &game.board();
|
||||
@@ -186,32 +186,40 @@ fn draw(frame: &mut Frame, game: &GameState, ui: &mut Ui) {
|
||||
draw_board_area(frame, inner, game, ui);
|
||||
}
|
||||
|
||||
// Scroll overlay: drawn last so it sits above all other content.
|
||||
// Suppressed during a wipe — enter_board() already cleared active_scroll.
|
||||
if ui.transition.is_none() && let Some(scroll) = &game.active_scroll {
|
||||
// Capture area before the mutable buffer borrow to satisfy the borrow checker.
|
||||
// Draw overlay animations (scroll open/close) or the fully-open scroll overlay.
|
||||
// Suppressed during a board-layer animation (transition wipe); enter_board()
|
||||
// already cleared active_scroll so there's nothing to show anyway.
|
||||
let is_overlay_anim = ui.active_animation.as_ref()
|
||||
.map(|a| matches!(a.layer(), AnimationLayer::Overlay))
|
||||
.unwrap_or(false);
|
||||
|
||||
if is_overlay_anim {
|
||||
let area = frame.area();
|
||||
frame.render_stateful_widget(ScrollOverlayWidget::new(scroll), area, &mut ui.overlay);
|
||||
frame.render_widget(AnimWidget(ui.active_animation.as_ref().unwrap().as_ref()), area);
|
||||
} else if let Some(scroll) = &game.active_scroll {
|
||||
let area = frame.area();
|
||||
frame.render_stateful_widget(ScrollOverlayWidget::new(&scroll.lines), area, &mut ui.overlay);
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders the inner board area: either the active wipe animation or the live board.
|
||||
/// Renders the inner board area: either the active board-layer animation or the live board.
|
||||
///
|
||||
/// If `ui.pending_transition` is set, pre-renders both boards into a new
|
||||
/// [`TransitionAnimation`] (now that we know the exact `inner` area) and activates it.
|
||||
/// [`TransitionAnimation`](transition::TransitionAnimation) (now that we know the
|
||||
/// exact `inner` area) and activates it via [`Ui::start_transition`].
|
||||
fn draw_board_area(frame: &mut Frame, inner: Rect, game: &GameState, ui: &mut Ui) {
|
||||
// Initialize any pending transition now that we know the exact area.
|
||||
if let Some((old_rc, new_rc)) = ui.pending_transition.take() {
|
||||
ui.transition = Some(TransitionAnimation::new(
|
||||
&old_rc.borrow(),
|
||||
&new_rc.borrow(),
|
||||
inner,
|
||||
));
|
||||
ui.start_transition(&old_rc.borrow(), &new_rc.borrow(), inner);
|
||||
}
|
||||
|
||||
if let Some(ref tr) = ui.transition {
|
||||
// Wipe in progress: blend old and new board buffers; suppress speech bubbles.
|
||||
frame.render_widget(tr, inner);
|
||||
let is_board_anim = ui.active_animation.as_ref()
|
||||
.map(|a| matches!(a.layer(), AnimationLayer::Board))
|
||||
.unwrap_or(false);
|
||||
|
||||
if is_board_anim {
|
||||
// Board-layer animation (wipe): replaces the board entirely.
|
||||
frame.render_widget(AnimWidget(ui.active_animation.as_ref().unwrap().as_ref()), inner);
|
||||
} else {
|
||||
let board = &game.board();
|
||||
frame.render_widget(BoardWidget::new(board), inner);
|
||||
|
||||
Reference in New Issue
Block a user