diff options
author | Loek Le Blansch <loek@pipeframe.xyz> | 2024-11-12 22:43:32 +0100 |
---|---|---|
committer | Loek Le Blansch <loek@pipeframe.xyz> | 2024-11-12 22:43:32 +0100 |
commit | 3e94ecb3dac5003a3d58210ed1a4d1f1cb2083d1 (patch) | |
tree | 67c3e1c122652ae09e58e7de49db668e252c4730 | |
parent | f2509e89c02894ebd3ad992324eb300103621d26 (diff) |
add script unit tests + major refactoring
50 files changed, 338 insertions, 161 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e4922df..445a8b2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -38,6 +38,5 @@ install( target_link_libraries(test_main PRIVATE gtest - PRIVATE gtest_main PUBLIC crepe ) diff --git a/src/crepe/Asset.cpp b/src/crepe/Asset.cpp index 8a2a11c..3d4df53 100644 --- a/src/crepe/Asset.cpp +++ b/src/crepe/Asset.cpp @@ -1,16 +1,20 @@ #include <filesystem> #include "Asset.h" +#include "Exception.h" using namespace crepe; +using namespace std; -Asset::Asset(const std::string & src) { - // FIXME: restore this - // this->src = std::filesystem::canonical(src); - this->src = src; - this->file = std::ifstream(this->src, std::ios::in | std::ios::binary); +Asset::Asset(const string & src) : src(src) { + try { + this->src = filesystem::canonical(src); + } catch (filesystem::filesystem_error & e) { + throw Exception("Asset error: %s", e.what()); + } + this->file = ifstream(this->src, ios::in | ios::binary); } -const std::istream & Asset::read() { return this->file; } +const istream & Asset::read() { return this->file; } -const char * Asset::canonical() { return this->src.c_str(); } +const char * Asset::canonical() const { return this->src.c_str(); } diff --git a/src/crepe/Asset.h b/src/crepe/Asset.h index 0cb5834..d4e4ba1 100644 --- a/src/crepe/Asset.h +++ b/src/crepe/Asset.h @@ -23,7 +23,7 @@ public: //! Get an input stream to the contents of this resource const std::istream & read(); //! Get the canonical path to this resource - const char * canonical(); + const char * canonical() const; private: std::string src; diff --git a/src/crepe/Collider.cpp b/src/crepe/Collider.cpp index bbec488..b408609 100644 --- a/src/crepe/Collider.cpp +++ b/src/crepe/Collider.cpp @@ -2,4 +2,3 @@ using namespace crepe; -Collider::Collider(game_object_id_t id) : Component(id) {} diff --git a/src/crepe/Collider.h b/src/crepe/Collider.h index 827f83d..a1e9095 100644 --- a/src/crepe/Collider.h +++ b/src/crepe/Collider.h @@ -6,7 +6,7 @@ namespace crepe { class Collider : public Component { public: - Collider(game_object_id_t id); + using Component::Component; int size; }; diff --git a/src/crepe/Component.cpp b/src/crepe/Component.cpp index 73c2d07..c133739 100644 --- a/src/crepe/Component.cpp +++ b/src/crepe/Component.cpp @@ -1,6 +1,6 @@ #include "Component.h" -#include "types.h" using namespace crepe; -Component::Component(game_object_id_t id) : game_object_id(id) {} +Component::Component(const Data & data) : data(data) {} + diff --git a/src/crepe/Component.h b/src/crepe/Component.h index 0fe60b2..c6d72df 100644 --- a/src/crepe/Component.h +++ b/src/crepe/Component.h @@ -2,8 +2,6 @@ #include "types.h" -#include <cstdint> - namespace crepe { class ComponentManager; @@ -15,13 +13,21 @@ class ComponentManager; * interface for all components. */ class Component { +public: + struct Data { + //! The ID of the GameObject this component belongs to + const game_object_id_t id; + //! The manager of this component + ComponentManager & component_manager; + }; + protected: - //! Only the ComponentManager can create components - friend class crepe::ComponentManager; /** - * \param id The id of the GameObject this component belongs to + * \param base Data */ - Component(game_object_id_t id); + Component(const Data & base); + //! Only the ComponentManager can create components + friend class crepe::ComponentManager; public: virtual ~Component() = default; @@ -37,8 +43,7 @@ public: virtual int get_instances_max() const { return -1; } public: - //! The id of the GameObject this component belongs to - const game_object_id_t game_object_id; + Data data; //! Whether the component is active bool active = true; }; diff --git a/src/crepe/ComponentManager.cpp b/src/crepe/ComponentManager.cpp index 85149c8..f6acc1a 100644 --- a/src/crepe/ComponentManager.cpp +++ b/src/crepe/ComponentManager.cpp @@ -1,13 +1,10 @@ +#include "api/GameObject.h" #include "util/log.h" #include "ComponentManager.h" using namespace crepe; - -ComponentManager & ComponentManager::get_instance() { - static ComponentManager instance; - return instance; -} +using namespace std; void ComponentManager::delete_all_components_of_id(game_object_id_t id) { // Loop through all the types (in the unordered_map<>) @@ -26,5 +23,12 @@ void ComponentManager::delete_all_components() { } ComponentManager::ComponentManager() { dbg_trace(); } - ComponentManager::~ComponentManager() { dbg_trace(); } + +GameObject & ComponentManager::new_object(const string & name, const string & tag, const Vector2 & position, double rotation, double scale) { + GameObject * object = new GameObject(*this, this->next_id, name, tag, position, rotation, scale); + this->objects.push_front(unique_ptr<GameObject>(object)); + this->next_id++; + return *object; +} + diff --git a/src/crepe/ComponentManager.h b/src/crepe/ComponentManager.h index c8c196c..e37bc4a 100644 --- a/src/crepe/ComponentManager.h +++ b/src/crepe/ComponentManager.h @@ -1,15 +1,18 @@ #pragma once -#include <cstdint> #include <memory> #include <typeindex> #include <unordered_map> #include <vector> +#include <forward_list> #include "Component.h" +#include "api/Vector2.h" namespace crepe { +class GameObject; + /** * \brief Manages all components * @@ -18,18 +21,10 @@ namespace crepe { */ class ComponentManager { public: - /** - * \brief Get the instance of the ComponentManager - * - * \return The instance of the ComponentManager - */ - static ComponentManager & get_instance(); - ComponentManager(const ComponentManager &) = delete; - ComponentManager(ComponentManager &&) = delete; - ComponentManager & operator=(const ComponentManager &) = delete; - ComponentManager & operator=(ComponentManager &&) = delete; - ~ComponentManager(); + ComponentManager(); // dbg_trace + ~ComponentManager(); // dbg_trace +public: /** * \brief Add a component to the ComponentManager * @@ -100,8 +95,8 @@ public: template <typename T> std::vector<std::reference_wrapper<T>> get_components_by_type() const; -private: - ComponentManager(); + // TODO: doxygen + GameObject & new_object(const std::string & name, const std::string & tag = "", const Vector2 & position = { 0, 0 }, double rotation = 0, double scale = 0); private: /** @@ -118,6 +113,10 @@ private: std::unordered_map<std::type_index, std::vector<std::vector<std::unique_ptr<Component>>>> components; + + //! ID of next GameObject + game_object_id_t next_id = 0; + std::forward_list<std::unique_ptr<GameObject>> objects; }; } // namespace crepe diff --git a/src/crepe/ComponentManager.hpp b/src/crepe/ComponentManager.hpp index 98efb49..89a8536 100644 --- a/src/crepe/ComponentManager.hpp +++ b/src/crepe/ComponentManager.hpp @@ -31,7 +31,10 @@ T & ComponentManager::add_component(game_object_id_t id, Args &&... args) { // Create a new component of type T (arguments directly forwarded). The // constructor must be called by ComponentManager. - T * instance_ptr = new T(id, forward<Args>(args)...); + T * instance_ptr = new T(Component::Data { + .id = id, + .component_manager = *this, + }, forward<Args>(args)...); if (instance_ptr == nullptr) throw std::bad_alloc(); T & instance_ref = *instance_ptr; diff --git a/src/crepe/Resource.h b/src/crepe/Resource.h new file mode 100644 index 0000000..dcf3dbd --- /dev/null +++ b/src/crepe/Resource.h @@ -0,0 +1,33 @@ +#pragma once + +#include <memory> + +namespace crepe { + +class ResourceManager; +class Asset; + +/** + * Resource is an interface class used to represent a (deserialized) game + * resource (e.g. textures, sounds). + */ +class Resource { +private: + /** + * \brief Prototype pattern clone function. + * + * \param src Source file of new resource (abstraction for file saved on + * disk) + * + * \returns New instance of concrete resource + */ + virtual std::unique_ptr<Resource> clone(const Asset & src) const = 0; + /** + * The resource manager uses \c clone to create new instances of the concrete + * resource class. This may be used to inherit references to classes that + * would otherwise need to be implemented as singletons. + */ + friend class ResourceManager; +}; + +} // namespace crepe diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp index 58fee2a..ad60981 100644 --- a/src/crepe/api/Animator.cpp +++ b/src/crepe/api/Animator.cpp @@ -9,8 +9,8 @@ using namespace crepe; -Animator::Animator(uint32_t id, Sprite & ss, int row, int col, int col_animator) - : Component(id), +Animator::Animator(const Component::Data & data, Sprite & ss, int row, int col, int col_animator) + : Component(data), spritesheet(ss), row(row), col(col) { diff --git a/src/crepe/api/Animator.h b/src/crepe/api/Animator.h index def0240..f66dc1a 100644 --- a/src/crepe/api/Animator.h +++ b/src/crepe/api/Animator.h @@ -6,6 +6,7 @@ #include "Sprite.h" namespace crepe { + class AnimatorSystem; class SDLContext; @@ -35,7 +36,7 @@ public: * * This constructor sets up the Animator with the given parameters, and initializes the animation system. */ - Animator(uint32_t id, Sprite & spritesheet, int row, int col, + Animator(const Component::Data & data, Sprite & spritesheet, int row, int col, int col_animate); ~Animator(); // dbg_trace diff --git a/src/crepe/api/BehaviorScript.cpp b/src/crepe/api/BehaviorScript.cpp index e69de29..ce1cfde 100644 --- a/src/crepe/api/BehaviorScript.cpp +++ b/src/crepe/api/BehaviorScript.cpp @@ -0,0 +1,4 @@ +#include "BehaviorScript.h" + +using namespace crepe; + diff --git a/src/crepe/api/BehaviorScript.h b/src/crepe/api/BehaviorScript.h index 6b1fec7..8d21a72 100644 --- a/src/crepe/api/BehaviorScript.h +++ b/src/crepe/api/BehaviorScript.h @@ -12,19 +12,35 @@ class Script; class BehaviorScript : public Component { protected: - friend class crepe::ComponentManager; using Component::Component; + //! Only ComponentManager is allowed to instantiate BehaviorScript + friend class ComponentManager; public: virtual ~BehaviorScript() = default; public: + /** + * \brief Set the concrete script of this component + * + * \tparam T Concrete script type (derived from \c crepe::Script) + * + * \returns Reference to BehaviorScript component (`*this`) + */ template <class T> BehaviorScript & set_script(); protected: - friend class crepe::ScriptSystem; + //! ScriptSystem needs direct access to the script instance + friend class ScriptSystem; + //! Flag to indicate if script->init() has been called already + bool initialized = false; std::unique_ptr<Script> script = nullptr; + +private: + //! Script accesses the component manager directly via its parent + // (BehaviorScript) reference + friend class Script; }; } // namespace crepe diff --git a/src/crepe/api/BehaviorScript.hpp b/src/crepe/api/BehaviorScript.hpp index 4751607..bb5d829 100644 --- a/src/crepe/api/BehaviorScript.hpp +++ b/src/crepe/api/BehaviorScript.hpp @@ -11,10 +11,10 @@ namespace crepe { template <class T> BehaviorScript & BehaviorScript::set_script() { - static_assert(std::is_base_of<Script, T>::value); dbg_trace(); + static_assert(std::is_base_of<Script, T>::value); Script * s = new T(); - s->parent = this; + s->parent_ref = this; this->script = std::unique_ptr<Script>(s); return *this; } diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 85696c4..d9cda57 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -14,11 +14,11 @@ target_sources(crepe PUBLIC Config.cpp Metadata.cpp Scene.cpp - SceneManager.cpp + # SceneManager.cpp Vector2.cpp Camera.cpp Animator.cpp - LoopManager.cpp + # LoopManager.cpp LoopTimer.cpp ) @@ -40,10 +40,10 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES SaveManager.h Scene.h Metadata.h - SceneManager.h - SceneManager.hpp + # SceneManager.h + # SceneManager.hpp Camera.h Animator.h - LoopManager.h + # LoopManager.h LoopTimer.h ) diff --git a/src/crepe/api/Camera.cpp b/src/crepe/api/Camera.cpp index 6355a03..fece199 100644 --- a/src/crepe/api/Camera.cpp +++ b/src/crepe/api/Camera.cpp @@ -1,6 +1,3 @@ - -#include <cstdint> - #include "util/log.h" #include "Camera.h" @@ -9,8 +6,8 @@ using namespace crepe; -Camera::Camera(uint32_t id, const Color & bg_color) - : Component(id), +Camera::Camera(const Component::Data & data, const Color & bg_color) + : Component(data), bg_color(bg_color) { dbg_trace(); } diff --git a/src/crepe/api/Camera.h b/src/crepe/api/Camera.h index ba3a9ef..a52f2f7 100644 --- a/src/crepe/api/Camera.h +++ b/src/crepe/api/Camera.h @@ -23,7 +23,7 @@ public: * \param id Unique identifier for the camera component. * \param bg_color Background color for the camera view. */ - Camera(uint32_t id, const Color & bg_color); + Camera(const Component::Data & data, const Color & bg_color); ~Camera(); // dbg_trace only public: diff --git a/src/crepe/api/GameObject.cpp b/src/crepe/api/GameObject.cpp index d252e77..bba1f26 100644 --- a/src/crepe/api/GameObject.cpp +++ b/src/crepe/api/GameObject.cpp @@ -6,18 +6,19 @@ using namespace crepe; using namespace std; -GameObject::GameObject(game_object_id_t id, const std::string & name, +GameObject::GameObject(ComponentManager & component_manager, game_object_id_t id, const std::string & name, const std::string & tag, const Vector2 & position, double rotation, double scale) - : id(id) { + : id(id), component_manager(component_manager) { + // Add Transform and Metadata components - ComponentManager & mgr = ComponentManager::get_instance(); + ComponentManager & mgr = this->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 = ComponentManager::get_instance(); + ComponentManager & mgr = this->component_manager; // Set parent on own Metadata component vector<reference_wrapper<Metadata>> this_metadata diff --git a/src/crepe/api/GameObject.h b/src/crepe/api/GameObject.h index d703730..d09938a 100644 --- a/src/crepe/api/GameObject.h +++ b/src/crepe/api/GameObject.h @@ -3,10 +3,11 @@ #include <string> #include "types.h" +#include "Vector2.h" namespace crepe { -class Vector2; +class ComponentManager; /** * \brief Represents a GameObject @@ -16,11 +17,12 @@ class Vector2; * done in the ComponentManager. */ class GameObject { -public: +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 id The id of the GameObject * \param name The name of the GameObject * \param tag The tag of the GameObject @@ -28,9 +30,11 @@ public: * \param rotation The rotation of the GameObject * \param scale The scale of the GameObject */ - GameObject(game_object_id_t id, const std::string & name, - const std::string & tag, const Vector2 & position, - double rotation, double scale); + GameObject(ComponentManager & component_manager, game_object_id_t id, const std::string & name, const std::string & tag, const Vector2 & position, double rotation, double scale); + //! ComponentManager instances GameObject + friend class ComponentManager; + +public: /** * \brief Set the parent of this GameObject * @@ -58,6 +62,9 @@ public: public: //! The id of the GameObject const game_object_id_t id; + +protected: + ComponentManager & component_manager; }; } // namespace crepe diff --git a/src/crepe/api/GameObject.hpp b/src/crepe/api/GameObject.hpp index bfba7fe..17b17d7 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 = ComponentManager::get_instance(); + ComponentManager & mgr = this->component_manager; return mgr.add_component<T>(this->id, std::forward<Args>(args)...); } diff --git a/src/crepe/api/Metadata.cpp b/src/crepe/api/Metadata.cpp index d421de5..6f0a280 100644 --- a/src/crepe/api/Metadata.cpp +++ b/src/crepe/api/Metadata.cpp @@ -3,7 +3,7 @@ using namespace crepe; using namespace std; -Metadata::Metadata(game_object_id_t id, const string & name, const string & tag) - : Component(id), +Metadata::Metadata(const Component::Data & data, const string & name, const string & tag) + : Component(data), name(name), tag(tag) {} diff --git a/src/crepe/api/Metadata.h b/src/crepe/api/Metadata.h index c61e006..8c91797 100644 --- a/src/crepe/api/Metadata.h +++ b/src/crepe/api/Metadata.h @@ -20,7 +20,7 @@ public: * \param name The name of the GameObject * \param tag The tag of the GameObject */ - Metadata(game_object_id_t id, const std::string & name, + Metadata(const Component::Data & data, const std::string & name, const std::string & tag); /** * \brief Get the maximum number of instances for this component diff --git a/src/crepe/api/ParticleEmitter.cpp b/src/crepe/api/ParticleEmitter.cpp index 0bc2197..ed4fec8 100644 --- a/src/crepe/api/ParticleEmitter.cpp +++ b/src/crepe/api/ParticleEmitter.cpp @@ -6,12 +6,12 @@ using namespace crepe; -ParticleEmitter::ParticleEmitter(game_object_id_t id, uint32_t max_particles, +ParticleEmitter::ParticleEmitter(const Component::Data & data, uint32_t max_particles, uint32_t emission_rate, uint32_t speed, uint32_t speed_offset, uint32_t angle, uint32_t angleOffset, float begin_lifespan, float end_lifespan) - : Component(id), + : Component(data), max_particles(max_particles), emission_rate(emission_rate), speed(speed), diff --git a/src/crepe/api/ParticleEmitter.h b/src/crepe/api/ParticleEmitter.h index 5939723..ba89538 100644 --- a/src/crepe/api/ParticleEmitter.h +++ b/src/crepe/api/ParticleEmitter.h @@ -10,7 +10,7 @@ namespace crepe { class ParticleEmitter : public Component { public: - ParticleEmitter(game_object_id_t id, uint32_t max_particles, + ParticleEmitter(const Component::Data & data, uint32_t max_particles, uint32_t emission_rate, uint32_t speed, uint32_t speed_offset, uint32_t angle, uint32_t angleOffset, float begin_lifespan, float end_lifespan); diff --git a/src/crepe/api/Rigidbody.cpp b/src/crepe/api/Rigidbody.cpp index 3bf1c5b..be6bb93 100644 --- a/src/crepe/api/Rigidbody.cpp +++ b/src/crepe/api/Rigidbody.cpp @@ -2,8 +2,8 @@ using namespace crepe; -crepe::Rigidbody::Rigidbody(uint32_t game_object_id, const Data & data) - : Component(game_object_id), +crepe::Rigidbody::Rigidbody(const Component::Data & component_data, const Data & data) + : Component(component_data), data(data) {} void crepe::Rigidbody::add_force_linear(const Vector2 & force) { diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index 68481f4..99837a6 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -82,7 +82,7 @@ public: * \param game_object_id id of the gameobject the rigibody is added to. * \param data struct to configure the rigidbody. */ - Rigidbody(uint32_t game_object_id, const Data & data); + Rigidbody(const Component::Data & component_data, const Data & data); //! struct to hold data of rigidbody Data data; diff --git a/src/crepe/api/Script.cpp b/src/crepe/api/Script.cpp index 390cec7..0423315 100644 --- a/src/crepe/api/Script.cpp +++ b/src/crepe/api/Script.cpp @@ -1,3 +1,4 @@ #include "Script.h" using namespace crepe; + diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 49e625f..d543df8 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -11,6 +11,7 @@ namespace crepe { class BehaviorScript; class Script { + //! ScriptSystem calls \c update() friend class crepe::ScriptSystem; protected: @@ -22,17 +23,25 @@ protected: // added event. protected: + //! Retrieve component from component manager (utility) template <typename T> T & get_component(); + //! Retrieve components from component manager (utility) template <typename T> std::vector<std::reference_wrapper<T>> get_components(); -private: - friend class crepe::BehaviorScript; - BehaviorScript * parent = nullptr; +protected: + // NOTE: Script must have a constructor without arguments so the game + // programmer doesn't need to manually add `using Script::Script` to their + // concrete script class. + Script() = default; + //! Only \c BehaviorScript instantiates Script + friend class BehaviorScript; + BehaviorScript * parent_ref = nullptr; }; } // namespace crepe #include "Script.hpp" + diff --git a/src/crepe/api/Script.hpp b/src/crepe/api/Script.hpp index d96c0e8..68bcc29 100644 --- a/src/crepe/api/Script.hpp +++ b/src/crepe/api/Script.hpp @@ -18,8 +18,10 @@ T & Script::get_component() { template <typename T> std::vector<std::reference_wrapper<T>> Script::get_components() { - ComponentManager & mgr = ComponentManager::get_instance(); - return mgr.get_components_by_id<T>(this->parent->game_object_id); + auto & parent = *this->parent_ref; + auto & mgr = parent.data.component_manager; + + return mgr.get_components_by_id<T>(parent.data.id); } } // namespace crepe diff --git a/src/crepe/api/Sprite.cpp b/src/crepe/api/Sprite.cpp index 6f0433f..716609f 100644 --- a/src/crepe/api/Sprite.cpp +++ b/src/crepe/api/Sprite.cpp @@ -10,9 +10,9 @@ using namespace std; using namespace crepe; -Sprite::Sprite(game_object_id_t id, const shared_ptr<Texture> image, +Sprite::Sprite(const Component::Data & data, const shared_ptr<Texture> image, const Color & color, const FlipSettings & flip) - : Component(id), + : Component(data), color(color), flip(flip), sprite_image(image) { diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h index deb3f93..171dfeb 100644 --- a/src/crepe/api/Sprite.h +++ b/src/crepe/api/Sprite.h @@ -43,7 +43,7 @@ public: * \param color Color tint applied to the sprite. * \param flip Flip settings for horizontal and vertical orientation. */ - Sprite(game_object_id_t id, const std::shared_ptr<Texture> image, + Sprite(const Component::Data & data, const std::shared_ptr<Texture> image, const Color & color, const FlipSettings & flip); /** diff --git a/src/crepe/api/Transform.cpp b/src/crepe/api/Transform.cpp index e401120..9645d03 100644 --- a/src/crepe/api/Transform.cpp +++ b/src/crepe/api/Transform.cpp @@ -4,9 +4,9 @@ using namespace crepe; -Transform::Transform(game_object_id_t id, const Vector2 & point, +Transform::Transform(const Component::Data & data, const Vector2 & point, double rotation, double scale) - : Component(id), + : Component(data), position(point), rotation(rotation), scale(scale) { diff --git a/src/crepe/api/Transform.h b/src/crepe/api/Transform.h index 756e45b..a7bcd89 100644 --- a/src/crepe/api/Transform.h +++ b/src/crepe/api/Transform.h @@ -20,7 +20,7 @@ public: * \param rotation The rotation of the GameObject * \param scale The scale of the GameObject */ - Transform(game_object_id_t id, const Vector2 & point, double rotation, + Transform(const Component::Data & data, const Vector2 & point, double rotation, double scale); /** * \brief Get the maximum number of instances for this component diff --git a/src/crepe/facade/Sound.cpp b/src/crepe/facade/Sound.cpp index 648ec81..3a6e1e1 100644 --- a/src/crepe/facade/Sound.cpp +++ b/src/crepe/facade/Sound.cpp @@ -1,26 +1,24 @@ +#include <memory> + #include "../util/log.h" +#include "../Asset.h" #include "Sound.h" #include "SoundContext.h" using namespace crepe; +using namespace std; -Sound::Sound(std::unique_ptr<Asset> res) { - dbg_trace(); - this->load(std::move(res)); -} +Sound::Sound(SoundContext & ctx) : context(ctx) { dbg_trace(); } -Sound::Sound(const char * src) { - dbg_trace(); - this->load(std::make_unique<Asset>(src)); -} - -void Sound::load(std::unique_ptr<Asset> res) { - this->sample.load(res->canonical()); +unique_ptr<Resource> Sound::clone(const Asset & src) const { + auto instance = make_unique<Sound>(*this); + instance->sample.load(src.canonical()); + return instance; } void Sound::play() { - SoundContext & ctx = SoundContext::get_instance(); + SoundContext & ctx = this->context; if (ctx.engine.getPause(this->handle)) { // resume if paused ctx.engine.setPause(this->handle, false); @@ -32,13 +30,13 @@ void Sound::play() { } void Sound::pause() { - SoundContext & ctx = SoundContext::get_instance(); + SoundContext & ctx = this->context; if (ctx.engine.getPause(this->handle)) return; ctx.engine.setPause(this->handle, true); } void Sound::rewind() { - SoundContext & ctx = SoundContext::get_instance(); + SoundContext & ctx = this->context; if (!ctx.engine.isValidVoiceHandle(this->handle)) return; ctx.engine.seek(this->handle, 0); } @@ -46,7 +44,7 @@ void Sound::rewind() { void Sound::set_volume(float volume) { this->volume = volume; - SoundContext & ctx = SoundContext::get_instance(); + SoundContext & ctx = this->context; if (!ctx.engine.isValidVoiceHandle(this->handle)) return; ctx.engine.setVolume(this->handle, this->volume); } @@ -54,7 +52,8 @@ void Sound::set_volume(float volume) { void Sound::set_looping(bool looping) { this->looping = looping; - SoundContext & ctx = SoundContext::get_instance(); + SoundContext & ctx = this->context; if (!ctx.engine.isValidVoiceHandle(this->handle)) return; ctx.engine.setLooping(this->handle, this->looping); } + diff --git a/src/crepe/facade/Sound.h b/src/crepe/facade/Sound.h index 183bd7c..e5b2f19 100644 --- a/src/crepe/facade/Sound.h +++ b/src/crepe/facade/Sound.h @@ -4,11 +4,13 @@ #include <soloud/soloud.h> #include <soloud/soloud_wav.h> -#include "../Asset.h" +#include "../Resource.h" namespace crepe { -class Sound { +class SoundContext; + +class Sound : public Resource { public: /** * \brief Pause this sample @@ -64,15 +66,13 @@ public: bool get_looping() const { return this->looping; } public: - Sound(const char * src); - Sound(std::unique_ptr<Asset> res); - -private: - void load(std::unique_ptr<Asset> res); + Sound(SoundContext & ctx); + std::unique_ptr<Resource> clone(const Asset & src) const override; private: SoLoud::Wav sample; SoLoud::handle handle; + SoundContext & context; float volume = 1.0f; bool looping = false; diff --git a/src/crepe/facade/SoundContext.cpp b/src/crepe/facade/SoundContext.cpp index 5e5a3a9..c89fb03 100644 --- a/src/crepe/facade/SoundContext.cpp +++ b/src/crepe/facade/SoundContext.cpp @@ -4,11 +4,6 @@ using namespace crepe; -SoundContext & SoundContext::get_instance() { - static SoundContext instance; - return instance; -} - SoundContext::SoundContext() { dbg_trace(); engine.init(); @@ -18,3 +13,4 @@ SoundContext::~SoundContext() { dbg_trace(); engine.deinit(); } + diff --git a/src/crepe/facade/SoundContext.h b/src/crepe/facade/SoundContext.h index d3123d2..c360fb8 100644 --- a/src/crepe/facade/SoundContext.h +++ b/src/crepe/facade/SoundContext.h @@ -7,19 +7,18 @@ namespace crepe { class SoundContext { -private: +public: SoundContext(); virtual ~SoundContext(); - // singleton - static SoundContext & get_instance(); - SoundContext(const SoundContext &) = delete; - SoundContext(SoundContext &&) = delete; - SoundContext & operator=(const SoundContext &) = delete; - SoundContext & operator=(SoundContext &&) = delete; + SoundContext(const SoundContext &) = delete; + SoundContext(SoundContext &&) = delete; + SoundContext & operator=(const SoundContext &) = delete; + SoundContext & operator=(SoundContext &&) = delete; private: SoLoud::Soloud engine; + //! Sound directly calls methods on \c engine friend class Sound; }; diff --git a/src/crepe/system/CMakeLists.txt b/src/crepe/system/CMakeLists.txt index 4c18b87..9ee12f6 100644 --- a/src/crepe/system/CMakeLists.txt +++ b/src/crepe/system/CMakeLists.txt @@ -1,17 +1,18 @@ target_sources(crepe PUBLIC - ParticleSystem.cpp + System.cpp + # ParticleSystem.cpp ScriptSystem.cpp - PhysicsSystem.cpp - CollisionSystem.cpp - RenderSystem.cpp - AnimatorSystem.cpp + # PhysicsSystem.cpp + # CollisionSystem.cpp + # RenderSystem.cpp + # AnimatorSystem.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES System.h ScriptSystem.h - PhysicsSystem.h - CollisionSystem.h - RenderSystem.h - AnimatorSystem.h + # PhysicsSystem.h + # CollisionSystem.h + # RenderSystem.h + # AnimatorSystem.h ) diff --git a/src/crepe/system/ScriptSystem.cpp b/src/crepe/system/ScriptSystem.cpp index f2673e7..0a87fcc 100644 --- a/src/crepe/system/ScriptSystem.cpp +++ b/src/crepe/system/ScriptSystem.cpp @@ -13,16 +13,24 @@ using namespace std; using namespace crepe; void ScriptSystem::update() { - using namespace std; dbg_trace(); - forward_list<Script *> scripts = this->get_scripts(); - for (Script * script : scripts) script->update(); + forward_list<reference_wrapper<Script>> scripts = this->get_scripts(); + + for (auto & script_ref : scripts) { + Script & script = script_ref.get(); + BehaviorScript & component = *script.parent_ref; + if (!component.initialized) { + script.init(); + component.initialized = true; + } + script.update(); + } } -forward_list<Script *> ScriptSystem::get_scripts() { - forward_list<Script *> scripts = {}; - ComponentManager & mgr = ComponentManager::get_instance(); +forward_list<reference_wrapper<Script>> ScriptSystem::get_scripts() { + forward_list<reference_wrapper<Script>> scripts = {}; + ComponentManager & mgr = this->component_manager; vector<reference_wrapper<BehaviorScript>> behavior_scripts = mgr.get_components_by_type<BehaviorScript>(); @@ -31,8 +39,9 @@ forward_list<Script *> ScriptSystem::get_scripts() { if (!behavior_script.active) continue; Script * script = behavior_script.script.get(); if (script == nullptr) continue; - scripts.push_front(script); + scripts.push_front(*script); } return scripts; } + diff --git a/src/crepe/system/ScriptSystem.h b/src/crepe/system/ScriptSystem.h index 4fa6141..b52e825 100644 --- a/src/crepe/system/ScriptSystem.h +++ b/src/crepe/system/ScriptSystem.h @@ -7,14 +7,15 @@ namespace crepe { class Script; +class BehaviorScript; class ScriptSystem : public System { public: + using System::System; void update(); private: - // TODO: to forward_list<reference_wrapper> - std::forward_list<Script *> get_scripts(); + std::forward_list<std::reference_wrapper<Script>> get_scripts(); }; } // namespace crepe diff --git a/src/crepe/system/System.cpp b/src/crepe/system/System.cpp new file mode 100644 index 0000000..296f1ed --- /dev/null +++ b/src/crepe/system/System.cpp @@ -0,0 +1,6 @@ +#include "System.h" + +using namespace crepe; + +System::System(ComponentManager & mgr) : component_manager(mgr) {} + diff --git a/src/crepe/system/System.h b/src/crepe/system/System.h index 3b81bef..7970e72 100644 --- a/src/crepe/system/System.h +++ b/src/crepe/system/System.h @@ -2,13 +2,18 @@ namespace crepe { +class ComponentManager; + class System { public: virtual void update() = 0; public: - System() = default; + System(ComponentManager &); virtual ~System() = default; + +protected: + ComponentManager & component_manager; }; } // namespace crepe diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 0e4eaed..9d303bc 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,6 +1,6 @@ target_sources(test_main PUBLIC - dummy.cpp - # audio.cpp - PhysicsTest.cpp + main.cpp + # PhysicsTest.cpp + ScriptTest.cpp ) diff --git a/src/test/PhysicsTest.cpp b/src/test/PhysicsTest.cpp index 5385962..538d244 100644 --- a/src/test/PhysicsTest.cpp +++ b/src/test/PhysicsTest.cpp @@ -11,9 +11,11 @@ using namespace std::chrono_literals; using namespace crepe; class PhysicsTest : public ::testing::Test { -protected: +public: GameObject * game_object; + ComponentManager component_manager; PhysicsSystem physics_system; + void SetUp() override { ComponentManager & mgr = ComponentManager::get_instance(); std::vector<std::reference_wrapper<Transform>> transforms diff --git a/src/test/ScriptTest.cpp b/src/test/ScriptTest.cpp new file mode 100644 index 0000000..ea49a35 --- /dev/null +++ b/src/test/ScriptTest.cpp @@ -0,0 +1,73 @@ +#include <gtest/gtest.h> + +// stupid hack to allow access to private/protected members under test +#define private public +#define protected public + +#include <crepe/ComponentManager.h> +#include <crepe/system/ScriptSystem.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Script.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Vector2.h> + +using namespace std; +using namespace crepe; +using namespace testing; + +class ScriptTest : public Test { +public: + ComponentManager component_manager {}; + ScriptSystem system { component_manager }; + + class MyScript : public Script { + // NOTE: default (private) visibility of init and update shouldn't cause + // issues! + void init() { this->init_count++; } + void update() { this->update_count++; } + + public: + unsigned init_count = 0; + unsigned update_count = 0; + }; + + BehaviorScript * behaviorscript_ref = nullptr; + MyScript * script_ref = nullptr; + + void SetUp() override { + auto & mgr = this->component_manager; + GameObject & entity = mgr.new_object("name"); + BehaviorScript & component = entity.add_component<BehaviorScript>(); + + this->behaviorscript_ref = &component; + EXPECT_EQ(this->behaviorscript_ref->script.get(), nullptr); + component.set_script<MyScript>(); + ASSERT_NE(this->behaviorscript_ref->script.get(), nullptr); + + this->script_ref = (MyScript *) this->behaviorscript_ref->script.get(); + ASSERT_NE(this->script_ref, nullptr); + } +}; + +TEST_F(ScriptTest, Default) { + EXPECT_EQ(0, this->script_ref->init_count); + EXPECT_EQ(0, this->script_ref->update_count); +} + +TEST_F(ScriptTest, UpdateOnce) { + EXPECT_EQ(0, this->script_ref->init_count); + EXPECT_EQ(0, this->script_ref->update_count); + + this->system.update(); + EXPECT_EQ(1, this->script_ref->init_count); + EXPECT_EQ(1, this->script_ref->update_count); +} + +TEST_F(ScriptTest, ListScripts) { + size_t script_count = 0; + for (auto & _ : this->system.get_scripts()) { + script_count++; + } + ASSERT_EQ(1, script_count); +} + diff --git a/src/test/audio.cpp b/src/test/audio.cpp deleted file mode 100644 index d6ff689..0000000 --- a/src/test/audio.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include <gtest/gtest.h> - -using namespace std; -using namespace std::chrono_literals; - -// using namespace crepe; - -// TODO: mock internal audio class - -TEST(audio, play) { ASSERT_TRUE(true); } diff --git a/src/test/dummy.cpp b/src/test/dummy.cpp deleted file mode 100644 index a00a9c6..0000000 --- a/src/test/dummy.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include <gtest/gtest.h> - -TEST(dummy, foo) { ASSERT_TRUE(1); } diff --git a/src/test/main.cpp b/src/test/main.cpp new file mode 100644 index 0000000..6830a01 --- /dev/null +++ b/src/test/main.cpp @@ -0,0 +1,15 @@ +#include <crepe/api/Config.h> + +#include <gtest/gtest.h> + +using namespace crepe; +using namespace testing; + +int main(int argc, char **argv) { + InitGoogleTest(&argc, argv); + + auto & cfg = Config::get_instance(); + cfg.log.level = LogLevel::ERROR; + + return RUN_ALL_TESTS(); +} |