Skip to content

Add Enemy health bars. #30

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
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
18 changes: 12 additions & 6 deletions assets/styles.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@
},
"progress_bars": {
"default": {
"background": "#ffffffff",
"fill": "#9f2b68ff",
"outline": "#702963ff",
"outline_width": 5
"background": "#9f2b68ff",
"fill": "#ffffffff",
"corner_ratio": 0.5,
"padding": 10
},
"enemy": {
"background": "#f75c03ff",
"fill": "#ffffffff",
"corner_ratio": 0.5,
"padding": 5
}
},
"loading_screen": {
Expand All @@ -50,7 +56,7 @@
"n_width": 0.800000,
"height": 50.000000,
"bottom_offset": 300.000000,
"outline_width": 10
"padding": 20
}
}
}
}
1 change: 1 addition & 0 deletions assets/worlds/playground.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"milk"
],
"spawn_rate": 2,
"initial_health": 2,
"death_emitter": "particles/explode.json"
}
]
Expand Down
2 changes: 2 additions & 0 deletions src/spaced/spaced/game/enemies/basic_creep_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ BasicCreepFactory::BasicCreepFactory(NotNull<Services const*> services, NotNull<
for (auto const& tint : json["tints"].array_view()) { tints.push_back(tint.as<std::string>()); }
if (auto const in_death_emitter = services->get<Resources>().get<ParticleEmitter>(json["death_emitter"].as_string())) { death_emitter = *in_death_emitter; }
spawn_rate = Seconds{json["spawn_rate"].as<float>(spawn_rate.count())};
initial_health = json["initial_health"].as<float>(initial_health);
}

