aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLoek Le Blansch <loek@pipeframe.xyz>2024-12-11 18:37:23 +0100
committerLoek Le Blansch <loek@pipeframe.xyz>2024-12-11 18:37:23 +0100
commitca6c4f30df6612f60db0fdfe4c2d366d7e4da8ea (patch)
tree199878898c2ddcdd2f7f6a1b76c165c2c7db5c8d
parentf0ecbea57a4d75905c4ee79608807187cd8f3e72 (diff)
parent30c17c98e54c1534664de08ca3838c40c859d166 (diff)
merge master
-rw-r--r--src/crepe/Resource.cpp3
-rw-r--r--src/crepe/Resource.h3
-rw-r--r--src/crepe/api/AI.cpp89
-rw-r--r--src/crepe/api/AI.h128
-rw-r--r--src/crepe/api/Animator.cpp20
-rw-r--r--src/crepe/api/Animator.h17
-rw-r--r--src/crepe/api/BehaviorScript.cpp4
-rw-r--r--src/crepe/api/BehaviorScript.h1
-rw-r--r--src/crepe/api/CMakeLists.txt4
-rw-r--r--src/crepe/api/GameObject.cpp10
-rw-r--r--src/crepe/api/GameObject.h8
-rw-r--r--src/crepe/api/GameObject.hpp2
-rw-r--r--src/crepe/api/LoopManager.cpp2
-rw-r--r--src/crepe/api/LoopManager.h12
-rw-r--r--src/crepe/api/LoopTimer.cpp14
-rw-r--r--src/crepe/api/LoopTimer.h12
-rw-r--r--src/crepe/api/Sprite.cpp11
-rw-r--r--src/crepe/api/Sprite.h23
-rw-r--r--src/crepe/api/Texture.cpp38
-rw-r--r--src/crepe/api/Texture.h69
-rw-r--r--src/crepe/api/Vector2.h24
-rw-r--r--src/crepe/api/Vector2.hpp48
-rw-r--r--src/crepe/facade/CMakeLists.txt2
-rw-r--r--src/crepe/facade/SDLContext.cpp54
-rw-r--r--src/crepe/facade/SDLContext.h77
-rw-r--r--src/crepe/facade/Sound.cpp2
-rw-r--r--src/crepe/facade/Sound.h3
-rw-r--r--src/crepe/facade/Texture.cpp28
-rw-r--r--src/crepe/facade/Texture.h69
-rw-r--r--src/crepe/manager/ComponentManager.cpp2
-rw-r--r--src/crepe/manager/ComponentManager.h1
-rw-r--r--src/crepe/manager/Mediator.h8
-rw-r--r--src/crepe/manager/ResourceManager.cpp2
-rw-r--r--src/crepe/manager/ResourceManager.hpp2
-rw-r--r--src/crepe/manager/SaveManager.cpp6
-rw-r--r--src/crepe/manager/SaveManager.h5
-rw-r--r--src/crepe/system/AISystem.cpp186
-rw-r--r--src/crepe/system/AISystem.h81
-rw-r--r--src/crepe/system/AnimatorSystem.cpp2
-rw-r--r--src/crepe/system/AudioSystem.cpp3
-rw-r--r--src/crepe/system/CMakeLists.txt2
-rw-r--r--src/crepe/system/InputSystem.cpp5
-rw-r--r--src/crepe/system/RenderSystem.cpp9
-rw-r--r--src/example/AITest.cpp86
-rw-r--r--src/example/CMakeLists.txt1
-rw-r--r--src/example/rendering_particle.cpp18
-rw-r--r--src/example/replay.cpp19
-rw-r--r--src/test/InputTest.cpp1
-rw-r--r--src/test/ParticleTest.cpp4
-rw-r--r--src/test/Profiling.cpp44
-rw-r--r--src/test/RenderSystemTest.cpp36
-rw-r--r--src/test/ResourceManagerTest.cpp5
-rw-r--r--src/test/Vector2Test.cpp148
53 files changed, 1106 insertions, 347 deletions
diff --git a/src/crepe/Resource.cpp b/src/crepe/Resource.cpp
index 27b4c4b..85913ed 100644
--- a/src/crepe/Resource.cpp
+++ b/src/crepe/Resource.cpp
@@ -1,5 +1,6 @@
#include "Resource.h"
+#include "manager/Mediator.h"
using namespace crepe;
-Resource::Resource(const Asset & asset) {}
+Resource::Resource(const Asset & asset, Mediator & mediator) {}
diff --git a/src/crepe/Resource.h b/src/crepe/Resource.h
index eceb15b..d65206b 100644
--- a/src/crepe/Resource.h
+++ b/src/crepe/Resource.h
@@ -4,6 +4,7 @@ namespace crepe {
class ResourceManager;
class Asset;
+class Mediator;
/**
* \brief Resource interface
@@ -17,7 +18,7 @@ class Asset;
*/
class Resource {
public:
- Resource(const Asset & src);
+ Resource(const Asset & src, Mediator & mediator);
virtual ~Resource() = default;
Resource(const Resource &) = delete;
diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp
new file mode 100644
index 0000000..2195249
--- /dev/null
+++ b/src/crepe/api/AI.cpp
@@ -0,0 +1,89 @@
+#include <stdexcept>
+#include <type_traits>
+
+#include "AI.h"
+#include "types.h"
+
+namespace crepe {
+
+AI::AI(game_object_id_t id, float max_force) : Component(id), max_force(max_force) {}
+
+void AI::make_circle_path(float radius, const vec2 & center, float start_angle,
+ bool clockwise) {
+ if (radius <= 0) {
+ throw std::runtime_error("Radius must be greater than 0");
+ }
+
+ // The step size is determined by the radius (step size is in radians)
+ float step = RADIUS_TO_STEP / radius;
+ // Force at least MIN_STEP steps (in case of a small radius)
+ if (step > 2 * M_PI / MIN_STEP) {
+ step = 2 * M_PI / MIN_STEP;
+ }
+ // The path node distance is determined by the step size and the radius
+ this->path_node_distance = radius * step * PATH_NODE_DISTANCE_FACTOR;
+
+ if (clockwise) {
+ for (float i = start_angle; i < 2 * M_PI + start_angle; i += step) {
+ path.push_back(vec2{static_cast<float>(center.x + radius * cos(i)),
+ static_cast<float>(center.y + radius * sin(i))});
+ }
+ } else {
+ for (float i = start_angle; i > start_angle - 2 * M_PI; i -= step) {
+ path.push_back(vec2{static_cast<float>(center.x + radius * cos(i)),
+ static_cast<float>(center.y + radius * sin(i))});
+ }
+ }
+}
+
+void AI::make_oval_path(float radius_x, float radius_y, const vec2 & center, float start_angle,
+ bool clockwise, float rotation) {
+ if (radius_x <= 0 && radius_y <= 0) {
+ throw std::runtime_error("Radius must be greater than 0");
+ }
+
+ float max_radius = std::max(radius_x, radius_y);
+ // The step size is determined by the radius (step size is in radians)
+ float step = RADIUS_TO_STEP / max_radius;
+ // Force at least MIN_STEP steps (in case of a small radius)
+ if (step > 2 * M_PI / MIN_STEP) {
+ step = 2 * M_PI / MIN_STEP;
+ }
+ // The path node distance is determined by the step size and the radius
+ this->path_node_distance = max_radius * step * PATH_NODE_DISTANCE_FACTOR;
+
+ std::function<vec2(vec2, vec2)> rotate_point = [rotation](vec2 point, vec2 center) {
+ float s = sin(rotation);
+ float c = cos(rotation);
+
+ // Translate point back to origin
+ point.x -= center.x;
+ point.y -= center.y;
+
+ // Rotate point
+ float xnew = point.x * c - point.y * s;
+ float ynew = point.x * s + point.y * c;
+
+ // Translate point back
+ point.x = xnew + center.x;
+ point.y = ynew + center.y;
+
+ return point;
+ };
+
+ if (clockwise) {
+ for (float i = start_angle; i < 2 * M_PI + start_angle; i += step) {
+ vec2 point = {static_cast<float>(center.x + radius_x * cos(i)),
+ static_cast<float>(center.y + radius_y * sin(i))};
+ path.push_back(rotate_point(point, center));
+ }
+ } else {
+ for (float i = start_angle; i > start_angle - 2 * M_PI; i -= step) {
+ vec2 point = {static_cast<float>(center.x + radius_x * cos(i)),
+ static_cast<float>(center.y + radius_y * sin(i))};
+ path.push_back(rotate_point(point, center));
+ }
+ }
+}
+
+} // namespace crepe
diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h
new file mode 100644
index 0000000..c780a91
--- /dev/null
+++ b/src/crepe/api/AI.h
@@ -0,0 +1,128 @@
+#pragma once
+
+#include "Component.h"
+#include "types.h"
+
+namespace crepe {
+
+/**
+ * \brief The AI component is used to control the movement of an entity using AI.
+ *
+ * The AI component can be used to control the movement of an entity. The AI component can be used
+ * to implement different behaviors such as seeking, fleeing, arriving, and path following.
+ */
+class AI : public Component {
+public:
+ //! The different types of behaviors that can be used
+ enum BehaviorTypeMask {
+ SEEK = 0x00002,
+ FLEE = 0x00004,
+ ARRIVE = 0x00008,
+ PATH_FOLLOW = 0x00010,
+ };
+
+public:
+ /**
+ * \param id The id of the game object
+ * \param max_force The maximum force that can be applied to the entity
+ */
+ AI(game_object_id_t id, float max_force);
+
+ /**
+ * \brief Check if a behavior is on (aka activated)
+ *
+ * \param behavior The behavior to check
+ * \return true if the behavior is on, false otherwise
+ */
+ bool on(BehaviorTypeMask behavior) const { return (flags & behavior); }
+ //! Turn on the seek behavior
+ void seek_on() { flags |= SEEK; }
+ //! Turn off the seek behavior
+ void seek_off() { flags &= ~SEEK; }
+ //! Turn on the flee behavior
+ void flee_on() { flags |= FLEE; }
+ //! Turn off the flee behavior
+ void flee_off() { flags &= ~FLEE; }
+ //! Turn on the arrive behavior
+ void arrive_on() { flags |= ARRIVE; }
+ //! Turn off the arrive behavior
+ void arrive_off() { flags &= ~ARRIVE; }
+ //! Turn on the path follow behavior
+ void path_follow_on() { flags |= PATH_FOLLOW; }
+ //! Turn off the path follow behavior
+ void path_follow_off() { flags &= ~PATH_FOLLOW; }
+
+ /**
+ * \brief Add a path node (for the path following behavior)
+ *
+ * \note The path is not relative to the entity's position (it is an absolute path)
+ *
+ * \param node The path node to add
+ */
+ void add_path_node(const vec2 & node) { path.push_back(node); }
+ /**
+ * \brief Make a circle path (for the path following behavior)
+ *
+ * \note The path is not relative to the entity's position (it is an absolute path)
+ *
+ * \param radius The radius of the circle (in game units)
+ * \param center The center of the circle (in game units)
+ * \param start_angle The start angle of the circle (in radians)
+ * \param clockwise The direction of the circle
+ */
+ void make_circle_path(float radius, const vec2 & center = {0, 0}, float start_angle = 0,
+ bool clockwise = true);
+ /**
+ * \brief Make an oval path (for the path following behavior)
+ *
+ * \note The path is not relative to the entity's position (it is an absolute path)
+ *
+ * \param radius_x The x radius of the oval (in game units)
+ * \param radius_y The y radius of the oval (in game units)
+ * \param center The center of the oval (in game units)
+ * \param start_angle The start angle of the oval (in radians)
+ * \param clockwise The direction of the oval
+ * \param rotation The rotation of the oval (in radians)
+ */
+ void make_oval_path(float radius_x, float radius_y, const vec2 & center = {0, 0},
+ float start_angle = 0, bool clockwise = true, float rotation = 0);
+
+public:
+ //! The maximum force that can be applied to the entity (higher values will make the entity adjust faster)
+ float max_force;
+
+ //! The target to seek at
+ vec2 seek_target;
+ //! The target to arrive at
+ vec2 arrive_target;
+ //! The target to flee from
+ vec2 flee_target;
+ //! The distance at which the entity will start to flee from the target
+ float square_flee_panic_distance = 200.0f * 200.0f;
+ //! The deceleration rate for the arrive behavior (higher values will make the entity decelerate faster (less overshoot))
+ float arrive_deceleration = 40.0f;
+ //! The path to follow (for the path following behavior)
+ std::vector<vec2> path;
+ //! The distance from the path node at which the entity will move to the next node (automatically set by make_circle_path())
+ float path_node_distance = 400.0f;
+ //! Looping behavior for the path
+ bool path_loop = true;
+
+private:
+ //! The flags for the behaviors
+ int flags = 0;
+ //! The current path index
+ size_t path_index = 0;
+
+ //! The AISystem is the only class that should access the flags and path_index variables
+ friend class AISystem;
+
+ //! The minimum amount of steps for the path following behavior
+ static constexpr int MIN_STEP = 16;
+ //! The radius to step size ratio for the path following behavior
+ static constexpr float RADIUS_TO_STEP = 400.0f;
+ //! The path node distance factor for the path following behavior
+ static constexpr float PATH_NODE_DISTANCE_FACTOR = 0.75f;
+};
+
+} // namespace crepe
diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp
index b8a91dc..4ce4bf0 100644
--- a/src/crepe/api/Animator.cpp
+++ b/src/crepe/api/Animator.cpp
@@ -7,23 +7,21 @@
using namespace crepe;
-Animator::Animator(game_object_id_t id, Sprite & spritesheet, unsigned int max_row,
- unsigned int max_col, const Animator::Data & data)
+Animator::Animator(game_object_id_t id, Sprite & spritesheet, const ivec2 & single_frame_size,
+ const uvec2 & grid_size, const Animator::Data & data)
: Component(id),
spritesheet(spritesheet),
- max_rows(max_row),
- max_columns(max_col),
+ grid_size(grid_size),
data(data) {
dbg_trace();
- this->spritesheet.mask.h /= this->max_columns;
- this->spritesheet.mask.w /= this->max_rows;
- this->spritesheet.mask.x = this->data.row * this->spritesheet.mask.w;
- this->spritesheet.mask.y = this->data.col * this->spritesheet.mask.h;
+ this->spritesheet.mask.w = single_frame_size.x;
+ this->spritesheet.mask.h = single_frame_size.y;
+ this->spritesheet.mask.x = 0;
+ this->spritesheet.mask.y = 0;
- // need to do this for to get the aspect ratio for a single clipping in the spritesheet
this->spritesheet.aspect_ratio
- = static_cast<double>(this->spritesheet.mask.w) / this->spritesheet.mask.h;
+ = static_cast<float>(single_frame_size.x) / single_frame_size.y;
}
Animator::~Animator() { dbg_trace(); }
@@ -54,6 +52,6 @@ void Animator::set_anim(int col) {
void Animator::next_anim() {
Animator::Data & ctx = this->data;
- ctx.row = ctx.row++ % this->max_rows;
+ ctx.row = ctx.row++ % this->grid_size.x;
this->spritesheet.mask.x = ctx.row * this->spritesheet.mask.w;
}
diff --git a/src/crepe/api/Animator.h b/src/crepe/api/Animator.h
index 7c850b8..5918800 100644
--- a/src/crepe/api/Animator.h
+++ b/src/crepe/api/Animator.h
@@ -75,27 +75,28 @@ public:
*
* \param id The unique identifier for the component, typically assigned automatically.
* \param spritesheet the reference to the spritesheet
- * \param max_row maximum of rows inside the given spritesheet
- * \param max_col maximum of columns inside the given spritesheet
+ * \param single_frame_size the width and height in pixels of a single frame inside the
+ * spritesheet
+ * \param grid_size the max rows and columns inside the given spritesheet
* \param data extra animation data for more control
*
* This constructor sets up the Animator with the given parameters, and initializes the
* animation system.
*/
- Animator(game_object_id_t id, Sprite & spritesheet, unsigned int max_row,
- unsigned int max_col, const Animator::Data & data);
+ Animator(game_object_id_t id, Sprite & spritesheet, const ivec2 & single_frame_size,
+ const uvec2 & grid_size, const Animator::Data & data);
~Animator(); // dbg_trace
public:
- //! The maximum number of columns in the sprite sheet.
- const unsigned int max_columns;
- //! The maximum number of rows in the sprite sheet.
- const unsigned int max_rows;
Animator::Data data;
private:
//! A reference to the Sprite sheet containing.
Sprite & spritesheet;
+
+ //! The maximum number of rows and columns inside the spritesheet
+ const uvec2 grid_size;
+
//! Uses the spritesheet
friend AnimatorSystem;
};
diff --git a/src/crepe/api/BehaviorScript.cpp b/src/crepe/api/BehaviorScript.cpp
index d22afdf..af7572c 100644
--- a/src/crepe/api/BehaviorScript.cpp
+++ b/src/crepe/api/BehaviorScript.cpp
@@ -10,6 +10,6 @@ BehaviorScript::BehaviorScript(game_object_id_t id, Mediator & mediator)
template <>
BehaviorScript & GameObject::add_component<BehaviorScript>() {
- ComponentManager & mgr = this->component_manager;
- return mgr.add_component<BehaviorScript>(this->id, mgr.mediator);
+ ComponentManager & mgr = this->mediator.component_manager;
+ return mgr.add_component<BehaviorScript>(this->id, this->mediator);
}
diff --git a/src/crepe/api/BehaviorScript.h b/src/crepe/api/BehaviorScript.h
index 3909b96..02d588a 100644
--- a/src/crepe/api/BehaviorScript.h
+++ b/src/crepe/api/BehaviorScript.h
@@ -9,6 +9,7 @@
namespace crepe {
class ScriptSystem;
+class Mediator;
class ComponentManager;
class Script;
diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt
index a163faf..46deb67 100644
--- a/src/crepe/api/CMakeLists.txt
+++ b/src/crepe/api/CMakeLists.txt
@@ -6,7 +6,6 @@ target_sources(crepe PUBLIC
ParticleEmitter.cpp
Transform.cpp
Color.cpp
- Texture.cpp
Sprite.cpp
Config.cpp
Metadata.cpp
@@ -23,6 +22,7 @@ target_sources(crepe PUBLIC
Script.cpp
Button.cpp
UIObject.cpp
+ AI.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -38,7 +38,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
Vector2.h
Vector2.hpp
Color.h
- Texture.h
Scene.h
Metadata.h
Camera.h
@@ -55,4 +54,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
Asset.h
Button.h
UIObject.h
+ AI.h
)
diff --git a/src/crepe/api/GameObject.cpp b/src/crepe/api/GameObject.cpp
index 9ef4682..ea9c425 100644
--- a/src/crepe/api/GameObject.cpp
+++ b/src/crepe/api/GameObject.cpp
@@ -7,20 +7,20 @@
using namespace crepe;
using namespace std;
-GameObject::GameObject(ComponentManager & component_manager, game_object_id_t id,
+GameObject::GameObject(Mediator & mediator, game_object_id_t id,
const std::string & name, const std::string & tag,
const vec2 & position, double rotation, double scale)
: id(id),
- component_manager(component_manager) {
+ mediator(mediator) {
// Add Transform and Metadata components
- ComponentManager & mgr = this->component_manager;
+ ComponentManager & mgr = this->mediator.component_manager;
mgr.add_component<Transform>(this->id, position, rotation, scale);
mgr.add_component<Metadata>(this->id, name, tag);
}
void GameObject::set_parent(const GameObject & parent) {
- ComponentManager & mgr = this->component_manager;
+ ComponentManager & mgr = this->mediator.component_manager;
// Set parent on own Metadata component
RefVector<Metadata> this_metadata = mgr.get_components_by_id<Metadata>(this->id);
@@ -32,7 +32,7 @@ void GameObject::set_parent(const GameObject & parent) {
}
void GameObject::set_persistent(bool persistent) {
- ComponentManager & mgr = this->component_manager;
+ ComponentManager & mgr = this->mediator.component_manager;
mgr.set_persistent(this->id, persistent);
}
diff --git a/src/crepe/api/GameObject.h b/src/crepe/api/GameObject.h
index ff80f49..a311c21 100644
--- a/src/crepe/api/GameObject.h
+++ b/src/crepe/api/GameObject.h
@@ -6,7 +6,7 @@
namespace crepe {
-class ComponentManager;
+class Mediator;
/**
* \brief Represents a GameObject
@@ -20,7 +20,7 @@ private:
* This constructor creates a new GameObject. It creates a new Transform and Metadata
* component and adds them to the ComponentManager.
*
- * \param component_manager Reference to component_manager
+ * \param mediator Reference to mediator
* \param id The id of the GameObject
* \param name The name of the GameObject
* \param tag The tag of the GameObject
@@ -28,7 +28,7 @@ private:
* \param rotation The rotation of the GameObject
* \param scale The scale of the GameObject
*/
- GameObject(ComponentManager & component_manager, game_object_id_t id,
+ GameObject(Mediator & mediator, game_object_id_t id,
const std::string & name, const std::string & tag, const vec2 & position,
double rotation, double scale);
//! ComponentManager instances GameObject
@@ -73,7 +73,7 @@ public:
const game_object_id_t id;
protected:
- ComponentManager & component_manager;
+ Mediator & mediator;
};
} // namespace crepe
diff --git a/src/crepe/api/GameObject.hpp b/src/crepe/api/GameObject.hpp
index a6b45b0..69f7d73 100644
--- a/src/crepe/api/GameObject.hpp
+++ b/src/crepe/api/GameObject.hpp
@@ -8,7 +8,7 @@ namespace crepe {
template <typename T, typename... Args>
T & GameObject::add_component(Args &&... args) {
- ComponentManager & mgr = this->component_manager;
+ ComponentManager & mgr = this->mediator.component_manager;
return mgr.add_component<T>(this->id, std::forward<Args>(args)...);
}
diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp
index ff428fd..3511bca 100644
--- a/src/crepe/api/LoopManager.cpp
+++ b/src/crepe/api/LoopManager.cpp
@@ -1,3 +1,4 @@
+#include "../system/AISystem.h"
#include "../system/AnimatorSystem.h"
#include "../system/AudioSystem.h"
#include "../system/CollisionSystem.h"
@@ -15,6 +16,7 @@ using namespace std;
LoopManager::LoopManager() {
this->load_system<ScriptSystem>();
+ this->load_system<AISystem>();
this->load_system<PhysicsSystem>();
this->load_system<CollisionSystem>();
this->load_system<AnimatorSystem>();
diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h
index 4b1fc1e..28aa423 100644
--- a/src/crepe/api/LoopManager.h
+++ b/src/crepe/api/LoopManager.h
@@ -3,11 +3,12 @@
#include "../facade/SDLContext.h"
#include "../manager/ComponentManager.h"
#include "../manager/ResourceManager.h"
-#include "../manager/SceneManager.h"
#include "../manager/SaveManager.h"
+#include "../manager/SceneManager.h"
#include "../system/System.h"
#include "LoopTimer.h"
+#include "manager/ResourceManager.h"
namespace crepe {
@@ -71,11 +72,10 @@ private:
ResourceManager resource_manager{mediator};
//! Save manager instance
SaveManager save_manager{mediator};
-
- //! SDL context \todo no more singletons!
- SDLContext & sdl_context = mediator.sdl_context;
- //! Loop timer \todo no more singletons!
- LoopTimer & loop_timer = LoopTimer::get_instance();
+ //! SDLContext instance
+ SDLContext sdl_context{mediator};
+ //! LoopTimer instance
+ LoopTimer loop_timer{mediator};
private:
/**
diff --git a/src/crepe/api/LoopTimer.cpp b/src/crepe/api/LoopTimer.cpp
index 15a0e3a..56e48d3 100644
--- a/src/crepe/api/LoopTimer.cpp
+++ b/src/crepe/api/LoopTimer.cpp
@@ -1,17 +1,16 @@
#include <chrono>
-#include "../facade/SDLContext.h"
#include "../util/Log.h"
+#include "facade/SDLContext.h"
+#include "manager/Manager.h"
#include "LoopTimer.h"
using namespace crepe;
-LoopTimer::LoopTimer() { dbg_trace(); }
-
-LoopTimer & LoopTimer::get_instance() {
- static LoopTimer instance;
- return instance;
+LoopTimer::LoopTimer(Mediator & mediator) : Manager(mediator) {
+ dbg_trace();
+ mediator.timer = *this;
}
void LoopTimer::start() {
@@ -67,7 +66,8 @@ void LoopTimer::enforce_frame_rate() {
= std::chrono::duration_cast<std::chrono::milliseconds>(this->frame_target_time
- frame_duration);
if (delay_time.count() > 0) {
- SDLContext::get_instance().delay(delay_time.count());
+ SDLContext & ctx = this->mediator.sdl_context;
+ ctx.delay(delay_time.count());
}
}
diff --git a/src/crepe/api/LoopTimer.h b/src/crepe/api/LoopTimer.h
index 9393439..0a73a4c 100644
--- a/src/crepe/api/LoopTimer.h
+++ b/src/crepe/api/LoopTimer.h
@@ -1,19 +1,13 @@
#pragma once
+#include "manager/Manager.h"
#include <chrono>
namespace crepe {
-class LoopTimer {
+class LoopTimer : public Manager {
public:
/**
- * \brief Get the singleton instance of LoopTimer.
- *
- * \return A reference to the LoopTimer instance.
- */
- static LoopTimer & get_instance();
-
- /**
* \brief Get the current delta time for the current frame.
*
* \return Delta time in seconds since the last frame.
@@ -102,7 +96,7 @@ private:
*
* Private constructor for singleton pattern to restrict instantiation outside the class.
*/
- LoopTimer();
+ LoopTimer(Mediator & mediator);
/**
* \brief Update the timer to the current frame.
diff --git a/src/crepe/api/Sprite.cpp b/src/crepe/api/Sprite.cpp
index cc0e20a..ba684ba 100644
--- a/src/crepe/api/Sprite.cpp
+++ b/src/crepe/api/Sprite.cpp
@@ -1,26 +1,21 @@
#include <cmath>
-#include <utility>
#include "../util/Log.h"
+#include "api/Asset.h"
#include "Component.h"
#include "Sprite.h"
-#include "Texture.h"
#include "types.h"
using namespace std;
using namespace crepe;
-Sprite::Sprite(game_object_id_t id, Texture & texture, const Sprite::Data & data)
+Sprite::Sprite(game_object_id_t id, const Asset & texture, const Sprite::Data & data)
: Component(id),
- texture(std::move(texture)),
+ source(texture),
data(data) {
dbg_trace();
-
- this->mask.w = this->texture.get_size().x;
- this->mask.h = this->texture.get_size().y;
- this->aspect_ratio = static_cast<double>(this->mask.w) / this->mask.h;
}
Sprite::~Sprite() { dbg_trace(); }
diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h
index dbf41e4..a2409c2 100644
--- a/src/crepe/api/Sprite.h
+++ b/src/crepe/api/Sprite.h
@@ -1,9 +1,9 @@
#pragma once
#include "../Component.h"
+#include "api/Asset.h"
#include "Color.h"
-#include "Texture.h"
#include "types.h"
namespace crepe {
@@ -74,24 +74,15 @@ public:
* \param texture asset of the image
* \param ctx all the sprite data
*/
- Sprite(game_object_id_t id, Texture & texture, const Data & data);
+ Sprite(game_object_id_t id, const Asset & texture, const Data & data);
~Sprite();
//! Texture used for the sprite
- const Texture texture;
+ const Asset source;
Data data;
private:
- /**
- * \brief ratio of the img
- *
- * - This will multiply one of \c size variable if it is 0.
- * - Will be adjusted if \c Animator component is added to an GameObject that is why this
- * value cannot be const.
- */
- float aspect_ratio;
-
//! Reads the mask of sprite
friend class SDLContext;
@@ -101,6 +92,14 @@ private:
//! Reads the all the variables plus the mask
friend class AnimatorSystem;
+ /**
+ * \aspect_ratio the ratio of the sprite image
+ *
+ * - this value will only be set by the \c Animator component for the ratio of the Animation
+ * - if \c Animator component is not added it will not use this ratio (because 0) and will use aspect_ratio of the Asset.
+ */
+ float aspect_ratio = 0;
+
struct Rect {
int w = 0;
int h = 0;
diff --git a/src/crepe/api/Texture.cpp b/src/crepe/api/Texture.cpp
deleted file mode 100644
index 2b56271..0000000
--- a/src/crepe/api/Texture.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#include "../facade/SDLContext.h"
-#include "../util/Log.h"
-
-#include "Asset.h"
-#include "Texture.h"
-#include "types.h"
-
-using namespace crepe;
-using namespace std;
-
-Texture::Texture(const Asset & src) {
- dbg_trace();
- this->load(src);
-}
-
-Texture::~Texture() {
- dbg_trace();
- this->texture.reset();
-}
-
-Texture::Texture(Texture && other) noexcept : texture(std::move(other.texture)) {}
-
-Texture & Texture::operator=(Texture && other) noexcept {
- if (this != &other) {
- texture = std::move(other.texture);
- }
- return *this;
-}
-
-void Texture::load(const Asset & res) {
- SDLContext & ctx = SDLContext::get_instance();
- this->texture = ctx.texture_from_path(res.get_path());
-}
-
-ivec2 Texture::get_size() const {
- if (this->texture == nullptr) return {};
- return SDLContext::get_instance().get_size(*this);
-}
diff --git a/src/crepe/api/Texture.h b/src/crepe/api/Texture.h
deleted file mode 100644
index 1817910..0000000
--- a/src/crepe/api/Texture.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#pragma once
-
-// FIXME: this header can't be included because this is an API header, and SDL2 development
-// headers won't be bundled with crepe. Why is this facade in the API namespace?
-
-#include <SDL2/SDL_render.h>
-#include <functional>
-#include <memory>
-
-#include "Asset.h"
-#include "types.h"
-
-namespace crepe {
-
-class SDLContext;
-class Animator;
-
-/**
- * \class Texture
- * \brief Manages texture loading and properties.
- *
- * The Texture class is responsible for loading an image from a source and providing access to
- * its dimensions. Textures can be used for rendering.
- */
-class Texture {
-
-public:
- /**
- * \brief Constructs a Texture from an Asset resource.
- * \param src Asset with texture data to load.
- */
- Texture(const Asset & src);
-
- /**
- * \brief Destroys the Texture instance, freeing associated resources.
- */
- ~Texture();
- // FIXME: this constructor shouldn't be necessary because this class doesn't manage memory
-
- Texture(Texture && other) noexcept;
- Texture & operator=(Texture && other) noexcept;
- Texture(const Texture &) = delete;
- Texture & operator=(const Texture &) = delete;
-
- /**
- * \brief Gets the width and height of the texture.
- * \return Width and height of the texture in pixels.
- */
- ivec2 get_size() const;
-
-private:
- /**
- * \brief Loads the texture from an Asset resource.
- * \param res Unique pointer to an Asset resource to load the texture from.
- */
- void load(const Asset & res);
-
-private:
- //! The texture of the class from the library
- std::unique_ptr<SDL_Texture, std::function<void(SDL_Texture *)>> texture;
-
- //! Grants SDLContext access to private members.
- friend class SDLContext;
-
- //! Grants Animator access to private members.
- friend class Animator;
-};
-
-} // namespace crepe
diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h
index c278c87..bf9d124 100644
--- a/src/crepe/api/Vector2.h
+++ b/src/crepe/api/Vector2.h
@@ -66,6 +66,30 @@ struct Vector2 {
//! Checks if this vector is not equal to another vector.
bool operator!=(const Vector2<T> & other) const;
+
+ //! Truncates the vector to a maximum length.
+ void truncate(T max);
+
+ //! Normalizes the vector (resulting in vector with a length of 1).
+ void normalize();
+
+ //! Returns the length of the vector.
+ T length() const;
+
+ //! Returns the squared length of the vector.
+ T length_squared() const;
+
+ //! Returns the dot product (inwendig product) of this vector and another vector.
+ T dot(const Vector2<T> & other) const;
+
+ //! Returns the distance between this vector and another vector.
+ T distance(const Vector2<T> & other) const;
+
+ //! Returns the squared distance between this vector and another vector.
+ T distance_squared(const Vector2<T> & other) const;
+
+ //! Returns the perpendicular vector to this vector.
+ Vector2 perpendicular() const;
};
} // namespace crepe
diff --git a/src/crepe/api/Vector2.hpp b/src/crepe/api/Vector2.hpp
index cad15f8..ff53cb0 100644
--- a/src/crepe/api/Vector2.hpp
+++ b/src/crepe/api/Vector2.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include <cmath>
+
#include "Vector2.h"
namespace crepe {
@@ -115,4 +117,50 @@ bool Vector2<T>::operator!=(const Vector2<T> & other) const {
return !(*this == other);
}
+template <class T>
+void Vector2<T>::truncate(T max) {
+ if (length() > max) {
+ normalize();
+ *this *= max;
+ }
+}
+
+template <class T>
+void Vector2<T>::normalize() {
+ T len = length();
+ if (len > 0) {
+ *this /= len;
+ }
+}
+
+template <class T>
+T Vector2<T>::length() const {
+ return std::sqrt(x * x + y * y);
+}
+
+template <class T>
+T Vector2<T>::length_squared() const {
+ return x * x + y * y;
+}
+
+template <class T>
+T Vector2<T>::dot(const Vector2<T> & other) const {
+ return x * other.x + y * other.y;
+}
+
+template <class T>
+T Vector2<T>::distance(const Vector2<T> & other) const {
+ return (*this - other).length();
+}
+
+template <class T>
+T Vector2<T>::distance_squared(const Vector2<T> & other) const {
+ return (*this - other).length_squared();
+}
+
+template <class T>
+Vector2<T> Vector2<T>::perpendicular() const {
+ return {-y, x};
+}
+
} // namespace crepe
diff --git a/src/crepe/facade/CMakeLists.txt b/src/crepe/facade/CMakeLists.txt
index 4cc53bc..0598e16 100644
--- a/src/crepe/facade/CMakeLists.txt
+++ b/src/crepe/facade/CMakeLists.txt
@@ -1,5 +1,6 @@
target_sources(crepe PUBLIC
Sound.cpp
+ Texture.cpp
SoundContext.cpp
SDLContext.cpp
DB.cpp
@@ -7,6 +8,7 @@ target_sources(crepe PUBLIC
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
Sound.h
+ Texture.h
SoundContext.h
SDLContext.h
DB.h
diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp
index 6becf60..1dbd6a5 100644
--- a/src/crepe/facade/SDLContext.cpp
+++ b/src/crepe/facade/SDLContext.cpp
@@ -18,23 +18,18 @@
#include "../api/Color.h"
#include "../api/Config.h"
#include "../api/Sprite.h"
-#include "../api/Texture.h"
#include "../util/Log.h"
+#include "manager/Mediator.h"
#include "SDLContext.h"
+#include "Texture.h"
#include "types.h"
using namespace crepe;
using namespace std;
-SDLContext & SDLContext::get_instance() {
- static SDLContext instance;
- return instance;
-}
-
-SDLContext::SDLContext() {
+SDLContext::SDLContext(Mediator & mediator) {
dbg_trace();
-
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
throw runtime_error(format("SDLContext: SDL_Init error: {}", SDL_GetError()));
}
@@ -62,6 +57,8 @@ SDLContext::SDLContext() {
if (!(IMG_Init(img_flags) & img_flags)) {
throw runtime_error("SDLContext: SDL_image could not initialize!");
}
+
+ mediator.sdl_context = *this;
}
SDLContext::~SDLContext() {
@@ -221,25 +218,19 @@ void SDLContext::present_screen() {
SDL_RenderPresent(this->game_renderer.get());
}
-SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) const {
- return SDL_Rect{
- .x = sprite.mask.x,
- .y = sprite.mask.y,
- .w = sprite.mask.w,
- .h = sprite.mask.h,
- };
-}
-
SDL_FRect SDLContext::get_dst_rect(const DestinationRectangleData & ctx) const {
const Sprite::Data & data = ctx.sprite.data;
+ float aspect_ratio
+ = (ctx.sprite.aspect_ratio == 0) ? ctx.texture.get_ratio() : ctx.sprite.aspect_ratio;
+
vec2 size = data.size;
if (data.size.x == 0 && data.size.y != 0) {
- size.x = data.size.y * ctx.sprite.aspect_ratio;
+ size.x = data.size.y * aspect_ratio;
}
if (data.size.y == 0 && data.size.x != 0) {
- size.y = data.size.x / ctx.sprite.aspect_ratio;
+ size.y = data.size.x / aspect_ratio;
}
const CameraValues & cam = ctx.cam;
@@ -260,15 +251,24 @@ SDL_FRect SDLContext::get_dst_rect(const DestinationRectangleData & ctx) const {
}
void SDLContext::draw(const RenderContext & ctx) {
-
const Sprite::Data & data = ctx.sprite.data;
SDL_RendererFlip render_flip
= (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * data.flip.flip_x)
| (SDL_FLIP_VERTICAL * data.flip.flip_y));
- SDL_Rect srcrect = this->get_src_rect(ctx.sprite);
+ SDL_Rect srcrect;
+ SDL_Rect * srcrect_ptr = NULL;
+ if (ctx.sprite.mask.w != 0 || ctx.sprite.mask.h != 0) {
+ srcrect.w = ctx.sprite.mask.w;
+ srcrect.h = ctx.sprite.mask.h;
+ srcrect.x = ctx.sprite.mask.x;
+ srcrect.y = ctx.sprite.mask.y;
+ srcrect_ptr = &srcrect;
+ }
+
SDL_FRect dstrect = this->get_dst_rect(SDLContext::DestinationRectangleData{
.sprite = ctx.sprite,
+ .texture = ctx.texture,
.cam = ctx.cam,
.pos = ctx.pos,
.img_scale = ctx.scale,
@@ -276,9 +276,9 @@ void SDLContext::draw(const RenderContext & ctx) {
double angle = ctx.angle + data.angle_offset;
- this->set_color_texture(ctx.sprite.texture, ctx.sprite.data.color);
- SDL_RenderCopyExF(this->game_renderer.get(), ctx.sprite.texture.texture.get(), &srcrect,
- &dstrect, angle, NULL, render_flip);
+ this->set_color_texture(ctx.texture, ctx.sprite.data.color);
+ SDL_RenderCopyExF(this->game_renderer.get(), ctx.texture.get_img(), srcrect_ptr, &dstrect,
+ angle, NULL, render_flip);
}
SDLContext::CameraValues SDLContext::set_camera(const Camera & cam) {
@@ -368,7 +368,7 @@ SDLContext::texture_from_path(const std::string & path) {
ivec2 SDLContext::get_size(const Texture & ctx) {
ivec2 size;
- SDL_QueryTexture(ctx.texture.get(), NULL, NULL, &size.x, &size.y);
+ SDL_QueryTexture(ctx.get_img(), NULL, NULL, &size.x, &size.y);
return size;
}
@@ -435,6 +435,6 @@ std::vector<SDLContext::EventData> SDLContext::get_events() {
return event_list;
}
void SDLContext::set_color_texture(const Texture & texture, const Color & color) {
- SDL_SetTextureColorMod(texture.texture.get(), color.r, color.g, color.b);
- SDL_SetTextureAlphaMod(texture.texture.get(), color.a);
+ SDL_SetTextureColorMod(texture.get_img(), color.r, color.g, color.b);
+ SDL_SetTextureAlphaMod(texture.get_img(), color.a);
}
diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h
index e232511..46b779f 100644
--- a/src/crepe/facade/SDLContext.h
+++ b/src/crepe/facade/SDLContext.h
@@ -14,14 +14,15 @@
#include "api/Color.h"
#include "api/KeyCodes.h"
#include "api/Sprite.h"
-#include "api/Texture.h"
#include "api/Transform.h"
+
#include "types.h"
namespace crepe {
-class LoopManager;
-class InputSystem;
+class Texture;
+class Mediator;
+
/**
* \class SDLContext
* \brief Facade for the SDL library
@@ -62,6 +63,7 @@ public:
//! rendering data needed to render on screen
struct RenderContext {
const Sprite & sprite;
+ const Texture & texture;
const CameraValues & cam;
const vec2 & pos;
const double & angle;
@@ -92,20 +94,27 @@ public:
float scroll_delta = INFINITY;
ivec2 rel_mouse_move = {-1, -1};
};
- /**
- * \brief Gets the singleton instance of SDLContext.
- * \return Reference to the SDLContext instance.
- */
- static SDLContext & get_instance();
+public:
SDLContext(const SDLContext &) = delete;
SDLContext(SDLContext &&) = delete;
SDLContext & operator=(const SDLContext &) = delete;
SDLContext & operator=(SDLContext &&) = delete;
-private:
- //! will only use get_events
- friend class InputSystem;
+public:
+ /**
+ * \brief Constructs an SDLContext instance.
+ * Initializes SDL, creates a window and renderer.
+ */
+ SDLContext(Mediator & mediator);
+
+ /**
+ * \brief Destroys the SDLContext instance.
+ * Cleans up SDL resources, including the window and renderer.
+ */
+ ~SDLContext();
+
+public:
/**
* \brief Retrieves a list of all events from the SDL context.
*
@@ -139,9 +148,7 @@ private:
*/
MouseButton sdl_to_mousebutton(Uint8 sdl_button);
-private:
- //! Will only use delay
- friend class LoopTimer;
+public:
/**
* \brief Gets the current SDL ticks since the program started.
* \return Current ticks in milliseconds as a constant uint64_t.
@@ -157,23 +164,7 @@ private:
*/
void delay(int ms) const;
-private:
- /**
- * \brief Constructs an SDLContext instance.
- * Initializes SDL, creates a window and renderer.
- */
- SDLContext();
-
- /**
- * \brief Destroys the SDLContext instance.
- * Cleans up SDL resources, including the window and renderer.
- */
- ~SDLContext();
-
-private:
- //! Will use the funtions: texture_from_path, get_width,get_height.
- friend class Texture;
-
+public:
/**
* \brief Loads a texture from a file path.
* \param path Path to the image file.
@@ -184,14 +175,11 @@ private:
/**
* \brief Gets the size of a texture.
* \param texture Reference to the Texture object.
- * \return Width and height of the texture as an integer.
+ * \return Width and height of the texture as an integer in pixels.
*/
ivec2 get_size(const Texture & ctx);
-private:
- //! Will use draw,clear_screen, present_screen, camera.
- friend class RenderSystem;
-
+public:
/**
* \brief Draws a sprite to the screen using the specified transform and camera.
* \param RenderContext Reference to rendering data to draw
@@ -207,33 +195,24 @@ private:
/**
* \brief sets the background of the camera (will be adjusted in future PR)
* \param camera Reference to the Camera object.
+ * \return camera data the component cannot store
*/
CameraValues set_camera(const Camera & camera);
-private:
+public:
//! the data needed to construct a sdl dst rectangle
struct DestinationRectangleData {
const Sprite & sprite;
+ const Texture & texture;
const CameraValues & cam;
const vec2 & pos;
const double & img_scale;
};
- /**
- * \brief calculates the sqaure size of the image
- *
- * \param sprite Reference to the sprite to calculate the rectangle
- * \return sdl rectangle to draw a src image
- */
- SDL_Rect get_src_rect(const Sprite & sprite) const;
/**
* \brief calculates the sqaure size of the image for destination
*
- * \param sprite Reference to the sprite to calculate rectangle
- * \param pos the pos in world units
- * \param cam the camera of the current scene
- * \param cam_pos the current postion of the camera
- * \param img_scale the image multiplier for increasing img size
+ * \param data needed to calculate a destination rectangle
* \return sdl rectangle to draw a dst image to draw on the screen
*/
SDL_FRect get_dst_rect(const DestinationRectangleData & data) const;
diff --git a/src/crepe/facade/Sound.cpp b/src/crepe/facade/Sound.cpp
index ad50637..97e455e 100644
--- a/src/crepe/facade/Sound.cpp
+++ b/src/crepe/facade/Sound.cpp
@@ -6,7 +6,7 @@
using namespace crepe;
using namespace std;
-Sound::Sound(const Asset & src) : Resource(src) {
+Sound::Sound(const Asset & src, Mediator & mediator) : Resource(src, mediator) {
this->sample.load(src.get_path().c_str());
dbg_trace();
}
diff --git a/src/crepe/facade/Sound.h b/src/crepe/facade/Sound.h
index 85d141b..4a5d692 100644
--- a/src/crepe/facade/Sound.h
+++ b/src/crepe/facade/Sound.h
@@ -8,6 +8,7 @@
namespace crepe {
class SoundContext;
+class Mediator;
/**
* \brief Sound resource facade
@@ -17,7 +18,7 @@ class SoundContext;
*/
class Sound : public Resource {
public:
- Sound(const Asset & src);
+ Sound(const Asset & src, Mediator & mediator);
~Sound(); // dbg_trace
private:
diff --git a/src/crepe/facade/Texture.cpp b/src/crepe/facade/Texture.cpp
new file mode 100644
index 0000000..b63403d
--- /dev/null
+++ b/src/crepe/facade/Texture.cpp
@@ -0,0 +1,28 @@
+#include "../util/Log.h"
+#include "facade/SDLContext.h"
+#include "manager/Mediator.h"
+
+#include "Resource.h"
+#include "Texture.h"
+#include "types.h"
+
+using namespace crepe;
+using namespace std;
+
+Texture::Texture(const Asset & src, Mediator & mediator) : Resource(src, mediator) {
+ dbg_trace();
+ SDLContext & ctx = mediator.sdl_context;
+ this->texture = ctx.texture_from_path(src.get_path());
+ this->size = ctx.get_size(*this);
+ this->aspect_ratio = static_cast<float>(this->size.x) / this->size.y;
+}
+
+Texture::~Texture() {
+ dbg_trace();
+ this->texture.reset();
+}
+
+const ivec2 & Texture::get_size() const noexcept { return this->size; }
+const float & Texture::get_ratio() const noexcept { return this->aspect_ratio; }
+
+SDL_Texture * Texture::get_img() const noexcept { return this->texture.get(); }
diff --git a/src/crepe/facade/Texture.h b/src/crepe/facade/Texture.h
new file mode 100644
index 0000000..cdacac4
--- /dev/null
+++ b/src/crepe/facade/Texture.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <SDL2/SDL_render.h>
+#include <memory>
+
+#include "../Resource.h"
+
+#include "types.h"
+
+namespace crepe {
+
+class Mediator;
+class Asset;
+
+/**
+ * \class Texture
+ * \brief Manages texture loading and properties.
+ *
+ * The Texture class is responsible for loading an image from a source and providing access to
+ * its dimensions. Textures can be used for rendering.
+ */
+class Texture : public Resource {
+
+public:
+ /**
+ * \brief Constructs a Texture from an Asset resource.
+ * \param src Asset with texture data to load.
+ * \param mediator use the SDLContext reference to load the image
+ */
+ Texture(const Asset & src, Mediator & mediator);
+
+ /**
+ * \brief Destroys the Texture instance
+ */
+ ~Texture();
+
+ /**
+ * \brief get width and height of image in pixels
+ * \return pixel size width and height
+ *
+ */
+ const ivec2 & get_size() const noexcept;
+
+ /**
+ * \brief aspect_ratio of image
+ * \return ratio
+ *
+ */
+ const float & get_ratio() const noexcept;
+
+ /**
+ * \brief get the image texture
+ * \return SDL_Texture
+ *
+ */
+ SDL_Texture * get_img() const noexcept;
+
+private:
+ //! The texture of the class from the library
+ std::unique_ptr<SDL_Texture, std::function<void(SDL_Texture *)>> texture;
+
+ // texture size in pixel
+ ivec2 size;
+
+ //! ratio of image
+ float aspect_ratio;
+};
+
+} // namespace crepe
diff --git a/src/crepe/manager/ComponentManager.cpp b/src/crepe/manager/ComponentManager.cpp
index df30d27..24ba0d7 100644
--- a/src/crepe/manager/ComponentManager.cpp
+++ b/src/crepe/manager/ComponentManager.cpp
@@ -53,7 +53,7 @@ GameObject ComponentManager::new_object(const string & name, const string & tag,
this->next_id++;
}
- GameObject object{*this, this->next_id, name, tag, position, rotation, scale};
+ GameObject object{this->mediator, this->next_id, name, tag, position, rotation, scale};
this->next_id++;
return object;
diff --git a/src/crepe/manager/ComponentManager.h b/src/crepe/manager/ComponentManager.h
index 94fd94f..dd7c154 100644
--- a/src/crepe/manager/ComponentManager.h
+++ b/src/crepe/manager/ComponentManager.h
@@ -143,7 +143,6 @@ public:
RefVector<T> get_components_by_tag(const std::string & tag) const;
struct SnapshotComponent {
- by_type<by_id_index<std::vector<std::unique_ptr<Component>>>> components;
Component component;
};
struct Snapshot {
diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h
index 35ac181..628154a 100644
--- a/src/crepe/manager/Mediator.h
+++ b/src/crepe/manager/Mediator.h
@@ -3,9 +3,7 @@
#include "../util/OptionalRef.h"
// TODO: remove these singletons:
-#include "../facade/SDLContext.h"
#include "EventManager.h"
-#include "api/LoopTimer.h"
namespace crepe {
@@ -13,6 +11,8 @@ class ComponentManager;
class SceneManager;
class SaveManager;
class ResourceManager;
+class SDLContext;
+class LoopTimer;
/**
* Struct to pass references to classes that would otherwise need to be singletons down to
@@ -27,13 +27,13 @@ class ResourceManager;
* \warning This class should never be directly accessible from the API
*/
struct Mediator {
+ OptionalRef<SDLContext> sdl_context;
OptionalRef<ComponentManager> component_manager;
OptionalRef<SceneManager> scene_manager;
OptionalRef<SaveManager> save_manager;
OptionalRef<EventManager> event_manager = EventManager::get_instance();
OptionalRef<ResourceManager> resource_manager;
- OptionalRef<SDLContext> sdl_context = SDLContext::get_instance();
- OptionalRef<LoopTimer> timer = LoopTimer::get_instance();
+ OptionalRef<LoopTimer> timer;
};
} // namespace crepe
diff --git a/src/crepe/manager/ResourceManager.cpp b/src/crepe/manager/ResourceManager.cpp
index 7c01808..a141a46 100644
--- a/src/crepe/manager/ResourceManager.cpp
+++ b/src/crepe/manager/ResourceManager.cpp
@@ -6,8 +6,8 @@ using namespace crepe;
using namespace std;
ResourceManager::ResourceManager(Mediator & mediator) : Manager(mediator) {
- mediator.resource_manager = *this;
dbg_trace();
+ mediator.resource_manager = *this;
}
ResourceManager::~ResourceManager() { dbg_trace(); }
diff --git a/src/crepe/manager/ResourceManager.hpp b/src/crepe/manager/ResourceManager.hpp
index 5167d71..cf5c949 100644
--- a/src/crepe/manager/ResourceManager.hpp
+++ b/src/crepe/manager/ResourceManager.hpp
@@ -13,7 +13,7 @@ T & ResourceManager::get(const Asset & asset) {
"cache must recieve a derivative class of Resource");
CacheEntry & entry = this->get_entry(asset);
- if (entry.resource == nullptr) entry.resource = make_unique<T>(asset);
+ if (entry.resource == nullptr) entry.resource = make_unique<T>(asset, this->mediator);
T * concrete_resource = dynamic_cast<T *>(entry.resource.get());
if (concrete_resource == nullptr)
diff --git a/src/crepe/manager/SaveManager.cpp b/src/crepe/manager/SaveManager.cpp
index 39b92d4..691ea2f 100644
--- a/src/crepe/manager/SaveManager.cpp
+++ b/src/crepe/manager/SaveManager.cpp
@@ -14,10 +14,8 @@ SaveManager::SaveManager(Mediator & mediator) : Manager(mediator) {
DB & SaveManager::get_db() {
if (this->db == nullptr) {
Config & cfg = Config::get_instance();
- this->db = {
- new DB(cfg.savemgr.location),
- [](void * db){ delete static_cast<DB *>(db); }
- };
+ this->db
+ = {new DB(cfg.savemgr.location), [](void * db) { delete static_cast<DB *>(db); }};
}
return *static_cast<DB *>(this->db.get());
}
diff --git a/src/crepe/manager/SaveManager.h b/src/crepe/manager/SaveManager.h
index 27e625c..61a978d 100644
--- a/src/crepe/manager/SaveManager.h
+++ b/src/crepe/manager/SaveManager.h
@@ -1,7 +1,7 @@
#pragma once
-#include <memory>
#include <functional>
+#include <memory>
#include "../ValueBroker.h"
@@ -95,9 +95,10 @@ private:
protected:
//! Create or return DB
virtual DB & get_db();
+
private:
//! Database
- std::unique_ptr<void, std::function<void(void*)>> db = nullptr;
+ std::unique_ptr<void, std::function<void(void *)>> db = nullptr;
};
} // namespace crepe
diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp
new file mode 100644
index 0000000..3c3fd93
--- /dev/null
+++ b/src/crepe/system/AISystem.cpp
@@ -0,0 +1,186 @@
+#include <algorithm>
+#include <cmath>
+
+#include "api/LoopTimer.h"
+#include "manager/ComponentManager.h"
+#include "manager/Mediator.h"
+
+#include "AISystem.h"
+
+using namespace crepe;
+
+void AISystem::fixed_update() {
+ const Mediator & mediator = this->mediator;
+ ComponentManager & mgr = mediator.component_manager;
+ LoopTimer & timer = mediator.timer;
+ RefVector<AI> ai_components = mgr.get_components_by_type<AI>();
+
+ //TODO: Use fixed loop dt (this is not available at master at the moment)
+ double dt = timer.get_delta_time();
+
+ // Loop through all AI components
+ for (AI & ai : ai_components) {
+ if (!ai.active) {
+ continue;
+ }
+
+ RefVector<Rigidbody> rigidbodies
+ = 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");
+ }
+ Rigidbody & rigidbody = rigidbodies.front().get();
+ if (!rigidbody.active) {
+ continue;
+ }
+ if (rigidbody.data.mass <= 0) {
+ throw std::runtime_error("Mass must be greater than 0");
+ }
+
+ // Calculate the force to apply to the entity
+ vec2 force = this->calculate(ai, rigidbody);
+ // Calculate the acceleration (using the above calculated force)
+ vec2 acceleration = force / rigidbody.data.mass;
+ // Finally, update Rigidbody's velocity
+ rigidbody.data.linear_velocity += acceleration * dt;
+ }
+}
+
+vec2 AISystem::calculate(AI & ai, const Rigidbody & rigidbody) {
+ const Mediator & mediator = this->mediator;
+ ComponentManager & mgr = mediator.component_manager;
+ RefVector<Transform> transforms = mgr.get_components_by_id<Transform>(ai.game_object_id);
+ Transform & transform = transforms.front().get();
+
+ vec2 force;
+
+ // Run all the behaviors that are on, and stop if the force gets too high
+ if (ai.on(AI::BehaviorTypeMask::FLEE)) {
+ vec2 force_to_add = this->flee(ai, rigidbody, transform);
+
+ if (!this->accumulate_force(ai, force, force_to_add)) {
+ return force;
+ }
+ }
+ if (ai.on(AI::BehaviorTypeMask::ARRIVE)) {
+ vec2 force_to_add = this->arrive(ai, rigidbody, transform);
+
+ if (!this->accumulate_force(ai, force, force_to_add)) {
+ return force;
+ }
+ }
+ if (ai.on(AI::BehaviorTypeMask::SEEK)) {
+ vec2 force_to_add = this->seek(ai, rigidbody, transform);
+
+ if (!this->accumulate_force(ai, force, force_to_add)) {
+ return force;
+ }
+ }
+ if (ai.on(AI::BehaviorTypeMask::PATH_FOLLOW)) {
+ vec2 force_to_add = this->path_follow(ai, rigidbody, transform);
+
+ if (!this->accumulate_force(ai, force, force_to_add)) {
+ return force;
+ }
+ }
+
+ return force;
+}
+
+bool AISystem::accumulate_force(const AI & ai, vec2 & running_total, vec2 & force_to_add) {
+ float magnitude = running_total.length();
+ float magnitude_remaining = ai.max_force - magnitude;
+
+ if (magnitude_remaining <= 0.0f) {
+ // If the force is already at/above the max force, return false
+ return false;
+ }
+
+ float magnitude_to_add = force_to_add.length();
+ if (magnitude_to_add < magnitude_remaining) {
+ // If the force to add is less than the remaining force, add it
+ running_total += force_to_add;
+ } else {
+ // If the force to add is greater than the remaining force, add a fraction of it
+ force_to_add.normalize();
+ running_total += force_to_add * magnitude_remaining;
+ }
+
+ return true;
+}
+
+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();
+ desired_velocity *= rigidbody.data.max_linear_velocity;
+
+ return desired_velocity - rigidbody.data.linear_velocity;
+}
+
+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};
+ }
+ desired_velocity.normalize();
+ desired_velocity *= rigidbody.data.max_linear_velocity;
+
+ return desired_velocity - rigidbody.data.linear_velocity;
+}
+
+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();
+ if (distance > 0.0f) {
+ if (ai.arrive_deceleration <= 0.0f) {
+ throw std::runtime_error("Deceleration rate must be greater than 0");
+ }
+
+ float speed = distance / ai.arrive_deceleration;
+ speed = std::min(speed, rigidbody.data.max_linear_velocity.length());
+ vec2 desired_velocity = to_target * (speed / distance);
+
+ return desired_velocity - rigidbody.data.linear_velocity;
+ }
+
+ return vec2{0, 0};
+}
+
+vec2 AISystem::path_follow(AI & ai, const Rigidbody & rigidbody, const Transform & transform) {
+ if (ai.path.empty()) {
+ return vec2{0, 0};
+ }
+
+ // Get the target node
+ vec2 target = ai.path.at(ai.path_index);
+ // Calculate the force to apply to the entity
+ vec2 to_target = target - transform.position;
+ if (to_target.length_squared() > ai.path_node_distance * ai.path_node_distance) {
+ // If the entity is not close enough to the target node, seek it
+ ai.seek_target = target;
+ ai.arrive_target = target;
+ } else {
+ // If the entity is close enough to the target node, move to the next node
+ ai.path_index++;
+ if (ai.path_index >= ai.path.size()) {
+ if (ai.path_loop) {
+ // If the path is looping, reset the path index
+ ai.path_index = 0;
+ } else {
+ // If the path is not looping, arrive at the last node
+ ai.path_index = ai.path.size() - 1;
+ return this->arrive(ai, rigidbody, transform);
+ }
+ }
+ }
+
+ // Seek the target node
+ return this->seek(ai, rigidbody, transform);
+}
diff --git a/src/crepe/system/AISystem.h b/src/crepe/system/AISystem.h
new file mode 100644
index 0000000..04807cf
--- /dev/null
+++ b/src/crepe/system/AISystem.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include "api/AI.h"
+#include "api/Rigidbody.h"
+
+#include "System.h"
+#include "api/Transform.h"
+#include "types.h"
+
+namespace crepe {
+
+/**
+ * \brief The AISystem is used to control the movement of entities using AI.
+ *
+ * The AISystem is used to control the movement of entities using AI. The AISystem can be used to
+ * implement different behaviors such as seeking, fleeing, arriving, and path following.
+ */
+class AISystem : public System {
+public:
+ using System::System;
+
+ //! Update the AI system
+ void fixed_update() override;
+
+private:
+ /**
+ * \brief Calculate the total force to apply to the entity
+ *
+ * \param ai The AI component
+ * \param rigidbody The Rigidbody component
+ */
+ vec2 calculate(AI & ai, const Rigidbody & rigidbody);
+ /**
+ * \brief Accumulate the force to apply to the entity
+ *
+ * \param ai The AI component
+ * \param running_total The running total of the force
+ * \param force_to_add The force to add
+ * \return true if the force was added, false otherwise
+ */
+ bool accumulate_force(const AI & ai, vec2 & running_total, vec2 & force_to_add);
+
+ /**
+ * \brief Calculate the seek force
+ *
+ * \param ai The AI component
+ * \param rigidbody The Rigidbody component
+ * \param transform The Transform component
+ * \return The seek force
+ */
+ vec2 seek(const AI & ai, const Rigidbody & rigidbody, const Transform & transform) const;
+ /**
+ * \brief Calculate the flee force
+ *
+ * \param ai The AI component
+ * \param rigidbody The Rigidbody component
+ * \param transform The Transform component
+ * \return The flee force
+ */
+ vec2 flee(const AI & ai, const Rigidbody & rigidbody, const Transform & transform) const;
+ /**
+ * \brief Calculate the arrive force
+ *
+ * \param ai The AI component
+ * \param rigidbody The Rigidbody component
+ * \param transform The Transform component
+ * \return The arrive force
+ */
+ vec2 arrive(const AI & ai, const Rigidbody & rigidbody, const Transform & transform) const;
+ /**
+ * \brief Calculate the path follow force
+ *
+ * \param ai The AI component
+ * \param rigidbody The Rigidbody component
+ * \param transform The Transform component
+ * \return The path follow force
+ */
+ vec2 path_follow(AI & ai, const Rigidbody & rigidbody, const Transform & transform);
+};
+
+} // namespace crepe
diff --git a/src/crepe/system/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp
index 8d6d8fa..02647f1 100644
--- a/src/crepe/system/AnimatorSystem.cpp
+++ b/src/crepe/system/AnimatorSystem.cpp
@@ -21,7 +21,7 @@ void AnimatorSystem::frame_update() {
int last_frame = ctx.row;
- int cycle_end = (ctx.cycle_end == -1) ? a.max_rows : ctx.cycle_end;
+ 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;
diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp
index 9b86069..d4e8b9f 100644
--- a/src/crepe/system/AudioSystem.cpp
+++ b/src/crepe/system/AudioSystem.cpp
@@ -30,8 +30,7 @@ void AudioSystem::diff_update(AudioSource & component, Sound & resource) {
context.stop(component.voice);
return;
}
- if (component.play_on_awake)
- component.oneshot_play = true;
+ if (component.play_on_awake) component.oneshot_play = true;
}
if (!component.active) return;
diff --git a/src/crepe/system/CMakeLists.txt b/src/crepe/system/CMakeLists.txt
index 1336114..3473876 100644
--- a/src/crepe/system/CMakeLists.txt
+++ b/src/crepe/system/CMakeLists.txt
@@ -10,6 +10,7 @@ target_sources(crepe PUBLIC
InputSystem.cpp
EventSystem.cpp
ReplaySystem.cpp
+ AISystem.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -22,4 +23,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
AnimatorSystem.h
InputSystem.h
EventSystem.h
+ AISystem.h
)
diff --git a/src/crepe/system/InputSystem.cpp b/src/crepe/system/InputSystem.cpp
index b31bd34..7796b47 100644
--- a/src/crepe/system/InputSystem.cpp
+++ b/src/crepe/system/InputSystem.cpp
@@ -1,6 +1,8 @@
#include "../api/Button.h"
#include "../manager/ComponentManager.h"
#include "../manager/EventManager.h"
+#include "facade/SDLContext.h"
+#include "util/Log.h"
#include "InputSystem.h"
@@ -9,7 +11,8 @@ using namespace crepe;
void InputSystem::fixed_update() {
ComponentManager & mgr = this->mediator.component_manager;
EventManager & event_mgr = this->mediator.event_manager;
- std::vector<SDLContext::EventData> event_list = SDLContext::get_instance().get_events();
+ SDLContext & context = this->mediator.sdl_context;
+ std::vector<SDLContext::EventData> event_list = context.get_events();
RefVector<Button> buttons = mgr.get_components_by_type<Button>();
RefVector<Camera> cameras = mgr.get_components_by_type<Camera>();
OptionalRef<Camera> curr_cam_ref;
diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp
index e147b9f..7e9dfc6 100644
--- a/src/crepe/system/RenderSystem.cpp
+++ b/src/crepe/system/RenderSystem.cpp
@@ -10,7 +10,9 @@
#include "../api/Sprite.h"
#include "../api/Transform.h"
#include "../facade/SDLContext.h"
+#include "../facade/Texture.h"
#include "../manager/ComponentManager.h"
+#include "../manager/ResourceManager.h"
#include "RenderSystem.h"
@@ -72,6 +74,8 @@ bool RenderSystem::render_particle(const Sprite & sprite, const SDLContext::Came
ComponentManager & mgr = this->mediator.component_manager;
SDLContext & ctx = this->mediator.sdl_context;
+ ResourceManager & resource_manager = this->mediator.resource_manager;
+ Texture & res = resource_manager.get<Texture>(sprite.source);
vector<reference_wrapper<ParticleEmitter>> emitters
= mgr.get_components_by_id<ParticleEmitter>(sprite.game_object_id);
@@ -88,6 +92,7 @@ bool RenderSystem::render_particle(const Sprite & sprite, const SDLContext::Came
ctx.draw(SDLContext::RenderContext{
.sprite = sprite,
+ .texture = res,
.cam = cam,
.pos = p.position,
.angle = p.angle,
@@ -100,8 +105,12 @@ bool RenderSystem::render_particle(const Sprite & sprite, const SDLContext::Came
void RenderSystem::render_normal(const Sprite & sprite, const SDLContext::CameraValues & cam,
const Transform & tm) {
SDLContext & ctx = this->mediator.sdl_context;
+ ResourceManager & resource_manager = this->mediator.resource_manager;
+ const Texture & res = resource_manager.get<Texture>(sprite.source);
+
ctx.draw(SDLContext::RenderContext{
.sprite = sprite,
+ .texture = res,
.cam = cam,
.pos = tm.position,
.angle = tm.rotation,
diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp
new file mode 100644
index 0000000..f4efc9f
--- /dev/null
+++ b/src/example/AITest.cpp
@@ -0,0 +1,86 @@
+#include <crepe/api/AI.h>
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/Camera.h>
+#include <crepe/api/Color.h>
+#include <crepe/api/GameObject.h>
+#include <crepe/api/LoopManager.h>
+#include <crepe/api/Rigidbody.h>
+#include <crepe/api/Scene.h>
+#include <crepe/api/Script.h>
+#include <crepe/api/Sprite.h>
+#include <crepe/api/Texture.h>
+#include <crepe/manager/Mediator.h>
+#include <crepe/types.h>
+
+using namespace crepe;
+using namespace std;
+
+class Script1 : public Script {
+ bool shutdown(const ShutDownEvent & event) {
+ // Very dirty way of shutting down the game
+ throw "ShutDownEvent";
+ return true;
+ }
+
+ bool mousemove(const MouseMoveEvent & event) {
+ /*RefVector<AI> aivec = this->get_components<AI>();
+ AI & ai = aivec.front().get();
+ ai.flee_target
+ = vec2{static_cast<float>(event.mouse_x), static_cast<float>(event.mouse_y)};*/
+ return true;
+ }
+
+ void init() {
+ subscribe<ShutDownEvent>(
+ [this](const ShutDownEvent & ev) -> bool { return this->shutdown(ev); });
+ subscribe<MouseMoveEvent>(
+ [this](const MouseMoveEvent & ev) -> bool { return this->mousemove(ev); });
+ }
+};
+
+class Scene1 : public Scene {
+public:
+ void load_scene() override {
+ Mediator & mediator = this->mediator;
+ ComponentManager & mgr = mediator.component_manager;
+
+ GameObject game_object1 = mgr.new_object("", "", vec2{0, 0}, 0, 1);
+ GameObject game_object2 = mgr.new_object("", "", vec2{0, 0}, 0, 1);
+
+ Texture img = Texture("asset/texture/test_ap43.png");
+ game_object1.add_component<Sprite>(img, Sprite::Data{
+ .color = Color::MAGENTA,
+ .flip = Sprite::FlipSettings{false, false},
+ .sorting_in_layer = 1,
+ .order_in_layer = 1,
+ .size = {0, 195},
+ });
+ AI & ai = game_object1.add_component<AI>(3000);
+ // ai.arrive_on();
+ // ai.flee_on();
+ ai.path_follow_on();
+ ai.make_oval_path(500, 1000, {0, -1000}, 1.5708, true);
+ ai.make_oval_path(1000, 500, {0, 500}, 4.7124, false);
+ game_object1.add_component<Rigidbody>(Rigidbody::Data{
+ .mass = 0.1f,
+ .max_linear_velocity = {40, 40},
+ });
+ game_object1.add_component<BehaviorScript>().set_script<Script1>();
+
+ game_object2.add_component<Camera>(ivec2{1080, 720}, vec2{5000, 5000},
+ Camera::Data{
+ .bg_color = Color::WHITE,
+ .zoom = 1,
+ });
+ }
+
+ string get_name() const override { return "Scene1"; }
+};
+
+int main() {
+ LoopManager engine;
+ engine.add_scene<Scene1>();
+ engine.start();
+
+ return 0;
+}
diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt
index 791001e..1bc31d8 100644
--- a/src/example/CMakeLists.txt
+++ b/src/example/CMakeLists.txt
@@ -20,3 +20,4 @@ add_example(rendering_particle)
add_example(game)
add_example(button)
add_example(replay)
+add_example(AITest)
diff --git a/src/example/rendering_particle.cpp b/src/example/rendering_particle.cpp
index 29d475d..bd4ef95 100644
--- a/src/example/rendering_particle.cpp
+++ b/src/example/rendering_particle.cpp
@@ -1,3 +1,4 @@
+#include "api/Asset.h"
#include <crepe/Component.h>
#include <crepe/api/Animator.h>
#include <crepe/api/Camera.h>
@@ -7,11 +8,11 @@
#include <crepe/api/ParticleEmitter.h>
#include <crepe/api/Rigidbody.h>
#include <crepe/api/Sprite.h>
-#include <crepe/api/Texture.h>
#include <crepe/api/Transform.h>
#include <crepe/manager/ComponentManager.h>
#include <crepe/manager/Mediator.h>
#include <crepe/types.h>
+#include <iostream>
using namespace crepe;
using namespace std;
@@ -41,13 +42,15 @@ using namespace std;
class TestScene : public Scene {
public:
void load_scene() {
+
+ cout << "TestScene" << endl;
Mediator & mediator = this->mediator;
ComponentManager & mgr = mediator.component_manager;
GameObject game_object = mgr.new_object("", "", vec2{0, 0}, 0, 1);
Color color(255, 255, 255, 255);
- auto img = Texture("asset/spritesheet/pokemon_spritesheet.png");
+ Asset img{"asset/spritesheet/spritesheet_test.png"};
Sprite & test_sprite = game_object.add_component<Sprite>(
img, Sprite::Data{
@@ -57,16 +60,11 @@ public:
.order_in_layer = 2,
.size = {0, 100},
.angle_offset = 0,
- .position_offset = {100, 0},
+ .position_offset = {0, 0},
});
- auto & anim = game_object.add_component<Animator>(test_sprite, 4, 4,
- Animator::Data{
- .fps = 1,
- .looping = false,
- });
- anim.set_anim(2);
- anim.active = false;
+ //auto & anim = game_object.add_component<Animator>(test_sprite,ivec2{32, 64}, uvec2{4,1}, Animator::Data{});
+ //anim.set_anim(0);
auto & cam = game_object.add_component<Camera>(ivec2{1280, 720}, vec2{400, 400},
Camera::Data{
diff --git a/src/example/replay.cpp b/src/example/replay.cpp
index a3c7fba..0c4f9b3 100644
--- a/src/example/replay.cpp
+++ b/src/example/replay.cpp
@@ -9,7 +9,6 @@
#include <crepe/api/Scene.h>
#include <crepe/api/Script.h>
#include <crepe/api/Sprite.h>
-#include <crepe/api/Texture.h>
#include <crepe/api/Transform.h>
#include <crepe/manager/ComponentManager.h>
#include <crepe/manager/Mediator.h>
@@ -41,19 +40,19 @@ class Timeline : public Script {
switch (i++) {
default: break;
case 10:
- mgr.record_start();
+ // mgr.record_start();
Log::logf("start");
break;
case 60:
- this->recording = mgr.record_end();
+ // this->recording = mgr.record_end();
Log::logf("stop");
break;
case 70:
- mgr.play(this->recording);
+ // mgr.play(this->recording);
Log::logf("play");
break;
case 71:
- mgr.release(this->recording);
+ // mgr.release(this->recording);
Log::logf("end");
break;
case 72:
@@ -78,10 +77,12 @@ public:
});
GameObject square = mgr.new_object("square");
- Texture texture{"asset/texture/square.png"};
- square.add_component<Sprite>(texture, Sprite::Data{
- .size = { 0.5, 0.5 },
- });
+ square.add_component<Sprite>(
+ Asset{"asset/texture/square.png"},
+ Sprite::Data{
+ .size = { 0.5, 0.5 },
+ }
+ );
square.add_component<BehaviorScript>().set_script<AnimationScript>();
GameObject scapegoat = mgr.new_object("");
diff --git a/src/test/InputTest.cpp b/src/test/InputTest.cpp
index 8c42c43..770d9b4 100644
--- a/src/test/InputTest.cpp
+++ b/src/test/InputTest.cpp
@@ -24,6 +24,7 @@ class InputTest : public ::testing::Test {
public:
Mediator mediator;
ComponentManager mgr{mediator};
+ SDLContext sdl_context{mediator};
InputSystem input_system{mediator};
diff --git a/src/test/ParticleTest.cpp b/src/test/ParticleTest.cpp
index c2a3c14..9ddb850 100644
--- a/src/test/ParticleTest.cpp
+++ b/src/test/ParticleTest.cpp
@@ -1,10 +1,10 @@
+#include "api/Asset.h"
#include <crepe/Particle.h>
#include <crepe/api/Config.h>
#include <crepe/api/GameObject.h>
#include <crepe/api/ParticleEmitter.h>
#include <crepe/api/Rigidbody.h>
#include <crepe/api/Sprite.h>
-#include <crepe/api/Texture.h>
#include <crepe/api/Transform.h>
#include <crepe/manager/ComponentManager.h>
#include <crepe/system/ParticleSystem.h>
@@ -30,7 +30,7 @@ public:
GameObject game_object = mgr.new_object("", "", vec2{0, 0}, 0, 0);
Color color(0, 0, 0, 0);
- auto s1 = Texture("asset/texture/img.png");
+ auto s1 = Asset("asset/texture/img.png");
Sprite & test_sprite = game_object.add_component<Sprite>(
s1, Sprite::Data{
.color = color,
diff --git a/src/test/Profiling.cpp b/src/test/Profiling.cpp
index 3f48ced..2c6deba 100644
--- a/src/test/Profiling.cpp
+++ b/src/test/Profiling.cpp
@@ -1,9 +1,11 @@
-#include "manager/Mediator.h"
-#include "system/ParticleSystem.h"
-#include "system/PhysicsSystem.h"
-#include "system/RenderSystem.h"
#include <chrono>
#include <cmath>
+#include <crepe/api/Asset.h>
+#include <crepe/manager/Mediator.h>
+#include <crepe/manager/ResourceManager.h>
+#include <crepe/system/ParticleSystem.h>
+#include <crepe/system/PhysicsSystem.h>
+#include <crepe/system/RenderSystem.h>
#include <gtest/gtest.h>
#define private public
@@ -54,6 +56,8 @@ public:
const std::chrono::microseconds duration = 16000us;
Mediator m;
+ SDLContext sdl_context{m};
+ ResourceManager resman{m};
ComponentManager mgr{m};
// Add system used for profling tests
CollisionSystem collision_sys{m};
@@ -167,15 +171,15 @@ TEST_F(DISABLED_ProfilingTest, Profiling_2) {
gameobject.add_component<BoxCollider>(vec2{0, 0}, vec2{1, 1});
gameobject.add_component<BehaviorScript>().set_script<TestScript>();
- auto img = Texture("asset/texture/square.png");
Sprite & test_sprite = gameobject.add_component<Sprite>(
- img, Sprite::Data{
- .color = {0, 0, 0, 0},
- .flip = {.flip_x = false, .flip_y = false},
- .sorting_in_layer = 1,
- .order_in_layer = 1,
- .size = {.y = 500},
- });
+ Asset{"asset/texture/square.png"},
+ Sprite::Data{
+ .color = {0, 0, 0, 0},
+ .flip = {.flip_x = false, .flip_y = false},
+ .sorting_in_layer = 1,
+ .order_in_layer = 1,
+ .size = {.y = 500},
+ });
}
this->game_object_count++;
@@ -205,15 +209,15 @@ TEST_F(DISABLED_ProfilingTest, Profiling_3) {
});
gameobject.add_component<BoxCollider>(vec2{0, 0}, vec2{1, 1});
gameobject.add_component<BehaviorScript>().set_script<TestScript>();
- auto img = Texture("asset/texture/square.png");
Sprite & test_sprite = gameobject.add_component<Sprite>(
- img, Sprite::Data{
- .color = {0, 0, 0, 0},
- .flip = {.flip_x = false, .flip_y = false},
- .sorting_in_layer = 1,
- .order_in_layer = 1,
- .size = {.y = 500},
- });
+ Asset{"asset/texture/square.png"},
+ Sprite::Data{
+ .color = {0, 0, 0, 0},
+ .flip = {.flip_x = false, .flip_y = false},
+ .sorting_in_layer = 1,
+ .order_in_layer = 1,
+ .size = {.y = 500},
+ });
auto & test = gameobject.add_component<ParticleEmitter>(ParticleEmitter::Data{
.max_particles = 10,
.emission_rate = 100,
diff --git a/src/test/RenderSystemTest.cpp b/src/test/RenderSystemTest.cpp
index b2c54b9..689a6d4 100644
--- a/src/test/RenderSystemTest.cpp
+++ b/src/test/RenderSystemTest.cpp
@@ -1,3 +1,6 @@
+#include "api/Asset.h"
+#include "facade/SDLContext.h"
+#include "manager/ResourceManager.h"
#include "types.h"
#include <functional>
#include <gtest/gtest.h>
@@ -11,7 +14,6 @@
#include <crepe/api/Color.h>
#include <crepe/api/GameObject.h>
#include <crepe/api/Sprite.h>
-#include <crepe/api/Texture.h>
#include <crepe/manager/ComponentManager.h>
#include <crepe/system/RenderSystem.h>
@@ -25,6 +27,8 @@ class RenderSystemTest : public Test {
public:
ComponentManager mgr{m};
+ SDLContext ctx{m};
+ ResourceManager resource_manager{m};
RenderSystem sys{m};
GameObject entity1 = this->mgr.new_object("name");
GameObject entity2 = this->mgr.new_object("name");
@@ -32,10 +36,10 @@ public:
GameObject entity4 = this->mgr.new_object("name");
void SetUp() override {
- auto s1 = Texture("asset/texture/img.png");
- auto s2 = Texture("asset/texture/img.png");
- auto s3 = Texture("asset/texture/img.png");
- auto s4 = Texture("asset/texture/img.png");
+ auto s1 = Asset("asset/texture/img.png");
+ auto s2 = Asset("asset/texture/img.png");
+ auto s3 = Asset("asset/texture/img.png");
+ auto s4 = Asset("asset/texture/img.png");
auto & sprite1
= entity1.add_component<Sprite>(s1, Sprite::Data{
.color = Color(0, 0, 0, 0),
@@ -45,7 +49,6 @@ public:
.size = {10, 10},
});
- ASSERT_NE(sprite1.texture.texture.get(), nullptr);
EXPECT_EQ(sprite1.data.order_in_layer, 5);
EXPECT_EQ(sprite1.data.sorting_in_layer, 5);
auto & sprite2
@@ -55,7 +58,6 @@ public:
.sorting_in_layer = 2,
.order_in_layer = 1,
});
- ASSERT_NE(sprite2.texture.texture.get(), nullptr);
EXPECT_EQ(sprite2.data.sorting_in_layer, 2);
EXPECT_EQ(sprite2.data.order_in_layer, 1);
@@ -66,7 +68,6 @@ public:
.sorting_in_layer = 1,
.order_in_layer = 2,
});
- ASSERT_NE(sprite3.texture.texture.get(), nullptr);
EXPECT_EQ(sprite3.data.sorting_in_layer, 1);
EXPECT_EQ(sprite3.data.order_in_layer, 2);
@@ -77,27 +78,12 @@ public:
.sorting_in_layer = 1,
.order_in_layer = 1,
});
- ASSERT_NE(sprite4.texture.texture.get(), nullptr);
EXPECT_EQ(sprite4.data.sorting_in_layer, 1);
EXPECT_EQ(sprite4.data.order_in_layer, 1);
}
};
-TEST_F(RenderSystemTest, expected_throws) {
- GameObject entity1 = this->mgr.new_object("NAME");
-
- // no texture img
- EXPECT_ANY_THROW({
- auto test = Texture("");
- auto & sprite1 = entity1.add_component<Sprite>(
- test, Sprite::Data{
- .color = Color(0, 0, 0, 0),
- .flip = Sprite::FlipSettings{false, false},
- .sorting_in_layer = 1,
- .order_in_layer = 1,
- });
- });
-
+TEST_F(RenderSystemTest, NoCamera) {
// No camera
EXPECT_ANY_THROW({ this->sys.frame_update(); });
}
@@ -185,7 +171,7 @@ TEST_F(RenderSystemTest, Color) {
Camera::Data{.bg_color = Color::WHITE, .zoom = 1.0f});
auto & sprite = this->mgr.get_components_by_id<Sprite>(entity1.id).front().get();
- ASSERT_NE(sprite.texture.texture.get(), nullptr);
+ //ASSERT_NE(sprite.texture.texture.get(), nullptr);
sprite.data.color = Color::GREEN;
EXPECT_EQ(sprite.data.color.r, Color::GREEN.r);
diff --git a/src/test/ResourceManagerTest.cpp b/src/test/ResourceManagerTest.cpp
index 44a5921..965eeab 100644
--- a/src/test/ResourceManagerTest.cpp
+++ b/src/test/ResourceManagerTest.cpp
@@ -1,3 +1,4 @@
+#include "manager/Mediator.h"
#include <gtest/gtest.h>
#define private public
@@ -30,7 +31,9 @@ public:
public:
const unsigned instance;
- TestResource(const Asset & src) : Resource(src), instance(this->instances++) {}
+ TestResource(const Asset & src, Mediator & mediator)
+ : Resource(src, mediator),
+ instance(this->instances++) {}
~TestResource() { this->instances--; }
bool operator==(const TestResource & other) const {
return this->instance == other.instance;
diff --git a/src/test/Vector2Test.cpp b/src/test/Vector2Test.cpp
index 17bca41..1e21af9 100644
--- a/src/test/Vector2Test.cpp
+++ b/src/test/Vector2Test.cpp
@@ -382,3 +382,151 @@ TEST_F(Vector2Test, NotEquals) {
EXPECT_FALSE(long_vec1 != long_vec1);
EXPECT_TRUE(long_vec1 != long_vec2);
}
+
+TEST_F(Vector2Test, Truncate) {
+ Vector2<int> vec = {3, 4};
+ vec.truncate(3);
+ EXPECT_EQ(vec.x, 0);
+ EXPECT_EQ(vec.y, 0);
+
+ Vector2<double> vec2 = {3.0, 4.0};
+ vec2.truncate(3.0);
+ EXPECT_FLOAT_EQ(vec2.x, 1.8);
+ EXPECT_FLOAT_EQ(vec2.y, 2.4);
+
+ Vector2<long> vec3 = {3, 4};
+ vec3.truncate(3);
+ EXPECT_EQ(vec3.x, 0);
+ EXPECT_EQ(vec3.y, 0);
+
+ Vector2<float> vec4 = {3.0f, 4.0f};
+ vec4.truncate(3.0f);
+ EXPECT_FLOAT_EQ(vec4.x, 1.8f);
+ EXPECT_FLOAT_EQ(vec4.y, 2.4f);
+}
+
+TEST_F(Vector2Test, Normalize) {
+ Vector2<int> vec = {3, 4};
+ vec.normalize();
+ EXPECT_EQ(vec.x, 0);
+ EXPECT_EQ(vec.y, 0);
+
+ Vector2<double> vec2 = {3.0, 4.0};
+ vec2.normalize();
+ EXPECT_FLOAT_EQ(vec2.x, 0.6);
+ EXPECT_FLOAT_EQ(vec2.y, 0.8);
+
+ Vector2<long> vec3 = {3, 4};
+ vec3.normalize();
+ EXPECT_EQ(vec3.x, 0);
+ EXPECT_EQ(vec3.y, 0);
+
+ Vector2<float> vec4 = {3.0f, 4.0f};
+ vec4.normalize();
+ EXPECT_FLOAT_EQ(vec4.x, 0.6f);
+ EXPECT_FLOAT_EQ(vec4.y, 0.8f);
+}
+
+TEST_F(Vector2Test, Length) {
+ Vector2<int> vec = {3, 4};
+ EXPECT_EQ(vec.length(), 5);
+
+ Vector2<double> vec2 = {3.0, 4.0};
+ EXPECT_FLOAT_EQ(vec2.length(), 5.0);
+
+ Vector2<long> vec3 = {3, 4};
+ EXPECT_EQ(vec3.length(), 5);
+
+ Vector2<float> vec4 = {3.0f, 4.0f};
+ EXPECT_FLOAT_EQ(vec4.length(), 5.0f);
+}
+
+TEST_F(Vector2Test, LengthSquared) {
+ Vector2<int> vec = {3, 4};
+ EXPECT_EQ(vec.length_squared(), 25);
+
+ Vector2<double> vec2 = {3.0, 4.0};
+ EXPECT_FLOAT_EQ(vec2.length_squared(), 25.0);
+
+ Vector2<long> vec3 = {3, 4};
+ EXPECT_EQ(vec3.length_squared(), 25);
+
+ Vector2<float> vec4 = {3.0f, 4.0f};
+ EXPECT_FLOAT_EQ(vec4.length_squared(), 25.0f);
+}
+
+TEST_F(Vector2Test, Dot) {
+ Vector2<int> vec1 = {3, 4};
+ Vector2<int> vec2 = {5, 6};
+ EXPECT_EQ(vec1.dot(vec2), 39);
+
+ Vector2<double> vec3 = {3.0, 4.0};
+ Vector2<double> vec4 = {5.0, 6.0};
+ EXPECT_FLOAT_EQ(vec3.dot(vec4), 39.0);
+
+ Vector2<long> vec5 = {3, 4};
+ Vector2<long> vec6 = {5, 6};
+ EXPECT_EQ(vec5.dot(vec6), 39);
+
+ Vector2<float> vec7 = {3.0f, 4.0f};
+ Vector2<float> vec8 = {5.0f, 6.0f};
+ EXPECT_FLOAT_EQ(vec7.dot(vec8), 39.0f);
+}
+
+TEST_F(Vector2Test, Distance) {
+ Vector2<int> vec1 = {1, 1};
+ Vector2<int> vec2 = {4, 5};
+ EXPECT_EQ(vec1.distance(vec2), 5);
+
+ Vector2<double> vec3 = {1.0, 1.0};
+ Vector2<double> vec4 = {4.0, 5.0};
+ EXPECT_FLOAT_EQ(vec3.distance(vec4), 5.0);
+
+ Vector2<long> vec5 = {1, 1};
+ Vector2<long> vec6 = {4, 5};
+ EXPECT_EQ(vec5.distance(vec6), 5);
+
+ Vector2<float> vec7 = {1.0f, 1.0f};
+ Vector2<float> vec8 = {4.0f, 5.0f};
+ EXPECT_FLOAT_EQ(vec7.distance(vec8), 5.0f);
+}
+
+TEST_F(Vector2Test, DistanceSquared) {
+ Vector2<int> vec1 = {3, 4};
+ Vector2<int> vec2 = {5, 6};
+ EXPECT_EQ(vec1.distance_squared(vec2), 8);
+
+ Vector2<double> vec3 = {3.0, 4.0};
+ Vector2<double> vec4 = {5.0, 6.0};
+ EXPECT_FLOAT_EQ(vec3.distance_squared(vec4), 8.0);
+
+ Vector2<long> vec5 = {3, 4};
+ Vector2<long> vec6 = {5, 6};
+ EXPECT_EQ(vec5.distance_squared(vec6), 8);
+
+ Vector2<float> vec7 = {3.0f, 4.0f};
+ Vector2<float> vec8 = {5.0f, 6.0f};
+ EXPECT_FLOAT_EQ(vec7.distance_squared(vec8), 8.0f);
+}
+
+TEST_F(Vector2Test, Perpendicular) {
+ Vector2<int> vec = {3, 4};
+ Vector2<int> result = vec.perpendicular();
+ EXPECT_EQ(result.x, -4);
+ EXPECT_EQ(result.y, 3);
+
+ Vector2<double> vec2 = {3.0, 4.0};
+ Vector2<double> result2 = vec2.perpendicular();
+ EXPECT_FLOAT_EQ(result2.x, -4.0);
+ EXPECT_FLOAT_EQ(result2.y, 3.0);
+
+ Vector2<long> vec3 = {3, 4};
+ Vector2<long> result3 = vec3.perpendicular();
+ EXPECT_EQ(result3.x, -4);
+ EXPECT_EQ(result3.y, 3);
+
+ Vector2<float> vec4 = {3.0f, 4.0f};
+ Vector2<float> result4 = vec4.perpendicular();
+ EXPECT_FLOAT_EQ(result4.x, -4.0f);
+ EXPECT_FLOAT_EQ(result4.y, 3.0f);
+}