aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/system
diff options
context:
space:
mode:
Diffstat (limited to 'src/crepe/system')
-rw-r--r--src/crepe/system/AnimatorSystem.cpp37
-rw-r--r--src/crepe/system/AnimatorSystem.h44
-rw-r--r--src/crepe/system/AudioSystem.cpp2
-rw-r--r--src/crepe/system/AudioSystem.h8
-rw-r--r--src/crepe/system/CMakeLists.txt2
-rw-r--r--src/crepe/system/ParticleSystem.cpp157
-rw-r--r--src/crepe/system/ParticleSystem.h67
-rw-r--r--src/crepe/system/PhysicsSystem.h10
-rw-r--r--src/crepe/system/RenderSystem.cpp36
-rw-r--r--src/crepe/system/RenderSystem.h49
10 files changed, 344 insertions, 68 deletions
diff --git a/src/crepe/system/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp
new file mode 100644
index 0000000..bf45362
--- /dev/null
+++ b/src/crepe/system/AnimatorSystem.cpp
@@ -0,0 +1,37 @@
+
+#include <cstdint>
+#include <functional>
+#include <vector>
+
+#include "api/Animator.h"
+#include "facade/SDLContext.h"
+#include "util/log.h"
+
+#include "AnimatorSystem.h"
+#include "ComponentManager.h"
+
+using namespace crepe;
+
+AnimatorSystem::AnimatorSystem() { dbg_trace(); }
+AnimatorSystem::~AnimatorSystem() { dbg_trace(); }
+
+AnimatorSystem & AnimatorSystem::get_instance() {
+ static AnimatorSystem instance;
+ return instance;
+}
+
+void AnimatorSystem::update() {
+ ComponentManager & mgr = ComponentManager::get_instance();
+
+ std::vector<std::reference_wrapper<Animator>> animations
+ = mgr.get_components_by_type<Animator>();
+
+ uint64_t tick = SDLContext::get_instance().get_ticks();
+ for (Animator & a : animations) {
+ if (a.active) {
+ a.curr_row = (tick / 100) % a.row;
+ a.animator_rect.x = (a.curr_row * a.animator_rect.w) + a.curr_col;
+ a.spritesheet.sprite_rect = a.animator_rect;
+ }
+ }
+}
diff --git a/src/crepe/system/AnimatorSystem.h b/src/crepe/system/AnimatorSystem.h
new file mode 100644
index 0000000..969e9d1
--- /dev/null
+++ b/src/crepe/system/AnimatorSystem.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "System.h"
+
+//TODO:
+// control if flip works with animation system
+
+namespace crepe {
+
+/**
+ * \brief The AnimatorSystem is responsible for managing and updating all Animator components.
+ *
+ * This system is responsible for controlling the behavior of the animations for all entities
+ * that have the Animator component attached. It updates the animations by controlling their
+ * frame changes, looping behavior, and overall animation state.
+ */
+class AnimatorSystem : public System {
+
+public:
+ /**
+ * \brief Retrieves the singleton instance of the AnimatorSystem.
+ *
+ * \return A reference to the single instance of the AnimatorSystem.
+ *
+ * This method ensures that there is only one instance of the AnimatorSystem, following the
+ * singleton design pattern. It can be used to access the system globally.
+ */
+ static AnimatorSystem & get_instance();
+
+ /**
+ * \brief Updates the Animator components.
+ *
+ * This method is called periodically (likely every frame) to update the state of all
+ * Animator components, moving the animations forward and managing their behavior (e.g., looping).
+ */
+ void update() override;
+
+private:
+ // private because singleton
+ AnimatorSystem(); // dbg_trace
+ ~AnimatorSystem(); // dbg_trace
+};
+
+} // namespace crepe
diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp
index 93c0955..9fdd7eb 100644
--- a/src/crepe/system/AudioSystem.cpp
+++ b/src/crepe/system/AudioSystem.cpp
@@ -1,5 +1,3 @@
-#pragma once
-
#include "AudioSystem.h"
#include "ComponentManager.h"
diff --git a/src/crepe/system/AudioSystem.h b/src/crepe/system/AudioSystem.h
index 8fb681f..e037f51 100644
--- a/src/crepe/system/AudioSystem.h
+++ b/src/crepe/system/AudioSystem.h
@@ -8,13 +8,11 @@ namespace crepe {
class AudioSystem : public System {
public:
- AudioSystem(SoundContext & ctx);
-
-public:
- void update();
+ using System::System;
+ void update() override;
private:
- SoundContext & ctx;
+ SoundContext context {};
};
} // namespace crepe
diff --git a/src/crepe/system/CMakeLists.txt b/src/crepe/system/CMakeLists.txt
index ca62add..f507b90 100644
--- a/src/crepe/system/CMakeLists.txt
+++ b/src/crepe/system/CMakeLists.txt
@@ -6,6 +6,7 @@ target_sources(crepe PUBLIC
CollisionSystem.cpp
RenderSystem.cpp
AudioSystem.cpp
+ AnimatorSystem.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -15,4 +16,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
CollisionSystem.h
RenderSystem.h
AudioSystem.h
+ AnimatorSystem.h
)
diff --git a/src/crepe/system/ParticleSystem.cpp b/src/crepe/system/ParticleSystem.cpp
index 397b586..e7a3bec 100644
--- a/src/crepe/system/ParticleSystem.cpp
+++ b/src/crepe/system/ParticleSystem.cpp
@@ -1,62 +1,141 @@
#include <cmath>
+#include <cstdlib>
#include <ctime>
-#include "../ComponentManager.h"
-#include "../api/ParticleEmitter.h"
+#include "api/ParticleEmitter.h"
+#include "api/Transform.h"
+#include "api/Vector2.h"
+#include "ComponentManager.h"
#include "ParticleSystem.h"
using namespace crepe;
-ParticleSystem::ParticleSystem() : elapsed_time(0.0f) {}
-
void ParticleSystem::update() {
+ // Get all emitters
ComponentManager & mgr = ComponentManager::get_instance();
std::vector<std::reference_wrapper<ParticleEmitter>> emitters
= mgr.get_components_by_type<ParticleEmitter>();
- float delta_time = 0.10;
+
for (ParticleEmitter & emitter : emitters) {
- float update_amount = 1 / static_cast<float>(emitter.emission_rate);
- for (float i = 0; i < delta_time; i += update_amount) {
- emit_particle(emitter);
+ // Get transform linked to emitter
+ const Transform & transform
+ = mgr.get_components_by_id<Transform>(emitter.game_object_id)
+ .front()
+ .get();
+
+ // Emit particles based on emission_rate
+ int updates
+ = calculate_update(this->update_count, emitter.data.emission_rate);
+ for (size_t i = 0; i < updates; i++) {
+ emit_particle(emitter, transform);
}
- for (size_t j = 0; j < emitter.particles.size(); j++) {
- if (emitter.particles[j].active) {
- emitter.particles[j].update(delta_time);
+
+ // Update all particles
+ for (Particle & particle : emitter.data.particles) {
+ if (particle.active) {
+ particle.update();
}
}
+
+ // Check if within boundary
+ check_bounds(emitter, transform);
}
+
+ this->update_count = (this->update_count + 1) % this->MAX_UPDATE_COUNT;
}
-void ParticleSystem::emit_particle(ParticleEmitter & emitter) {
- Position initial_position = {emitter.position.x, emitter.position.y};
- float random_angle = 0.0f;
- if (emitter.max_angle < emitter.min_angle) {
- random_angle = ((emitter.min_angle
- + (std::rand()
- % (static_cast<uint32_t>(emitter.max_angle + 360
- - emitter.min_angle + 1))))
- % 360);
- } else {
- random_angle = emitter.min_angle
- + (std::rand()
- % (static_cast<uint32_t>(emitter.max_angle
- - emitter.min_angle + 1)));
- }
- float angle_in_radians = random_angle * (M_PI / 180.0f);
- float random_speed_offset = (static_cast<float>(std::rand()) / RAND_MAX)
- * (2 * emitter.speed_offset)
- - emitter.speed_offset;
- float velocity_x
- = (emitter.speed + random_speed_offset) * std::cos(angle_in_radians);
- float velocity_y
- = (emitter.speed + random_speed_offset) * std::sin(angle_in_radians);
- Position initial_velocity = {velocity_x, velocity_y};
- for (size_t i = 0; i < emitter.particles.size(); i++) {
- if (!emitter.particles[i].active) {
- emitter.particles[i].reset(emitter.end_lifespan, initial_position,
- initial_velocity);
+void ParticleSystem::emit_particle(ParticleEmitter & emitter,
+ const Transform & transform) {
+ constexpr double DEG_TO_RAD = M_PI / 180.0;
+
+ Vector2 initial_position = emitter.data.position + transform.position;
+ double random_angle
+ = generate_random_angle(emitter.data.min_angle, emitter.data.max_angle);
+
+ double random_speed
+ = generate_random_speed(emitter.data.min_speed, emitter.data.max_speed);
+ double angle_radians = random_angle * DEG_TO_RAD;
+
+ Vector2 velocity = {random_speed * std::cos(angle_radians),
+ random_speed * std::sin(angle_radians)};
+
+ for (Particle & particle : emitter.data.particles) {
+ if (!particle.active) {
+ particle.reset(emitter.data.end_lifespan, initial_position,
+ velocity, random_angle);
break;
}
}
}
+
+int ParticleSystem::calculate_update(int count, double emission) const {
+ double integer_part = std::floor(emission);
+ double fractional_part = emission - integer_part;
+
+ if (fractional_part > 0) {
+ int denominator = static_cast<int>(1.0 / fractional_part);
+ return (count % denominator == 0) ? 1 : 0;
+ }
+
+ return static_cast<int>(emission);
+}
+
+void ParticleSystem::check_bounds(ParticleEmitter & emitter,
+ const Transform & transform) {
+ Vector2 offset = emitter.data.boundary.offset + transform.position
+ + emitter.data.position;
+ double half_width = emitter.data.boundary.width / 2.0;
+ double half_height = emitter.data.boundary.height / 2.0;
+
+ const double LEFT = offset.x - half_width;
+ const double RIGHT = offset.x + half_width;
+ const double TOP = offset.y - half_height;
+ const double BOTTOM = offset.y + half_height;
+
+ for (Particle & particle : emitter.data.particles) {
+ const Vector2 & position = particle.position;
+ bool within_bounds = (position.x >= LEFT && position.x <= RIGHT
+ && position.y >= TOP && position.y <= BOTTOM);
+
+ if (!within_bounds) {
+ if (emitter.data.boundary.reset_on_exit) {
+ particle.active = false;
+ } else {
+ particle.velocity = {0, 0};
+ if (position.x < LEFT) particle.position.x = LEFT;
+ else if (position.x > RIGHT) particle.position.x = RIGHT;
+ if (position.y < TOP) particle.position.y = TOP;
+ else if (position.y > BOTTOM) particle.position.y = BOTTOM;
+ }
+ }
+ }
+}
+
+double ParticleSystem::generate_random_angle(double min_angle,
+ double max_angle) const {
+ if (min_angle == max_angle) {
+ return min_angle;
+ } else if (min_angle < max_angle) {
+ return min_angle
+ + static_cast<double>(std::rand()
+ % static_cast<int>(max_angle - min_angle));
+ } else {
+ double angle_offset = (360 - min_angle) + max_angle;
+ double random_angle = min_angle
+ + static_cast<double>(
+ std::rand() % static_cast<int>(angle_offset));
+ return (random_angle >= 360) ? random_angle - 360 : random_angle;
+ }
+}
+
+double ParticleSystem::generate_random_speed(double min_speed,
+ double max_speed) const {
+ if (min_speed == max_speed) {
+ return min_speed;
+ } else {
+ return min_speed
+ + static_cast<double>(std::rand()
+ % static_cast<int>(max_speed - min_speed));
+ }
+}
diff --git a/src/crepe/system/ParticleSystem.h b/src/crepe/system/ParticleSystem.h
index 3ac1d3f..d7ca148 100644
--- a/src/crepe/system/ParticleSystem.h
+++ b/src/crepe/system/ParticleSystem.h
@@ -1,18 +1,71 @@
#pragma once
-#include "../api/ParticleEmitter.h"
+#include <cstdint>
-namespace crepe {
+#include "System.h"
-class ParticleSystem {
+namespace crepe {
+class ParticleEmitter;
+class Transform;
+/**
+ * \brief ParticleSystem class responsible for managing particle emission, updates, and bounds checking.
+ */
+class ParticleSystem : public System {
public:
- ParticleSystem();
- void update();
+ /**
+ * \brief Updates all particle emitters by emitting particles, updating particle states, and checking bounds.
+ */
+ void update() override;
private:
- void emit_particle(ParticleEmitter & emitter); //emits a new particle
+ /**
+ * \brief Emits a particle from the specified emitter based on its emission properties.
+ *
+ * \param emitter Reference to the ParticleEmitter.
+ * \param transform Const reference to the Transform component associated with the emitter.
+ */
+ void emit_particle(ParticleEmitter & emitter, const Transform & transform);
+
+ /**
+ * \brief Calculates the number of times particles should be emitted based on emission rate and update count.
+ *
+ * \param count Current update count.
+ * \param emission Emission rate.
+ * \return The number of particles to emit.
+ */
+ int calculate_update(int count, double emission) const;
+
+ /**
+ * \brief Checks whether particles are within the emitter’s boundary, resets or stops particles if they exit.
+ *
+ * \param emitter Reference to the ParticleEmitter.
+ * \param transform Const reference to the Transform component associated with the emitter.
+ */
+ void check_bounds(ParticleEmitter & emitter, const Transform & transform);
- float elapsed_time; //elapsed time since the last emission
+ /**
+ * \brief Generates a random angle for particle emission within the specified range.
+ *
+ * \param min_angle Minimum emission angle in degrees.
+ * \param max_angle Maximum emission angle in degrees.
+ * \return Random angle in degrees.
+ */
+ double generate_random_angle(double min_angle, double max_angle) const;
+
+ /**
+ * \brief Generates a random speed for particle emission within the specified range.
+ *
+ * \param min_speed Minimum emission speed.
+ * \param max_speed Maximum emission speed.
+ * \return Random speed.
+ */
+ double generate_random_speed(double min_speed, double max_speed) const;
+
+private:
+ //! Counter to count updates to determine how many times emit_particle is called.
+ unsigned int update_count = 0;
+ //! Determines the lowest amount of emission rate (1000 = 0.001 = 1 particle per 1000 updates).
+ static constexpr unsigned int MAX_UPDATE_COUNT = 100;
};
} // namespace crepe
diff --git a/src/crepe/system/PhysicsSystem.h b/src/crepe/system/PhysicsSystem.h
index cc13b70..038c120 100644
--- a/src/crepe/system/PhysicsSystem.h
+++ b/src/crepe/system/PhysicsSystem.h
@@ -1,5 +1,7 @@
#pragma once
+#include "System.h"
+
namespace crepe {
/**
* \brief System that controls all physics
@@ -7,18 +9,14 @@ namespace crepe {
* This class is a physics system that uses a rigidbody and transform
* to add physics to a game object.
*/
-class PhysicsSystem {
+class PhysicsSystem : public System {
public:
/**
- * Constructor is default
- */
- PhysicsSystem() = default;
- /**
* \brief updates the physics system.
*
* It calculates new velocties and changes the postion in the transform.
*/
- void update();
+ void update() override;
};
} // namespace crepe
diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp
index 5a07cc2..10211a3 100644
--- a/src/crepe/system/RenderSystem.cpp
+++ b/src/crepe/system/RenderSystem.cpp
@@ -20,7 +20,25 @@ RenderSystem & RenderSystem::get_instance() {
return instance;
}
-void RenderSystem::update() {
+void RenderSystem::clear_screen() const {
+ SDLContext::get_instance().clear_screen();
+}
+
+void RenderSystem::present_screen() const {
+ SDLContext::get_instance().present_screen();
+}
+void RenderSystem::update_camera() {
+ ComponentManager & mgr = ComponentManager::get_instance();
+
+ std::vector<std::reference_wrapper<Camera>> cameras
+ = mgr.get_components_by_type<Camera>();
+
+ for (Camera & cam : cameras) {
+ SDLContext::get_instance().camera(cam);
+ this->curr_cam = &cam;
+ }
+}
+void RenderSystem::render_sprites() const {
ComponentManager & mgr = ComponentManager::get_instance();
@@ -28,14 +46,16 @@ void RenderSystem::update() {
= mgr.get_components_by_type<Sprite>();
SDLContext & render = SDLContext::get_instance();
- render.clear_screen();
-
for (const Sprite & sprite : sprites) {
- std::vector<std::reference_wrapper<Transform>> transforms
+ auto transforms
= mgr.get_components_by_id<Transform>(sprite.game_object_id);
- for (const Transform & transform : transforms) {
- render.draw(sprite, transform);
- }
+ render.draw(sprite, transforms[0], *curr_cam);
}
- render.present_screen();
+}
+
+void RenderSystem::update() {
+ this->clear_screen();
+ this->update_camera();
+ this->render_sprites();
+ this->present_screen();
}
diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h
index 4b910a4..70db21a 100644
--- a/src/crepe/system/RenderSystem.h
+++ b/src/crepe/system/RenderSystem.h
@@ -1,17 +1,64 @@
#pragma once
+#include "api/Camera.h"
+
#include "System.h"
namespace crepe {
+/**
+ * \class RenderSystem
+ * \brief Manages rendering operations for all game objects.
+ *
+ * RenderSystem is responsible for rendering sprites, clearing and presenting the screen,
+ * and managing the active camera. It functions as a singleton, providing centralized
+ * rendering services for the application.
+ */
class RenderSystem : public System {
public:
+ /**
+ * \brief Gets the singleton instance of RenderSystem.
+ * \return Reference to the RenderSystem instance.
+ */
static RenderSystem & get_instance();
- void update();
+
+ /**
+ * \brief Updates the RenderSystem for the current frame.
+ * This method is called to perform all rendering operations for the current game frame.
+ */
+ void update() override;
private:
+ // Private constructor to enforce singleton pattern.
RenderSystem();
~RenderSystem();
+
+ //! Clears the screen in preparation for rendering.
+ void clear_screen() const;
+
+ //! Presents the rendered frame to the display.
+ void present_screen() const;
+
+ //! Updates the active camera used for rendering.
+ void update_camera();
+
+ //! Renders all active sprites to the screen.
+ void render_sprites() const;
+
+ /**
+ * \todo Include color handling for sprites.
+ * \todo Implement particle emitter rendering with sprites.
+ * \todo Add text rendering using SDL_ttf for text components.
+ * \todo Implement a text component and a button component.
+ * \todo Ensure each sprite is checked for active status before rendering.
+ * \todo Sort all layers by order before rendering.
+ * \todo Consider adding text input functionality.
+ */
+
+private:
+ //! Pointer to the current active camera for rendering
+ Camera * curr_cam = nullptr;
+ // TODO: needs a better solution
};
} // namespace crepe