Brought over the storyboard thing from my other game for the intro sequence.
This commit is contained in:
parent
279faf6dd5
commit
0df63ea074
10 changed files with 204 additions and 3 deletions
|
|
@ -4,7 +4,8 @@
|
||||||
"pickup": "assets/sounds/pickup.ogg",
|
"pickup": "assets/sounds/pickup.ogg",
|
||||||
"ui_click": "assets/sounds/ui_click.ogg",
|
"ui_click": "assets/sounds/ui_click.ogg",
|
||||||
"ui_hover": "assets/sounds/ui_hover.ogg",
|
"ui_hover": "assets/sounds/ui_hover.ogg",
|
||||||
"walk": "assets/sounds/walk.ogg"
|
"walk": "assets/sounds/walk.ogg",
|
||||||
|
"test_story": "assets/sounds/test_story.ogg"
|
||||||
},
|
},
|
||||||
"sprites": {
|
"sprites": {
|
||||||
"spider_bot":
|
"spider_bot":
|
||||||
|
|
@ -81,6 +82,11 @@
|
||||||
{"path": "assets/scenes/win_scene.png",
|
{"path": "assets/scenes/win_scene.png",
|
||||||
"frame_width": 1920,
|
"frame_width": 1920,
|
||||||
"frame_height": 1080
|
"frame_height": 1080
|
||||||
|
},
|
||||||
|
"test_story":
|
||||||
|
{"path": "assets/stories/test_storyboard.png",
|
||||||
|
"frame_width": 1280,
|
||||||
|
"frame_height": 720
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"worldgen": {
|
"worldgen": {
|
||||||
|
|
|
||||||
BIN
assets/sounds/test_story.ogg
Normal file
BIN
assets/sounds/test_story.ogg
Normal file
Binary file not shown.
26
assets/stories.json
Normal file
26
assets/stories.json
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"intro_story":
|
||||||
|
{"_type": "Storyboard",
|
||||||
|
"image": "test_story",
|
||||||
|
"audio": "test_story",
|
||||||
|
"layout": [
|
||||||
|
"[a|b|c1]",
|
||||||
|
"[d|e|c2]",
|
||||||
|
"[g|h|i]"
|
||||||
|
],
|
||||||
|
"beats": [
|
||||||
|
["00:00", "a","pan", "60"],
|
||||||
|
["00:01", "b","shake", "30"],
|
||||||
|
["00:5", "g","pan", "60"],
|
||||||
|
["00:6", "h","pan", "60"],
|
||||||
|
["00:7", "h","bounce", "60"],
|
||||||
|
["00:8", "c1","pan", "60"],
|
||||||
|
["00:9", "c2","pan", "60"],
|
||||||
|
["00:10", "d","bounce", "60"],
|
||||||
|
["00:11", "e","shake", "60"],
|
||||||
|
["00:12", "i","pan", "60"],
|
||||||
|
["00:13", "i","shake", "60"],
|
||||||
|
["00:14", "i","bounce", "60"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
assets/stories/test_storyboard.png
Normal file
BIN
assets/stories/test_storyboard.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
|
|
@ -31,6 +31,7 @@ namespace gui {
|
||||||
void FSM::event(Event ev, std::any data) {
|
void FSM::event(Event ev, std::any data) {
|
||||||
switch($state) {
|
switch($state) {
|
||||||
FSM_STATE(State, START, ev);
|
FSM_STATE(State, START, ev);
|
||||||
|
FSM_STATE(State, INTRO, ev);
|
||||||
FSM_STATE(State, START_SCENE, ev);
|
FSM_STATE(State, START_SCENE, ev);
|
||||||
FSM_STATE(State, DEATH_SCENE, ev);
|
FSM_STATE(State, DEATH_SCENE, ev);
|
||||||
FSM_STATE(State, WIN_SCENE, ev);
|
FSM_STATE(State, WIN_SCENE, ev);
|
||||||
|
|
@ -58,10 +59,24 @@ namespace gui {
|
||||||
$debug_ui.init(cell);
|
$debug_ui.init(cell);
|
||||||
$status_ui.init();
|
$status_ui.init();
|
||||||
run_systems();
|
run_systems();
|
||||||
|
$story = std::make_shared<storyboard::UI>("intro_story");
|
||||||
|
$story->init();
|
||||||
|
state(State::INTRO);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
show_scene("STARTING");
|
||||||
state(State::START_SCENE);
|
state(State::START_SCENE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FSM::START_SCENE(Event ev) {
|
void FSM::START_SCENE(Event ev) {
|
||||||
using enum Event;
|
using enum Event;
|
||||||
|
|
@ -407,6 +422,8 @@ namespace gui {
|
||||||
void FSM::draw_gui() {
|
void FSM::draw_gui() {
|
||||||
if($cur_scene != nullptr) {
|
if($cur_scene != nullptr) {
|
||||||
$cur_scene->render($window);
|
$cur_scene->render($window);
|
||||||
|
} else if($story != nullptr) {
|
||||||
|
$story->render($window);
|
||||||
} else {
|
} else {
|
||||||
$main_ui.render();
|
$main_ui.render();
|
||||||
$status_ui.render($window);
|
$status_ui.render($window);
|
||||||
|
|
@ -422,6 +439,8 @@ namespace gui {
|
||||||
void FSM::update() {
|
void FSM::update() {
|
||||||
if($cur_scene != nullptr) {
|
if($cur_scene != nullptr) {
|
||||||
$cur_scene->update();
|
$cur_scene->update();
|
||||||
|
} else if($story != nullptr) {
|
||||||
|
$story->update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,12 @@
|
||||||
#include "gui/dnd_loot.hpp"
|
#include "gui/dnd_loot.hpp"
|
||||||
#include "events.hpp"
|
#include "events.hpp"
|
||||||
#include "gui/scene_ui.hpp"
|
#include "gui/scene_ui.hpp"
|
||||||
|
#include "gui/storyboard.hpp"
|
||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
enum class State {
|
enum class State {
|
||||||
START=__LINE__,
|
START=__LINE__,
|
||||||
|
INTRO=__LINE__,
|
||||||
START_SCENE=__LINE__,
|
START_SCENE=__LINE__,
|
||||||
DEATH_SCENE=__LINE__,
|
DEATH_SCENE=__LINE__,
|
||||||
WIN_SCENE=__LINE__,
|
WIN_SCENE=__LINE__,
|
||||||
|
|
@ -47,12 +49,14 @@ namespace gui {
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<gui::SceneUI> $cur_scene = nullptr;
|
std::shared_ptr<gui::SceneUI> $cur_scene = nullptr;
|
||||||
|
std::shared_ptr<storyboard::UI> $story = nullptr;
|
||||||
|
|
||||||
FSM();
|
FSM();
|
||||||
|
|
||||||
void event(game::Event ev, std::any data={});
|
void event(game::Event ev, std::any data={});
|
||||||
|
|
||||||
void START(game::Event ev);
|
void START(game::Event ev);
|
||||||
|
void INTRO(game::Event ev);
|
||||||
void START_SCENE(game::Event ev);
|
void START_SCENE(game::Event ev);
|
||||||
void WIN_SCENE(game::Event ev);
|
void WIN_SCENE(game::Event ev);
|
||||||
void DEATH_SCENE(game::Event ev);
|
void DEATH_SCENE(game::Event ev);
|
||||||
|
|
|
||||||
109
src/gui/storyboard.cpp
Normal file
109
src/gui/storyboard.cpp
Normal 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
35
src/gui/storyboard.hpp
Normal 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -34,6 +34,7 @@ int main(int argc, char* argv[]) {
|
||||||
// BUG: need to sort out how to deal with this in the FSM
|
// BUG: need to sort out how to deal with this in the FSM
|
||||||
if(main.in_state(gui::State::IDLE)
|
if(main.in_state(gui::State::IDLE)
|
||||||
|| main.in_state(gui::State::START_SCENE)
|
|| 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::WIN_SCENE)
|
||||||
|| main.in_state(gui::State::DEATH_SCENE)
|
|| main.in_state(gui::State::DEATH_SCENE)
|
||||||
|| main.in_state(gui::State::NEXT_LEVEL_SCENE)
|
|| main.in_state(gui::State::NEXT_LEVEL_SCENE)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ sources = files(
|
||||||
'gui/overlay_ui.cpp',
|
'gui/overlay_ui.cpp',
|
||||||
'gui/body_ui.cpp',
|
'gui/body_ui.cpp',
|
||||||
'gui/scene_ui.cpp',
|
'gui/scene_ui.cpp',
|
||||||
|
'gui/storyboard.cpp',
|
||||||
|
|
||||||
# graphics
|
# graphics
|
||||||
'graphics/animation.cpp',
|
'graphics/animation.cpp',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue