Skip to content

Commit 3145c3f

Browse files
authored
Add game over dialog. (#36)
* Fix class/struct mismatch, upgrade bave to v0.5.1. * Remove `IEnemyDeathListener`. * Add `ui::Dialog`. * Add game over dialog.
1 parent d4a138e commit 3145c3f

File tree

18 files changed

+159
-36
lines changed

18 files changed

+159
-36
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ include(FetchContent)
1111
FetchContent_Declare(
1212
bave
1313
GIT_REPOSITORY https://github.com/karnkaul/bave
14-
GIT_TAG v0.5.0
14+
GIT_TAG v0.5.1
1515
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ext/bave"
1616
)
1717

assets/styles.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"grey": "#535151ff",
55
"mocha": "#6f5a48ff",
66
"milk": "#e5cdaeff",
7-
"ice": "#0xd6dbe1e1",
7+
"ice": "#d6dbe1e1",
88
"orange": "#f75c03ff",
99
"gun_beam": "#bc96e6ff"
1010
},
@@ -43,6 +43,18 @@
4343
"padding": 5
4444
}
4545
},
46+
"dialogs": {
47+
"default": {
48+
"footer_padding": [
49+
20.000000,
50+
10.000000
51+
],
52+
"corner_ratio": 0.25,
53+
"background_tint": "#e5cdaeff",
54+
"outline_tint": "#231d2aff",
55+
"content_text_tint": "#231d2aff"
56+
}
57+
},
4658
"loading_screen": {
4759
"background_tint": "#231d2aff",
4860
"spinner": {

src/spaced/spaced/game/enemy.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include <bave/graphics/shape.hpp>
44
#include <bave/platform.hpp>
55
#include <spaced/game/damageable.hpp>
6-
#include <spaced/game/enemy_death.hpp>
76
#include <spaced/game/health.hpp>
87
#include <spaced/services/layout.hpp>
98
#include <spaced/services/services.hpp>

src/spaced/spaced/game/enemy_death.hpp

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/spaced/spaced/game/player.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ void Player::tick(State const& state, Seconds const dt) {
5555

5656
for (auto const& target : state.targets) {
5757
if (is_intersecting(target->get_bounds(), ship.get_bounds())) {
58-
on_death();
58+
on_death(dt);
5959
target->force_death();
6060
return;
6161
}
@@ -92,10 +92,11 @@ void Player::set_controller(std::unique_ptr<IController> controller) {
9292
m_controller = std::move(controller);
9393
}
9494

95-
void Player::on_death() {
95+
void Player::on_death(Seconds const dt) {
9696
health = 0.0f;
9797
m_death = m_death_source;
9898
m_death->set_position(ship.transform.position);
99+
m_death->tick(dt);
99100
}
100101

101102
void Player::do_inspect() {

src/spaced/spaced/game/player.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class Player : public bave::IDrawable {
3535

3636
void set_special_weapon(std::unique_ptr<Weapon> weapon) { m_arsenal.set_special(std::move(weapon)); }
3737

38+
void on_death(bave::Seconds dt);
39+
3840
void inspect() {
3941
if constexpr (bave::debug_v) { do_inspect(); }
4042
}
@@ -43,8 +45,6 @@ class Player : public bave::IDrawable {
4345
Health health{};
4446

4547
private:
46-
void on_death();
47-
4848
void do_inspect();
4949

5050
bave::Logger m_log{"Player"};

src/spaced/spaced/game/world.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,6 @@ World::World(bave::NotNull<Services const*> services, bave::NotNull<IScorer*> sc
3939
m_enemy_factories["CreepFactory"] = std::make_unique<CreepFactory>(services);
4040
}
4141

42-
void World::on_death(EnemyDeath const& death) {
43-
m_scorer->add_score(death.points);
44-
45-
// temp
46-
if (random_in_range(0, 10) < 3) { debug_spawn_powerup(death.position); }
47-
// temp
48-
}
49-
5042
void World::tick(Seconds const dt) {
5143
bool const in_play = !player.health.is_dead();
5244

src/spaced/spaced/game/world.hpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,14 @@
55
#include <spaced/game/target_provider.hpp>
66

77
namespace spaced {
8-
class Resources;
8+
struct Resources;
99

10-
class World : public ITargetProvider, public IEnemyDeathListener {
10+
class World : public ITargetProvider {
1111
public:
1212
explicit World(bave::NotNull<Services const*> services, bave::NotNull<IScorer*> scorer);
1313

1414
[[nodiscard]] auto get_targets() const -> std::span<bave::NotNull<IDamageable*> const> final { return m_targets; }
1515

16-
void on_death(EnemyDeath const& death) final;
17-
1816
void tick(bave::Seconds dt);
1917
void draw(bave::Shader& shader) const;
2018

src/spaced/spaced/scenes/game.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <spaced/scenes/home.hpp>
66
#include <spaced/services/scene_switcher.hpp>
77
#include <spaced/services/styles.hpp>
8+
#include <spaced/ui/button.hpp>
9+
#include <spaced/ui/dialog.hpp>
810

911
namespace spaced {
1012
using bave::Action;
@@ -59,6 +61,7 @@ void Game::tick(Seconds const dt) {
5961
auto ft = bave::DeltaTime{};
6062

6163
m_world.tick(dt);
64+
if (m_world.player.health.is_dead() && !m_game_over_dialog_pushed) { on_game_over(); }
6265

6366
if constexpr (bave::debug_v) { inspect(dt, ft.update()); }
6467
}
@@ -70,6 +73,19 @@ void Game::add_score(std::int64_t const score) {
7073
m_hud->set_score(m_score);
7174
}
7275

76+
void Game::on_game_over() {
77+
auto dci = ui::DialogCreateInfo{
78+
.size = {600.0f, 200.0f},
79+
.content_text = "GAME OVER",
80+
.main_button = {.text = "RESTART", .callback = [this] { get_services().get<ISceneSwitcher>().switch_to<Game>(); }},
81+
.second_button = {.text = "QUIT", .callback = [this] { get_app().shutdown(); }},
82+
};
83+
84+
auto dialog = std::make_unique<ui::Dialog>(get_services(), std::move(dci));
85+
m_game_over_dialog_pushed = true;
86+
push_view(std::move(dialog));
87+
}
88+
7389
void Game::inspect(Seconds const dt, Seconds const frame_time) {
7490
if constexpr (bave::imgui_v) {
7591
m_debug.fps.tick(dt);
@@ -83,6 +99,9 @@ void Game::inspect(Seconds const dt, Seconds const frame_time) {
8399
ImGui::Separator();
84100
im_text("score: {}", get_score());
85101

102+
ImGui::Separator();
103+
if (ImGui::Button("end game")) { m_world.player.on_death({}); }
104+
86105
ImGui::Separator();
87106
im_text("dt: {:05.2f}", std::chrono::duration<float, std::milli>(dt).count());
88107
im_text("fps: {}", m_debug.fps.fps);

src/spaced/spaced/scenes/game.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ class Game : public Scene, public IScorer {
2424

2525
[[nodiscard]] auto get_score() const -> std::int64_t final { return m_score; }
2626
void add_score(std::int64_t score) final;
27+
void on_game_over();
2728

2829
void inspect(bave::Seconds dt, bave::Seconds frame_time);
2930

3031
World m_world;
3132
std::int64_t m_score{};
3233
bave::Ptr<Hud> m_hud{};
34+
bool m_game_over_dialog_pushed{};
3335

3436
struct {
3537
struct {

src/spaced/spaced/scenes/home.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <spaced/services/resources.hpp>
55
#include <spaced/services/scene_switcher.hpp>
66
#include <spaced/ui/button.hpp>
7+
#include <spaced/ui/dialog.hpp>
78
#include <spaced/ui/text.hpp>
89
#include <spaced/util.hpp>
910

@@ -12,7 +13,7 @@ using bave::App;
1213
using bave::Seconds;
1314
using bave::TextHeight;
1415

15-
auto Home::get_text_heights() -> std::vector<TextHeight> { return {TextHeight{100}, TextHeight{60}}; }
16+
auto Home::get_text_heights() -> std::vector<TextHeight> { return {TextHeight{100}, TextHeight{60}, ui::Dialog::text_height_v}; }
1617

1718
Home::Home(App& app, Services const& services) : Scene(app, services, "Home") { create_ui(); }
1819

src/spaced/spaced/services/styles.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ auto Styles::load(dj::Json const& json) -> Styles {
3535
load_styles(ret.rgbas, json["rgbas"]);
3636
load_styles(ret.buttons, json["buttons"]);
3737
load_styles(ret.progress_bars, json["progress_bars"]);
38+
load_styles(ret.dialogs, json["dialogs"]);
3839
if (auto const& loading_screen = json["loading_screen"]) { from_json(loading_screen, ret.loading_screen); }
3940
return ret;
4041
}
@@ -44,6 +45,7 @@ auto Styles::save() const -> dj::Json {
4445
save_styles(rgbas, ret, "rgbas");
4546
save_styles(buttons, ret, "buttons");
4647
save_styles(progress_bars, ret, "progress_bars");
48+
save_styles(dialogs, ret, "dialogs");
4749
to_json(ret["loading_screen"], loading_screen);
4850
return ret;
4951
}

src/spaced/spaced/services/styles.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct Styles : IService {
1212
StringMap<bave::Rgba> rgbas{};
1313
StringMap<ui::ButtonStyle> buttons{};
1414
StringMap<ui::ProgressBarStyle> progress_bars{};
15+
StringMap<ui::DialogStyle> dialogs{};
1516
ui::LoadingScreenStyle loading_screen{};
1617

1718
static auto load(dj::Json const& json) -> Styles;

src/spaced/spaced/ui/dialog.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <spaced/services/styles.hpp>
2+
#include <spaced/ui/dialog.hpp>
3+
4+
namespace spaced::ui {
5+
Dialog::Dialog(Services const& services, CreateInfo create_info) : View(services), m_style(services.get<Styles>().dialogs["default"]) {
6+
auto main_button = std::make_unique<Button>(services);
7+
auto const footer_height = main_button->get_size().y + m_style.footer_padding.y;
8+
auto const footer_position = glm::vec2{0.0f, -0.5f * (create_info.size.y - footer_height)};
9+
10+
auto background = std::make_unique<OutlineQuad>();
11+
background->set_size({create_info.size.x, create_info.size.y + footer_height});
12+
background->set_tint(m_style.background_tint);
13+
background->set_outline_tint(m_style.outline_tint);
14+
background->set_corner_ratio(0.25f);
15+
push(std::move(background));
16+
17+
auto content_text = std::make_unique<Text>(services);
18+
content_text->text.set_string(std::move(create_info.content_text));
19+
content_text->text.set_height(text_height_v);
20+
content_text->text.tint = m_style.content_text_tint;
21+
push(std::move(content_text));
22+
23+
main_button->set_text(std::move(create_info.main_button.text));
24+
main_button->callback = [this, f = std::move(create_info.main_button.callback)] {
25+
if (f) { f(); }
26+
set_destroyed();
27+
};
28+
if (create_info.second_button.text.empty()) {
29+
main_button->set_position(footer_position);
30+
} else {
31+
auto const x_offset = -0.5f * (create_info.size.x - main_button->get_size().x) + m_style.footer_padding.x;
32+
main_button->set_position({footer_position.x + x_offset, footer_position.y});
33+
}
34+
push(std::move(main_button));
35+
36+
if (!create_info.second_button.text.empty()) {
37+
auto second_button = std::make_unique<Button>(services);
38+
second_button->set_text(std::move(create_info.second_button.text));
39+
second_button->callback = [this, f = std::move(create_info.second_button.callback)] {
40+
if (f) { f(); }
41+
set_destroyed();
42+
};
43+
auto const x_offset = 0.5f * (create_info.size.x - second_button->get_size().x) - m_style.footer_padding.x;
44+
second_button->set_position({footer_position.x + x_offset, footer_position.y});
45+
push(std::move(second_button));
46+
}
47+
}
48+
} // namespace spaced::ui

src/spaced/spaced/ui/dialog.hpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#pragma once
2+
#include <spaced/ui/button.hpp>
3+
#include <spaced/ui/outline_quad.hpp>
4+
#include <spaced/ui/text.hpp>
5+
#include <spaced/ui/view.hpp>
6+
7+
namespace spaced::ui {
8+
struct DialogCreateInfo {
9+
struct ButtonInfo {
10+
std::string text{};
11+
std::function<void()> callback{};
12+
};
13+
14+
glm::vec2 size{500.0f, 200.0f};
15+
std::string content_text{"Content text."};
16+
ButtonInfo main_button{.text = "OK"};
17+
ButtonInfo second_button{};
18+
};
19+
20+
class Dialog : public ui::View {
21+
public:
22+
using CreateInfo = DialogCreateInfo;
23+
24+
static constexpr auto text_height_v = bave::TextHeight{static_cast<int>(bave::TextHeight::eDefault) + 16};
25+
26+
explicit Dialog(Services const& services, CreateInfo create_info = {});
27+
28+
protected:
29+
DialogStyle m_style{};
30+
31+
bave::Ptr<OutlineQuad> m_background{};
32+
bave::Ptr<Text> m_content_text{};
33+
std::array<bave::Ptr<ui::Button>, 2> m_footer_buttons{};
34+
};
35+
} // namespace spaced::ui

src/spaced/spaced/ui/style.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,12 @@ struct ProgressBarStyle {
3838
float corner_ratio{0.5f};
3939
float padding{10.0f};
4040
};
41+
42+
struct DialogStyle {
43+
glm::vec2 footer_padding{20.0f, 10.0f};
44+
float corner_ratio{0.25f};
45+
bave::Rgba background_tint{bave::yellow_v};
46+
bave::Rgba outline_tint{bave::cyan_v};
47+
bave::Rgba content_text_tint{bave::black_v};
48+
};
4149
} // namespace spaced::ui

src/spaced/spaced/util.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,24 @@ void util::from_json(dj::Json const& json, ui::ProgressBarStyle& out) {
7171
out.padding = json["padding"].as<float>(out.padding);
7272
}
7373

74+
void util::to_json(dj::Json& out, ui::DialogStyle const& dialog_style) {
75+
using bave::to_json;
76+
to_json(out["footer_padding"], dialog_style.footer_padding);
77+
to_json(out["corner_ratio"], dialog_style.corner_ratio);
78+
to_json(out["background_tint"], dialog_style.background_tint);
79+
to_json(out["outline_tint"], dialog_style.outline_tint);
80+
to_json(out["content_text_tint"], dialog_style.content_text_tint);
81+
}
82+
83+
void util::from_json(dj::Json const& json, ui::DialogStyle& out) {
84+
using bave::from_json;
85+
from_json(json["footer_padding"], out.footer_padding);
86+
from_json(json["corner_ratio"], out.corner_ratio);
87+
from_json(json["background_tint"], out.background_tint);
88+
from_json(json["outline_tint"], out.outline_tint);
89+
from_json(json["content_text_tint"], out.content_text_tint);
90+
}
91+
7492
auto util::create_font_atlas_task(std::shared_ptr<bave::Font> font, std::vector<bave::TextHeight> heights) -> std::function<void()> {
7593
if (!font || heights.empty()) { return {}; }
7694
return [font = std::move(font), heights = std::move(heights)] {

src/spaced/spaced/util.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,8 @@ void from_json(dj::Json const& json, ui::ButtonStyle& out);
1717
void to_json(dj::Json& out, ui::ProgressBarStyle const& progress_bar_style);
1818
void from_json(dj::Json const& json, ui::ProgressBarStyle& out);
1919

20+
void to_json(dj::Json& out, ui::DialogStyle const& dialog_style);
21+
void from_json(dj::Json const& json, ui::DialogStyle& out);
22+
2023
auto create_font_atlas_task(std::shared_ptr<bave::Font> font, std::vector<bave::TextHeight> heights) -> std::function<void()>;
2124
} // namespace spaced::util

0 commit comments

Comments
 (0)