Skip to content

Commit b096144

Browse files
authored
Add some flair/polish to countdown (#29)
1 parent e094057 commit b096144

8 files changed

Lines changed: 122 additions & 17 deletions

File tree

ext/depzip.jsonc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"packages": [
33
{
44
"uri": "karnkaul/le2d",
5-
"branch": "v0.4.7"
5+
"branch": "v0.4.8"
66
}
77
]
88
}

ext/src.zip

1.12 KB
Binary file not shown.

lib/include/chomper/runtimes/game.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33
#include "chomper/engine.hpp"
44
#include "chomper/player.hpp"
55
#include "chomper/runtime.hpp"
6+
#include "chomper/ui/countdown.hpp"
67
#include "chomper/world.hpp"
78
#include <klib/ptr.hpp>
89
#include <le2d/drawable/text.hpp>
910
#include <le2d/input/action.hpp>
1011
#include <le2d/input/scoped_mapping.hpp>
12+
#include <le2d/random.hpp>
13+
#include <le2d/resource/texture.hpp>
14+
#include <optional>
1115

1216
namespace chomper::runtime {
1317
// driven by Engine, owner (whether indirectly) of all game things.
@@ -49,7 +53,6 @@ class Game : public IRuntime, public klib::Pinned {
4953

5054
std::vector<int> m_emptyTiles{};
5155

52-
le::drawable::Text m_countdownText{};
53-
kvf::Seconds m_countdown{3};
56+
std::optional<ui::Countdown> m_countdown{};
5457
};
5558
} // namespace chomper::runtime

lib/include/chomper/theme.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#pragma once
2+
#include <kvf/color.hpp>
3+
4+
namespace chomper::theme {
5+
constexpr auto clearColor_v = kvf::Color{glm::vec4{.34f, .54f, .2f, 1.f}};
6+
} // namespace chomper::theme
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
#include "le2d/drawable/shape.hpp"
3+
#include "le2d/drawable/text.hpp"
4+
#include <kvf/time.hpp>
5+
6+
namespace chomper::ui {
7+
class Countdown {
8+
public:
9+
static constexpr auto textHeight_v = le::TextHeight{120};
10+
11+
explicit Countdown(gsl::not_null<le::IFont*> font, le::TextHeight textHeight = textHeight_v, kvf::Seconds timer = 3s);
12+
13+
[[nodiscard]] auto getRemain() const -> kvf::Seconds {
14+
return m_remain;
15+
}
16+
17+
void tick(kvf::Seconds dt);
18+
void draw(le::IRenderer& renderer) const;
19+
20+
private:
21+
void setTimerText(std::chrono::seconds value);
22+
void updateSector();
23+
24+
gsl::not_null<le::IFont*> m_font;
25+
le::TextHeight m_textHeight{};
26+
27+
le::drawable::Sector m_sector{};
28+
le::drawable::Circle m_background{};
29+
le::drawable::Text m_text{};
30+
31+
kvf::Seconds m_timer{};
32+
kvf::Seconds m_remain{};
33+
};
34+
} // namespace chomper::ui

lib/src/engine.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "chomper/build_version.hpp"
33
#include "chomper/inclusive_range.hpp"
44
#include "chomper/runtimes/entrypoint.hpp"
5+
#include "chomper/theme.hpp"
56
#include "chomper/viewport.hpp"
67
#include <imgui.h>
78
#include <klib/assert.hpp>
@@ -12,8 +13,6 @@
1213

