Skip to content

Commit 037c44e

Browse files
Refactor lighthouse (#4)
* Refactor lighthouse - Create Lighthouse class - Add texture rendering with placeholder texture * Add very basic enemy spawn and render * Add util/random, demo in app (#5) * Refactor Enemy - add targeted movement - change spawn point generation * Add enemy waves * Add simple collision detection and enemy removal * Extract enemy starter movement values to dedicated struct --------- Co-authored-by: Karn Kaul <karnkaul@gmail.com>
1 parent 279c008 commit 037c44e

File tree

11 files changed

+220
-21
lines changed

11 files changed

+220
-21
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ file(GLOB_RECURSE sources LIST_DIRECTORIES false "src/*.[hc]pp")
2323
target_sources(${PROJECT_NAME} PRIVATE
2424
${sources}
2525
)
26+
27+
target_precompile_headers(${PROJECT_NAME} REUSE_FROM le2d)

assets/images/lighthouse.png

41.2 KB
Loading

src/app.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <game.hpp>
55
#include <klib/visitor.hpp>
66
#include <log.hpp>
7+
#include <util/random.hpp>
78

89
namespace miracle {
910
namespace {
@@ -18,6 +19,7 @@ App::App() : m_context(context_ci), m_data_loader(le::FileDataLoader::upfind("as
1819
// test code, remove later.
1920
auto json = dj::Json{};
2021
if (m_services.get<le::IDataLoader>().load_json(json, "test_file.json")) { log.info("loaded JSON: {}", json); }
22+
log.debug("random_range(1, 100): {}", util::random_range(1, 100));
2123
}
2224

2325
void App::run() {

src/enemy.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include <enemy.hpp>
2+
#include <algorithm>
3+
#include "enemy_params.hpp"
4+
#include "glm/geometric.hpp"
5+
#include "glm/vec2.hpp"
6+
#include "kvf/color.hpp"
7+
#include "util/random.hpp"
8+
9+
namespace miracle {
10+
Enemy::Enemy(gsl::not_null<le::ServiceLocator const*> services, EnemyParams const& params)
11+
: m_services(services), m_target_pos(params.target_pos), m_move_speed(params.move_speed), m_diameter(util::random_range(40.0f, 60.0f)) {
12+
m_sprite.create(m_diameter, kvf::red_v);
13+
auto const framebuffer_size = m_services->get<le::Context>().framebuffer_size();
14+
auto const radius = static_cast<float>(std::max(framebuffer_size.x, framebuffer_size.y)) / 2.0f;
15+
16+
m_sprite.transform.position = util::get_random_location_on_radius(radius);
17+
// TODO: add proper textures
18+
}
19+
20+
void Enemy::render(le::Renderer& renderer) const { m_sprite.draw(renderer); }
21+
22+
void Enemy::translate(kvf::Seconds const dt) {
23+
glm::vec2 const direction = glm::normalize(m_target_pos - m_sprite.transform.position);
24+
glm::vec2 const movement = direction * m_move_speed * dt.count();
25+
m_sprite.transform.position += movement;
26+
}
27+
28+
void Enemy::check_collision(glm::vec2 pos, float radius) {
29+
if (glm::distance(pos, m_sprite.transform.position) < radius + m_diameter / 2) { m_health = 0; }
30+
}
31+
32+
} // namespace miracle

src/enemy.hpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
#include <glm/gtx/norm.hpp>
3+
#include <kvf/time.hpp>
4+
#include <le2d/context.hpp>
5+
#include <le2d/drawable/shape.hpp>
6+
#include <le2d/event.hpp>
7+
#include <le2d/renderer.hpp>
8+
#include <le2d/service_locator.hpp>
9+
#include <optional>
10+
#include "enemy_params.hpp"
11+
#include "glm/vec2.hpp"
12+
#include "le2d/texture.hpp"
13+
14+
namespace miracle {
15+
class Enemy {
16+
public:
17+
explicit Enemy(gsl::not_null<le::ServiceLocator const*> services, EnemyParams const& params);
18+
19+
void render(le::Renderer& renderer) const;
20+
void translate(kvf::Seconds dt);
21+
// There are temporary parameters, will take the light beam object once it is created
22+
void check_collision(glm::vec2 pos, float radius);
23+
[[nodiscard]] std::size_t get_health() const { return m_health; }
24+
25+
private:
26+
gsl::not_null<le::ServiceLocator const*> m_services;
27+
std::optional<le::Texture> m_texture;
28+
le::drawable::Circle m_sprite{};
29+
glm::vec2 m_target_pos{};
30+
float m_move_speed{};
31+
float m_diameter{};
32+
std::size_t m_health{100};
33+
};
34+
} // namespace miracle

src/enemy_params.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
#include "glm/vec2.hpp"
3+
4+
struct EnemyParams {
5+
glm::vec2 target_pos{};
6+
float move_speed{};
7+
};

src/game.cpp

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
#include <game.hpp>
22
#include <glm/gtx/norm.hpp>
33
#include <le2d/context.hpp>
4-
#include <cmath>
4+
#include <cstddef>
5+
#include <vector>
6+
#include "enemy.hpp"
7+
#include "enemy_params.hpp"
8+
#include "kvf/time.hpp"
9+
#include "lighhouse.hpp"
10+
#include "util/random.hpp"
511

612
namespace miracle {
7-
Game::Game(gsl::not_null<le::ServiceLocator const*> services) : m_services(services) {
8-
m_triangle.vertices = {
9-
le::Vertex{.position = {-50.0f, -50.0f}},
10-
le::Vertex{.position = {+50.0f, -50.0f}},
11-
le::Vertex{.position = {+0.0f, +75.0f}},
12-
};
13-
m_circle.create(50.0f);
13+
Game::Game(gsl::not_null<le::ServiceLocator const*> services) : m_services(services), m_lighthouse(services) {
14+
m_circle.create(70.0f);
15+
spawn_wave();
1416
}
1517

1618
void Game::on_cursor_pos(le::event::CursorPos const& cursor_pos) {
@@ -19,21 +21,36 @@ void Game::on_cursor_pos(le::event::CursorPos const& cursor_pos) {
1921
}
2022

2123
void Game::tick([[maybe_unused]] kvf::Seconds const dt) {
22-
m_circle.transform.position = m_cursor_pos;
23-
24-
auto const dist_sq = glm::length2(m_cursor_pos);
25-
if (dist_sq > 0.1f) {
26-
auto const dist = std::sqrt(dist_sq);
27-
auto const normalized = m_cursor_pos / dist;
28-
static constexpr auto up_v = glm::vec2{0.0f, 1.0f};
29-
auto const dot = glm::dot(normalized, up_v);
30-
auto const angle = glm::degrees(std::acos(dot));
31-
m_triangle.transform.orientation = m_cursor_pos.x > 0.0f ? -angle : angle;
24+
if (!m_running) { return; }
25+
m_time_since_last_wave_spawn += dt;
26+
if (m_time_since_last_wave_spawn >= m_wave_interval) {
27+
spawn_wave();
28+
m_time_since_last_wave_spawn = kvf::Seconds{};
3229
}
30+
for (auto& enemy : m_enemies) {
31+
enemy.check_collision(m_circle.transform.position, 50.0f);
32+
enemy.translate(dt);
33+
}
34+
std::erase_if(m_enemies, [](Enemy const& enemy) { return !enemy.get_health(); });
35+
m_circle.transform.position = m_cursor_pos;
36+
m_lighthouse.rotate_towards_cursor(m_cursor_pos);
3337
}
3438

3539
void Game::render(le::Renderer& renderer) const {
36-
m_triangle.draw(renderer);
3740
m_circle.draw(renderer);
41+
m_lighthouse.render(renderer);
42+
for (auto const& enemy : m_enemies) { enemy.render(renderer); }
43+
}
44+
45+
void Game::spawn_wave() {
46+
++m_wave_count;
47+
m_wave_interval += kvf::Seconds{5};
48+
std::vector<Enemy> new_wave;
49+
std::size_t const wave_size = m_wave_count * 3;
50+
new_wave.reserve(wave_size);
51+
for (std::size_t i = 0; i < wave_size; ++i) {
52+
new_wave.emplace_back(m_services, EnemyParams{.target_pos = glm::vec2{0.0f, 0.0f}, .move_speed = util::random_range(35.0f, 65.0f)});
53+
}
54+
m_enemies.insert(m_enemies.end(), std::make_move_iterator(new_wave.begin()), std::make_move_iterator(new_wave.end()));
3855
}
3956
} // namespace miracle

src/game.hpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
#include <le2d/event.hpp>
55
#include <le2d/renderer.hpp>
66
#include <le2d/service_locator.hpp>
7+
#include <cstddef>
8+
#include "enemy.hpp"
9+
#include "lighhouse.hpp"
710

811
namespace miracle {
912
class Game {
@@ -14,13 +17,18 @@ class Game {
1417

1518
void tick(kvf::Seconds dt);
1619
void render(le::Renderer& renderer) const;
20+
void spawn_wave();
1721

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

21-
le::drawable::Triangle m_triangle{};
2225
le::drawable::Circle m_circle{};
23-
26+
Lighthouse m_lighthouse;
2427
glm::vec2 m_cursor_pos{};
28+
std::size_t m_wave_count{};
29+
bool m_running{true};
30+
kvf::Seconds m_wave_interval{};
31+
kvf::Seconds m_time_since_last_wave_spawn{};
32+
std::vector<Enemy> m_enemies{};
2533
};
2634
} // namespace miracle

src/lighhouse.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#pragma once
2+
#include <glm/gtx/norm.hpp>
3+
#include <kvf/time.hpp>
4+
#include <le2d/context.hpp>
5+
#include <le2d/drawable/shape.hpp>
6+
#include <le2d/event.hpp>
7+
#include <le2d/renderer.hpp>
8+
#include <le2d/service_locator.hpp>
9+
#include <optional>
10+
#include "le2d/texture.hpp"
11+
12+
namespace miracle {
13+
class Lighthouse {
14+
public:
15+
explicit Lighthouse(gsl::not_null<le::ServiceLocator const*> services);
16+
17+
void rotate_towards_cursor(glm::vec2 cursor_pos);
18+
void render(le::Renderer& renderer) const;
19+
20+
private:
21+
gsl::not_null<le::ServiceLocator const*> m_services;
22+
std::optional<le::Texture> m_texture;
23+
le::drawable::Circle m_sprite{};
24+
};
25+
} // namespace miracle

src/lighthouse.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <lighhouse.hpp>
2+
#include "le2d/asset_loader.hpp"
3+
#include "le2d/data_loader.hpp"
4+
5+
namespace miracle {
6+
Lighthouse::Lighthouse(gsl::not_null<le::ServiceLocator const*> services) : m_services(services) {
7+
m_sprite.create(200.0f);
8+
auto const& data_loader = services->get<le::IDataLoader>();
9+
auto const& context = services->get<le::Context>();
10+
auto const asset_loader = le::AssetLoader{&data_loader, &context};
11+
m_texture = asset_loader.load_texture("images/lighthouse.png");
12+
m_sprite.texture = &m_texture.value();
13+
}
14+
15+
void Lighthouse::rotate_towards_cursor(glm::vec2 cursor_pos) {
16+
auto const dist_sq = glm::length2((cursor_pos));
17+
if (dist_sq > 0.1f) {
18+
auto const dist = std::sqrt(dist_sq);
19+
auto const normalized = cursor_pos / dist;
20+
static constexpr auto up_v = glm::vec2(0.0f, 1.0f);
21+
auto const dot = glm::dot(normalized, up_v);
22+
auto const angle = glm::degrees(std::acos(dot));
23+
m_sprite.transform.orientation = cursor_pos.x > 0.0f ? -angle : angle;
24+
}
25+
}
26+
27+
void Lighthouse::render(le::Renderer& renderer) const { m_sprite.draw(renderer); }
28+
} // namespace miracle

0 commit comments

Comments
 (0)