Brought over the storyboard thing from my other game for the intro sequence.

This commit is contained in:
Zed A. Shaw 2026-04-03 00:05:37 -04:00
parent 279faf6dd5
commit 0df63ea074
10 changed files with 204 additions and 3 deletions

View file

@ -31,6 +31,7 @@ namespace gui {
void FSM::event(Event ev, std::any data) {
switch($state) {
FSM_STATE(State, START, ev);
FSM_STATE(State, INTRO, ev);
FSM_STATE(State, START_SCENE, ev);
FSM_STATE(State, DEATH_SCENE, ev);
FSM_STATE(State, WIN_SCENE, ev);
@ -58,9 +59,23 @@ namespace gui {
$debug_ui.init(cell);
$status_ui.init();
run_systems();
$story = std::make_shared<storyboard::UI>("intro_story");
$story->init();
state(State::INTRO);
}
show_scene("STARTING");
state(State::START_SCENE);
void FSM::INTRO(Event ev) {
dbc::check($story != nullptr, "you forgot the stroy");
if($story->playing()) {
if(ev == game::Event::MOUSE_CLICK) {
$story->reset();
}
} else {
$story = nullptr;
show_scene("STARTING");
state(State::START_SCENE);
}
}
void FSM::START_SCENE(Event ev) {
@ -407,6 +422,8 @@ namespace gui {
void FSM::draw_gui() {
if($cur_scene != nullptr) {
$cur_scene->render($window);
} else if($story != nullptr) {
$story->render($window);
} else {
$main_ui.render();
$status_ui.render($window);
@ -422,6 +439,8 @@ namespace gui {
void FSM::update() {
if($cur_scene != nullptr) {
$cur_scene->update();
} else if($story != nullptr) {
$story->update();
}
}

View file

@ -12,10 +12,12 @@
#include "gui/dnd_loot.hpp"
#include "events.hpp"
#include "gui/scene_ui.hpp"
#include "gui/storyboard.hpp"
namespace gui {
enum class State {
START=__LINE__,
INTRO=__LINE__,
START_SCENE=__LINE__,
DEATH_SCENE=__LINE__,
WIN_SCENE=__LINE__,
@ -47,12 +49,14 @@ namespace gui {
};
std::shared_ptr<gui::SceneUI> $cur_scene = nullptr;
std::shared_ptr<storyboard::UI> $story = nullptr;
FSM();
void event(game::Event ev, std::any data={});
void START(game::Event ev);
void INTRO(game::Event ev);
void START_SCENE(game::Event ev);
void WIN_SCENE(game::Event ev);
void DEATH_SCENE(game::Event ev);

109
src/gui/storyboard.cpp Normal file
View file

@ -0,0 +1,109 @@
#include "gui/storyboard.hpp"
#include "game/components.hpp"
#include "game/sound.hpp"
#include "game/config.hpp"
#include <chrono>
#include <iostream>
#include <locale>
#include <sstream>
namespace storyboard {
UI::UI(const std::string& story_name) :
$view_texture({SCREEN_WIDTH, SCREEN_HEIGHT}),
$view_sprite($view_texture.getTexture())
{
$view_sprite.setPosition({0, 0});
auto config = settings::get("stories");
$story = components::convert<components::Storyboard>(config[story_name]);
$audio = sound::get_sound_pair($story.audio).sound;
$camera.from_story($story);
}
void UI::init() {
$ui.position(0,0, SCREEN_WIDTH, SCREEN_HEIGHT);
$ui.set<guecs::Background>($ui.MAIN, {$ui.$parser, guecs::THEME.TRANSPARENT});
auto& background = $ui.get<guecs::Background>($ui.MAIN);
background.set_sprite($story.image, true);
for(auto& line : $story.layout) {
$layout.append(line);
}
$ui.layout($layout);
$audio->play();
}
void UI::render(sf::RenderWindow &window) {
track_audio();
$view_texture.clear();
$camera.render($view_texture);
$ui.render($view_texture);
// $ui.debug_layout($view_texture);
$view_texture.display();
window.draw($view_sprite);
}
bool UI::playing() {
return $audio->getStatus() == sf::SoundSource::Status::Playing;
}
sf::Time parse_time_code(const std::string& time) {
std::chrono::seconds out{};
std::istringstream is{time};
is >> std::chrono::parse("%M:%S", out);
dbc::check(!is.fail(), $F("Time parse failed: {}", time));
return sf::Time(out);
}
void UI::update() {
$camera.update();
}
void UI::track_audio() {
auto& [timecode, cell_name, form, _] = $story.beats[cur_beat % $story.beats.size()];
auto track_head = $audio->getPlayingOffset();
auto next_beat = parse_time_code(timecode);
if(track_head >= next_beat) {
if($moving) return;
$moving = true; // prevent motion until next tick
// get the original zoom target as from
auto& from_cell = $ui.cell_for($zoom_target);
$camera.position(from_cell.mid_x, from_cell.mid_y);
$zoom_target = cell_name;
$camera.style(timecode);
// get the new target from the cell names
zoom($zoom_target);
$camera.play();
cur_beat++;
} else {
$moving = false;
}
}
bool UI::mouse(float, float, guecs::Modifiers) {
$audio->stop();
return true;
}
void UI::zoom(const std::string &cell_name) {
auto& cell = $ui.cell_for(cell_name);
$camera.resize(float(cell.w));
$camera.move(float(cell.mid_x), float(cell.mid_y));
}
void UI::reset() {
$camera.reset($view_texture);
}
}

35
src/gui/storyboard.hpp Normal file
View file

@ -0,0 +1,35 @@
#pragma once
#include "constants.hpp"
#include <guecs/ui.hpp>
#include "graphics/camera.hpp"
#include <SFML/Audio/Sound.hpp>
#include "game/components.hpp"
namespace storyboard {
struct UI {
guecs::UI $ui;
sf::RenderTexture $view_texture;
sf::Sprite $view_sprite;
cinematic::Camera $camera{{SCREEN_WIDTH, SCREEN_HEIGHT}, "story"};
std::shared_ptr<sf::Sound> $audio;
std::string $zoom_target = "a";
bool $moving = false;
int cur_beat = 0;
components::Storyboard $story;
std::string $layout;
UI(const std::string& story_name);
void init();
void update();
void render(sf::RenderWindow &window);
bool mouse(float x, float y, guecs::Modifiers mods);
void zoom(const std::string &cell_name);
void reset();
void track_audio();
bool playing();
void config_camera(cinematic::Camera &camera);
};
}

View file

@ -34,6 +34,7 @@ int main(int argc, char* argv[]) {
// BUG: need to sort out how to deal with this in the FSM
if(main.in_state(gui::State::IDLE)
|| main.in_state(gui::State::START_SCENE)
|| main.in_state(gui::State::INTRO)
|| main.in_state(gui::State::WIN_SCENE)
|| main.in_state(gui::State::DEATH_SCENE)
|| main.in_state(gui::State::NEXT_LEVEL_SCENE)

View file

@ -21,6 +21,7 @@ sources = files(
'gui/overlay_ui.cpp',
'gui/body_ui.cpp',
'gui/scene_ui.cpp',
'gui/storyboard.cpp',
# graphics
'graphics/animation.cpp',