Skip to content

Commit 1290b70

Browse files
authored
GameScene subclass approach. (#51)
* Replace `IScorer` with `SigPlayerScored`. * Starfield density in prefs. * Add `GameScene` subclass: `EndlessScene`. * Make `Creep` self dependent. Simplify `CreepFactory` in preparation for removal. * Move `Creep` spawning logic into `EndlessScene`. * Remove `EnemyFactory` and dependencies. * Move powerup spawnage to `EndlessScene`. * Refactor powerup hierarchy. * Use braced init for aggregate member. * Cleanup. * Make `SpawnTimer` polymorphic, store vector.
1 parent 82d8f9a commit 1290b70

29 files changed

+262
-257
lines changed
+15-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
1+
#include <bave/services/resources.hpp>
12
#include <spaced/game/enemies/creep.hpp>
23

3-
namespace spaced {
4+
namespace spaced::enemy {
5+
using bave::Resources;
46
using bave::Seconds;
7+
using bave::Texture;
8+
9+
Creep::Creep(bave::Services const& services) : Enemy(services, "Creep") {
10+
m_sprite.set_texture(services.get<Resources>().get<Texture>("images/creep_ship.png"));
11+
m_sprite.set_size(glm::vec2{80.0f});
12+
health = 2.0f;
13+
}
514

615
void Creep::tick(Seconds const dt, bool const in_play) {
7-
Enemy::tick(dt, in_play);
816
if (!in_play) { return; }
917

10-
sprite.transform.position.x -= x_speed * dt.count();
11-
if (sprite.transform.position.x < -0.5f * (get_layout().world_space.x + sprite.get_shape().size.x)) { set_destroyed(); }
18+
m_sprite.transform.position.x -= x_speed * dt.count();
19+
if (m_sprite.transform.position.x < -0.5f * (get_layout().world_space.x + m_sprite.get_shape().size.x)) { set_destroyed(); }
20+
21+
update_health_bar();
1222
}
13-
} // namespace spaced
23+
} // namespace spaced::enemy
+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#pragma once
22
#include <spaced/game/enemy.hpp>
33

4-
namespace spaced {
4+
namespace spaced::enemy {
55
class Creep : public Enemy {
66
public:
7-
explicit Creep(bave::Services const& services) : Enemy(services, "Creep") {}
7+
explicit Creep(bave::Services const& services);
88

99
void tick(bave::Seconds dt, bool in_play) override;
1010

1111
float x_speed{100.0f};
1212
};
13-
} // namespace spaced
13+
} // namespace spaced::enemy

src/spaced/spaced/game/enemies/creep_factory.cpp

-22
This file was deleted.

src/spaced/spaced/game/enemies/creep_factory.hpp

-15
This file was deleted.

src/spaced/spaced/game/enemy.cpp

+12-10
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ Enemy::Enemy(Services const& services, std::string_view const type) : m_layout(&
2222
setup(init_size_v, random_in_range(y_min, y_max));
2323

2424
m_health_bar.set_style(services.get<Styles>().progress_bars["enemy"]);
25+
26+
update_health_bar();
2527
}
2628

2729
auto Enemy::get_bounds() const -> bave::Rect<> {
28-
if (hitbox) { return Rect<>::from_size(*hitbox, sprite.transform.position); }
29-
return sprite.get_bounds();
30+
if (m_hitbox) { return Rect<>::from_size(*m_hitbox, m_sprite.transform.position); }
31+
return m_sprite.get_bounds();
3032
}
3133

3234
auto Enemy::take_damage(float const damage) -> bool {
@@ -40,25 +42,25 @@ void Enemy::force_death() {
4042
m_health_bar.set_progress(0.0f);
4143
}
4244

43-
void Enemy::tick(Seconds const /*dt*/, bool const /*in_play*/) {
44-
m_health_bar.position = sprite.transform.position;
45-
m_health_bar.position.y += 0.5f * sprite.get_shape().size.y + 20.0f;
46-
m_health_bar.size = {sprite.get_shape().size.x, 10.0f};
45+
void Enemy::update_health_bar() {
46+
m_health_bar.position = m_sprite.transform.position;
47+
m_health_bar.position.y += 0.5f * m_sprite.get_shape().size.y + 20.0f;
48+
m_health_bar.size = {m_sprite.get_shape().size.x, 10.0f};
4749
m_health_bar.set_progress(health.get_hit_points() / health.get_total_hit_points());
4850
}
4951

5052
void Enemy::draw(Shader& shader) const {
51-
sprite.draw(shader);
53+
m_sprite.draw(shader);
5254
m_health_bar.draw(shader);
5355
}
5456

5557
void Enemy::setup(glm::vec2 max_size, float y_position) {
5658
auto rounded_quad = RoundedQuad{};
5759
rounded_quad.size = max_size;
5860
rounded_quad.corner_radius = 0.2f * max_size.x;
59-
sprite.set_shape(rounded_quad);
60-
sprite.transform.position.x = 0.5f * (get_layout().world_space.x + rounded_quad.size.x);
61-
sprite.transform.position.y = y_position;
61+
m_sprite.set_shape(rounded_quad);
62+
m_sprite.transform.position.x = 0.5f * (get_layout().world_space.x + rounded_quad.size.x);
63+
m_sprite.transform.position.y = y_position;
6264
}
6365

6466
void Enemy::do_inspect() {

src/spaced/spaced/game/enemy.hpp

+9-4
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,40 @@ class Enemy : public IDamageable, public bave::IDrawable {
1515

1616
[[nodiscard]] auto get_instigator() const -> Instigator final { return Instigator::eEnemy; }
1717
[[nodiscard]] auto get_bounds() const -> bave::Rect<> override;
18+
[[nodiscard]] auto get_position() const -> glm::vec2 { return m_sprite.transform.position; }
19+
1820
auto take_damage(float damage) -> bool override;
1921
void force_death() override;
2022

2123
[[nodiscard]] auto is_dead() const -> bool { return health.is_dead(); }
2224
[[nodiscard]] auto is_destroyed() const -> bool { return is_dead() || m_destroyed; }
2325
void set_destroyed() { m_destroyed = true; }
2426

25-
virtual void tick(bave::Seconds dt, bool in_play);
27+
virtual void tick(bave::Seconds dt, bool in_play) = 0;
2628
void draw(bave::Shader& shader) const override;
2729

2830
void setup(glm::vec2 max_size, float y_position);
31+
void update_health_bar();
2932

3033
[[nodiscard]] auto get_layout() const -> Layout const& { return *m_layout; }
3134

3235
void inspect() {
3336
if constexpr (bave::debug_v) { do_inspect(); }
3437
}
3538

36-
bave::Sprite sprite{};
37-
std::optional<glm::vec2> hitbox{};
3839
Health health{};
3940
std::int64_t points{10};
4041

4142
std::string death_emitter{"particles/explode.json"};
4243
std::vector<std::string> death_sfx{"sfx/swish.wav"};
4344

44-
private:
45+
protected:
46+
bave::Sprite m_sprite{};
47+
std::optional<glm::vec2> m_hitbox{};
48+
4549
virtual void do_inspect();
4650

51+
private:
4752
bave::NotNull<Layout const*> m_layout;
4853

4954
bave::ui::ProgressBar m_health_bar;

src/spaced/spaced/game/enemy_factory.cpp

-22
This file was deleted.

src/spaced/spaced/game/enemy_factory.hpp

-25
This file was deleted.

src/spaced/spaced/game/player.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Player : public bave::IDrawable {
1515
public:
1616
struct State {
1717
std::span<bave::NotNull<IDamageable*> const> targets{};
18-
std::span<bave::NotNull<IPowerup*> const> powerups{};
18+
std::span<bave::NotNull<Powerup*> const> powerups{};
1919
};
2020

2121
explicit Player(bave::Services const& services, std::unique_ptr<IController> controller);

src/spaced/spaced/game/powerups/pu_base.cpp renamed to src/spaced/spaced/game/powerup.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#include <bave/services/resources.hpp>
2-
#include <spaced/game/powerups/pu_base.hpp>
2+
#include <spaced/game/powerup.hpp>
33

44
namespace spaced {
55
using bave::Circle;
@@ -9,7 +9,7 @@ using bave::Seconds;
99
using bave::Services;
1010
using bave::Shader;
1111

12-
PUBase::PUBase(Services const& services, std::string_view const name) : m_services(&services), m_layout(&services.get<Layout>()), m_name(name) {
12+
Powerup::Powerup(Services const& services, std::string_view const name) : m_services(&services), m_layout(&services.get<Layout>()), m_name(name) {
1313
auto circle = Circle{};
1414
circle.diameter = 40.0f;
1515
shape.set_shape(circle);
@@ -20,7 +20,7 @@ PUBase::PUBase(Services const& services, std::string_view const name) : m_servic
2020
emitter.config.respawn = true;
2121
}
2222

23-
void PUBase::tick(Seconds const dt) {
23+
void Powerup::tick(Seconds const dt) {
2424
shape.transform.position.x -= speed * dt.count();
2525
if (shape.transform.position.x < m_layout->play_area.lt.x - 0.5f * shape.get_shape().diameter) { m_destroyed = true; }
2626

@@ -32,12 +32,12 @@ void PUBase::tick(Seconds const dt) {
3232
emitter.tick(dt);
3333
}
3434

35-
void PUBase::draw(Shader& shader) const {
35+
void Powerup::draw(Shader& shader) const {
3636
shape.draw(shader);
3737
emitter.draw(shader);
3838
}
3939

40-
void PUBase::activate(Player& player) {
40+
void Powerup::activate(Player& player) {
4141
do_activate(player);
4242
m_destroyed = true;
4343
}

src/spaced/spaced/game/powerup.hpp

+25-8
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,36 @@
11
#pragma once
2-
#include <bave/core/polymorphic.hpp>
32
#include <bave/core/time.hpp>
4-
#include <bave/graphics/drawable.hpp>
5-
#include <bave/graphics/rect.hpp>
3+
#include <bave/graphics/particle_system.hpp>
4+
#include <bave/graphics/shape.hpp>
5+
#include <bave/services/services.hpp>
6+
#include <spaced/services/layout.hpp>
67

78
namespace spaced {
89
class Player;
910

10-
class IPowerup : public bave::IDrawable {
11+
class Powerup : public bave::IDrawable {
1112
public:
12-
[[nodiscard]] virtual auto get_bounds() const -> bave::Rect<> = 0;
13-
virtual void activate(Player& player) = 0;
13+
explicit Powerup(bave::Services const& services, std::string_view name);
1414

15-
[[nodiscard]] virtual auto is_destroyed() const -> bool = 0;
15+
void tick(bave::Seconds dt);
16+
void draw(bave::Shader& shader) const final;
1617

17-
virtual void tick(bave::Seconds dt) = 0;
18+
[[nodiscard]] auto get_bounds() const -> bave::Rect<> { return shape.get_bounds(); }
19+
void activate(Player& player);
20+
21+
[[nodiscard]] auto is_destroyed() const -> bool { return m_destroyed; }
22+
23+
float speed{300.0f};
24+
bave::CircleShape shape{};
25+
bave::ParticleEmitter emitter{};
26+
27+
protected:
28+
virtual void do_activate(Player& player) = 0;
29+
30+
bave::NotNull<bave::Services const*> m_services;
31+
bave::NotNull<Layout const*> m_layout;
32+
std::string_view m_name{};
33+
bool m_emitter_ticked{};
34+
bool m_destroyed{};
1835
};
1936
} // namespace spaced
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
#include <bave/services/styles.hpp>
22
#include <spaced/game/player.hpp>
3-
#include <spaced/game/powerups/pu_beam.hpp>
3+
#include <spaced/game/powerups/beam.hpp>
44
#include <spaced/game/weapons/gun_beam.hpp>
55

6-
namespace spaced {
6+
namespace spaced::powerup {
77
using bave::Services;
88
using bave::Styles;
99

10-
PUBeam::PUBeam(Services const& services, int rounds) : PUBase(services, "Beam"), m_rounds(rounds) {
10+
Beam::Beam(Services const& services, int rounds) : Powerup(services, "Beam"), m_rounds(rounds) {
1111
emitter.config.lerp.tint.lo = emitter.config.lerp.tint.hi = shape.tint = services.get<Styles>().rgbas["gun_beam"];
1212
emitter.config.lerp.tint.hi.channels.w = 0;
1313
}
1414

15-
void PUBeam::do_activate(Player& player) {
15+
void Beam::do_activate(Player& player) {
1616
auto beam = std::make_unique<GunBeam>(*m_services);
1717
beam->rounds = m_rounds;
1818
player.set_special_weapon(std::move(beam));
1919
}
20-
} // namespace spaced
20+
} // namespace spaced::powerup
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#pragma once
2+
#include <spaced/game/powerup.hpp>
3+
4+
namespace spaced::powerup {
5+
class Beam : public Powerup {
6+
public:
7+
explicit Beam(bave::Services const& services, int rounds = 2);
8+
9+
private:
10+
void do_activate(Player& player) final;
11+
12+
int m_rounds{};
13+
};
14+
} // namespace spaced::powerup

src/spaced/spaced/game/powerups/pu_base.hpp

-35
This file was deleted.

0 commit comments

Comments
 (0)