Skip to content

Nikola/light #6

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 7 commits into from
Jun 27, 2025
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
Binary file added assets/fonts/specialElite.ttf
Binary file not shown.
9 changes: 9 additions & 0 deletions src/EnemyColliderInfo.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once
#include <glm/vec2.hpp>

namespace miracle {
struct CollisionParams {
glm::vec2 pos;
float diameter;
};
} // namespace miracle
10 changes: 7 additions & 3 deletions src/enemy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,20 @@ Enemy::Enemy(gsl::not_null<le::ServiceLocator const*> services, EnemyParams cons
// TODO: add proper textures
}

void Enemy::render(le::Renderer& renderer) const { m_sprite.draw(renderer); }
void Enemy::render(le::Renderer& renderer) const {
if (m_can_render) { m_sprite.draw(renderer); }
}

void Enemy::translate(kvf::Seconds const dt) {
glm::vec2 const direction = glm::normalize(m_target_pos - m_sprite.transform.position);
glm::vec2 const movement = direction * m_move_speed * dt.count();
m_sprite.transform.position += movement;
}

void Enemy::check_collision(glm::vec2 pos, float radius) {
if (glm::distance(pos, m_sprite.transform.position) < radius + m_diameter / 2) { m_health = 0; }
CollisionParams Enemy::get_collision_params() const { return {.pos = m_sprite.transform.position, .diameter = m_diameter}; }
void Enemy::take_damage(std::size_t dmg) {
m_can_render = true;
m_health = (dmg >= m_health) ? 0 : (m_health - dmg);
}

} // namespace miracle
7 changes: 5 additions & 2 deletions src/enemy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
#include <le2d/event.hpp>
#include <le2d/renderer.hpp>
#include <le2d/service_locator.hpp>
#include <cstddef>
#include <optional>
#include "EnemyColliderInfo.hpp"
#include "enemy_params.hpp"
#include "glm/vec2.hpp"
#include "le2d/texture.hpp"
Expand All @@ -18,9 +20,10 @@ class Enemy {

void render(le::Renderer& renderer) const;
void translate(kvf::Seconds dt);
// There are temporary parameters, will take the light beam object once it is created
void check_collision(glm::vec2 pos, float radius);
void take_damage(std::size_t dmg);
[[nodiscard]] std::size_t get_health() const { return m_health; }
[[nodiscard]] CollisionParams get_collision_params() const;
bool m_can_render{false};

private:
gsl::not_null<le::ServiceLocator const*> m_services;
Expand Down
33 changes: 27 additions & 6 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,26 @@
#include <glm/gtx/norm.hpp>
#include <le2d/context.hpp>
#include <cstddef>
#include <format>
#include <iterator>
#include <string>
#include <vector>
#include "enemy.hpp"
#include "enemy_params.hpp"
#include "kvf/time.hpp"
#include "le2d/asset_loader.hpp"
#include "le2d/data_loader.hpp"
#include "le2d/drawable/text.hpp"
#include "lighhouse.hpp"
#include "util/random.hpp"

namespace miracle {
Game::Game(gsl::not_null<le::ServiceLocator const*> services) : m_services(services), m_lighthouse(services) {
m_circle.create(70.0f);
Game::Game(gsl::not_null<le::ServiceLocator const*> services) : m_services(services), m_lighthouse(services), m_light(services) {
spawn_wave();
auto const& data_loader = services->get<le::IDataLoader>();
auto const& context = services->get<le::Context>();
auto const asset_loader = le::AssetLoader{&data_loader, &context};
m_font = asset_loader.load_font("fonts/specialElite.ttf");
}

void Game::on_cursor_pos(le::event::CursorPos const& cursor_pos) {
Expand All @@ -28,18 +37,21 @@ void Game::tick([[maybe_unused]] kvf::Seconds const dt) {
m_time_since_last_wave_spawn = kvf::Seconds{};
}
for (auto& enemy : m_enemies) {
enemy.check_collision(m_circle.transform.position, 50.0f);
m_light.check_enemy_collision(enemy);
enemy.translate(dt);
}
std::erase_if(m_enemies, [](Enemy const& enemy) { return !enemy.get_health(); });
m_circle.transform.position = m_cursor_pos;
// Keep track of how many enemies were defeated and calculate score
auto res = std::erase_if(m_enemies, [](Enemy const& enemy) { return !enemy.get_health(); });
update_score(static_cast<int>(res * 10));
m_light.set_position(m_cursor_pos);
m_lighthouse.rotate_towards_cursor(m_cursor_pos);
}

void Game::render(le::Renderer& renderer) const {
m_circle.draw(renderer);
m_light.render(renderer);
m_lighthouse.render(renderer);
for (auto const& enemy : m_enemies) { enemy.render(renderer); }
m_score_text.draw(renderer);
}

void Game::spawn_wave() {
Expand All @@ -53,4 +65,13 @@ void Game::spawn_wave() {
}
m_enemies.insert(m_enemies.end(), std::make_move_iterator(new_wave.begin()), std::make_move_iterator(new_wave.end()));
}

void Game::update_score(int points) {
auto const framebuffer_size = m_services->get<le::Context>().framebuffer_size();
m_score_text.transform.position.y = static_cast<float>(framebuffer_size.y) / 2.0f - 50.0f;
m_score += points;
m_score_str.clear();
std::format_to(std::back_inserter(m_score_str), "Score: {}", m_score);
m_score_text.set_string(m_font, m_score_str);
}
} // namespace miracle
13 changes: 11 additions & 2 deletions src/game.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
#include <le2d/service_locator.hpp>
#include <cstddef>
#include "enemy.hpp"
#include "le2d/drawable/text.hpp"
#include "le2d/font.hpp"
#include "lighhouse.hpp"
#include "light.hpp"

namespace miracle {
class Game {
Expand All @@ -17,13 +20,19 @@ class Game {

void tick(kvf::Seconds dt);
void render(le::Renderer& renderer) const;
void update_score(int points);
void spawn_wave();

private:
gsl::not_null<le::ServiceLocator const*> m_services;

le::drawable::Circle m_circle{};
Lighthouse m_lighthouse;
Light m_light;

le::Font m_font{};
le::drawable::Text m_score_text{};
int m_score{};
std::string m_score_str;

glm::vec2 m_cursor_pos{};
std::size_t m_wave_count{};
bool m_running{true};
Expand Down
17 changes: 17 additions & 0 deletions src/light.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <light.hpp>
#include "kvf/color.hpp"

namespace miracle {
Light::Light(gsl::not_null<le::ServiceLocator const*> services) : m_services(services), m_diameter(100) { m_sprite.create(150.0f, kvf::white_v); }

void Light::check_enemy_collision(Enemy& enemy) {
auto const [pos, diameter] = enemy.get_collision_params();
if (glm::distance(pos, m_sprite.transform.position) < (diameter + m_diameter) / 2) {
Copy link
Member

Choose a reason for hiding this comment

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

You can avoid square rooting here by comparing square magnitude instead of magnitude.

enemy.take_damage(1);
} else {
enemy.m_can_render = false;
}
}
void Light::render(le::Renderer& renderer) const { m_sprite.draw(renderer); }
void Light::set_position(glm::vec2 cursor_pos) { m_sprite.transform.position = cursor_pos; }
} // namespace miracle
26 changes: 26 additions & 0 deletions src/light.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include "enemy.hpp"
#include "glm/vec2.hpp"
#include "gsl/pointers"
#include "le2d/drawable/shape.hpp"
#include "le2d/renderer.hpp"
#include "le2d/service_locator.hpp"
#include "le2d/texture.hpp"

namespace miracle {
class Light {
public:
explicit Light(gsl::not_null<le::ServiceLocator const*> services);

void render(le::Renderer& renderer) const;
void set_position(glm::vec2 cursor_pos);
void check_enemy_collision(Enemy& enemy);

private:
gsl::not_null<le::ServiceLocator const*> m_services;
std::optional<le::Texture> m_texture;
le::drawable::Circle m_sprite{};
float m_diameter{};
};
} // namespace miracle
Loading