Skip to content

Commit 3709ad8

Browse files
authored
Add Hud. (#22)
* Add Hud. - Divide viewport into hud and game areas. - Add lavender hex for gun beam in styles. * Update bave ref to stable 0.4.7.
1 parent 3fdd5d0 commit 3709ad8

File tree

15 files changed

+122
-14
lines changed

15 files changed

+122
-14
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 2b1b7ce206a031aa2c2c957f67c8bf92cc031b10 # v0.4.6
14+
GIT_TAG 13ef94fe81e8914335b903c37c58bb2207fd786d # v0.4.7
1515
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ext/bave"
1616
)
1717

assets/styles.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"mocha": "#6f5a48ff",
66
"milk": "#e5cdaeff",
77
"ice": "#0xd6dbe1e1",
8-
"orange": "#f75c03ff"
8+
"orange": "#f75c03ff",
9+
"gun_beam": "#bc96e6ff"
910
},
1011
"buttons": {
1112
"default": {

src/spaced/spaced/game/enemies/creep.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ using bave::Seconds;
55

66
void Creep::tick(Seconds const dt) {
77
shape.transform.position.x -= x_speed * dt.count();
8-
if (shape.transform.position.x < -0.5f * (get_layout().get_world_space().x + shape.get_shape().size.x)) { health = 0.0f; }
8+
if (shape.transform.position.x < -0.5f * (get_layout().get_world_space().x + shape.get_shape().size.x)) { set_destroyed(); }
99
}
1010
} // namespace spaced

src/spaced/spaced/game/enemy.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ using bave::RoundedQuad;
1010
Enemy::Enemy(Services const& services, bave::NotNull<IScorer*> scorer, std::string_view const type)
1111
: m_layout(&services.get<ILayout>()), m_scorer(scorer), m_type(type) {
1212
static constexpr auto init_size_v = glm::vec2{100.0f};
13-
auto const y_bounds = 0.5f * (get_layout().get_world_space().y - 0.5f * init_size_v.y);
14-
setup(init_size_v, random_in_range(-y_bounds, y_bounds));
13+
auto const play_area = m_layout->get_play_area();
14+
auto const y_min = play_area.rb.y + 0.5f * init_size_v.y;
15+
auto const y_max = play_area.lt.y - 0.5f * init_size_v.y;
16+
setup(init_size_v, random_in_range(y_min, y_max));
1517
}
1618

1719
auto Enemy::take_damage(float const damage) -> bool {

src/spaced/spaced/game/enemy.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ class Enemy : public IDamageable, public bave::IDrawable {
1616
[[nodiscard]] auto get_bounds() const -> bave::Rect<> override { return shape.get_bounds(); }
1717
auto take_damage(float damage) -> bool override;
1818

19-
[[nodiscard]] auto is_destroyed() const -> bool { return health.is_dead(); }
19+
[[nodiscard]] auto is_dead() const -> bool { return health.is_dead(); }
20+
[[nodiscard]] auto is_destroyed() const -> bool { return is_dead() || m_destroyed; }
21+
void set_destroyed() { m_destroyed = true; }
2022

2123
virtual void tick(bave::Seconds dt) = 0;
2224
void draw(bave::Shader& shader) const override { shape.draw(shader); }
@@ -40,5 +42,6 @@ class Enemy : public IDamageable, public bave::IDrawable {
4042
bave::NotNull<ILayout const*> m_layout;
4143
bave::NotNull<IScorer*> m_scorer;
4244
std::string_view m_type{};
45+
bool m_destroyed{};
4346
};
4447
} // namespace spaced

src/spaced/spaced/game/enemy_spawner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ EnemySpawner::EnemySpawner(Spawn spawn, ParticleEmitter explode) : m_spawn(std::
1515
void EnemySpawner::tick(Seconds const dt) {
1616
for (auto const& enemy : m_enemies) {
1717
enemy->tick(dt);
18-
if (enemy->is_destroyed()) { explode_at(enemy->get_bounds().centre()); }
18+
if (enemy->is_dead()) { explode_at(enemy->get_bounds().centre()); }
1919
}
2020

2121
for (auto& emitter : m_explodes) { emitter.tick(dt); }

src/spaced/spaced/game/hud.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include <fmt/format.h>
2+
#include <spaced/game/hud.hpp>
3+
#include <spaced/services/styles.hpp>
4+
5+
namespace spaced {
6+
using bave::TextHeight;
7+
8+
Hud::Hud(Services const& services) : ui::View(services), m_styles(&services.get<Styles>()), m_area(m_layout->get_hud_area()) {
9+
create_background();
10+
create_score(services);
11+
12+
block_input_events = false;
13+
}
14+
15+
void Hud::set_score(std::int64_t const score) { m_score->text.set_string(fmt::format("{}", score)); }
16+
17+
void Hud::create_background() {
18+
auto background = std::make_unique<ui::OutlineQuad>();
19+
m_background = background.get();
20+
background->set_outline_width(0.0f);
21+
background->set_size(m_area.size());
22+
background->set_position(m_area.centre());
23+
background->set_tint(m_styles->rgbas["milk"]);
24+
push(std::move(background));
25+
}
26+
27+
void Hud::create_score(Services const& services) {
28+
auto const& rgbas = m_styles->rgbas;
29+
30+
auto text = std::make_unique<ui::Text>(services);
31+
m_score = text.get();
32+
text->text.set_height(TextHeight{60});
33+
text->text.set_string("9999999999");
34+
auto const text_bounds = text->text.get_bounds();
35+
auto const text_bounds_size = text_bounds.size();
36+
text->text.transform.position = m_area.centre();
37+
text->text.transform.position.y -= 0.5f * text_bounds_size.y;
38+
text->text.set_string("0");
39+
text->text.tint = rgbas["grey"];
40+
41+
push(std::move(text));
42+
}
43+
} // namespace spaced

src/spaced/spaced/game/hud.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
#include <spaced/services/styles.hpp>
3+
#include <spaced/ui/outline_quad.hpp>
4+
#include <spaced/ui/text.hpp>
5+
#include <spaced/ui/view.hpp>
6+
7+
namespace spaced {
8+
class Hud : public ui::View {
9+
public:
10+
explicit Hud(Services const& services);
11+
12+
void set_score(std::int64_t score);
13+
14+
private:
15+
void create_background();
16+
void create_score(Services const& services);
17+
18+
bave::NotNull<Styles const*> m_styles;
19+
bave::Rect<> m_area{};
20+
21+
bave::Ptr<ui::OutlineQuad> m_background{};
22+
bave::Ptr<ui::Text> m_score{};
23+
};
24+
} // namespace spaced

src/spaced/spaced/game/player.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,11 @@ void Player::do_inspect() {
9494
}
9595

9696
void Player::setup_ship() {
97-
auto const x = m_services->get<ILayout>().get_player_x();
97+
auto const& layout = m_services->get<ILayout>();
98+
auto const x = layout.get_player_x();
9899
ship.transform.position.x = x;
99100
auto rounded_quad = RoundedQuad{};
100-
rounded_quad.size = glm::vec2{100.0f};
101+
rounded_quad.size = layout.get_player_size();
101102
rounded_quad.corner_radius = 20.0f;
102103
ship.set_shape(rounded_quad);
103104
}

src/spaced/spaced/scenes/game.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ using bave::KeyMods;
1919
using bave::PointerMove;
2020
using bave::PointerTap;
2121
using bave::Ptr;
22+
using bave::Rgba;
2223
using bave::Seconds;
2324
using bave::Shader;
2425
using bave::Texture;
@@ -27,6 +28,11 @@ namespace {
2728
[[nodiscard]] auto make_player_controller(Services const& services) {
2829
auto ret = std::make_unique<PlayerController>(services);
2930
if constexpr (bave::platform_v == bave::Platform::eAndroid) { ret->set_type(PlayerController::Type::eTouch); }
31+
auto const& layout = services.get<ILayout>();
32+
auto const half_size = 0.5f * layout.get_player_size();
33+
auto const play_area = layout.get_play_area();
34+
ret->max_y = play_area.lt.y - half_size.y;
35+
ret->min_y = play_area.rb.y + half_size.y;
3036
return ret;
3137
}
3238

@@ -38,8 +44,10 @@ namespace {
3844
Game::Game(App& app, Services const& services) : Scene(app, services, "Game"), m_player(services, make_player_controller(services)) {
3945
clear_colour = services.get<Styles>().rgbas["mocha"];
4046
auto asset_loader = AssetLoader{make_loader(), &services.get<Resources>()};
41-
auto task = asset_loader.make_load_texture("images/foam_bubble.png");
42-
add_load_tasks({&task, 1});
47+
auto tasks = std::array{
48+
asset_loader.make_load_texture("images/foam_bubble.png"),
49+
};
50+
add_load_tasks(tasks);
4351
}
4452

4553
void Game::on_loaded() {
@@ -59,6 +67,10 @@ void Game::on_loaded() {
5967
emitter.config.lerp.tint = {rgbas["orange"], rgbas["milk"]};
6068
emitter.config.lerp.tint.hi.channels.w = 0x0;
6169
m_enemy_spawner.emplace(spawn, std::move(emitter));
70+
71+
auto hud = std::make_unique<Hud>(get_services());
72+
m_hud = hud.get();
73+
push_view(std::move(hud));
6274
}
6375

6476
void Game::on_focus(bave::FocusChange const& focus_change) { m_player.on_focus(focus_change); }
@@ -97,6 +109,11 @@ void Game::render(Shader& shader) const {
97109
m_player.draw(shader);
98110
}
99111

112+
void Game::add_score(std::int64_t const score) {
113+
m_score += score;
114+
m_hud->set_score(m_score);
115+
}
116+
100117
void Game::inspect(Seconds const dt, Seconds const frame_time) {
101118
if constexpr (bave::imgui_v) {
102119
m_debug.fps.tick(dt);

src/spaced/spaced/scenes/game.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22
#include <spaced/game/enemy_spawner.hpp>
3+
#include <spaced/game/hud.hpp>
34
#include <spaced/game/player.hpp>
45
#include <spaced/game/scorer.hpp>
56
#include <spaced/game/target_provider.hpp>
@@ -24,14 +25,15 @@ class Game : public Scene, public ITargetProvider, public IScorer {
2425
[[nodiscard]] auto get_targets() const -> std::span<bave::NotNull<IDamageable*> const> final { return m_targets; }
2526

2627
[[nodiscard]] auto get_score() const -> std::int64_t final { return m_score; }
27-
void add_score(std::int64_t const score) final { m_score += score; }
28+
void add_score(std::int64_t score) final;
2829

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

3132
Player m_player;
3233
std::int64_t m_score{};
3334
std::optional<EnemySpawner> m_enemy_spawner{};
3435
std::vector<bave::NotNull<IDamageable*>> m_targets{};
36+
bave::Ptr<Hud> m_hud{};
3537

3638
struct {
3739
struct {

src/spaced/spaced/scenes/home.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ using bave::TextHeight;
1414
Home::Home(bave::App& app, Services const& services) : Scene(app, services, "Home") {
1515
auto const& resources = services.get<Resources>();
1616
auto tasks = std::array{
17-
util::create_font_atlas_task(resources.main_font, {TextHeight{100}}),
17+
util::create_font_atlas_task(resources.main_font, {TextHeight{100}, TextHeight{60}}),
1818
};
1919
add_load_tasks(tasks);
2020
}

src/spaced/spaced/services/layout.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ class ILayout : public IService {
88
[[nodiscard]] virtual auto get_main_view() const -> bave::RenderView const& = 0;
99
[[nodiscard]] virtual auto get_framebuffer_size() const -> glm::vec2 = 0;
1010
[[nodiscard]] virtual auto get_world_space() const -> glm::vec2 = 0;
11+
[[nodiscard]] virtual auto get_play_area() const -> bave::Rect<> = 0;
12+
[[nodiscard]] virtual auto get_hud_area() const -> bave::Rect<> = 0;
1113
[[nodiscard]] virtual auto project_to_world(glm::vec2 fb_point) const -> glm::vec2 = 0;
1214
[[nodiscard]] virtual auto unproject(glm::vec2 pointer) const -> glm::vec2 = 0;
1315
[[nodiscard]] virtual auto get_player_x() const -> float = 0;
16+
[[nodiscard]] virtual auto get_player_size() const -> glm::vec2 = 0;
1417

1518
virtual void set_framebuffer_size(glm::vec2 size) = 0;
1619
};

src/spaced/spaced/spaced.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ using bave::MouseScroll;
2020
using bave::NotNull;
2121
using bave::PointerMove;
2222
using bave::PointerTap;
23+
using bave::Rect;
2324
using bave::RenderDevice;
2425
using bave::RenderView;
2526

@@ -48,12 +49,16 @@ struct Layout : ILayout {
4849
NotNull<RenderDevice const*> render_device;
4950
RenderView main_view{};
5051
glm::vec2 framebuffer_size{};
52+
Rect<> play_area{};
53+
Rect<> hud_area{};
5154

5255
explicit Layout(NotNull<RenderDevice const*> render_device) : render_device(render_device) {}
5356

5457
[[nodiscard]] auto get_main_view() const -> RenderView const& final { return main_view; }
5558
[[nodiscard]] auto get_framebuffer_size() const -> glm::vec2 final { return framebuffer_size; }
5659
[[nodiscard]] auto get_world_space() const -> glm::vec2 final { return main_view.viewport; }
60+
[[nodiscard]] auto get_play_area() const -> bave::Rect<> final { return play_area; }
61+
[[nodiscard]] auto get_hud_area() const -> bave::Rect<> final { return hud_area; }
5762

5863
[[nodiscard]] auto project_to_world(glm::vec2 fb_point) const -> glm::vec2 final { return render_device->project_to(get_world_space(), fb_point); }
5964

@@ -63,6 +68,7 @@ struct Layout : ILayout {
6368
}
6469

6570
[[nodiscard]] auto get_player_x() const -> float final { return -700.0f; }
71+
[[nodiscard]] auto get_player_size() const -> glm::vec2 final { return glm::vec2{100.0f}; }
6672

6773
void set_framebuffer_size(glm::vec2 const size) final { framebuffer_size = size; }
6874
};
@@ -136,6 +142,12 @@ void Spaced::set_layout() {
136142
layout->main_view = app.get_render_device().get_default_view();
137143
layout->main_view.viewport = app.get_render_device().get_viewport_scaler().match_height({1920.0f, 1080.0f});
138144
layout->framebuffer_size = app.get_framebuffer_size();
145+
auto const hud_size = glm::vec2{layout->main_view.viewport.x, 100.0f};
146+
auto const hud_origin = glm::vec2{0.0f, 0.5f * (layout->main_view.viewport.y - hud_size.y)};
147+
layout->hud_area = Rect<>::from_size(hud_size, hud_origin);
148+
auto const play_size = glm::vec2{hud_size.x, layout->main_view.viewport.y - hud_size.y};
149+
auto const play_origin = glm::vec2{0.0f, -0.5f * (layout->main_view.viewport.y - play_size.y)};
150+
layout->play_area = Rect<>::from_size(play_size, play_origin);
139151
m_services.bind<ILayout>(std::move(layout));
140152
}
141153

src/spaced/spaced/ui/view.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ void View::tick(Seconds const dt) {
2727
}
2828

2929
void View::render(Shader& shader) const {
30-
if (m_widgets.empty()) { return; }
30+
if (m_elements.empty()) { return; }
3131
shader.set_render_view(m_layout->get_main_view());
3232
for (auto const& element : m_elements) { element->draw(shader); }
3333
}

0 commit comments

Comments
 (0)