1314
namespace chomper {
1415
namespace {
15-
constexpr auto clearColor_v = kvf::Color{glm::vec4{.34f, .54f, .2f, 1.f}};
16-
1716
std::unique_ptr<IRuntime> createEntrypoint(Engine& engine) {
1817
return std::make_unique<runtime::Entrypoint>(&engine);
1918
}
@@ -52,7 +51,7 @@ void Engine::run() {
5251
m_runtime->tick(scaledDt);
5352

5453
// render runtime.
55-
auto& renderer = m_context->begin_render(clearColor_v);
54+
auto& renderer = m_context->begin_render(theme::clearColor_v);
5655
renderer.viewport = viewport_v;
5756
renderer.polygon_mode = m_runtimeState.wireframe ? vk::PolygonMode::eLine : vk::PolygonMode::eFill;
5857

lib/src/runtimes/game.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@
66
#include <algorithm>
77

88
namespace chomper::runtime {
9-
namespace {
10-
constexpr auto countdownParams_v = le::drawable::Text::Params{
11-
.height = le::TextHeight{60},
12-
};
13-
} // namespace
149
using ActionValue = le::input::action::Value;
1510

1611
Game::Game(gsl::not_null<Engine*> engine) : m_engine(engine), m_mapping(&engine->getInputRouter()) {
@@ -21,7 +16,7 @@ Game::Game(gsl::not_null<Engine*> engine) : m_engine(engine), m_mapping(&engine-
2116

2217
m_collectibles->spawn(*m_player);
2318

24-
m_countdownText.set_string(engine->getResources().getMainFont(), "3", countdownParams_v);
19+
m_countdown.emplace(&engine->getResources().getMainFont());
2520
}
2621

2722
void Game::tick(kvf::Seconds const dt) {
@@ -31,9 +26,11 @@ void Game::tick(kvf::Seconds const dt) {
3126
}
3227
ImGui::End();
3328

34-
if (m_countdown.count() > 0) {
35-
m_countdown -= dt;
36-
m_countdownText.set_string(m_engine->getResources().getMainFont(), std::format("{}", static_cast<int>(m_countdown.count() + 1)), countdownParams_v);
29+
if (m_countdown) {
30+
m_countdown->tick(dt);
31+
if (m_countdown->getRemain() <= 0s) {
32+
m_countdown.reset();
33+
}
3734
return;
3835
}
3936

@@ -51,8 +48,8 @@ void Game::render(le::IRenderer& renderer) const {
5148
m_world->draw(renderer);
5249
m_collectibles->draw(renderer);
5350
m_player->draw(renderer);
54-
if (m_countdown.count() > 0) {
55-
m_countdownText.draw(renderer);
51+
if (m_countdown) {
52+
m_countdown->draw(renderer);
5653
}
5754
}
5855

lib/src/ui/countdown.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#include "chomper/ui/countdown.hpp"
2+
#include "chomper/theme.hpp"
3+
#include <klib/assert.hpp>
4+
5+
namespace chomper::ui {
6+
Countdown::Countdown(gsl::not_null<le::IFont*> font, le::TextHeight const textHeight, kvf::Seconds const timer)
7+
: m_font(font), m_textHeight(textHeight), m_timer(timer), m_remain(timer) {
8+
auto const diameter = float(m_textHeight) + 30.0f;
9+
m_background.create(diameter);
10+
m_background.tint = theme::clearColor_v;
11+
}
12+
13+
void Countdown::tick(kvf::Seconds const dt) {
14+
if (m_remain <= 0s) {
15+
return;
16+
}
17+
18+
auto const prevSeconds = std::chrono::duration_cast<std::chrono::seconds>(m_remain);
19+
m_remain -= dt;
20+
auto const currSeconds = std::chrono::duration_cast<std::chrono::seconds>(m_remain);
21+
if (prevSeconds > currSeconds) {
22+
setTimerText(currSeconds + 1s);
23+
}
24+
25+
updateSector();
26+
}
27+
28+
void Countdown::draw(le::IRenderer& renderer) const {
29+
if (m_remain <= 0s) {
30+
return;
31+
}
32+
33+
m_sector.draw(renderer);
34+
m_background.draw(renderer);
35+
m_text.draw(renderer);
36+
}
37+
38+
void Countdown::setTimerText(std::chrono::seconds const value) {
39+
auto const params = le::drawable::Text::Params{
40+
.height = m_textHeight,
41+
.expand = le::drawable::TextExpand::eBoth,
42+
};
43+
auto const text = std::format("{}", value.count());
44+
m_text.set_string(*m_font, text, params);
45+
46+
// technically this isn't correct y-centering because parts of glyphs can be above/below the baseline,
47+
// and Text::get_size() is insufficient to adjust for that.
48+
// here, since each displayed glyph (0-9) is entirely above the baseline (unlike say 'g'),
49+
// it can be pushed down by half the size and it will "look" consistently y-centered.
50+
// this is what is known as a "hack".
51+
m_text.transform.position.y = -0.5f * m_text.get_size().y;
52+
}
53+
54+
void Countdown::updateSector() {
55+
KLIB_ASSERT(m_timer > 0s);
56+
auto const ratio = m_remain / m_timer;
57+
static constexpr auto degreesBegin_v{90.0f};
58+
auto const degreesEnd = degreesBegin_v + (ratio * 360.0f);
59+
auto const diameter = m_background.get_diameter() + 30.0f;
60+
auto const sectorParams = le::shape::Sector::Params{
61+
.degrees_begin = degreesBegin_v,
62+
.degrees_end = degreesEnd,
63+
};
64+
m_sector.create(diameter, sectorParams);
65+
}
66+
} // namespace chomper::ui

0 commit comments

Comments
 (0)