Skip to content

Commit 40801e4

Browse files
authored
Sprites part2 (#48)
* Add creep ship texture. * Add kinetic projectile texture. * Fixup explode and exhaust particles. * Add kinetic SFX, improve round lifetime. * Add beam fire SFX. * Replace explode SFX.
1 parent 5bdea86 commit 40801e4

28 files changed

+91
-76
lines changed

assets/images/creep_ship.png

7.91 KB
Loading

assets/images/explode.png

6.38 KB
Loading

assets/images/foam_bubble.png

18.5 KB
Loading

assets/images/kinetic_projectile.png

4.56 KB
Loading

assets/particles/exhaust.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
"velocity": {
1919
"linear": {
2020
"angle": {
21-
"lo": 80.000000,
22-
"hi": 100.000000
21+
"lo": 85.000000,
22+
"hi": 95.000000
2323
},
2424
"speed": {
2525
"lo": -360.000000,
@@ -34,7 +34,7 @@
3434
"lerp": {
3535
"tint": {
3636
"lo": "#f48018ff",
37-
"hi": "#ffffff00"
37+
"hi": "#00000000"
3838
},
3939
"scale": {
4040
"lo": [

assets/particles/explode.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"asset_type": "ParticleEmitter",
3-
"texture": "images/foam_bubble.png",
3+
"texture": "images/explode.png",
44
"config": {
55
"initial": {
66
"position": {
@@ -22,8 +22,8 @@
2222
"hi": 180.000000
2323
},
2424
"speed": {
25-
"lo": -360.000000,
26-
"hi": -80.000000
25+
"lo": -200.000000,
26+
"hi": 200.000000
2727
}
2828
},
2929
"angular": {
@@ -33,8 +33,8 @@
3333
},
3434
"lerp": {
3535
"tint": {
36-
"lo": "#f75c03ff",
37-
"hi": "#e5cdaeff"
36+
"lo": "#ffffffff",
37+
"hi": "#00000000"
3838
},
3939
"scale": {
4040
"lo": [
@@ -48,12 +48,12 @@
4848
}
4949
},
5050
"ttl": {
51-
"lo": 0.500000,
52-
"hi": 3.000000
51+
"lo": 0.200000,
52+
"hi": 0.800000
5353
},
5454
"quad_size": [
55-
50.000000,
56-
50.000000
55+
100.000000,
56+
100.000000
5757
],
5858
"count": 40,
5959
"respawn": true

assets/sfx/beam_fire.wav

776 KB
Binary file not shown.

assets/sfx/bubble.wav

-26 KB
Binary file not shown.

assets/sfx/kinetic_fire.wav

103 KB
Binary file not shown.

assets/sfx/swish.wav

73.4 KB
Binary file not shown.

assets/styles.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"progress_bars": {
3333
"default": {
3434
"background": "#9f2b68ff",
35-
"fill": "#ffffffff",
35+
"fill": "milk",
3636
"corner_ratio": 0.5,
3737
"padding": 10
3838
},

attribution.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
SpaceShooterRedux: https://opengameart.org/content/space-shooter-redux, https://www.kenney.nl
2+
sfx/beam_fire.wav: https://opengameart.org/content/laser-rifle
3+
sfx/swish.wav: https://opengameart.org/content/battle-sound-effects

src/spaced/spaced/game/arsenal.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ auto Arsenal::get_weapon() -> Weapon& {
2020
void Arsenal::tick(IWeaponRound::State const& round_state, bool const fire, Seconds const dt) {
2121
tick_weapons(dt);
2222
check_switch_weapon();
23-
if (fire) { fire_weapon(round_state.muzzle_position); }
23+
if (round_state.in_play && fire) { fire_weapon(round_state.muzzle_position); }
2424
tick_rounds(round_state, dt);
2525
}
2626

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ void Creep::tick(Seconds const dt, bool const in_play) {
77
Enemy::tick(dt, in_play);
88
if (!in_play) { return; }
99

10-
shape.transform.position.x -= x_speed * dt.count();
11-
if (shape.transform.position.x < -0.5f * (get_layout().world_space.x + shape.get_shape().size.x)) { set_destroyed(); }
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(); }
1212
}
1313
} // namespace spaced

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
#include <bave/core/random.hpp>
21
#include <bave/services/resources.hpp>
3-
#include <bave/services/styles.hpp>
42
#include <spaced/game/enemies/creep.hpp>
53
#include <spaced/game/enemies/creep_factory.hpp>
64

75
namespace spaced {
8-
using bave::random_in_range;
6+
using bave::NotNull;
7+
using bave::Resources;
98
using bave::Seconds;
10-
using bave::Styles;
9+
using bave::Services;
10+
using bave::Texture;
11+
12+
CreepFactory::CreepFactory(NotNull<Services const*> services)
13+
: EnemyFactory(services), m_ship_texture(services->get<Resources>().get<Texture>("images/creep_ship.png")) {}
1114

1215
auto CreepFactory::spawn_enemy() -> std::unique_ptr<Enemy> {
1316
auto ret = std::make_unique<Creep>(get_services());
14-
if (!m_tints.empty()) {
15-
auto const& rgbas = get_services().get<Styles>().rgbas;
16-
auto const tint_index = random_in_range(std::size_t{}, m_tints.size() - 1);
17-
ret->shape.tint = rgbas[m_tints.at(tint_index)];
18-
}
17+
ret->sprite.set_texture(m_ship_texture);
18+
ret->sprite.set_size(glm::vec2{80.0f});
1919
ret->health = m_initial_health;
2020
return ret;
2121
}
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
#pragma once
2-
#include <djson/json.hpp>
32
#include <spaced/game/enemy_factory.hpp>
43

54
namespace spaced {
65
class CreepFactory : public EnemyFactory {
76
public:
8-
using EnemyFactory::EnemyFactory;
7+
explicit CreepFactory(bave::NotNull<bave::Services const*> services);
98

109
[[nodiscard]] auto spawn_enemy() -> std::unique_ptr<Enemy> final;
1110

1211
private:
13-
std::array<std::string_view, 2> m_tints{"orange", "milk"};
12+
std::shared_ptr<bave::Texture const> m_ship_texture{};
1413
float m_initial_health{2.0f};
1514
};
1615
} // namespace spaced

src/spaced/spaced/game/enemy.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
namespace spaced {
88
using bave::im_text;
99
using bave::random_in_range;
10+
using bave::Rect;
1011
using bave::RoundedQuad;
1112
using bave::Seconds;
1213
using bave::Services;
@@ -23,6 +24,11 @@ Enemy::Enemy(Services const& services, std::string_view const type) : m_layout(&
2324
m_health_bar.set_style(services.get<Styles>().progress_bars["enemy"]);
2425
}
2526

27+
auto Enemy::get_bounds() const -> bave::Rect<> {
28+
if (hitbox) { return Rect<>::from_size(*hitbox, sprite.transform.position); }
29+
return sprite.get_bounds();
30+
}
31+
2632
auto Enemy::take_damage(float const damage) -> bool {
2733
if (is_destroyed()) { return false; }
2834
health.inflict_damage(damage);
@@ -35,24 +41,24 @@ void Enemy::force_death() {
3541
}
3642

3743
void Enemy::tick(Seconds const /*dt*/, bool const /*in_play*/) {
38-
m_health_bar.position = shape.transform.position;
39-
m_health_bar.position.y += 0.5f * shape.get_shape().size.y + 20.0f;
40-
m_health_bar.size = {shape.get_shape().size.x, 10.0f};
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};
4147
m_health_bar.set_progress(health.get_hit_points() / health.get_total_hit_points());
4248
}
4349

4450
void Enemy::draw(Shader& shader) const {
45-
shape.draw(shader);
51+
sprite.draw(shader);
4652
m_health_bar.draw(shader);
4753
}
4854

4955
void Enemy::setup(glm::vec2 max_size, float y_position) {
5056
auto rounded_quad = RoundedQuad{};
5157
rounded_quad.size = max_size;
5258
rounded_quad.corner_radius = 0.2f * max_size.x;
53-
shape.set_shape(rounded_quad);
54-
shape.transform.position.x = 0.5f * (get_layout().world_space.x + rounded_quad.size.x);
55-
shape.transform.position.y = y_position;
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;
5662
}
5763

5864
void Enemy::do_inspect() {

src/spaced/spaced/game/enemy.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#pragma once
22
#include <bave/core/time.hpp>
3-
#include <bave/graphics/shape.hpp>
3+
#include <bave/graphics/sprite.hpp>
44
#include <bave/platform.hpp>
55
#include <bave/services/services.hpp>
66
#include <bave/ui/progress_bar.hpp>
@@ -14,7 +14,7 @@ class Enemy : public IDamageable, public bave::IDrawable {
1414
explicit Enemy(bave::Services const& services, std::string_view type);
1515

1616
[[nodiscard]] auto get_instigator() const -> Instigator final { return Instigator::eEnemy; }
17-
[[nodiscard]] auto get_bounds() const -> bave::Rect<> override { return shape.get_bounds(); }
17+
[[nodiscard]] auto get_bounds() const -> bave::Rect<> override;
1818
auto take_damage(float damage) -> bool override;
1919
void force_death() override;
2020

@@ -33,12 +33,13 @@ class Enemy : public IDamageable, public bave::IDrawable {
3333
if constexpr (bave::debug_v) { do_inspect(); }
3434
}
3535

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

4041
std::string death_emitter{"particles/explode.json"};
41-
std::vector<std::string> death_sfx{"sfx/bubble.wav"};
42+
std::vector<std::string> death_sfx{"sfx/swish.wav"};
4243

4344
private:
4445
virtual void do_inspect();

src/spaced/spaced/game/player.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ void Player::tick(State const& state, Seconds const dt) {
5151
if (m_death->active_particles() == 0) { m_death.reset(); }
5252
}
5353

54+
auto const round_state = IWeaponRound::State{
55+
.targets = state.targets,
56+
.muzzle_position = get_muzzle_position(),
57+
.in_play = !health.is_dead(),
58+
};
59+
m_arsenal.tick(round_state, m_controller->is_firing(), dt);
60+
5461
if (health.is_dead()) { return; }
5562

5663
auto const y_position = m_controller->tick(dt);
@@ -65,9 +72,6 @@ void Player::tick(State const& state, Seconds const dt) {
6572
}
6673
}
6774

68-
auto const round_state = IWeaponRound::State{.targets = state.targets, .muzzle_position = get_muzzle_position()};
69-
m_arsenal.tick(round_state, m_controller->is_firing(), dt);
70-
7175
m_exhaust.set_position(get_exhaust_position());
7276
m_exhaust.tick(dt);
7377

src/spaced/spaced/game/weapon.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include <bave/imgui/im_text.hpp>
2-
#include <bave/services/audio.hpp>
32
#include <spaced/game/weapon.hpp>
43

54
namespace spaced {
@@ -10,11 +9,7 @@ using bave::Services;
109

1110
Weapon::Weapon(Services const& services, std::string name) : m_log{std::move(name)}, m_display(&services.get<IDisplay>()), m_audio(&services.get<IAudio>()) {}
1211

13-
auto Weapon::fire(glm::vec2 const muzzle_position) -> std::unique_ptr<Round> {
14-
auto ret = do_fire(muzzle_position);
15-
if (ret) { m_audio->play_any_sfx(m_fire_sfx); }
16-
return ret;
17-
}
12+
auto Weapon::fire(glm::vec2 const muzzle_position) -> std::unique_ptr<Round> { return do_fire(muzzle_position); }
1813

1914
void Weapon::do_inspect() {
2015
if constexpr (bave::imgui_v) { im_text("rounds remaining: {}", get_rounds_remaining()); }

src/spaced/spaced/game/weapon.hpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
#pragma once
22
#include <bave/logger.hpp>
33
#include <bave/platform.hpp>
4+
#include <bave/services/audio.hpp>
45
#include <bave/services/display.hpp>
56
#include <bave/services/services.hpp>
67
#include <spaced/game/weapon_round.hpp>
78

8-
namespace bave {
9-
class IAudio;
10-
}
11-
129
namespace spaced {
1310
class Weapon : public bave::Polymorphic {
1411
public:
@@ -31,12 +28,12 @@ class Weapon : public bave::Polymorphic {
3128

3229
protected:
3330
[[nodiscard]] auto get_display() const -> bave::IDisplay const& { return *m_display; }
31+
[[nodiscard]] auto get_audio() const -> bave::IAudio& { return *m_audio; }
3432

3533
virtual auto do_fire(glm::vec2 muzzle_position) -> std::unique_ptr<Round> = 0;
3634
virtual void do_inspect();
3735

3836
bave::Logger m_log{};
39-
std::vector<std::string> m_fire_sfx{};
4037

4138
private:
4239
bave::NotNull<bave::IDisplay const*> m_display;

src/spaced/spaced/game/weapon_round.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class IWeaponRound : public bave::IDrawable {
1010
struct State {
1111
std::span<bave::NotNull<IDamageable*> const> targets{};
1212
glm::vec2 muzzle_position{};
13+
bool in_play{true};
1314
};
1415

1516
virtual void tick(State const& state, bave::Seconds dt) = 0;

src/spaced/spaced/game/weapons/gun_beam.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,14 @@ class LaserCharge : public IWeaponRound {
2626
m_ray.transform.position.y = muzzle_position.y;
2727
}
2828

29-
[[nodiscard]] auto is_destroyed() const -> bool final { return m_fire_remain <= 0s; }
29+
[[nodiscard]] auto is_destroyed() const -> bool final { return m_destroyed; }
3030

3131
void tick(State const& state, bave::Seconds dt) final {
32+
if (!state.in_play || m_fire_remain <= 0s) {
33+
m_destroyed = true;
34+
return;
35+
}
36+
3237
if (m_fire_remain > 0s) { m_fire_remain -= dt; }
3338

3439
sort_entries(state.targets, state.muzzle_position);
@@ -97,6 +102,7 @@ class LaserCharge : public IWeaponRound {
97102
Sprite m_ray{};
98103
Seconds m_fire_remain{};
99104
std::vector<Entry> m_entries{};
105+
bool m_destroyed{};
100106
};
101107
} // namespace
102108

@@ -122,6 +128,7 @@ auto GunBeam::do_fire(glm::vec2 const muzzle_position) -> std::unique_ptr<Round>
122128
if (rounds > 0) { --rounds; }
123129
m_fire_remain = config.fire_duration;
124130
m_reload_remain = 0s;
131+
get_audio().play_sfx("sfx/beam_fire.wav");
125132
return std::make_unique<LaserCharge>(&get_display(), config, muzzle_position);
126133
}
127134

src/spaced/spaced/game/weapons/gun_kinetic.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
#include <bave/imgui/im_text.hpp>
2-
#include <bave/services/styles.hpp>
2+
#include <bave/services/resources.hpp>
33
#include <spaced/game/weapons/gun_kinetic.hpp>
44

55
namespace spaced {
66
using bave::IAudio;
77
using bave::im_text;
8+
using bave::Resources;
89
using bave::Rgba;
910
using bave::Seconds;
1011
using bave::Services;
11-
using bave::Styles;
12+
using bave::Texture;
1213

1314
GunKinetic::GunKinetic(Services const& services) : Weapon(services, "GunKinetic"), m_audio(&services.get<IAudio>()) {
14-
projectile_config.tint = services.get<Styles>().rgbas["black"];
15+
projectile_config.texture = services.get<Resources>().get<Texture>("images/kinetic_projectile.png");
16+
if (projectile_config.texture) { projectile_config.size = projectile_config.texture->get_size(); }
1517
}
1618

1719
void GunKinetic::tick(Seconds const dt) {
@@ -23,6 +25,7 @@ auto GunKinetic::do_fire(glm::vec2 const muzzle_position) -> std::unique_ptr<Rou
2325

2426
if (rounds > 0) { --rounds; }
2527
m_reload_remain = reload_delay;
28+
get_audio().play_sfx("sfx/kinetic_fire.wav");
2629
return std::make_unique<Projectile>(&get_display(), projectile_config, muzzle_position);
2730
}
2831

0 commit comments

Comments
 (0)