From e37ebf280284ab04b9c0ef19fd9492b79aee955e Mon Sep 17 00:00:00 2001 From: Karn Kaul Date: Thu, 2 May 2024 14:43:34 +0530 Subject: [PATCH] Persist and show high score. (#42) --- .gitignore | 1 + CMakeLists.txt | 2 +- src/spaced/spaced/game/game_save.cpp | 33 +++++++++++++++++++++++++ src/spaced/spaced/game/game_save.hpp | 37 ++++++++++++++++++++++++++++ src/spaced/spaced/game/hud.cpp | 29 ++++++++++++++++------ src/spaced/spaced/game/hud.hpp | 2 ++ src/spaced/spaced/scenes/game.cpp | 10 +++++++- src/spaced/spaced/scenes/game.hpp | 4 +++ 8 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 src/spaced/spaced/game/game_save.cpp create mode 100644 src/spaced/spaced/game/game_save.hpp diff --git a/.gitignore b/.gitignore index 6419c60..7a70de4 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ compile_commands.json imgui.ini bave*.log +/spaced diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a91ed8..b448584 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ include(FetchContent) FetchContent_Declare( bave GIT_REPOSITORY https://github.com/karnkaul/bave - GIT_TAG v0.5.1 + GIT_TAG v0.5.2 SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ext/bave" ) diff --git a/src/spaced/spaced/game/game_save.cpp b/src/spaced/spaced/game/game_save.cpp new file mode 100644 index 0000000..f98aec1 --- /dev/null +++ b/src/spaced/spaced/game/game_save.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include + +namespace spaced { +using bave::App; +using bave::NotNull; +using bave::Persistor; + +namespace { +constexpr std::string_view uri_v{"spaced/game_save.bin"}; +} // namespace + +GameSave::GameSave(NotNull app) : m_app(app) { + auto const persistor = Persistor{*m_app}; + if (persistor.exists(uri_v)) { + auto const blob_bytes = persistor.read_bytes(uri_v); + std::memcpy(&m_blob, blob_bytes.data(), blob_bytes.size()); + } +} + +GameSave::~GameSave() { save(); } + +auto GameSave::save() -> bool { + auto const persistor = Persistor{*m_app}; + auto blob_bytes = std::array{}; + std::memcpy(blob_bytes.data(), &m_blob, sizeof(Blob)); + return persistor.write_bytes(uri_v, blob_bytes); +} +} // namespace spaced diff --git a/src/spaced/spaced/game/game_save.hpp b/src/spaced/spaced/game/game_save.hpp new file mode 100644 index 0000000..108c95b --- /dev/null +++ b/src/spaced/spaced/game/game_save.hpp @@ -0,0 +1,37 @@ +#pragma once +#include +#include + +namespace bave { +class App; +} + +namespace spaced { +class GameSave { + public: + GameSave(GameSave const&) = delete; + GameSave(GameSave&&) = delete; + auto operator=(GameSave const&) = delete; + auto operator=(GameSave&&) = delete; + + explicit GameSave(bave::NotNull app); + ~GameSave(); + + [[nodiscard]] auto get_hi_score() const -> std::int64_t { return m_blob.hi_score; } + void set_hi_score(std::int64_t const hi_score) { m_blob.hi_score = hi_score; } + + auto save() -> bool; + + private: + struct Blob { + // struct must remain backwards compatible: + // fields must NEVER be removed / reordered! + // new fields can be added at the bottom. + + std::int64_t hi_score{}; + }; + + bave::NotNull m_app; + Blob m_blob{}; +}; +} // namespace spaced diff --git a/src/spaced/spaced/game/hud.cpp b/src/spaced/spaced/game/hud.cpp index 5b9639a..9799892 100644 --- a/src/spaced/spaced/game/hud.cpp +++ b/src/spaced/spaced/game/hud.cpp @@ -14,6 +14,8 @@ Hud::Hud(Services const& services) : ui::View(services), m_styles(&services.get< void Hud::set_score(std::int64_t const score) { m_score->text.set_string(fmt::format("{}", score)); } +void Hud::set_hi_score(std::int64_t const score) { m_hi_score->text.set_string(fmt::format("HI {}", score)); } + void Hud::create_background() { auto background = std::make_unique(); m_background = background.get(); @@ -27,16 +29,29 @@ void Hud::create_background() { void Hud::create_score(Services const& services) { auto const& rgbas = m_styles->rgbas; - auto text = std::make_unique(services); + auto make_text = [&] { + auto text = std::make_unique(services); + text->text.set_height(TextHeight{60}); + text->text.transform.position = m_area.centre(); + text->text.tint = rgbas["grey"]; + return text; + }; + + auto text = make_text(); m_score = text.get(); - text->text.set_height(TextHeight{60}); text->text.set_string("9999999999"); - auto const text_bounds = text->text.get_bounds(); - auto const text_bounds_size = text_bounds.size(); - text->text.transform.position = m_area.centre(); + auto const text_bounds_size = text->text.get_bounds().size(); + text->text.transform.position.y -= 0.5f * text_bounds_size.y; + set_score(0); + + push(std::move(text)); + + text = make_text(); + m_hi_score = text.get(); + text->text.transform.position.x = m_area.rb.x - 50.0f; text->text.transform.position.y -= 0.5f * text_bounds_size.y; - text->text.set_string("0"); - text->text.tint = rgbas["grey"]; + text->text.set_align(bave::Text::Align::eLeft); + set_hi_score(0); push(std::move(text)); } diff --git a/src/spaced/spaced/game/hud.hpp b/src/spaced/spaced/game/hud.hpp index 4fc1157..0f1d0bb 100644 --- a/src/spaced/spaced/game/hud.hpp +++ b/src/spaced/spaced/game/hud.hpp @@ -10,6 +10,7 @@ class Hud : public ui::View { explicit Hud(Services const& services); void set_score(std::int64_t score); + void set_hi_score(std::int64_t score); private: void create_background(); @@ -20,5 +21,6 @@ class Hud : public ui::View { bave::Ptr m_background{}; bave::Ptr m_score{}; + bave::Ptr m_hi_score{}; }; } // namespace spaced diff --git a/src/spaced/spaced/scenes/game.cpp b/src/spaced/spaced/scenes/game.cpp index 5656e1e..9f78f37 100644 --- a/src/spaced/spaced/scenes/game.cpp +++ b/src/spaced/spaced/scenes/game.cpp @@ -37,11 +37,12 @@ auto Game::get_manifest() -> AssetManifest { }; } -Game::Game(App& app, Services const& services) : Scene(app, services, "Game"), m_world(&services, this) { +Game::Game(App& app, Services const& services) : Scene(app, services, "Game"), m_save(&app), m_world(&services, this) { clear_colour = services.get().rgbas["mocha"]; auto hud = std::make_unique(services); m_hud = hud.get(); + m_hud->set_hi_score(m_save.get_hi_score()); push_view(std::move(hud)); } @@ -71,6 +72,7 @@ void Game::render(Shader& shader) const { m_world.draw(shader); } void Game::add_score(std::int64_t const score) { m_score += score; m_hud->set_score(m_score); + update_hi_score(); } void Game::on_game_over() { @@ -86,6 +88,12 @@ void Game::on_game_over() { push_view(std::move(dialog)); } +void Game::update_hi_score() { + if (m_score <= m_save.get_hi_score()) { return; } + m_save.set_hi_score(m_score); + m_hud->set_hi_score(m_save.get_hi_score()); +} + void Game::inspect(Seconds const dt, Seconds const frame_time) { if constexpr (bave::imgui_v) { m_debug.fps.tick(dt); diff --git a/src/spaced/spaced/scenes/game.hpp b/src/spaced/spaced/scenes/game.hpp index e93cb5d..44419c9 100644 --- a/src/spaced/spaced/scenes/game.hpp +++ b/src/spaced/spaced/scenes/game.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include #include @@ -26,8 +27,11 @@ class Game : public Scene, public IScorer { void add_score(std::int64_t score) final; void on_game_over(); + void update_hi_score(); + void inspect(bave::Seconds dt, bave::Seconds frame_time); + GameSave m_save; World m_world; std::int64_t m_score{}; bave::Ptr m_hud{};