Skip to content

YAGNI: Simplify asset workflow, remove reflected factories, etc. #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <spaced/game/asset_list.hpp>
#include <spaced/game/asset_loader.hpp>
#include <spaced/assets/asset_list.hpp>
#include <spaced/assets/asset_loader.hpp>
#include <spaced/services/resources.hpp>

namespace spaced {
Expand Down Expand Up @@ -37,31 +37,12 @@ auto AssetList::add_audio_clip(std::string uri) -> AssetList& {
return *this;
}

auto AssetList::read_world_spec(std::string_view const uri) -> WorldSpec {
if (uri.empty()) { return {}; }

auto const json = m_loader.load_json(uri);
if (!json) { return {}; }

auto ret = WorldSpec{};
ret.name = json["name"].as_string();
ret.background_tint = json["background_tint"].as_string();

if (auto const& player = json["player"]) {
ret.player.tint = player["tint"].as_string();
ret.player.exhaust_emitter = player["exhaust_emitter"].as_string();
ret.player.death_emitter = player["death_emitter"].as_string();
add_particle_emitter(ret.player.exhaust_emitter);
add_particle_emitter(ret.player.death_emitter);
}

for (auto const& enemy_factory : json["enemy_factories"].array_view()) {
add_particle_emitter(enemy_factory["death_emitter"].as<std::string>());
for (auto const& death_sfx : enemy_factory["death_sfx"].array_view()) { add_audio_clip(death_sfx.as<std::string>()); }
ret.enemy_factories.push_back(enemy_factory);
}

return ret;
void AssetList::add_manifest(AssetManifest manifest) {
for (auto& uri : manifest.textures) { add_texture(std::move(uri), false); }
for (auto& uri : manifest.mip_mapped_textures) { add_texture(std::move(uri), true); }
for (auto& uri : manifest.fonts) { add_font(std::move(uri)); }
for (auto& uri : manifest.audio_clips) { add_audio_clip(std::move(uri)); }
for (auto& uri : manifest.particle_emitters) { add_particle_emitter(std::move(uri)); }
}

auto AssetList::build_task_stages() const -> std::vector<AsyncExec::Stage> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once
#include <bave/loader.hpp>
#include <spaced/assets/asset_manifest.hpp>
#include <spaced/async_exec.hpp>
#include <spaced/game/world_spec.hpp>
#include <spaced/services/services.hpp>
#include <set>

Expand All @@ -18,7 +18,7 @@ class AssetList {
auto add_particle_emitter(std::string uri) -> AssetList&;
auto add_audio_clip(std::string uri) -> AssetList&;

auto read_world_spec(std::string_view uri) -> WorldSpec;
void add_manifest(AssetManifest manifest);

[[nodiscard]] auto build_task_stages() const -> std::vector<AsyncExec::Stage>;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <bave/graphics/particle_system.hpp>
#include <bave/json_io.hpp>
#include <bave/logger.hpp>
#include <spaced/game/asset_loader.hpp>
#include <spaced/assets/asset_loader.hpp>
#include <mutex>

namespace spaced {
Expand Down
13 changes: 13 additions & 0 deletions src/spaced/spaced/assets/asset_manifest.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include <vector>

namespace spaced {
struct AssetManifest {
std::vector<std::string> textures{};
std::vector<std::string> mip_mapped_textures{};
std::vector<std::string> fonts{};
std::vector<std::string> audio_clips{};
std::vector<std::string> particle_emitters{};
};
} // namespace spaced
4 changes: 2 additions & 2 deletions src/spaced/spaced/async_exec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
namespace spaced {
using namespace std::chrono_literals;

AsyncExec::AsyncExec(std::span<Task const> tasks) {
AsyncExec::AsyncExec(std::vector<Task> tasks) {
if (tasks.empty()) { return; }

m_total = static_cast<int>(tasks.size());
enqueue(tasks);
}

AsyncExec::AsyncExec(std::span<Stage> stages) {
AsyncExec::AsyncExec(std::vector<Stage> stages) {
if (stages.empty()) { return; }
std::move(stages.begin(), stages.end(), std::back_inserter(m_stages));
m_total = std::accumulate(m_stages.begin(), m_stages.end(), 0, [](int count, auto const& tasks) { return static_cast<int>(tasks.size()) + count; });
Expand Down
4 changes: 2 additions & 2 deletions src/spaced/spaced/async_exec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class AsyncExec {

struct Status;

explicit AsyncExec(std::span<Task const> tasks);
explicit AsyncExec(std::span<Stage> stages);
explicit AsyncExec(std::vector<Task> tasks);
explicit AsyncExec(std::vector<Stage> stages);

auto update() -> Status;

Expand Down
54 changes: 0 additions & 54 deletions src/spaced/spaced/game/enemies/basic_creep_factory.cpp

This file was deleted.

29 changes: 0 additions & 29 deletions src/spaced/spaced/game/enemies/basic_creep_factory.hpp

This file was deleted.

2 changes: 1 addition & 1 deletion src/spaced/spaced/game/enemies/creep.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace spaced {
class Creep : public Enemy {
public:
explicit Creep(Services const& services, bave::NotNull<IEnemyDeathListener*> listener) : Enemy(services, listener, "Creep") {}
explicit Creep(Services const& services) : Enemy(services, "Creep") {}

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

Expand Down
21 changes: 21 additions & 0 deletions src/spaced/spaced/game/enemies/creep_factory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <bave/core/random.hpp>
#include <spaced/game/enemies/creep.hpp>
#include <spaced/game/enemies/creep_factory.hpp>
#include <spaced/services/resources.hpp>
#include <spaced/services/styles.hpp>

namespace spaced {
using bave::random_in_range;
using bave::Seconds;

auto CreepFactory::spawn_enemy() -> std::unique_ptr<Enemy> {
auto ret = std::make_unique<Creep>(get_services());
if (!m_tints.empty()) {
auto const& rgbas = get_services().get<Styles>().rgbas;
auto const tint_index = random_in_range(std::size_t{}, m_tints.size() - 1);
ret->shape.tint = rgbas[m_tints.at(tint_index)];
}
ret->health = m_initial_health;
return ret;
}
} // namespace spaced
16 changes: 16 additions & 0 deletions src/spaced/spaced/game/enemies/creep_factory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once
#include <djson/json.hpp>
#include <spaced/game/enemy_factory.hpp>

namespace spaced {
class CreepFactory : public EnemyFactory {
public:
using EnemyFactory::EnemyFactory;

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

private:
std::array<std::string_view, 2> m_tints{"orange", "milk"};
float m_initial_health{2.0f};
};
} // namespace spaced
21 changes: 9 additions & 12 deletions src/spaced/spaced/game/enemy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,38 @@ using bave::RoundedQuad;
using bave::Seconds;
using bave::Shader;

Enemy::Enemy(Services const& services, bave::NotNull<IEnemyDeathListener*> listener, std::string_view const type)
: health_bar(services), m_layout(&services.get<ILayout>()), m_listener(listener), m_type(type) {
Enemy::Enemy(Services const& services, std::string_view const type) : m_layout(&services.get<ILayout>()), m_health_bar(services), m_type(type) {
static constexpr auto init_size_v = glm::vec2{100.0f};
auto const play_area = m_layout->get_play_area();
auto const y_min = play_area.rb.y + 0.5f * init_size_v.y;
auto const y_max = play_area.lt.y - 0.5f * init_size_v.y - 50.0f;
setup(init_size_v, random_in_range(y_min, y_max));

health_bar.set_style(services.get<Styles>().progress_bars["enemy"]);
m_health_bar.set_style(services.get<Styles>().progress_bars["enemy"]);
}

auto Enemy::take_damage(float const damage) -> bool {
if (is_destroyed()) { return false; }
health.inflict_damage(damage);
if (health.is_dead()) { m_listener->on_death(EnemyDeath{.position = shape.transform.position, .points = points}); }
return true;
}

void Enemy::force_death() {
health = 0.0f;
health_bar.set_progress(0.0f);
m_listener->on_death(EnemyDeath{.position = shape.transform.position});
m_health_bar.set_progress(0.0f);
}

void Enemy::tick(Seconds const dt, bool const /*in_play*/) {
health_bar.position = shape.transform.position;
health_bar.position.y += 0.5f * shape.get_shape().size.y + 20.0f;
health_bar.size = {shape.get_shape().size.x, 10.0f};
health_bar.set_progress(health.get_hit_points() / health.get_total_hit_points());
health_bar.tick(dt);
m_health_bar.position = shape.transform.position;
m_health_bar.position.y += 0.5f * shape.get_shape().size.y + 20.0f;
m_health_bar.size = {shape.get_shape().size.x, 10.0f};
m_health_bar.set_progress(health.get_hit_points() / health.get_total_hit_points());
m_health_bar.tick(dt);
}

void Enemy::draw(Shader& shader) const {
shape.draw(shader);
health_bar.draw(shader);
m_health_bar.draw(shader);
}

void Enemy::setup(glm::vec2 max_size, float y_position) {
Expand Down
11 changes: 7 additions & 4 deletions src/spaced/spaced/game/enemy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace spaced {
class Enemy : public IDamageable, public bave::IDrawable {
public:
explicit Enemy(Services const& services, bave::NotNull<IEnemyDeathListener*> listener, std::string_view type);
explicit Enemy(Services const& services, std::string_view type);

[[nodiscard]] auto get_bounds() const -> bave::Rect<> override { return shape.get_bounds(); }
auto take_damage(float damage) -> bool override;
Expand All @@ -28,22 +28,25 @@ class Enemy : public IDamageable, public bave::IDrawable {
void setup(glm::vec2 max_size, float y_position);

[[nodiscard]] auto get_layout() const -> ILayout const& { return *m_layout; }
[[nodiscard]] auto get_death_listener() const -> IEnemyDeathListener& { return *m_listener; }

void inspect() {
if constexpr (bave::debug_v) { do_inspect(); }
}

bave::RoundedQuadShape shape{};
ui::ProgressBar health_bar;
Health health{};
std::int64_t points{10};

std::string death_emitter{"particles/explode.json"};
std::vector<std::string> death_sfx{"sfx/bubble.wav"};

private:
virtual void do_inspect();

bave::NotNull<ILayout const*> m_layout;
bave::NotNull<IEnemyDeathListener*> m_listener;

ui::ProgressBar m_health_bar;

std::string_view m_type{};
bool m_destroyed{};
};
Expand Down
14 changes: 12 additions & 2 deletions src/spaced/spaced/game/enemy_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,18 @@

namespace spaced {
using bave::NotNull;
using bave::Seconds;

IEnemyFactory::IEnemyFactory(NotNull<Services const*> services) : m_services(services), m_audio(&services->get<IAudio>()) {}
EnemyFactory::EnemyFactory(NotNull<Services const*> services) : m_services(services), m_audio(&services->get<IAudio>()) {}

void IEnemyFactory::play_death_sfx() { m_audio->play_any_sfx(m_death_sfx); }
auto EnemyFactory::tick(Seconds const dt) -> std::unique_ptr<Enemy> {
if (spawn_rate <= 0s) { return {}; }

m_elapsed += dt;
if (m_elapsed >= spawn_rate) {
m_elapsed = 0s;
return spawn_enemy();
}
return {};
}
} // namespace spaced
Loading