auto BasicCreepFactory::spawn_enemy() -> std::unique_ptr<Enemy> {
Expand All @@ -25,6 +26,7 @@ auto BasicCreepFactory::spawn_enemy() -> std::unique_ptr<Enemy> {
auto const& rgbas = m_services->get<Styles>().rgbas;
auto const tint_index = random_in_range(std::size_t{}, tints.size() - 1);
ret->shape.tint = rgbas[tints.at(tint_index)];
ret->health = initial_health;
}
return ret;
}
Expand Down
1 change: 1 addition & 0 deletions src/spaced/spaced/game/enemies/basic_creep_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class BasicCreepFactory : public IEnemyFactory {
std::vector<std::string> tints{};
bave::ParticleEmitter death_emitter{};
bave::Seconds spawn_rate{2s};
float initial_health{1.0f};

private:
void do_inspect() final;
Expand Down
1 change: 1 addition & 0 deletions src/spaced/spaced/game/enemies/creep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace spaced {
using bave::Seconds;

void Creep::tick(Seconds const dt) {
Enemy::tick(dt);
shape.transform.position.x -= x_speed * dt.count();
if (shape.transform.position.x < -0.5f * (get_layout().get_world_space().x + shape.get_shape().size.x)) { set_destroyed(); }
}
Expand Down
21 changes: 20 additions & 1 deletion src/spaced/spaced/game/enemy.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
#include <bave/core/random.hpp>
#include <bave/imgui/im_text.hpp>
#include <spaced/game/enemy.hpp>
#include <spaced/services/services.hpp>
#include <spaced/services/styles.hpp>

namespace spaced {
using bave::im_text;
using bave::random_in_range;
using bave::RoundedQuad;
using bave::Seconds;
using bave::Shader;

Enemy::Enemy(Services const& services, bave::NotNull<IEnemyDeathListener*> listener, std::string_view const type)
: m_layout(&services.get<ILayout>()), m_listener(listener), m_type(type) {
: health_bar(services), m_layout(&services.get<ILayout>()), m_listener(listener), 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;
setup(init_size_v, random_in_range(y_min, y_max));

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

auto Enemy::take_damage(float const damage) -> bool {
Expand All @@ -23,6 +29,19 @@ auto Enemy::take_damage(float const damage) -> bool {
return true;
}

void Enemy::tick(Seconds const dt) {
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);
}

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

void Enemy::setup(glm::vec2 max_size, float y_position) {
auto rounded_quad = RoundedQuad{};
rounded_quad.size = max_size;
Expand Down
6 changes: 4 additions & 2 deletions src/spaced/spaced/game/enemy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <spaced/game/health.hpp>
#include <spaced/services/layout.hpp>
#include <spaced/services/services.hpp>
#include <spaced/ui/progress_bar.hpp>

namespace spaced {
class Enemy : public IDamageable, public bave::IDrawable {
Expand All @@ -20,8 +21,8 @@ class Enemy : public IDamageable, public bave::IDrawable {
[[nodiscard]] auto is_destroyed() const -> bool { return is_dead() || m_destroyed; }
void set_destroyed() { m_destroyed = true; }

virtual void tick(bave::Seconds dt) = 0;
void draw(bave::Shader& shader) const override { shape.draw(shader); }
virtual void tick(bave::Seconds dt);
void draw(bave::Shader& shader) const override;

void setup(glm::vec2 max_size, float y_position);

Expand All @@ -33,6 +34,7 @@ class Enemy : public IDamageable, public bave::IDrawable {
}

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

Expand Down
12 changes: 6 additions & 6 deletions src/spaced/spaced/game/health.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
#include <algorithm>

namespace spaced {
void Health::inflict_damage(float const amount) { set_hit_points(m_hit_points - amount); }
void Health::inflict_damage(float const amount) { set_hit_points(m_current_hp - amount); }

bool Health::is_dead() const { return m_hit_points <= 0.f; }
bool Health::is_dead() const { return m_current_hp <= 0.f; }

float Health::get_hit_points() const { return m_hit_points; }
float Health::get_hit_points() const { return m_current_hp; }

void Health::set_hit_points(float const hit_points) { m_hit_points = std::max(hit_points, 0.0f); }
void Health::set_hit_points(float const hit_points) { m_current_hp = std::max(hit_points, 0.0f); }

void Health::do_inspect() {
if constexpr (bave::imgui_v) {
if (ImGui::TreeNode("health")) {
bave::im_text("health: {:.2f}", m_hit_points);
bave::im_text("health: {:.2f}", m_current_hp);
bave::im_text("dead: {}", is_dead() ? "yes" : "no");
if (ImGui::Button("inflict 10 damage")) { inflict_damage(10.f); }
ImGui::SliderFloat("health", &m_hit_points, 0.f, 100.f, "%.2f");
ImGui::SliderFloat("health", &m_current_hp, 0.f, 100.f, "%.2f");
ImGui::TreePop();
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/spaced/spaced/game/health.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ class Health {
public:
static constexpr auto hit_points_v{1.0f};

/*implicit*/ Health(float const hit_points = hit_points_v) : m_hit_points(hit_points) {}
/*implicit*/ Health(float const hit_points = hit_points_v) : m_total_hp(hit_points), m_current_hp(hit_points) {}

void inflict_damage(float amount);
[[nodiscard]] bool is_dead() const;
[[nodiscard]] float get_hit_points() const;
[[nodiscard]] float get_total_hit_points() const { return m_total_hp; }
void set_hit_points(float hit_points);

operator float() const { return get_hit_points(); }
Expand All @@ -22,6 +23,7 @@ class Health {
private:
void do_inspect();

float m_hit_points{};
float m_total_hp{};
float m_current_hp{};
};
} // namespace spaced
2 changes: 1 addition & 1 deletion src/spaced/spaced/game/weapons/gun_beam.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class GunBeam final : public Weapon {
bave::Seconds fire_duration{2s};
bave::Seconds reload_delay{1s};
bave::Rgba beam_tint{bave::red_v};
float dps{1.0f};
float dps{10.0f};
};

explicit GunBeam(Services const& services);
Expand Down
2 changes: 1 addition & 1 deletion src/spaced/spaced/game/weapons/gun_kinetic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class GunKinetic final : public Weapon {
void tick(bave::Seconds dt) final;

Projectile::Config projectile_config{};
bave::Seconds reload_delay{0.2s};
bave::Seconds reload_delay{0.25s};

private:
void do_inspect() final;
Expand Down
5 changes: 5 additions & 0 deletions src/spaced/spaced/scenes/home.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <spaced/ui/text.hpp>
#include <spaced/util.hpp>

#include <thread>

namespace spaced {
using bave::Seconds;
using bave::TextHeight;
Expand All @@ -15,6 +17,9 @@ Home::Home(bave::App& app, Services const& services) : Scene(app, services, "Hom
auto const& resources = services.get<Resources>();
auto const tasks = std::array{
util::create_font_atlas_task(resources.main_font, {TextHeight{100}, TextHeight{60}}),
std::function<void()>{[] { std::this_thread::sleep_for(1s); }},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's this doing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops this needs to be reverted, nice catch! It's basically test code to "see" the progress bar update when loading the home scene. Since there's only one task we never get to see it move.

std::function<void()>{[] { std::this_thread::sleep_for(2s); }},
std::function<void()>{[] { std::this_thread::sleep_for(1s); }},
};
add_load_tasks(tasks);
}
Expand Down
2 changes: 1 addition & 1 deletion src/spaced/spaced/ui/loading_screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ LoadingScreen::LoadingScreen(Services const& services)
m_progress_bar.size = {m_style.progress_bar.n_width * world_space.x, m_style.progress_bar.height};
m_progress_bar.position.y = -0.5f * world_space.y + m_style.progress_bar.bottom_offset;
auto style = m_progress_bar.get_style();
style.outline_width = m_style.progress_bar.outline_width;
style.padding = m_style.progress_bar.padding;
m_progress_bar.set_style(style);
}

Expand Down
21 changes: 11 additions & 10 deletions src/spaced/spaced/ui/progress_bar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,27 @@ ProgressBar::ProgressBar(Services const& services) : m_style(services.get<Styles

void ProgressBar::set_progress(float const progress) {
m_progress = progress;
auto const width = progress * size.x;

m_background.set_size(size);
m_background.set_corner_ratio(0.0f);
auto const width = (1.0f - progress) * size.x;

auto bg_size = size;
bg_size.x += m_style.corner_ratio * bg_size.y;
auto quad = bave::RoundedQuad{};
quad.size = size;
quad.size = bg_size;
quad.corner_radius = m_style.corner_ratio * std::min(bg_size.x, bg_size.y);
m_background.set_shape(quad);

quad.size = size - m_style.padding;
quad.corner_radius = 0.0f;
quad.size.x = width;
m_fill.set_shape(quad);

m_background.set_tint(m_style.background);
m_background.set_outline_tint(m_style.outline);
m_background.tint = m_style.background;
m_fill.tint = m_style.fill;

m_fill.tint.channels.w = 0xff;

m_background.set_position(position);
m_fill.transform.position = position;
m_fill.transform.position.x += 0.5f * (-size.x + width);
m_background.transform.position = m_fill.transform.position = position;
m_fill.transform.position.x += 0.5f * (size.x - width);
}

void ProgressBar::set_style(Style style) {
Expand Down
4 changes: 2 additions & 2 deletions src/spaced/spaced/ui/progress_bar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ class ProgressBar : public IWidget {
[[nodiscard]] auto get_style() const -> Style const& { return m_style; }
void set_style(Style style);

[[nodiscard]] auto get_size() const -> glm::vec2 final { return m_background.get_size(); }
[[nodiscard]] auto get_size() const -> glm::vec2 final { return size; }
[[nodiscard]] auto get_position() const -> glm::vec2 final { return position; }
void set_position(glm::vec2 position) final { this->position = position; }

private:
Style m_style{};

OutlineQuad m_background{};
bave::RoundedQuadShape m_background{};
bave::QuadShape m_fill{};

float m_progress{};
Expand Down
6 changes: 3 additions & 3 deletions src/spaced/spaced/ui/style.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct LoadingScreenStyle {
float n_width{0.9f};
float height{50.0f};
float bottom_offset{200.0f};
float outline_width{10.0f};
float padding{30.0f};
} progress_bar{};
};

Expand All @@ -35,7 +35,7 @@ struct ButtonStyle {
struct ProgressBarStyle {
bave::Rgba background{bave::white_v};
bave::Rgba fill{bave::yellow_v};
bave::Rgba outline{bave::red_v};
float outline_width{5.0f};
float corner_ratio{0.5f};
float padding{10.0f};
};
} // namespace spaced::ui
20 changes: 10 additions & 10 deletions src/spaced/spaced/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ void util::to_json(dj::Json& out, ui::LoadingScreenStyle const& loading_screen_s
progress_bar["n_width"] = loading_screen_style.progress_bar.n_width;
progress_bar["height"] = loading_screen_style.progress_bar.height;
progress_bar["bottom_offset"] = loading_screen_style.progress_bar.bottom_offset;
progress_bar["outline_width"] = loading_screen_style.progress_bar.outline_width;
progress_bar["padding"] = loading_screen_style.progress_bar.padding;
}

void util::from_json(dj::Json const& json, ui::LoadingScreenStyle& out) {
using bave::from_json;
from_json(json["background_tint"], out.background_tint);
auto const& spinner = json["spinner"];
from_json(spinner["size"], out.spinner.size);
out.spinner.spin_rate.value = spinner["spin_rate"].as<float>();
out.spinner.spin_rate.value = spinner["spin_rate"].as<float>(out.spinner.spin_rate.value);
auto const& progress_bar = json["progress_bar"];
out.progress_bar.n_width = progress_bar["n_width"].as<float>();
out.progress_bar.height = progress_bar["height"].as<float>();
out.progress_bar.bottom_offset = progress_bar["bottom_offset"].as<float>();
out.progress_bar.outline_width = progress_bar["outline_width"].as<float>();
out.progress_bar.n_width = progress_bar["n_width"].as<float>(out.progress_bar.n_width);
out.progress_bar.height = progress_bar["height"].as<float>(out.progress_bar.height);
out.progress_bar.bottom_offset = progress_bar["bottom_offset"].as<float>(out.progress_bar.bottom_offset);
out.progress_bar.padding = progress_bar["padding"].as<float>(out.progress_bar.padding);
}

void util::to_json(dj::Json& out, ui::ButtonStyle::Tint const& button_tint) {
Expand Down Expand Up @@ -60,15 +60,15 @@ void util::from_json(dj::Json const& json, ui::ButtonStyle& out) {
void util::to_json(dj::Json& out, ui::ProgressBarStyle const& progress_bar_style) {
to_json(out["background"], progress_bar_style.background);
to_json(out["fill"], progress_bar_style.fill);
to_json(out["outline"], progress_bar_style.outline);
out["outline_width"] = progress_bar_style.outline_width;
out["corner_ratio"] = progress_bar_style.corner_ratio;
out["padding"] = progress_bar_style.padding;
}

void util::from_json(dj::Json const& json, ui::ProgressBarStyle& out) {
from_json(json["background"], out.background);
from_json(json["fill"], out.fill);
from_json(json["outline"], out.outline);
out.outline_width = json["outline_width"].as<float>();
out.corner_ratio = json["corner_ratio"].as<float>(out.corner_ratio);
out.padding = json["padding"].as<float>(out.padding);
}

auto util::create_font_atlas_task(std::shared_ptr<bave::Font> font, std::vector<bave::TextHeight> heights) -> std::function<void()> {
Expand Down