aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/system
diff options
context:
space:
mode:
Diffstat (limited to 'src/crepe/system')
-rw-r--r--src/crepe/system/AISystem.cpp23
-rw-r--r--src/crepe/system/AISystem.h2
-rw-r--r--src/crepe/system/AnimatorSystem.cpp32
-rw-r--r--src/crepe/system/AnimatorSystem.h2
-rw-r--r--src/crepe/system/AudioSystem.cpp4
-rw-r--r--src/crepe/system/AudioSystem.h2
-rw-r--r--src/crepe/system/CMakeLists.txt4
-rw-r--r--src/crepe/system/CollisionSystem.cpp83
-rw-r--r--src/crepe/system/CollisionSystem.h42
-rw-r--r--src/crepe/system/EventSystem.cpp9
-rw-r--r--src/crepe/system/EventSystem.h21
-rw-r--r--src/crepe/system/InputSystem.cpp96
-rw-r--r--src/crepe/system/InputSystem.h35
-rw-r--r--src/crepe/system/ParticleSystem.cpp19
-rw-r--r--src/crepe/system/ParticleSystem.h2
-rw-r--r--src/crepe/system/PhysicsSystem.cpp3
-rw-r--r--src/crepe/system/PhysicsSystem.h2
-rw-r--r--src/crepe/system/RenderSystem.cpp8
-rw-r--r--src/crepe/system/RenderSystem.h2
-rw-r--r--src/crepe/system/ReplaySystem.cpp54
-rw-r--r--src/crepe/system/ReplaySystem.h44
-rw-r--r--src/crepe/system/ScriptSystem.cpp20
-rw-r--r--src/crepe/system/ScriptSystem.h23
-rw-r--r--src/crepe/system/System.h10
24 files changed, 372 insertions, 170 deletions
diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp
index 680dbb8..94445c7 100644
--- a/src/crepe/system/AISystem.cpp
+++ b/src/crepe/system/AISystem.cpp
@@ -10,7 +10,7 @@
using namespace crepe;
using namespace std::chrono;
-void AISystem::update() {
+void AISystem::fixed_update() {
const Mediator & mediator = this->mediator;
ComponentManager & mgr = mediator.component_manager;
LoopTimerManager & loop_timer = mediator.loop_timer;
@@ -28,7 +28,8 @@ void AISystem::update() {
= mgr.get_components_by_id<Rigidbody>(ai.game_object_id);
if (rigidbodies.empty()) {
throw std::runtime_error(
- "AI component must be attached to a GameObject with a Rigidbody component");
+ "AI component must be attached to a GameObject with a Rigidbody component"
+ );
}
Rigidbody & rigidbody = rigidbodies.front().get();
if (!rigidbody.active) {
@@ -110,8 +111,8 @@ bool AISystem::accumulate_force(const AI & ai, vec2 & running_total, vec2 & forc
return true;
}
-vec2 AISystem::seek(const AI & ai, const Rigidbody & rigidbody,
- const Transform & transform) const {
+vec2 AISystem::seek(const AI & ai, const Rigidbody & rigidbody, const Transform & transform)
+ const {
// Calculate the desired velocity
vec2 desired_velocity = ai.seek_target - transform.position;
desired_velocity.normalize();
@@ -120,12 +121,12 @@ vec2 AISystem::seek(const AI & ai, const Rigidbody & rigidbody,
return desired_velocity - rigidbody.data.linear_velocity;
}
-vec2 AISystem::flee(const AI & ai, const Rigidbody & rigidbody,
- const Transform & transform) const {
+vec2 AISystem::flee(const AI & ai, const Rigidbody & rigidbody, const Transform & transform)
+ const {
// Calculate the desired velocity if the entity is within the panic distance
vec2 desired_velocity = transform.position - ai.flee_target;
if (desired_velocity.length_squared() > ai.square_flee_panic_distance) {
- return vec2{0, 0};
+ return vec2 {0, 0};
}
desired_velocity.normalize();
desired_velocity *= rigidbody.data.max_linear_velocity;
@@ -133,8 +134,8 @@ vec2 AISystem::flee(const AI & ai, const Rigidbody & rigidbody,
return desired_velocity - rigidbody.data.linear_velocity;
}
-vec2 AISystem::arrive(const AI & ai, const Rigidbody & rigidbody,
- const Transform & transform) const {
+vec2 AISystem::arrive(const AI & ai, const Rigidbody & rigidbody, const Transform & transform)
+ const {
// Calculate the desired velocity (taking into account the deceleration rate)
vec2 to_target = ai.arrive_target - transform.position;
float distance = to_target.length();
@@ -150,12 +151,12 @@ vec2 AISystem::arrive(const AI & ai, const Rigidbody & rigidbody,
return desired_velocity - rigidbody.data.linear_velocity;
}
- return vec2{0, 0};
+ return vec2 {0, 0};
}
vec2 AISystem::path_follow(AI & ai, const Rigidbody & rigidbody, const Transform & transform) {
if (ai.path.empty()) {
- return vec2{0, 0};
+ return vec2 {0, 0};
}
// Get the target node
diff --git a/src/crepe/system/AISystem.h b/src/crepe/system/AISystem.h
index d5f8a8e..04807cf 100644
--- a/src/crepe/system/AISystem.h
+++ b/src/crepe/system/AISystem.h
@@ -20,7 +20,7 @@ public:
using System::System;
//! Update the AI system
- void update() override;
+ void fixed_update() override;
private:
/**
diff --git a/src/crepe/system/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp
index 107b25d..143d5d6 100644
--- a/src/crepe/system/AnimatorSystem.cpp
+++ b/src/crepe/system/AnimatorSystem.cpp
@@ -1,42 +1,44 @@
-
+#include <chrono>
#include "../api/Animator.h"
#include "../manager/ComponentManager.h"
#include "../manager/LoopTimerManager.h"
-#include <chrono>
#include "AnimatorSystem.h"
using namespace crepe;
using namespace std::chrono;
-void AnimatorSystem::update() {
+void AnimatorSystem::frame_update() {
ComponentManager & mgr = this->mediator.component_manager;
LoopTimerManager & timer = this->mediator.loop_timer;
RefVector<Animator> animations = mgr.get_components_by_type<Animator>();
- float elapsed_time = duration_cast<duration<float>>(timer.get_elapsed_time()).count();
+ duration_t elapsed_time = timer.get_delta_time();
for (Animator & a : animations) {
if (!a.active) continue;
if (a.data.fps == 0) continue;
Animator::Data & ctx = a.data;
- float frame_duration = 1.0f / ctx.fps;
- int last_frame = ctx.row;
+ a.elapsed_time += elapsed_time;
+ duration_t frame_duration = 1000ms / ctx.fps;
int cycle_end = (ctx.cycle_end == -1) ? a.grid_size.x : ctx.cycle_end;
- int total_frames = cycle_end - ctx.cycle_start;
-
- int curr_frame = static_cast<int>(elapsed_time / frame_duration) % total_frames;
+ if (a.elapsed_time >= frame_duration) {
+ a.elapsed_time = 0ms;
+ a.frame++;
+ if (a.frame == cycle_end) {
+ a.frame = ctx.cycle_start;
+ if (!ctx.looping) {
+ a.active = false;
+ continue;
+ }
+ }
+ }
- ctx.row = ctx.cycle_start + curr_frame;
+ ctx.row = ctx.cycle_start + a.frame;
a.spritesheet.mask.x = ctx.row * a.spritesheet.mask.w;
- a.spritesheet.mask.y = (ctx.col * a.spritesheet.mask.h);
-
- if (!ctx.looping && curr_frame == ctx.cycle_start && last_frame == total_frames - 1) {
- a.active = false;
- }
}
}
diff --git a/src/crepe/system/AnimatorSystem.h b/src/crepe/system/AnimatorSystem.h
index 7d3f565..092e131 100644
--- a/src/crepe/system/AnimatorSystem.h
+++ b/src/crepe/system/AnimatorSystem.h
@@ -22,7 +22,7 @@ public:
* Animator components, moving the animations forward and managing their behavior (e.g.,
* looping).
*/
- void update() override;
+ void frame_update() override;
};
} // namespace crepe
diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp
index b1aa0f8..3c2232f 100644
--- a/src/crepe/system/AudioSystem.cpp
+++ b/src/crepe/system/AudioSystem.cpp
@@ -7,7 +7,7 @@
using namespace crepe;
using namespace std;
-void AudioSystem::update() {
+void AudioSystem::fixed_update() {
ComponentManager & component_manager = this->mediator.component_manager;
ResourceManager & resource_manager = this->mediator.resource_manager;
RefVector<AudioSource> components
@@ -36,6 +36,8 @@ void AudioSystem::diff_update(AudioSource & component, Sound & resource) {
if (component.oneshot_play) {
component.voice = context.play(resource);
+ context.set_loop(component.voice, component.loop);
+ context.set_volume(component.voice, component.volume);
component.oneshot_play = false;
}
if (component.oneshot_stop) {
diff --git a/src/crepe/system/AudioSystem.h b/src/crepe/system/AudioSystem.h
index 2ddc443..56fc98c 100644
--- a/src/crepe/system/AudioSystem.h
+++ b/src/crepe/system/AudioSystem.h
@@ -11,7 +11,7 @@ namespace crepe {
class AudioSystem : public System {
public:
using System::System;
- void update() override;
+ void fixed_update() override;
private:
/**
diff --git a/src/crepe/system/CMakeLists.txt b/src/crepe/system/CMakeLists.txt
index 0e2db76..52369d0 100644
--- a/src/crepe/system/CMakeLists.txt
+++ b/src/crepe/system/CMakeLists.txt
@@ -8,6 +8,8 @@ target_sources(crepe PUBLIC
AudioSystem.cpp
AnimatorSystem.cpp
InputSystem.cpp
+ EventSystem.cpp
+ ReplaySystem.cpp
AISystem.cpp
)
@@ -20,5 +22,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
AudioSystem.h
AnimatorSystem.h
InputSystem.h
+ EventSystem.h
+ ReplaySystem.h
AISystem.h
)
diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp
index 3653d10..571ac70 100644
--- a/src/crepe/system/CollisionSystem.cpp
+++ b/src/crepe/system/CollisionSystem.cpp
@@ -34,7 +34,7 @@ CollisionSystem::CollisionInfo CollisionSystem::CollisionInfo::operator-() const
};
}
-void CollisionSystem::update() {
+void CollisionSystem::fixed_update() {
std::vector<CollisionInternal> all_colliders;
game_object_id_t id = 0;
ComponentManager & mgr = this->mediator.component_manager;
@@ -50,9 +50,11 @@ void CollisionSystem::update() {
for (BoxCollider & boxcollider : boxcolliders) {
if (boxcollider.game_object_id != id) continue;
if (!boxcollider.active) continue;
- all_colliders.push_back({.id = id,
- .collider = collider_variant{boxcollider},
- .info = {transform, rigidbody, metadata}});
+ all_colliders.push_back(
+ {.id = id,
+ .collider = collider_variant {boxcollider},
+ .info = {transform, rigidbody, metadata}}
+ );
}
// Check if the circlecollider is active and has the same id as the rigidbody.
RefVector<CircleCollider> circlecolliders
@@ -60,9 +62,11 @@ void CollisionSystem::update() {
for (CircleCollider & circlecollider : circlecolliders) {
if (circlecollider.game_object_id != id) continue;
if (!circlecollider.active) continue;
- all_colliders.push_back({.id = id,
- .collider = collider_variant{circlecollider},
- .info = {transform, rigidbody, metadata}});
+ all_colliders.push_back(
+ {.id = id,
+ .collider = collider_variant {circlecollider},
+ .info = {transform, rigidbody, metadata}}
+ );
}
}
@@ -110,8 +114,9 @@ CollisionSystem::gather_collisions(std::vector<CollisionInternal> & colliders) {
return collisions_ret;
}
-bool CollisionSystem::should_collide(const CollisionInternal & self,
- const CollisionInternal & other) const {
+bool CollisionSystem::should_collide(
+ const CollisionInternal & self, const CollisionInternal & other
+) const {
const Rigidbody::Data & self_rigidbody = self.info.rigidbody.data;
const Rigidbody::Data & other_rigidbody = other.info.rigidbody.data;
@@ -133,9 +138,9 @@ bool CollisionSystem::should_collide(const CollisionInternal & self,
return false;
}
-CollisionSystem::CollisionInternalType
-CollisionSystem::get_collider_type(const collider_variant & collider1,
- const collider_variant & collider2) const {
+CollisionSystem::CollisionInternalType CollisionSystem::get_collider_type(
+ const collider_variant & collider1, const collider_variant & collider2
+) const {
if (std::holds_alternative<std::reference_wrapper<CircleCollider>>(collider1)) {
if (std::holds_alternative<std::reference_wrapper<CircleCollider>>(collider2)) {
return CollisionInternalType::CIRCLE_CIRCLE;
@@ -151,8 +156,9 @@ CollisionSystem::get_collider_type(const collider_variant & collider1,
}
}
-bool CollisionSystem::detect_collision(CollisionInternal & self, CollisionInternal & other,
- const CollisionInternalType & type) {
+bool CollisionSystem::detect_collision(
+ CollisionInternal & self, CollisionInternal & other, const CollisionInternalType & type
+) {
vec2 resolution;
switch (type) {
case CollisionInternalType::BOX_BOX: {
@@ -177,10 +183,11 @@ bool CollisionSystem::detect_collision(CollisionInternal & self, CollisionIntern
= {.collider = std::get<std::reference_wrapper<BoxCollider>>(self.collider),
.transform = self.info.transform,
.rigidbody = self.info.rigidbody};
- const CircleColliderInternal CIRCLE2 = {
- .collider = std::get<std::reference_wrapper<CircleCollider>>(other.collider),
- .transform = other.info.transform,
- .rigidbody = other.info.rigidbody};
+ const CircleColliderInternal CIRCLE2
+ = {.collider
+ = std::get<std::reference_wrapper<CircleCollider>>(other.collider),
+ .transform = other.info.transform,
+ .rigidbody = other.info.rigidbody};
// Get resolution vector from box-circle collision detection
resolution = this->get_box_circle_detection(BOX1, CIRCLE2);
// If no collision (NaN values), return false
@@ -195,10 +202,11 @@ bool CollisionSystem::detect_collision(CollisionInternal & self, CollisionIntern
= {.collider = std::get<std::reference_wrapper<CircleCollider>>(self.collider),
.transform = self.info.transform,
.rigidbody = self.info.rigidbody};
- const CircleColliderInternal CIRCLE2 = {
- .collider = std::get<std::reference_wrapper<CircleCollider>>(other.collider),
- .transform = other.info.transform,
- .rigidbody = other.info.rigidbody};
+ const CircleColliderInternal CIRCLE2
+ = {.collider
+ = std::get<std::reference_wrapper<CircleCollider>>(other.collider),
+ .transform = other.info.transform,
+ .rigidbody = other.info.rigidbody};
// Get resolution vector from circle-circle collision detection
resolution = this->get_circle_circle_detection(CIRCLE1, CIRCLE2);
// If no collision (NaN values), return false
@@ -239,9 +247,10 @@ bool CollisionSystem::detect_collision(CollisionInternal & self, CollisionIntern
return true;
}
-vec2 CollisionSystem::get_box_box_detection(const BoxColliderInternal & box1,
- const BoxColliderInternal & box2) const {
- vec2 resolution{NAN, NAN};
+vec2 CollisionSystem::get_box_box_detection(
+ const BoxColliderInternal & box1, const BoxColliderInternal & box2
+) const {
+ vec2 resolution {NAN, NAN};
// Get current positions of colliders
vec2 pos1 = AbsolutePosition::get_position(box1.transform, box1.collider.offset);
vec2 pos2 = AbsolutePosition::get_position(box2.transform, box2.collider.offset);
@@ -282,8 +291,9 @@ vec2 CollisionSystem::get_box_box_detection(const BoxColliderInternal & box1,
return resolution;
}
-vec2 CollisionSystem::get_box_circle_detection(const BoxColliderInternal & box,
- const CircleColliderInternal & circle) const {
+vec2 CollisionSystem::get_box_circle_detection(
+ const BoxColliderInternal & box, const CircleColliderInternal & circle
+) const {
/// Get current positions of colliders
vec2 box_pos = AbsolutePosition::get_position(box.transform, box.collider.offset);
vec2 circle_pos = AbsolutePosition::get_position(circle.transform, circle.collider.offset);
@@ -324,14 +334,15 @@ vec2 CollisionSystem::get_box_circle_detection(const BoxColliderInternal & box,
float penetration_depth = scaled_circle_radius - distance;
// Compute the resolution vector
- return vec2{collision_normal * penetration_depth};
+ return vec2 {collision_normal * penetration_depth};
}
// No collision
- return vec2{NAN, NAN};
+ return vec2 {NAN, NAN};
}
vec2 CollisionSystem::get_circle_circle_detection(
- const CircleColliderInternal & circle1, const CircleColliderInternal & circle2) const {
+ const CircleColliderInternal & circle1, const CircleColliderInternal & circle2
+) const {
// Get current positions of colliders
vec2 final_position1
= AbsolutePosition::get_position(circle1.transform, circle1.collider.offset);
@@ -371,7 +382,7 @@ vec2 CollisionSystem::get_circle_circle_detection(
return resolution;
}
// No collision
- return vec2{NAN, NAN};
+ return vec2 {NAN, NAN};
;
}
@@ -402,17 +413,17 @@ CollisionSystem::resolution_correction(vec2 & resolution, const Rigidbody::Data
return resolution_direction;
}
-CollisionSystem::CollisionInfo
-CollisionSystem::get_collision_info(const CollisionInternal & in_self,
- const CollisionInternal & in_other) const {
+CollisionSystem::CollisionInfo CollisionSystem::get_collision_info(
+ const CollisionInternal & in_self, const CollisionInternal & in_other
+) const {
- crepe::CollisionSystem::ColliderInfo self{
+ crepe::CollisionSystem::ColliderInfo self {
.transform = in_self.info.transform,
.rigidbody = in_self.info.rigidbody,
.metadata = in_self.info.metadata,
};
- crepe::CollisionSystem::ColliderInfo other{
+ crepe::CollisionSystem::ColliderInfo other {
.transform = in_other.info.transform,
.rigidbody = in_other.info.rigidbody,
.metadata = in_other.info.metadata,
diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h
index 7be280a..ff2d35f 100644
--- a/src/crepe/system/CollisionSystem.h
+++ b/src/crepe/system/CollisionSystem.h
@@ -60,8 +60,8 @@ public:
private:
//! A variant type that can hold either a BoxCollider or a CircleCollider.
- using collider_variant = std::variant<std::reference_wrapper<BoxCollider>,
- std::reference_wrapper<CircleCollider>>;
+ using collider_variant = std::variant<
+ std::reference_wrapper<BoxCollider>, std::reference_wrapper<CircleCollider>>;
//! Enum representing the types of collider pairs for collision detection.
enum class CollisionInternalType {
@@ -102,7 +102,7 @@ private:
public:
//! Updates the collision system by checking for collisions between colliders and handling them.
- void update() override;
+ void fixed_update() override;
private:
/**
@@ -114,8 +114,9 @@ private:
* \param collider2 Second collider variant (BoxCollider or CircleCollider).
* \return The combined type of the two colliders.
*/
- CollisionInternalType get_collider_type(const collider_variant & collider1,
- const collider_variant & collider2) const;
+ CollisionInternalType get_collider_type(
+ const collider_variant & collider1, const collider_variant & collider2
+ ) const;
private:
/**
@@ -128,8 +129,8 @@ private:
* \param data1 Collision data for the first collider.
* \param data2 Collision data for the second collider.
*/
- CollisionInfo get_collision_info(const CollisionInternal & data1,
- const CollisionInternal & data2) const;
+ CollisionInfo
+ get_collision_info(const CollisionInternal & data1, const CollisionInternal & data2) const;
/**
* \brief Corrects the collision resolution vector and determines its direction.
@@ -221,8 +222,10 @@ private:
* \param other_metadata Rigidbody of second object
* \return Returns true if there is at least one comparison found.
*/
- bool should_collide(const CollisionInternal & self,
- const CollisionInternal & other) const; //done
+ bool should_collide(
+ const CollisionInternal & self,
+ const CollisionInternal & other
+ ) const; //done
/**
* \brief Checks for collision between two colliders.
@@ -236,8 +239,10 @@ private:
* \param type The type of collider pair.
* \return True if a collision is detected, otherwise false.
*/
- bool detect_collision(CollisionInternal & first_info, CollisionInternal & second_info,
- const CollisionInternalType & type);
+ bool detect_collision(
+ CollisionInternal & first_info, CollisionInternal & second_info,
+ const CollisionInternalType & type
+ );
/**
* \brief Detects collisions between two BoxColliders.
@@ -250,8 +255,9 @@ private:
* \param box2 Information about the second BoxCollider.
* \return If colliding, returns the resolution vector; otherwise, returns {NaN, NaN}.
*/
- vec2 get_box_box_detection(const BoxColliderInternal & box1,
- const BoxColliderInternal & box2) const;
+ vec2 get_box_box_detection(
+ const BoxColliderInternal & box1, const BoxColliderInternal & box2
+ ) const;
/**
* \brief Check collision for box on circle collider
@@ -264,8 +270,9 @@ private:
* \param circle2 Information about the circleCollider.
* \return If colliding, returns the resolution vector; otherwise, returns {NaN, NaN}.
*/
- vec2 get_box_circle_detection(const BoxColliderInternal & box1,
- const CircleColliderInternal & circle2) const;
+ vec2 get_box_circle_detection(
+ const BoxColliderInternal & box1, const CircleColliderInternal & circle2
+ ) const;
/**
* \brief Check collision for circle on circle collider
@@ -278,8 +285,9 @@ private:
* \param circle2 Information about the second circleCollider.
* \return If colliding, returns the resolution vector; otherwise, returns {NaN, NaN}.
*/
- vec2 get_circle_circle_detection(const CircleColliderInternal & circle1,
- const CircleColliderInternal & circle2) const;
+ vec2 get_circle_circle_detection(
+ const CircleColliderInternal & circle1, const CircleColliderInternal & circle2
+ ) const;
};
/**
diff --git a/src/crepe/system/EventSystem.cpp b/src/crepe/system/EventSystem.cpp
new file mode 100644
index 0000000..7e168ab
--- /dev/null
+++ b/src/crepe/system/EventSystem.cpp
@@ -0,0 +1,9 @@
+#include "EventSystem.h"
+#include "../manager/EventManager.h"
+
+using namespace crepe;
+
+void EventSystem::fixed_update() {
+ EventManager & ev = this->mediator.event_manager;
+ ev.dispatch_events();
+}
diff --git a/src/crepe/system/EventSystem.h b/src/crepe/system/EventSystem.h
new file mode 100644
index 0000000..0ae48d2
--- /dev/null
+++ b/src/crepe/system/EventSystem.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "System.h"
+
+namespace crepe {
+
+/**
+ * \brief EventManager dispatch helper system
+ */
+class EventSystem : public System {
+public:
+ using System::System;
+
+ /**
+ * \brief Dispatch queued events
+ * \see EventManager::dispatch_events
+ */
+ void fixed_update() override;
+};
+
+} // namespace crepe
diff --git a/src/crepe/system/InputSystem.cpp b/src/crepe/system/InputSystem.cpp
index 60daa55..be7eda6 100644
--- a/src/crepe/system/InputSystem.cpp
+++ b/src/crepe/system/InputSystem.cpp
@@ -1,18 +1,18 @@
#include "../api/Button.h"
+#include "../api/Config.h"
#include "../facade/SDLContext.h"
#include "../manager/ComponentManager.h"
#include "../manager/EventManager.h"
-#include "util/Log.h"
#include "InputSystem.h"
using namespace crepe;
-void InputSystem::update() {
+void InputSystem::fixed_update() {
ComponentManager & mgr = this->mediator.component_manager;
SDLContext & context = this->mediator.sdl_context;
std::vector<EventData> event_list = context.get_events();
- RefVector<Camera> cameras = mgr.get_components_by_type<Camera>();
+ const RefVector<Camera> cameras = mgr.get_components_by_type<Camera>();
OptionalRef<Camera> curr_cam_ref;
// Find the active camera
@@ -24,9 +24,8 @@ void InputSystem::update() {
if (!curr_cam_ref) return;
Camera & current_cam = curr_cam_ref;
- RefVector<Transform> transform_vec
- = mgr.get_components_by_id<Transform>(current_cam.game_object_id);
- Transform & cam_transform = transform_vec.front().get();
+ const Transform & cam_transform
+ = mgr.get_components_by_id<Transform>(current_cam.game_object_id).front();
vec2 camera_origin = cam_transform.position + current_cam.data.postion_offset
- (current_cam.viewport_size / 2);
@@ -45,12 +44,13 @@ void InputSystem::update() {
}
}
-void InputSystem::handle_mouse_event(const EventData & event, const vec2 & camera_origin,
- const Camera & current_cam) {
+void InputSystem::handle_mouse_event(
+ const EventData & event, const vec2 & camera_origin, const Camera & current_cam
+) {
EventManager & event_mgr = this->mediator.event_manager;
vec2 adjusted_mouse;
adjusted_mouse.x = event.data.mouse_data.mouse_position.x + camera_origin.x;
- adjusted_mouse.x = event.data.mouse_data.mouse_position.y + camera_origin.y;
+ adjusted_mouse.y = event.data.mouse_data.mouse_position.y + camera_origin.y;
// Check if the mouse is within the viewport
if ((adjusted_mouse.x < camera_origin.x
|| adjusted_mouse.x > camera_origin.x + current_cam.viewport_size.x
@@ -83,7 +83,9 @@ void InputSystem::handle_mouse_event(const EventData & event, const vec2 & camer
.mouse_pos = adjusted_mouse,
.button = event.data.mouse_data.mouse_button,
});
- this->handle_click(event.data.mouse_data.mouse_button, adjusted_mouse);
+ this->handle_click(
+ event.data.mouse_data.mouse_button, adjusted_mouse, current_cam
+ );
}
break;
}
@@ -93,7 +95,7 @@ void InputSystem::handle_mouse_event(const EventData & event, const vec2 & camer
.mouse_pos = adjusted_mouse,
.mouse_delta = event.data.mouse_data.rel_mouse_move,
});
- this->handle_move(event, adjusted_mouse);
+ this->handle_move(event, adjusted_mouse, current_cam);
break;
case EventType::MOUSE_WHEEL:
@@ -115,7 +117,8 @@ void InputSystem::handle_non_mouse_event(const EventData & event) {
case EventType::KEY_DOWN:
event_mgr.queue_event<KeyPressEvent>(
- {.repeat = event.data.key_data.key_repeat, .key = event.data.key_data.key});
+ {.repeat = event.data.key_data.key_repeat, .key = event.data.key_data.key}
+ );
break;
case EventType::KEY_UP:
event_mgr.queue_event<KeyReleaseEvent>({.key = event.data.key_data.key});
@@ -128,11 +131,13 @@ void InputSystem::handle_non_mouse_event(const EventData & event) {
break;
case EventType::WINDOW_RESIZE:
event_mgr.queue_event<WindowResizeEvent>(
- WindowResizeEvent{.dimensions = event.data.window_data.resize_dimension});
+ WindowResizeEvent {.dimensions = event.data.window_data.resize_dimension}
+ );
break;
case EventType::WINDOW_MOVE:
event_mgr.queue_event<WindowMoveEvent>(
- {.delta_move = event.data.window_data.move_delta});
+ {.delta_move = event.data.window_data.move_delta}
+ );
break;
case EventType::WINDOW_MINIMIZE:
event_mgr.queue_event<WindowMinimizeEvent>({});
@@ -151,59 +156,70 @@ void InputSystem::handle_non_mouse_event(const EventData & event) {
}
}
-void InputSystem::handle_move(const EventData & event_data, const vec2 & mouse_pos) {
+void InputSystem::handle_move(
+ const EventData & event_data, const vec2 & mouse_pos, const Camera & current_cam
+) {
ComponentManager & mgr = this->mediator.component_manager;
EventManager & event_mgr = this->mediator.event_manager;
- RefVector<Button> buttons = mgr.get_components_by_type<Button>();
+ const RefVector<Button> buttons = mgr.get_components_by_type<Button>();
for (Button & button : buttons) {
if (!button.active) continue;
- Metadata & metadata
- = mgr.get_components_by_id<Metadata>(button.game_object_id).front();
- Transform & transform
+
+ const Transform & transform
= mgr.get_components_by_id<Transform>(button.game_object_id).front();
+ const Transform & cam_transform
+ = mgr.get_components_by_id<Transform>(current_cam.game_object_id).front();
+ const Metadata & metadata
+ = mgr.get_components_by_id<Metadata>(button.game_object_id).front();
bool was_hovering = button.hover;
- if (this->is_mouse_inside_button(mouse_pos, button, transform)) {
+
+ if (this->is_mouse_inside_button(mouse_pos, button, transform, cam_transform)) {
button.hover = true;
if (!was_hovering) {
- event_mgr.trigger_event<ButtonEnterEvent>(metadata);
+ event_mgr.trigger_event<ButtonEnterEvent>(metadata, metadata.game_object_id);
}
} else {
button.hover = false;
if (was_hovering) {
- event_mgr.trigger_event<ButtonExitEvent>(metadata);
+ event_mgr.trigger_event<ButtonExitEvent>(metadata, metadata.game_object_id);
}
}
}
}
-void InputSystem::handle_click(const MouseButton & mouse_button, const vec2 & mouse_pos) {
+void InputSystem::handle_click(
+ const MouseButton & mouse_button, const vec2 & mouse_pos, const Camera & current_cam
+) {
ComponentManager & mgr = this->mediator.component_manager;
EventManager & event_mgr = this->mediator.event_manager;
- RefVector<Button> buttons = mgr.get_components_by_type<Button>();
-
+ const RefVector<Button> buttons = mgr.get_components_by_type<Button>();
+ const Transform & cam_transform
+ = mgr.get_components_by_id<Transform>(current_cam.game_object_id).front();
for (Button & button : buttons) {
if (!button.active) continue;
- Metadata & metadata
+ const Metadata & metadata
= mgr.get_components_by_id<Metadata>(button.game_object_id).front();
- Transform & transform
+ const Transform & transform
= mgr.get_components_by_id<Transform>(button.game_object_id).front();
-
- if (this->is_mouse_inside_button(mouse_pos, button, transform)) {
- event_mgr.trigger_event<ButtonPressEvent>(metadata);
+ if (this->is_mouse_inside_button(mouse_pos, button, transform, cam_transform)) {
+ event_mgr.trigger_event<ButtonPressEvent>(metadata, metadata.game_object_id);
}
}
}
-bool InputSystem::is_mouse_inside_button(const vec2 & mouse_pos, const Button & button,
- const Transform & transform) {
- int actual_x = transform.position.x + button.offset.x;
- int actual_y = transform.position.y + button.offset.y;
-
- int half_width = button.dimensions.x / 2;
- int half_height = button.dimensions.y / 2;
+bool InputSystem::is_mouse_inside_button(
+ const vec2 & mouse_pos, const Button & button, const Transform & transform,
+ const Transform & cam_transform
+) {
+ vec2 actual_pos = transform.position + button.offset;
+ if (!button.data.world_space) {
+ actual_pos += cam_transform.position;
+ }
+ vec2 half_dimensions = button.dimensions * transform.scale / 2;
- // Check if the mouse is within the button's boundaries
- return mouse_pos.x >= actual_x - half_width && mouse_pos.x <= actual_x + half_width
- && mouse_pos.y >= actual_y - half_height && mouse_pos.y <= actual_y + half_height;
+ return mouse_pos.x >= actual_pos.x - half_dimensions.x
+ && mouse_pos.x <= actual_pos.x + half_dimensions.x
+ && mouse_pos.y >= actual_pos.y - half_dimensions.y
+ && mouse_pos.y <= actual_pos.y + half_dimensions.y;
}
diff --git a/src/crepe/system/InputSystem.h b/src/crepe/system/InputSystem.h
index e580d8e..be62367 100644
--- a/src/crepe/system/InputSystem.h
+++ b/src/crepe/system/InputSystem.h
@@ -1,12 +1,9 @@
#pragma once
-#include "../api/Config.h"
-#include "../facade/EventData.h"
-
#include "../api/Event.h"
#include "../api/Metadata.h"
+#include "../facade/EventData.h"
#include "../types.h"
-#include "../util/OptionalRef.h"
#include "System.h"
@@ -23,7 +20,7 @@ public:
/**
* \param metadata Metadata of the button pressed
*/
- ButtonPressEvent(const Metadata & metadata) : metadata(metadata){};
+ ButtonPressEvent(const Metadata & metadata) : metadata(metadata) {};
};
//! Event triggered when the mouse enters a button
class ButtonEnterEvent : public Event {
@@ -33,7 +30,7 @@ public:
/**
* \param metadata Metadata of the button pressed
*/
- ButtonEnterEvent(const Metadata & metadata) : metadata(metadata){};
+ ButtonEnterEvent(const Metadata & metadata) : metadata(metadata) {};
};
//! Event triggered when the mouse leaves a button
class ButtonExitEvent : public Event {
@@ -43,7 +40,7 @@ public:
/**
* \param metadata Metadata of the button pressed
*/
- ButtonExitEvent(const Metadata & metadata) : metadata(metadata){};
+ ButtonExitEvent(const Metadata & metadata) : metadata(metadata) {};
};
/**
@@ -61,7 +58,7 @@ public:
* \brief Updates the system, processing all input events.
* This method processes all events and triggers corresponding actions.
*/
- void update() override;
+ void fixed_update() override;
private:
//! Stores the last position of the mouse when the button was pressed.
@@ -79,8 +76,9 @@ private:
* This method processes mouse events, adjusts the mouse position to world coordinates,
* and triggers the appropriate mouse-specific event handling logic.
*/
- void handle_mouse_event(const EventData & event, const vec2 & camera_origin,
- const Camera & current_cam);
+ void handle_mouse_event(
+ const EventData & event, const vec2 & camera_origin, const Camera & current_cam
+ );
/**
* \brief Handles non-mouse-related events.
* \param event The event data for the non-mouse event.
@@ -94,20 +92,26 @@ private:
* \param mouse_button The mouse button involved in the click.
* \param world_mouse_x The X coordinate of the mouse in world space.
* \param world_mouse_y The Y coordinate of the mouse in world space.
+ * \param current_cam The current active camera.
*
* This method processes the mouse click event and triggers the corresponding button action.
*/
- void handle_click(const MouseButton & mouse_button, const vec2 & mouse_pos);
+ void handle_click(
+ const MouseButton & mouse_button, const vec2 & mouse_pos, const Camera & current_cam
+ );
/**
* \brief Handles the mouse movement event.
* \param event_data The event data containing information about the mouse movement.
* \param world_mouse_x The X coordinate of the mouse in world space.
* \param world_mouse_y The Y coordinate of the mouse in world space.
+ * \param current_cam The current active camera.
*
* This method processes the mouse movement event and updates the button hover state.
*/
- void handle_move(const EventData & event_data, const vec2 & mouse_pos);
+ void handle_move(
+ const EventData & event_data, const vec2 & mouse_pos, const Camera & current_cam
+ );
/**
* \brief Checks if the mouse position is inside the bounds of the button.
@@ -115,10 +119,13 @@ private:
* \param world_mouse_y The Y coordinate of the mouse in world space.
* \param button The button to check.
* \param transform The transform component of the button.
+ * \param cam_transform the transform of the current active camera
* \return True if the mouse is inside the button, false otherwise.
*/
- bool is_mouse_inside_button(const vec2 & mouse_pos, const Button & button,
- const Transform & transform);
+ bool is_mouse_inside_button(
+ const vec2 & mouse_pos, const Button & button, const Transform & transform,
+ const Transform & cam_transform
+ );
/**
* \brief Handles the button press event, calling the on_click callback if necessary.
diff --git a/src/crepe/system/ParticleSystem.cpp b/src/crepe/system/ParticleSystem.cpp
index e66c603..f026390 100644
--- a/src/crepe/system/ParticleSystem.cpp
+++ b/src/crepe/system/ParticleSystem.cpp
@@ -13,7 +13,7 @@
using namespace crepe;
-void ParticleSystem::update() {
+void ParticleSystem::fixed_update() {
// Get all emitters
const Mediator & mediator = this->mediator;
LoopTimerManager & loop_timer = mediator.loop_timer;
@@ -50,9 +50,10 @@ void ParticleSystem::emit_particle(ParticleEmitter & emitter, const Transform &
constexpr float DEG_TO_RAD = M_PI / 180.0;
vec2 initial_position = AbsolutePosition::get_position(transform, emitter.data.offset);
- float random_angle
- = this->generate_random_angle(emitter.data.min_angle + transform.rotation,
- emitter.data.max_angle + transform.rotation);
+ float random_angle = this->generate_random_angle(
+ emitter.data.min_angle + transform.rotation,
+ emitter.data.max_angle + transform.rotation
+ );
float random_speed
= this->generate_random_speed(emitter.data.min_speed, emitter.data.max_speed);
@@ -63,8 +64,9 @@ void ParticleSystem::emit_particle(ParticleEmitter & emitter, const Transform &
for (Particle & particle : emitter.particles) {
if (!particle.active) {
- particle.reset(emitter.data.end_lifespan, initial_position, velocity,
- random_angle);
+ particle.reset(
+ emitter.data.end_lifespan, initial_position, velocity, random_angle
+ );
break;
}
}
@@ -82,8 +84,9 @@ void ParticleSystem::check_bounds(ParticleEmitter & emitter, const Transform & t
for (Particle & particle : emitter.particles) {
const vec2 & position = particle.position;
- bool within_bounds = (position.x >= left && position.x <= right && position.y >= top
- && position.y <= bottom);
+ bool within_bounds
+ = (position.x >= left && position.x <= right && position.y >= top
+ && position.y <= bottom);
//if not within bounds do a reset or stop velocity
if (!within_bounds) {
if (emitter.data.boundary.reset_on_exit) {
diff --git a/src/crepe/system/ParticleSystem.h b/src/crepe/system/ParticleSystem.h
index 154521d..4296ff3 100644
--- a/src/crepe/system/ParticleSystem.h
+++ b/src/crepe/system/ParticleSystem.h
@@ -20,7 +20,7 @@ public:
* \brief Updates all particle emitters by emitting particles, updating particle states, and
* checking bounds.
*/
- void update() override;
+ void fixed_update() override;
private:
/**
diff --git a/src/crepe/system/PhysicsSystem.cpp b/src/crepe/system/PhysicsSystem.cpp
index 3b3b8ab..62f8132 100644
--- a/src/crepe/system/PhysicsSystem.cpp
+++ b/src/crepe/system/PhysicsSystem.cpp
@@ -12,8 +12,7 @@
using namespace crepe;
-void PhysicsSystem::update() {
-
+void PhysicsSystem::fixed_update() {
const Mediator & mediator = this->mediator;
ComponentManager & mgr = mediator.component_manager;
LoopTimerManager & loop_timer = mediator.loop_timer;
diff --git a/src/crepe/system/PhysicsSystem.h b/src/crepe/system/PhysicsSystem.h
index 26152a5..5ed624f 100644
--- a/src/crepe/system/PhysicsSystem.h
+++ b/src/crepe/system/PhysicsSystem.h
@@ -18,7 +18,7 @@ public:
*
* It calculates new velocties and changes the postion in the transform.
*/
- void update() override;
+ void fixed_update() override;
};
} // namespace crepe
diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp
index 8c31743..30bb422 100644
--- a/src/crepe/system/RenderSystem.cpp
+++ b/src/crepe/system/RenderSystem.cpp
@@ -70,7 +70,7 @@ RefVector<Sprite> RenderSystem::sort(RefVector<Sprite> & objs) const {
return sorted_objs;
}
-void RenderSystem::update() {
+void RenderSystem::frame_update() {
this->clear_screen();
this->render();
this->render_text();
@@ -92,7 +92,7 @@ void RenderSystem::render_text() {
const Font & font = resource_manager.get<Font>(text.font.value());
const auto & transform
= mgr.get_components_by_id<Transform>(text.game_object_id).front().get();
- ctx.draw_text(SDLContext::RenderText{
+ ctx.draw_text(SDLContext::RenderText {
.text = text,
.font = font,
.transform = transform,
@@ -120,7 +120,7 @@ bool RenderSystem::render_particle(const Sprite & sprite, const Transform & tran
if (!p.active) continue;
if (p.time_in_life < em.data.begin_lifespan) continue;
- ctx.draw(SDLContext::RenderContext{
+ ctx.draw(SDLContext::RenderContext {
.sprite = sprite,
.texture = res,
.pos = p.position,
@@ -136,7 +136,7 @@ void RenderSystem::render_normal(const Sprite & sprite, const Transform & transf
ResourceManager & resource_manager = this->mediator.resource_manager;
const Texture & res = resource_manager.get<Texture>(sprite.source);
vec2 pos = AbsolutePosition::get_position(transform, sprite.data.position_offset);
- ctx.draw(SDLContext::RenderContext{
+ ctx.draw(SDLContext::RenderContext {
.sprite = sprite,
.texture = res,
.pos = pos,
diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h
index 14e5c2d..627a743 100644
--- a/src/crepe/system/RenderSystem.h
+++ b/src/crepe/system/RenderSystem.h
@@ -24,7 +24,7 @@ public:
* \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;
+ void frame_update() override;
private:
//! Clears the screen in preparation for rendering.
diff --git a/src/crepe/system/ReplaySystem.cpp b/src/crepe/system/ReplaySystem.cpp
new file mode 100644
index 0000000..efc3be4
--- /dev/null
+++ b/src/crepe/system/ReplaySystem.cpp
@@ -0,0 +1,54 @@
+#include "../manager/ReplayManager.h"
+#include "../manager/SystemManager.h"
+
+#include "EventSystem.h"
+#include "RenderSystem.h"
+#include "ReplaySystem.h"
+
+using namespace crepe;
+using namespace std;
+
+void ReplaySystem::fixed_update() {
+ ReplayManager & replay = this->mediator.replay_manager;
+ ReplayManager::State state = replay.get_state();
+ ReplayManager::State last_state = this->last_state;
+ this->last_state = state;
+
+ switch (state) {
+ case ReplayManager::IDLE:
+ break;
+ case ReplayManager::RECORDING: {
+ replay.frame_record();
+ break;
+ }
+ case ReplayManager::PLAYING: {
+ if (last_state != ReplayManager::PLAYING) this->playback_begin();
+ bool last = replay.frame_step();
+ if (last) this->playback_end();
+ break;
+ }
+ }
+}
+
+void ReplaySystem::playback_begin() {
+ SystemManager & systems = this->mediator.system_manager;
+ ComponentManager & components = this->mediator.component_manager;
+
+ this->playback = {
+ .components = components.save(),
+ .systems = systems.save(),
+ };
+
+ systems.disable_all();
+ systems.get_system<RenderSystem>().active = true;
+ systems.get_system<ReplaySystem>().active = true;
+ systems.get_system<EventSystem>().active = true;
+}
+
+void ReplaySystem::playback_end() {
+ SystemManager & systems = this->mediator.system_manager;
+ ComponentManager & components = this->mediator.component_manager;
+
+ components.restore(this->playback.components);
+ systems.restore(this->playback.systems);
+}
diff --git a/src/crepe/system/ReplaySystem.h b/src/crepe/system/ReplaySystem.h
new file mode 100644
index 0000000..bbc8d76
--- /dev/null
+++ b/src/crepe/system/ReplaySystem.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "../manager/ReplayManager.h"
+#include "../manager/SystemManager.h"
+
+#include "System.h"
+
+namespace crepe {
+
+/**
+ * \brief ReplayManager helper system
+ *
+ * This system records and replays recordings using ReplayManager.
+ */
+class ReplaySystem : public System {
+public:
+ using System::System;
+
+ void fixed_update() override;
+
+private:
+ //! Last ReplayManager state
+ ReplayManager::State last_state = ReplayManager::IDLE;
+
+ /**
+ * \brief Playback snapshot
+ *
+ * When starting playback, the component state is saved and most systems are disabled. This
+ * struct stores the engine state before ReplayManager::play is called.
+ */
+ struct Snapshot {
+ ComponentManager::Snapshot components;
+ SystemManager::Snapshot systems;
+ };
+ //! Before playback snapshot
+ Snapshot playback;
+
+ //! Snapshot state and disable systems during playback
+ void playback_begin();
+ //! Restore state from before \c playback_begin()
+ void playback_end();
+};
+
+} // namespace crepe
diff --git a/src/crepe/system/ScriptSystem.cpp b/src/crepe/system/ScriptSystem.cpp
index 0605c7a..ed0c7cc 100644
--- a/src/crepe/system/ScriptSystem.cpp
+++ b/src/crepe/system/ScriptSystem.cpp
@@ -7,11 +7,22 @@
using namespace std;
using namespace crepe;
-void ScriptSystem::update() {
- dbg_trace();
+void ScriptSystem::fixed_update() {
+ LoopTimerManager & timer = this->mediator.loop_timer;
+ duration_t delta_time = timer.get_scaled_fixed_delta_time();
+ this->update(&Script::fixed_update, delta_time);
+}
- ComponentManager & mgr = this->mediator.component_manager;
+void ScriptSystem::frame_update() {
LoopTimerManager & timer = this->mediator.loop_timer;
+ duration_t delta_time = timer.get_delta_time();
+ this->update(&Script::frame_update, delta_time);
+}
+
+void ScriptSystem::update(
+ void (Script::*update_function)(duration_t), const duration_t & delta_time
+) {
+ ComponentManager & mgr = this->mediator.component_manager;
RefVector<BehaviorScript> behavior_scripts = mgr.get_components_by_type<BehaviorScript>();
for (BehaviorScript & behavior_script : behavior_scripts) {
@@ -25,7 +36,6 @@ void ScriptSystem::update() {
script->initialized = true;
}
- duration_t delta_time = timer.get_scaled_fixed_delta_time();
- script->update(delta_time);
+ (*script.*update_function)(delta_time);
}
}
diff --git a/src/crepe/system/ScriptSystem.h b/src/crepe/system/ScriptSystem.h
index 3db1b1e..257b615 100644
--- a/src/crepe/system/ScriptSystem.h
+++ b/src/crepe/system/ScriptSystem.h
@@ -1,5 +1,7 @@
#pragma once
+#include "../manager/LoopTimerManager.h"
+
#include "System.h"
namespace crepe {
@@ -9,20 +11,27 @@ class Script;
/**
* \brief Script system
*
- * The script system is responsible for all \c BehaviorScript components, and
- * calls the methods on classes derived from \c Script.
+ * The script system is responsible for all \c BehaviorScript components, and calls the methods
+ * on classes derived from \c Script.
*/
class ScriptSystem : public System {
public:
using System::System;
+
+public:
+ //! Call Script::fixed_update() on all active \c BehaviorScript instances
+ void fixed_update() override;
+ //! Call Script::frame_update() on all active \c BehaviorScript instances
+ void frame_update() override;
+
+private:
/**
- * \brief Call Script::update() on all active \c BehaviorScript instances
+ * \brief Call Script `*_update` member function on all active \c BehaviorScript instances
*
- * This routine updates all scripts sequentially using the Script::update()
- * method. It also calls Script::init() if this has not been done before on
- * the \c BehaviorScript instance.
+ * \note This routine also calls Script::init() if this has not been done before on the \c
+ * BehaviorScript instance.
*/
- void update() override;
+ void update(void (Script::*update_function)(duration_t), const duration_t & delta_time);
};
} // namespace crepe
diff --git a/src/crepe/system/System.h b/src/crepe/system/System.h
index 063dfbf..e2ce7eb 100644
--- a/src/crepe/system/System.h
+++ b/src/crepe/system/System.h
@@ -14,10 +14,12 @@ class ComponentManager;
*/
class System {
public:
- /**
- * \brief Process all components this system is responsible for.
- */
- virtual void update() = 0;
+ //! Code that runs in the fixed loop
+ virtual void fixed_update() {};
+ //! Code that runs in the frame loop
+ virtual void frame_update() {};
+ //! Indicates that the update functions of this system should be run
+ bool active = true;
public:
System(const Mediator & m);