diff options
| author | WBoerenkamps <wrj.boerenkamps@student.avans.nl> | 2024-11-24 16:39:52 +0100 | 
|---|---|---|
| committer | WBoerenkamps <wrj.boerenkamps@student.avans.nl> | 2024-11-24 16:39:52 +0100 | 
| commit | eb11f6609ab91bc46948ca9fc5743078f88ae48e (patch) | |
| tree | df8044d7df87b5e5011d6f72d5acc6bbca454445 | |
| parent | 020cdfddcd06e162515deee4941ce91f3a945ee6 (diff) | |
| parent | 1499363d85abedbdb571e33801b821f4dfabc638 (diff) | |
Merge branch 'master' of https://github.com/lonkaars/crepe into wouter/gameloop
49 files changed, 1062 insertions, 234 deletions
| @@ -19,15 +19,17 @@ TAB_SIZE = 2  HTML_INDEX_NUM_ENTRIES = 2  HTML_EXTRA_STYLESHEET = src/doc/style.css +SHOW_HEADERFILE = NO  USE_MDFILE_AS_MAINPAGE = ./readme.md  REPEAT_BRIEF = NO -INTERNAL_DOCS = YES -EXTRACT_PRIVATE = YES  EXTRACT_STATIC = YES  HIDE_UNDOC_NAMESPACES = YES  HIDE_UNDOC_CLASSES = YES  QUIET = YES +# set these to NO for user-only docs +INTERNAL_DOCS = YES +EXTRACT_PRIVATE = YES diff --git a/contributing.md b/contributing.md index 77a2908..0a90e86 100644 --- a/contributing.md +++ b/contributing.md @@ -17,6 +17,7 @@ that you can click on to open them.    working/compiling version of the project  - Pull requests for new code include either automated tests for the new code or    an explanation as to why the code can not (reliably) be tested +  <!--  - TODO: tagging / versions  --> @@ -495,6 +496,12 @@ that you can click on to open them.    </td></tr></table></details>  - <details><summary>    Ensure const-correctness + +  > [!IMPORTANT] +  > C-style APIs that work on (possibly internal) references to structs can be +  > called from const member functions in C++. If the compiler allows you to +  > mark a function as `const` even though it has side effects, it should +  > **not** be marked as `const`.    </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td>    ```cpp @@ -795,6 +802,23 @@ that you can click on to open them.    ```    </td></tr></table></details>  - Do not implement new classes as singletons +- <details><summary> +  Retrieving the first or last indices for iterators with a known or expected +  size should be done using <code>.front()</code> or <code>.back()</code> +  instead of by index +  </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td> + +  ```cpp +  vector<int> foo = { 1, 2, 3 }; +  int bar = foo.first(); +  ``` +  </td><td> + +  ```cpp +  vector<int> foo = { 1, 2, 3 }; +  int bar = foo[0]; +  ``` +  </td></tr></table></details>  ## CMakeLists-specific diff --git a/src/crepe/ComponentManager.cpp b/src/crepe/ComponentManager.cpp index e310577..e4de027 100644 --- a/src/crepe/ComponentManager.cpp +++ b/src/crepe/ComponentManager.cpp @@ -26,8 +26,7 @@ void ComponentManager::delete_all_components() {  }  GameObject ComponentManager::new_object(const string & name, const string & tag, -										const Vector2 & position, double rotation, -										double scale) { +										const vec2 & position, double rotation, double scale) {  	GameObject object{*this, this->next_id, name, tag, position, rotation, scale};  	this->next_id++;  	return object; diff --git a/src/crepe/ComponentManager.h b/src/crepe/ComponentManager.h index 0956d1e..1cb0b5f 100644 --- a/src/crepe/ComponentManager.h +++ b/src/crepe/ComponentManager.h @@ -5,8 +5,6 @@  #include <unordered_map>  #include <vector> -#include "api/Vector2.h" -  #include "Component.h"  #include "types.h" @@ -45,7 +43,7 @@ public:  	 * \note This method automatically assigns a new entity ID  	 */  	GameObject new_object(const std::string & name, const std::string & tag = "", -						  const Vector2 & position = {0, 0}, double rotation = 0, +						  const vec2 & position = {0, 0}, double rotation = 0,  						  double scale = 1);  protected: diff --git a/src/crepe/Particle.cpp b/src/crepe/Particle.cpp index 1068cbf..485a0d4 100644 --- a/src/crepe/Particle.cpp +++ b/src/crepe/Particle.cpp @@ -2,7 +2,7 @@  using namespace crepe; -void Particle::reset(uint32_t lifespan, const Vector2 & position, const Vector2 & velocity, +void Particle::reset(uint32_t lifespan, const vec2 & position, const vec2 & velocity,  					 double angle) {  	// Initialize the particle state  	this->time_in_life = 0; diff --git a/src/crepe/Particle.h b/src/crepe/Particle.h index 19859fe..d0397c9 100644 --- a/src/crepe/Particle.h +++ b/src/crepe/Particle.h @@ -2,7 +2,7 @@  #include <cstdint> -#include "api/Vector2.h" +#include "types.h"  namespace crepe { @@ -18,11 +18,11 @@ class Particle {  public:  	//! Position of the particle in 2D space. -	Vector2 position; +	vec2 position;  	//! Velocity vector indicating the speed and direction of the particle. -	Vector2 velocity; +	vec2 velocity;  	//! Accumulated force affecting the particle over time. -	Vector2 force_over_time; +	vec2 force_over_time;  	//! Total lifespan of the particle in milliseconds.  	uint32_t lifespan;  	//! Active state of the particle; true if it is in use, false otherwise. @@ -43,8 +43,7 @@ public:  	 * \param velocity  The initial velocity of the particle.  	 * \param angle     The angle of the particle's trajectory or orientation.  	 */ -	void reset(uint32_t lifespan, const Vector2 & position, const Vector2 & velocity, -			   double angle); +	void reset(uint32_t lifespan, const vec2 & position, const vec2 & velocity, double angle);  	/**  	 * \brief Updates the particle's state.  	 * diff --git a/src/crepe/api/BehaviorScript.h b/src/crepe/api/BehaviorScript.h index 9d85d4c..d556fe5 100644 --- a/src/crepe/api/BehaviorScript.h +++ b/src/crepe/api/BehaviorScript.h @@ -39,11 +39,14 @@ public:  	 * \brief Set the concrete script of this component  	 *  	 * \tparam T Concrete script type (derived from \c crepe::Script) +	 * \tparam Args Arguments for concrete script constructor +	 * +	 * \param args Arguments for concrete script constructor (forwarded using perfect forwarding)  	 *  	 * \returns Reference to BehaviorScript component (`*this`)  	 */ -	template <class T> -	BehaviorScript & set_script(); +	template <class T, typename... Args> +	BehaviorScript & set_script(Args &&... args);  protected:  	//! Script instance diff --git a/src/crepe/api/BehaviorScript.hpp b/src/crepe/api/BehaviorScript.hpp index d80321d..bd59337 100644 --- a/src/crepe/api/BehaviorScript.hpp +++ b/src/crepe/api/BehaviorScript.hpp @@ -9,13 +9,17 @@  namespace crepe { -template <class T> -BehaviorScript & BehaviorScript::set_script() { +template <class T, typename... Args> +BehaviorScript & BehaviorScript::set_script(Args &&... args) {  	dbg_trace();  	static_assert(std::is_base_of<Script, T>::value); -	Script * s = new T(); +	Script * s = new T(std::forward<Args>(args)...); +  	s->game_object_id = this->game_object_id; -	s->component_manager_ref = &this->component_manager; +	s->active = this->active; +	s->component_manager = this->component_manager; +	s->event_manager = EventManager::get_instance(); +  	this->script = std::unique_ptr<Script>(s);  	return *this;  } diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index d6b6801..c3e0b37 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -14,7 +14,6 @@ target_sources(crepe PUBLIC  	Metadata.cpp  	Scene.cpp  	SceneManager.cpp -	Vector2.cpp  	Camera.cpp  	Animator.cpp  	EventManager.cpp @@ -24,6 +23,7 @@ target_sources(crepe PUBLIC  	LoopTimer.cpp  	Asset.cpp  	EventHandler.cpp +	Script.cpp  )  target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -37,6 +37,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES  	Rigidbody.h  	Sprite.h  	Vector2.h +	Vector2.hpp  	Color.h  	Texture.h   	AssetManager.h  diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h index 06cf7f3..b267e3e 100644 --- a/src/crepe/api/Event.h +++ b/src/crepe/api/Event.h @@ -1,10 +1,12 @@ -// TODO discussing the location of these events  #pragma once +// TODO discussing the location of these events  #include <string>  #include "KeyCodes.h" +namespace crepe { +  /**   * \brief Base class for all event types in the system.   */ @@ -91,11 +93,7 @@ public:  /**   * \brief Event triggered during a collision between objects.   */ -class CollisionEvent : public Event { -public: -	//! Data describing the collision (currently not implemented). -	// Collision collisionData; -}; +class CollisionEvent : public Event {};  /**   * \brief Event triggered when text is submitted, e.g., from a text input. @@ -110,3 +108,5 @@ public:   * \brief Event triggered to indicate the application is shutting down.   */  class ShutDownEvent : public Event {}; + +} // namespace crepe diff --git a/src/crepe/api/EventHandler.hpp b/src/crepe/api/EventHandler.hpp index 391dcca..050e57e 100644 --- a/src/crepe/api/EventHandler.hpp +++ b/src/crepe/api/EventHandler.hpp @@ -1,3 +1,5 @@ +#pragma once +  #include <typeindex>  #include "EventHandler.h" diff --git a/src/crepe/api/EventManager.h b/src/crepe/api/EventManager.h index 348a04d..1a33023 100644 --- a/src/crepe/api/EventManager.h +++ b/src/crepe/api/EventManager.h @@ -77,7 +77,7 @@ public:  	 * \param channel The channel to trigger the event on (default is CHANNEL_ALL, which triggers on all channels).  	 */  	template <typename EventType> -	void trigger_event(const EventType & event, event_channel_t channel = CHANNEL_ALL); +	void trigger_event(const EventType & event = {}, event_channel_t channel = CHANNEL_ALL);  	/**  	 * \brief Queue an event for later processing. @@ -89,7 +89,7 @@ public:  	 * \param channel The channel to associate with the event (default is CHANNEL_ALL).  	 */  	template <typename EventType> -	void queue_event(const EventType & event, event_channel_t channel = CHANNEL_ALL); +	void queue_event(const EventType & event = {}, event_channel_t channel = CHANNEL_ALL);  	/**  	 * \brief Process all queued events. diff --git a/src/crepe/api/GameObject.cpp b/src/crepe/api/GameObject.cpp index 4874426..3c36a21 100644 --- a/src/crepe/api/GameObject.cpp +++ b/src/crepe/api/GameObject.cpp @@ -9,7 +9,7 @@ using namespace std;  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) +					   const vec2 & position, double rotation, double scale)  	: id(id),  	  component_manager(component_manager) { diff --git a/src/crepe/api/GameObject.h b/src/crepe/api/GameObject.h index 34ef8bb..fcb8d9a 100644 --- a/src/crepe/api/GameObject.h +++ b/src/crepe/api/GameObject.h @@ -2,7 +2,6 @@  #include <string> -#include "Vector2.h"  #include "types.h"  namespace crepe { @@ -30,7 +29,7 @@ private:  	 * \param scale The scale of the GameObject  	 */  	GameObject(ComponentManager & component_manager, game_object_id_t id, -			   const std::string & name, const std::string & tag, const Vector2 & position, +			   const std::string & name, const std::string & tag, const vec2 & position,  			   double rotation, double scale);  	//! ComponentManager instances GameObject  	friend class ComponentManager; diff --git a/src/crepe/api/ParticleEmitter.h b/src/crepe/api/ParticleEmitter.h index 33112e1..b83fd61 100644 --- a/src/crepe/api/ParticleEmitter.h +++ b/src/crepe/api/ParticleEmitter.h @@ -4,7 +4,7 @@  #include "Component.h"  #include "Particle.h" -#include "Vector2.h" +#include "types.h"  namespace crepe { @@ -30,7 +30,7 @@ public:  		//! boundary height (midpoint is emitter location)  		double height = 0.0;  		//! boundary offset from particle emitter location -		Vector2 offset; +		vec2 offset;  		//! reset on exit or stop velocity and set max postion  		bool reset_on_exit = false;  	}; @@ -43,7 +43,7 @@ public:  	 */  	struct Data {  		//! position of the emitter -		Vector2 position; +		vec2 position;  		//! maximum number of particles  		const unsigned int max_particles = 0;  		//! rate of particle emission per update (Lowest value = 0.001 any lower is ignored) @@ -61,7 +61,7 @@ public:  		//! end Lifespan of particle  		double end_lifespan = 0.0;  		//! force over time (physics) -		Vector2 force_over_time; +		vec2 force_over_time;  		//! particle boundary  		Boundary boundary;  		//! collection of particles diff --git a/src/crepe/api/Rigidbody.cpp b/src/crepe/api/Rigidbody.cpp index 6b87695..576ca45 100644 --- a/src/crepe/api/Rigidbody.cpp +++ b/src/crepe/api/Rigidbody.cpp @@ -6,7 +6,7 @@ crepe::Rigidbody::Rigidbody(game_object_id_t id, const Data & data)  	: Component(id),  	  data(data) {} -void crepe::Rigidbody::add_force_linear(const Vector2 & force) { +void crepe::Rigidbody::add_force_linear(const vec2 & force) {  	this->data.linear_velocity += force;  } diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index 3e5c7a3..3b0588f 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -2,7 +2,7 @@  #include "../Component.h" -#include "Vector2.h" +#include "types.h"  namespace crepe { @@ -56,11 +56,11 @@ public:  		//! Changes if physics apply  		BodyType body_type = BodyType::DYNAMIC;  		//! linear velocity of object -		Vector2 linear_velocity; +		vec2 linear_velocity;  		//! maximum linear velocity of object -		Vector2 max_linear_velocity; +		vec2 max_linear_velocity;  		//! linear damping of object -		Vector2 linear_damping; +		vec2 linear_damping;  		//! angular velocity of object  		double angular_velocity = 0.0;  		//! max angular velocity of object @@ -90,7 +90,7 @@ public:  	 *   	 * \param force Vector2 that is added to the linear force.  	 */ -	void add_force_linear(const Vector2 & force); +	void add_force_linear(const vec2 & force);  	/**   	 * \brief add a angular force to the Rigidbody.  	 *  diff --git a/src/crepe/api/Script.cpp b/src/crepe/api/Script.cpp new file mode 100644 index 0000000..fcbe4c7 --- /dev/null +++ b/src/crepe/api/Script.cpp @@ -0,0 +1,15 @@ +#include "Script.h" + +using namespace crepe; + +Script::~Script() { +	EventManager & evmgr = this->event_manager; +	for (auto id : this->listeners) { +		evmgr.unsubscribe(id); +	} +} + +template <> +void Script::subscribe(const EventHandler<CollisionEvent> & callback) { +	this->subscribe_internal(callback, this->game_object_id); +} diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 839d937..a0870cb 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -3,6 +3,9 @@  #include <vector>  #include "../types.h" +#include "../util/OptionalRef.h" + +#include "EventManager.h"  namespace crepe { @@ -16,13 +19,23 @@ class ComponentManager;   * This class is used as a base class for user-defined scripts that can be added to game   * objects using the \c BehaviorScript component.   * - * \note Additional *events* (like Unity's OnDisable and OnEnable) should be implemented as + * \info Additional *events* (like Unity's OnDisable and OnEnable) should be implemented as   * member or lambda methods in derivative user script classes and registered in \c init(). + * + * \warning Concrete scripts are allowed do create a custom constructor, but the utility + * functions should not be called inside the constructor as they rely on late references that + * are only available after the constructor returns. + * + * \see feature_script   */  class Script {  protected:  	/** -	 * \brief Script initialization function +	 * \name Interface functions +	 * \{ +	 */ +	/** +	 * \brief Script initialization function (empty by default)  	 *  	 * This function is called during the ScriptSystem::update() routine *before*  	 * Script::update() if it (a) has not yet been called and (b) the \c BehaviorScript component @@ -30,24 +43,31 @@ protected:  	 */  	virtual void init() {}  	/** -	 * \brief Script update function +	 * \brief Script update function (empty by default)  	 *  	 * This function is called during the ScriptSystem::update() routine if the \c BehaviorScript  	 * component holding this script instance is active.  	 */  	virtual void update() {} +	//! \} +  	//! ScriptSystem calls \c init() and \c update()  	friend class crepe::ScriptSystem;  protected:  	/** -	 * \brief Get single component of type \c T on this game object (utility) +	 * \name Utility functions +	 * \{ +	 */ + +	/** +	 * \brief Get single component of type \c T on this game object  	 *  	 * \tparam T Type of component  	 *  	 * \returns Reference to component  	 * -	 * \throws nullptr if this game object does not have a component matching type \c T +	 * \throws std::runtime_error if this game object does not have a component with type \c T  	 */  	template <typename T>  	T & get_component() const; @@ -55,7 +75,7 @@ protected:  	// cause compile-time errors  	/** -	 * \brief Get all components of type \c T on this game object (utility) +	 * \brief Get all components of type \c T on this game object  	 *  	 * \tparam T Type of component  	 * @@ -64,25 +84,108 @@ protected:  	template <typename T>  	RefVector<T> get_components() const; +	/** +	 * \brief Log a message using Log::logf +	 * +	 * \tparam Args Log::logf parameters +	 * \param args  Log::logf parameters +	 */ +	template <typename... Args> +	void logf(Args &&... args); + +	/** +	 * \brief Subscribe to an event with an explicit channel +	 * \see EventManager::subscribe +	 */ +	template <typename EventType> +	void subscribe(const EventHandler<EventType> & callback, event_channel_t channel); +	/** +	 * \brief Subscribe to an event on EventManager::CHANNEL_ALL +	 * \see EventManager::subscribe +	 */ +	template <typename EventType> +	void subscribe(const EventHandler<EventType> & callback); + +	//! \} + +private: +	/** +	 * \brief Internal subscribe function +	 * +	 * This function exists so certain template specializations of Script::subscribe can be +	 * explicitly deleted, and does the following: +	 * - Wrap the user-provided callback in a check that tests if the parent BehaviorScript +	 *   component is still active +	 * - Store the subscriber handle returned by the event manager so this listener is +	 *   automatically unsubscribed at the end of this Script instance's life +	 * +	 * \tparam EventType concrete Event class +	 * \param callback User-provided callback function +	 * \param channel Event channel (may have been overridden by template specializations) +	 */ +	template <typename EventType> +	void subscribe_internal(const EventHandler<EventType> & callback, event_channel_t channel); +  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. +	// NOTE: This must be the only constructor on Script, see "Late references" below  	Script() = default;  	//! Only \c BehaviorScript instantiates Script  	friend class BehaviorScript; +public: +	// std::unique_ptr destroys script +	virtual ~Script(); + +private: +	Script(const Script &) = delete; +	Script(Script &&) = delete; +	Script & operator=(const Script &) = delete; +	Script & operator=(Script &&) = delete; +  private: -	// These references are set by BehaviorScript immediately after calling the constructor of -	// Script. -	game_object_id_t game_object_id = -1; -	ComponentManager * component_manager_ref = nullptr; -	// TODO: use OptionalRef instead of pointer +	/** +	 * \name Late references +	 * +	 * These references are set by BehaviorScript immediately after calling the constructor of +	 * Script. +	 * +	 * \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 if they want to +	 * implement a non-default constructor (e.g. for passing references to their own concrete +	 * Script classes). +	 * +	 * \{ +	 */ +	//! Game object ID of game object parent BehaviorScript is attached to +	game_object_id_t game_object_id; +	//! Reference to parent component +	OptionalRef<bool> active; +	//! Reference to component manager instance +	OptionalRef<ComponentManager> component_manager; +	//! Reference to event manager instance +	OptionalRef<EventManager> event_manager; +	//! \}  private:  	//! Flag to indicate if \c init() has been called already  	bool initialized = false; +	//! List of subscribed events +	std::vector<subscription_t> listeners;  }; +/** + * \brief Subscribe to CollisionEvent for the current GameObject + * + * This is a template specialization for Script::subscribe which automatically sets the event + * channel so the callback handler is only called for CollisionEvent events that apply to the + * current GameObject the parent BehaviorScript is attached to. + */ +template <> +void Script::subscribe(const EventHandler<CollisionEvent> & callback); +template <> +void Script::subscribe(const EventHandler<CollisionEvent> & callback, event_channel_t) +	= delete; +  } // namespace crepe  #include "Script.hpp" diff --git a/src/crepe/api/Script.hpp b/src/crepe/api/Script.hpp index a85d814..a2463bf 100644 --- a/src/crepe/api/Script.hpp +++ b/src/crepe/api/Script.hpp @@ -20,8 +20,38 @@ T & Script::get_component() const {  template <typename T>  RefVector<T> Script::get_components() const { -	auto & mgr = *this->component_manager_ref; +	ComponentManager & mgr = this->component_manager; +  	return mgr.get_components_by_id<T>(this->game_object_id);  } +template <typename... Args> +void Script::logf(Args &&... args) { +	Log::logf(std::forward<Args>(args)...); +} + +template <typename EventType> +void Script::subscribe_internal(const EventHandler<EventType> & callback, +								event_channel_t channel) { +	EventManager & mgr = this->event_manager; +	subscription_t listener = mgr.subscribe<EventType>( +		[this, callback](const EventType & data) -> bool { +			bool & active = this->active; +			if (!active) return false; +			return callback(data); +		}, +		channel); +	this->listeners.push_back(listener); +} + +template <typename EventType> +void Script::subscribe(const EventHandler<EventType> & callback, event_channel_t channel) { +	this->subscribe_internal(callback, channel); +} + +template <typename EventType> +void Script::subscribe(const EventHandler<EventType> & callback) { +	this->subscribe_internal(callback, EventManager::CHANNEL_ALL); +} +  } // namespace crepe diff --git a/src/crepe/api/Transform.cpp b/src/crepe/api/Transform.cpp index cd944bd..a85b792 100644 --- a/src/crepe/api/Transform.cpp +++ b/src/crepe/api/Transform.cpp @@ -4,7 +4,7 @@  using namespace crepe; -Transform::Transform(game_object_id_t id, const Vector2 & point, double rotation, double scale) +Transform::Transform(game_object_id_t id, const vec2 & point, double rotation, double scale)  	: Component(id),  	  position(point),  	  rotation(rotation), diff --git a/src/crepe/api/Transform.h b/src/crepe/api/Transform.h index 18aa293..6243a93 100644 --- a/src/crepe/api/Transform.h +++ b/src/crepe/api/Transform.h @@ -1,8 +1,7 @@  #pragma once -#include "api/Vector2.h" -  #include "Component.h" +#include "types.h"  namespace crepe { @@ -15,7 +14,7 @@ namespace crepe {  class Transform : public Component {  public:  	//! Translation (shift) -	Vector2 position = {0, 0}; +	vec2 position = {0, 0};  	//! Rotation, in degrees  	double rotation = 0;  	//! Multiplication factor @@ -28,7 +27,7 @@ protected:  	 * \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, double scale); +	Transform(game_object_id_t id, const vec2 & point, double rotation, double scale);  	/**  	 * There is always exactly one transform component per entity  	 * \return 1 diff --git a/src/crepe/api/Vector2.cpp b/src/crepe/api/Vector2.cpp deleted file mode 100644 index 30b968e..0000000 --- a/src/crepe/api/Vector2.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "Vector2.h" - -using namespace crepe; - -Vector2 Vector2::operator-(const Vector2 & other) const { return {x - other.x, y - other.y}; } - -Vector2 Vector2::operator+(const Vector2 & other) const { return {x + other.x, y + other.y}; } - -Vector2 Vector2::operator*(double scalar) const { return {x * scalar, y * scalar}; } - -Vector2 & Vector2::operator*=(const Vector2 & other) { -	x *= other.x; -	y *= other.y; -	return *this; -} - -Vector2 & Vector2::operator+=(const Vector2 & other) { -	x += other.x; -	y += other.y; -	return *this; -} - -Vector2 & Vector2::operator+=(double other) { -	x += other; -	y += other; -	return *this; -} - -Vector2 Vector2::operator-() const { return {-x, -y}; } - -bool Vector2::operator==(const Vector2 & other) const { return x == other.x && y == other.y; } - -bool Vector2::operator!=(const Vector2 & other) const { return !(*this == other); } diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h index 2fb6136..c278c87 100644 --- a/src/crepe/api/Vector2.h +++ b/src/crepe/api/Vector2.h @@ -3,38 +3,71 @@  namespace crepe {  //! 2D vector +template <class T>  struct Vector2 {  	//! X component of the vector -	double x = 0; +	T x = 0;  	//! Y component of the vector -	double y = 0; +	T y = 0;  	//! Subtracts another vector from this vector and returns the result. -	Vector2 operator-(const Vector2 & other) const; +	Vector2 operator-(const Vector2<T> & other) const; + +	//! Subtracts a scalar value from both components of this vector and returns the result. +	Vector2 operator-(T scalar) const;  	//! Adds another vector to this vector and returns the result. -	Vector2 operator+(const Vector2 & other) const; +	Vector2 operator+(const Vector2<T> & other) const; + +	//! Adds a scalar value to both components of this vector and returns the result. +	Vector2 operator+(T scalar) const; + +	//! Multiplies this vector by another vector element-wise and returns the result. +	Vector2 operator*(const Vector2<T> & other) const;  	//! Multiplies this vector by a scalar and returns the result. -	Vector2 operator*(double scalar) const; +	Vector2 operator*(T scalar) const; -	//! Multiplies this vector by another vector element-wise and updates this vector. -	Vector2 & operator*=(const Vector2 & other); +	//! Divides this vector by another vector element-wise and returns the result. +	Vector2 operator/(const Vector2<T> & other) const; + +	//! Divides this vector by a scalar and returns the result. +	Vector2 operator/(T scalar) const;  	//! Adds another vector to this vector and updates this vector. -	Vector2 & operator+=(const Vector2 & other); +	Vector2 & operator+=(const Vector2<T> & other);  	//! Adds a scalar value to both components of this vector and updates this vector. -	Vector2 & operator+=(double other); +	Vector2 & operator+=(T other); + +	//! Subtracts another vector from this vector and updates this vector. +	Vector2 & operator-=(const Vector2<T> & other); + +	//! Subtracts a scalar value from both components of this vector and updates this vector. +	Vector2 & operator-=(T other); + +	//! Multiplies this vector by another vector element-wise and updates this vector. +	Vector2 & operator*=(const Vector2<T> & other); + +	//! Multiplies this vector by a scalar and updates this vector. +	Vector2 & operator*=(T other); + +	//! Divides this vector by another vector element-wise and updates this vector. +	Vector2 & operator/=(const Vector2<T> & other); + +	//! Divides this vector by a scalar and updates this vector. +	Vector2 & operator/=(T other);  	//! Returns the negation of this vector.  	Vector2 operator-() const;  	//! Checks if this vector is equal to another vector. -	bool operator==(const Vector2 & other) const; +	bool operator==(const Vector2<T> & other) const;  	//! Checks if this vector is not equal to another vector. -	bool operator!=(const Vector2 & other) const; +	bool operator!=(const Vector2<T> & other) const;  };  } // namespace crepe + +#include "Vector2.hpp" diff --git a/src/crepe/api/Vector2.hpp b/src/crepe/api/Vector2.hpp new file mode 100644 index 0000000..cad15f8 --- /dev/null +++ b/src/crepe/api/Vector2.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include "Vector2.h" + +namespace crepe { + +template <class T> +Vector2<T> Vector2<T>::operator-(const Vector2<T> & other) const { +	return {x - other.x, y - other.y}; +} + +template <class T> +Vector2<T> Vector2<T>::operator-(T scalar) const { +	return {x - scalar, y - scalar}; +} + +template <class T> +Vector2<T> Vector2<T>::operator+(const Vector2<T> & other) const { +	return {x + other.x, y + other.y}; +} + +template <class T> +Vector2<T> Vector2<T>::operator+(T scalar) const { +	return {x + scalar, y + scalar}; +} + +template <class T> +Vector2<T> Vector2<T>::operator*(const Vector2<T> & other) const { +	return {x * other.x, y * other.y}; +} + +template <class T> +Vector2<T> Vector2<T>::operator*(T scalar) const { +	return {x * scalar, y * scalar}; +} + +template <class T> +Vector2<T> Vector2<T>::operator/(const Vector2<T> & other) const { +	return {x / other.x, y / other.y}; +} + +template <class T> +Vector2<T> Vector2<T>::operator/(T scalar) const { +	return {x / scalar, y / scalar}; +} + +template <class T> +Vector2<T> & Vector2<T>::operator+=(const Vector2<T> & other) { +	x += other.x; +	y += other.y; +	return *this; +} + +template <class T> +Vector2<T> & Vector2<T>::operator+=(T other) { +	x += other; +	y += other; +	return *this; +} + +template <class T> +Vector2<T> & Vector2<T>::operator-=(const Vector2<T> & other) { +	x -= other.x; +	y -= other.y; +	return *this; +} + +template <class T> +Vector2<T> & Vector2<T>::operator-=(T other) { +	x -= other; +	y -= other; +	return *this; +} + +template <class T> +Vector2<T> & Vector2<T>::operator*=(const Vector2<T> & other) { +	x *= other.x; +	y *= other.y; +	return *this; +} + +template <class T> +Vector2<T> & Vector2<T>::operator*=(T other) { +	x *= other; +	y *= other; +	return *this; +} + +template <class T> +Vector2<T> & Vector2<T>::operator/=(const Vector2<T> & other) { +	x /= other.x; +	y /= other.y; +	return *this; +} + +template <class T> +Vector2<T> & Vector2<T>::operator/=(T other) { +	x /= other; +	y /= other; +	return *this; +} + +template <class T> +Vector2<T> Vector2<T>::operator-() const { +	return {-x, -y}; +} + +template <class T> +bool Vector2<T>::operator==(const Vector2<T> & other) const { +	return x == other.x && y == other.y; +} + +template <class T> +bool Vector2<T>::operator!=(const Vector2<T> & other) const { +	return !(*this == other); +} + +} // namespace crepe diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 00523a6..b3298a7 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -104,13 +104,13 @@ SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) const {  		.h = sprite.sprite_rect.h,  	};  } -SDL_Rect SDLContext::get_dst_rect(const Sprite & sprite, const Vector2 & pos, +SDL_Rect SDLContext::get_dst_rect(const Sprite & sprite, const vec2 & pos,  								  const double & scale, const Camera & cam) const { -	double adjusted_x = (pos.x - cam.x) * cam.zoom; -	double adjusted_y = (pos.y - cam.y) * cam.zoom;  	double adjusted_w = sprite.sprite_rect.w * scale * cam.zoom;  	double adjusted_h = sprite.sprite_rect.h * scale * cam.zoom; +	double adjusted_x = (pos.x - cam.x) * cam.zoom - adjusted_w / 2; +	double adjusted_y = (pos.y - cam.y) * cam.zoom - adjusted_h / 2;  	return SDL_Rect{  		.x = static_cast<int>(adjusted_x), @@ -120,9 +120,8 @@ SDL_Rect SDLContext::get_dst_rect(const Sprite & sprite, const Vector2 & pos,  	};  } -void SDLContext::draw_particle(const Sprite & sprite, const Vector2 & pos, -							   const double & angle, const double & scale, -							   const Camera & camera) { +void SDLContext::draw_particle(const Sprite & sprite, const vec2 & pos, const double & angle, +							   const double & scale, const Camera & camera) {  	SDL_RendererFlip render_flip  		= (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index 841ffc9..20e30b3 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -12,7 +12,8 @@  #include "../api/Sprite.h"  #include "../api/Transform.h"  #include "api/Camera.h" -#include "api/Vector2.h" + +#include "types.h"  namespace crepe { @@ -120,7 +121,7 @@ private:  	 */  	void draw(const Sprite & sprite, const Transform & transform, const Camera & camera); -	void draw_particle(const Sprite & sprite, const Vector2 & pos, const double & angle, +	void draw_particle(const Sprite & sprite, const vec2 & pos, const double & angle,  					   const double & scale, const Camera & camera);  	//! Clears the screen, preparing for a new frame. @@ -153,7 +154,7 @@ private:  	 * on the camera   	 * \return sdl rectangle to draw a dst image to draw on the screen  	 */ -	SDL_Rect get_dst_rect(const Sprite & sprite, const Vector2 & pos, const double & scale, +	SDL_Rect get_dst_rect(const Sprite & sprite, const vec2 & pos, const double & scale,  						  const Camera & cam) const;  private: diff --git a/src/crepe/system/ParticleSystem.cpp b/src/crepe/system/ParticleSystem.cpp index fcf7522..0e62a57 100644 --- a/src/crepe/system/ParticleSystem.cpp +++ b/src/crepe/system/ParticleSystem.cpp @@ -4,7 +4,6 @@  #include "api/ParticleEmitter.h"  #include "api/Transform.h" -#include "api/Vector2.h"  #include "ComponentManager.h"  #include "ParticleSystem.h" @@ -42,17 +41,15 @@ void ParticleSystem::update() {  }  void ParticleSystem::emit_particle(ParticleEmitter & emitter, const Transform & transform) { -	constexpr double DEG_TO_RAD = M_PI / 180.0; +	constexpr float DEG_TO_RAD = M_PI / 180.0; -	Vector2 initial_position = emitter.data.position + transform.position; -	double random_angle -		= generate_random_angle(emitter.data.min_angle, emitter.data.max_angle); +	vec2 initial_position = emitter.data.position + transform.position; +	float random_angle = generate_random_angle(emitter.data.min_angle, emitter.data.max_angle); -	double random_speed -		= generate_random_speed(emitter.data.min_speed, emitter.data.max_speed); -	double angle_radians = random_angle * DEG_TO_RAD; +	float random_speed = generate_random_speed(emitter.data.min_speed, emitter.data.max_speed); +	float angle_radians = random_angle * DEG_TO_RAD; -	Vector2 velocity +	vec2 velocity  		= {random_speed * std::cos(angle_radians), random_speed * std::sin(angle_radians)};  	for (Particle & particle : emitter.data.particles) { @@ -77,7 +74,7 @@ int ParticleSystem::calculate_update(int count, double emission) const {  }  void ParticleSystem::check_bounds(ParticleEmitter & emitter, const Transform & transform) { -	Vector2 offset = emitter.data.boundary.offset + transform.position + emitter.data.position; +	vec2 offset = emitter.data.boundary.offset + transform.position + emitter.data.position;  	double half_width = emitter.data.boundary.width / 2.0;  	double half_height = emitter.data.boundary.height / 2.0; @@ -87,7 +84,7 @@ void ParticleSystem::check_bounds(ParticleEmitter & emitter, const Transform & t  	const double BOTTOM = offset.y + half_height;  	for (Particle & particle : emitter.data.particles) { -		const Vector2 & position = particle.position; +		const vec2 & position = particle.position;  		bool within_bounds = (position.x >= LEFT && position.x <= RIGHT && position.y >= TOP  							  && position.y <= BOTTOM); diff --git a/src/crepe/system/PhysicsSystem.cpp b/src/crepe/system/PhysicsSystem.cpp index bcde431..514a4b3 100644 --- a/src/crepe/system/PhysicsSystem.cpp +++ b/src/crepe/system/PhysicsSystem.cpp @@ -34,7 +34,7 @@ void PhysicsSystem::update() {  						if (rigidbody.data.angular_damping != 0) {  							rigidbody.data.angular_velocity *= rigidbody.data.angular_damping;  						} -						if (rigidbody.data.linear_damping != Vector2{0, 0}) { +						if (rigidbody.data.linear_damping != vec2{0, 0}) {  							rigidbody.data.linear_velocity *= rigidbody.data.linear_damping;  						} diff --git a/src/crepe/system/ScriptSystem.cpp b/src/crepe/system/ScriptSystem.cpp index c33309c..20a83f7 100644 --- a/src/crepe/system/ScriptSystem.cpp +++ b/src/crepe/system/ScriptSystem.cpp @@ -1,5 +1,3 @@ -#include <functional> -  #include "../ComponentManager.h"  #include "../api/BehaviorScript.h"  #include "../api/Script.h" @@ -12,30 +10,19 @@ using namespace crepe;  void ScriptSystem::update() {  	dbg_trace(); -	RefVector<Script> scripts = this->get_scripts(); - -	for (auto & script_ref : scripts) { -		Script & script = script_ref.get(); -		if (!script.initialized) { -			script.init(); -			script.initialized = true; -		} -		script.update(); -	} -} - -RefVector<Script> ScriptSystem::get_scripts() const { -	RefVector<Script> scripts = {};  	ComponentManager & mgr = this->component_manager;  	RefVector<BehaviorScript> behavior_scripts = mgr.get_components_by_type<BehaviorScript>(); -	for (auto behavior_script_ref : behavior_scripts) { -		BehaviorScript & behavior_script = behavior_script_ref.get(); +	for (BehaviorScript & behavior_script : behavior_scripts) {  		if (!behavior_script.active) continue; +  		Script * script = behavior_script.script.get();  		if (script == nullptr) continue; -		scripts.push_back(*script); -	} -	return scripts; +		if (!script->initialized) { +			script->init(); +			script->initialized = true; +		} +		script->update(); +	}  } diff --git a/src/crepe/system/ScriptSystem.h b/src/crepe/system/ScriptSystem.h index 32e1fcd..936e9ca 100644 --- a/src/crepe/system/ScriptSystem.h +++ b/src/crepe/system/ScriptSystem.h @@ -2,8 +2,6 @@  #include "System.h" -#include "../types.h" -  namespace crepe {  class Script; @@ -25,15 +23,6 @@ public:  	 * the \c BehaviorScript instance.  	 */  	void update() override; - -private: -	/** -	 * \brief Aggregate all active \c BehaviorScript components and return a list -	 * of references to their \c Script instances (utility) -	 * -	 * \returns List of active \c Script instances -	 */ -	RefVector<Script> get_scripts() const;  };  } // namespace crepe diff --git a/src/crepe/types.h b/src/crepe/types.h index 914c76c..17f1619 100644 --- a/src/crepe/types.h +++ b/src/crepe/types.h @@ -1,5 +1,7 @@  #pragma once +#include "api/Vector2.h" +  #include <cstdint>  #include <functional>  #include <vector> @@ -13,4 +15,16 @@ typedef uint32_t game_object_id_t;  template <typename T>  using RefVector = std::vector<std::reference_wrapper<T>>; +//! Default Vector2<int> type +typedef Vector2<int> ivec2; + +//! Default Vector2<unsigned int> type +typedef Vector2<unsigned int> uvec2; + +//! Default Vector2<float> type +typedef Vector2<float> vec2; + +//! Default Vector2<double> type +typedef Vector2<double> dvec2; +  } // namespace crepe diff --git a/src/crepe/util/Log.h b/src/crepe/util/Log.h index d55b11e..fc0bb3a 100644 --- a/src/crepe/util/Log.h +++ b/src/crepe/util/Log.h @@ -34,11 +34,11 @@ class Log {  public:  	//! Log message severity  	enum Level { -		TRACE, //< Include (internal) function calls -		DEBUG, //< Include dbg_logf output -		INFO, //< General-purpose messages -		WARNING, //< Non-fatal errors -		ERROR, //< Fatal errors +		TRACE, //!< Include (internal) function calls +		DEBUG, //!< Include dbg_logf output +		INFO, //!< General-purpose messages +		WARNING, //!< Non-fatal errors +		ERROR, //!< Fatal errors  	};  	/** diff --git a/src/doc/feature/scene.dox b/src/doc/feature/scene.dox index 5f34446..eedc69a 100644 --- a/src/doc/feature/scene.dox +++ b/src/doc/feature/scene.dox @@ -46,8 +46,8 @@ public:  	void load_scene() {  		auto & mgr = this->component_manager; -		GameObject object1 = mgr.new_object("object1", "tag_my_scene", Vector2{0, 0}, 0, 1); -		GameObject object2 = mgr.new_object("object2", "tag_my_scene", Vector2{1, 0}, 0, 1); +		GameObject object1 = mgr.new_object("object1", "tag_my_scene", vec2{0, 0}, 0, 1); +		GameObject object2 = mgr.new_object("object2", "tag_my_scene", vec2{1, 0}, 0, 1);  	}  	string get_name() const { return "my_scene"; } diff --git a/src/doc/internal/component.dox b/src/doc/internal/component.dox new file mode 100644 index 0000000..0dd4cb5 --- /dev/null +++ b/src/doc/internal/component.dox @@ -0,0 +1,41 @@ +// vim:ft=doxygen +namespace crepe { +/** + +\defgroup internal_component Components +\ingroup internal +\brief ECS Components + +Components are attached to GameObject instances and are composed by the game +programmer to create specific entities in the game world. While they are +implemented as C++ classes, components should be treated as C-style structs, +meaning all members are public and they do not contain functions. + +A basic component has the following structure: +```cpp +#include <crepe/Component.h> + +class MyComponent : public crepe::Component { +public: +	// Add your custom component's ininitializer properties after the `id` +	// parameter. The first parameter is controlled by GameObject::add_component, +	// while all other parameters are forwarded using std::forward. +	MyComponent(game_object_id_t id, ...); + +	// Optionally define the `get_instances_max` method to limit the amount of +	// instances of this component per GameObject. The default implementation for +	// this function returns -1, which means the instance count does not have an +	// upper limit: +	virtual int get_instances_max() const { return -1; } + +	// Properties +	// ... +}; +``` + +Generally, components are "handled" by \ref internal_system "systems", which may +optionally change the components' state. Components' state may also be +controlled by the game programmer through \ref feature_script "scripts". + +*/ +} diff --git a/src/doc/internal/resource.dox b/src/doc/internal/resource.dox new file mode 100644 index 0000000..56f1de0 --- /dev/null +++ b/src/doc/internal/resource.dox @@ -0,0 +1,12 @@ +// vim:ft=doxygen +namespace crepe { +/** + +\defgroup internal_resource Resources +\ingroup internal +\brief Concrete resources + +\todo This section is incomplete + +*/ +} diff --git a/src/doc/internal/style.dox b/src/doc/internal/style.dox new file mode 100644 index 0000000..dad2df0 --- /dev/null +++ b/src/doc/internal/style.dox @@ -0,0 +1,9 @@ +// vim:ft=doxygen +/** + +\defgroup internal_style Code style +\ingroup internal +\brief Coding conventions +\include{doc} contributing.md + +*/ diff --git a/src/doc/internal/system.dox b/src/doc/internal/system.dox new file mode 100644 index 0000000..17a101e --- /dev/null +++ b/src/doc/internal/system.dox @@ -0,0 +1,26 @@ +// vim:ft=doxygen +namespace crepe { +/** + +\defgroup internal_system Systems +\ingroup internal +\brief ECS Systems + +\todo This section is incomplete + +A system is responsible for processing the data stored in \ref +internal_component "components". + +A basic system has the following structure: +```cpp +#include <crepe/system/System.h> + +class MySystem : public System { +public: +	using System::System; +	void update() override; +}; +``` + +*/ +} diff --git a/src/doc/internals.dox b/src/doc/internals.dox new file mode 100644 index 0000000..2d2ca56 --- /dev/null +++ b/src/doc/internals.dox @@ -0,0 +1,10 @@ +// vim:ft=doxygen +/** + +\defgroup internal Internals +\brief Internal engine structure and other conventions + +\todo This page is incomplete +\todo Anything about Contexts? + +*/ diff --git a/src/doc/layout.xml b/src/doc/layout.xml index 2244fa7..fb4cc0c 100644 --- a/src/doc/layout.xml +++ b/src/doc/layout.xml @@ -1,10 +1,13 @@  <?xml version="1.0" encoding="UTF-8"?>  <doxygenlayout version="1.0">  	<navindex> -		<tab type="mainpage" visible="yes" title=""/> +		<tab type="mainpage" visible="yes" title="Intro"/> +		<tab type="user" url="@ref install" title="Installation"/> +		<tab type="user" url="@ref feature" title="Features"/> +		<tab type="user" url="@ref internal" title="Internals"/>  		<tab type="pages" visible="no" title="" intro=""/> -		<tab type="topics" visible="yes" title="" intro=""/> -		<tab type="modules" visible="yes" title="" intro=""> +		<tab type="topics" visible="no" title="" intro=""/> +		<tab type="modules" visible="no" title="" intro="">  			<tab type="modulelist" visible="yes" title="" intro=""/>  			<tab type="modulemembers" visible="yes" title="" intro=""/>  		</tab> @@ -12,9 +15,9 @@  			<tab type="namespacelist" visible="yes" title="" intro=""/>  			<tab type="namespacemembers" visible="yes" title="" intro=""/>  		</tab> -		<tab type="concepts" visible="yes" title=""> +		<tab type="concepts" visible="no" title="">  		</tab> -		<tab type="interfaces" visible="yes" title=""> +		<tab type="interfaces" visible="no" title="">  			<tab type="interfacelist" visible="yes" title="" intro=""/>  			<tab type="interfaceindex" visible="$ALPHABETICAL_INDEX" title=""/>  			<tab type="interfacehierarchy" visible="yes" title="" intro=""/> @@ -25,23 +28,24 @@  			<tab type="hierarchy" visible="yes" title="" intro=""/>  			<tab type="classmembers" visible="yes" title="" intro=""/>  		</tab> -		<tab type="structs" visible="yes" title=""> +		<tab type="structs" visible="no" title="">  			<tab type="structlist" visible="yes" title="" intro=""/>  			<tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/>  		</tab> -		<tab type="exceptions" visible="yes" title=""> +		<tab type="exceptions" visible="no" title="">  			<tab type="exceptionlist" visible="yes" title="" intro=""/>  			<tab type="exceptionindex" visible="$ALPHABETICAL_INDEX" title=""/>  			<tab type="exceptionhierarchy" visible="yes" title="" intro=""/>  		</tab> -		<tab type="files" visible="yes" title=""> +		<tab type="files" visible="no" title="">  			<tab type="filelist" visible="yes" title="" intro=""/>  			<tab type="globals" visible="yes" title="" intro=""/>  		</tab> -		<tab type="examples" visible="yes" title="" intro=""/> +		<tab type="examples" visible="no" title="" intro=""/>  	</navindex>  	<class>  		<briefdescription visible="yes"/> +		<detaileddescription title=""/>  		<includes visible="$SHOW_HEADERFILE"/>  		<inheritancegraph visible="yes"/>  		<collaborationgraph visible="yes"/> @@ -79,7 +83,6 @@  			<related title="" subtitle=""/>  			<membergroups visible="yes"/>  		</memberdecl> -		<detaileddescription title=""/>  		<memberdef>  			<inlineclasses title=""/>  			<typedefs title=""/> diff --git a/src/doc/style.css b/src/doc/style.css index 08bc9f5..daabd39 100644 --- a/src/doc/style.css +++ b/src/doc/style.css @@ -2,3 +2,5 @@  address {  	display: none;  } + +h2.groupheader { margin-top: revert; } diff --git a/src/example/rendering_particle.cpp b/src/example/rendering_particle.cpp index 4571afb..b38e860 100644 --- a/src/example/rendering_particle.cpp +++ b/src/example/rendering_particle.cpp @@ -1,5 +1,6 @@  #include "api/Camera.h"  #include "system/ParticleSystem.h" +#include "types.h"  #include <SDL2/SDL_timer.h>  #include <crepe/ComponentManager.h> @@ -23,14 +24,14 @@ using namespace std;  int main(int argc, char * argv[]) {  	ComponentManager mgr; -	GameObject game_object = mgr.new_object("", "", Vector2{100, 100}, 0, 0.1); +	GameObject game_object = mgr.new_object("", "", vec2{0, 0}, 0, 0.1);  	RenderSystem sys{mgr};  	ParticleSystem psys{mgr};  	Color color(255, 255, 255, 255);  	Sprite & test_sprite = game_object.add_component<Sprite>( -		make_shared<Texture>("../asset/texture/img.png"), color, FlipSettings{false, false}); +		make_shared<Texture>("asset/texture/img.png"), color, FlipSettings{false, false});  	test_sprite.order_in_layer = 5;  	auto & test = game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{ @@ -43,11 +44,11 @@ int main(int argc, char * argv[]) {  		.max_angle = 20,  		.begin_lifespan = 0,  		.end_lifespan = 60, -		.force_over_time = Vector2{0, 0}, +		.force_over_time = vec2{0, 0},  		.boundary{  			.width = 1000,  			.height = 1000, -			.offset = Vector2{0, 0}, +			.offset = vec2{0, 0},  			.reset_on_exit = false,  		},  		.sprite = test_sprite, @@ -55,7 +56,7 @@ int main(int argc, char * argv[]) {  	game_object.add_component<Camera>(Color::WHITE);  	game_object -		.add_component<Sprite>(make_shared<Texture>("../asset/texture/img.png"), color, +		.add_component<Sprite>(make_shared<Texture>("asset/texture/img.png"), color,  							   FlipSettings{false, false})  		.order_in_layer  		= 6; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 8cb4232..d310f6a 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -11,5 +11,5 @@ target_sources(test_main PUBLIC  	SceneManagerTest.cpp  	ValueBrokerTest.cpp  	DBTest.cpp +	Vector2Test.cpp  ) - diff --git a/src/test/ECSTest.cpp b/src/test/ECSTest.cpp index d5a5826..80b936b 100644 --- a/src/test/ECSTest.cpp +++ b/src/test/ECSTest.cpp @@ -17,7 +17,7 @@ public:  };  TEST_F(ECSTest, createGameObject) { -	GameObject obj = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); +	GameObject obj = mgr.new_object("body", "person", vec2{0, 0}, 0, 1);  	vector<reference_wrapper<Metadata>> metadata = mgr.get_components_by_type<Metadata>();  	vector<reference_wrapper<Transform>> transform = mgr.get_components_by_type<Transform>(); @@ -37,8 +37,8 @@ TEST_F(ECSTest, createGameObject) {  }  TEST_F(ECSTest, deleteAllGameObjects) { -	GameObject obj0 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); -	GameObject obj1 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); +	GameObject obj0 = mgr.new_object("body", "person", vec2{0, 0}, 0, 1); +	GameObject obj1 = mgr.new_object("body", "person", vec2{0, 0}, 0, 1);  	mgr.delete_all_components(); @@ -48,7 +48,7 @@ TEST_F(ECSTest, deleteAllGameObjects) {  	EXPECT_EQ(metadata.size(), 0);  	EXPECT_EQ(transform.size(), 0); -	GameObject obj2 = mgr.new_object("body2", "person2", Vector2{1, 0}, 5, 1); +	GameObject obj2 = mgr.new_object("body2", "person2", vec2{1, 0}, 5, 1);  	metadata = mgr.get_components_by_type<Metadata>();  	transform = mgr.get_components_by_type<Transform>(); @@ -70,8 +70,8 @@ TEST_F(ECSTest, deleteAllGameObjects) {  }  TEST_F(ECSTest, deleteGameObject) { -	GameObject obj0 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); -	GameObject obj1 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); +	GameObject obj0 = mgr.new_object("body", "person", vec2{0, 0}, 0, 1); +	GameObject obj1 = mgr.new_object("body", "person", vec2{0, 0}, 0, 1);  	mgr.delete_all_components_of_id(0); @@ -96,7 +96,7 @@ TEST_F(ECSTest, deleteGameObject) {  TEST_F(ECSTest, manyGameObjects) {  	for (int i = 0; i < 5000; i++) { -		GameObject obj = mgr.new_object("body", "person", Vector2{0, 0}, 0, i); +		GameObject obj = mgr.new_object("body", "person", vec2{0, 0}, 0, i);  	}  	vector<reference_wrapper<Metadata>> metadata = mgr.get_components_by_type<Metadata>(); @@ -128,7 +128,7 @@ TEST_F(ECSTest, manyGameObjects) {  	for (int i = 0; i < 10000 - 5000; i++) {  		string tag = "person" + to_string(i); -		GameObject obj = mgr.new_object("body", tag, Vector2{0, 0}, i, 0); +		GameObject obj = mgr.new_object("body", tag, vec2{0, 0}, i, 0);  	}  	metadata = mgr.get_components_by_type<Metadata>(); @@ -139,8 +139,8 @@ TEST_F(ECSTest, manyGameObjects) {  }  TEST_F(ECSTest, getComponentsByID) { -	GameObject obj0 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); -	GameObject obj1 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); +	GameObject obj0 = mgr.new_object("body", "person", vec2{0, 0}, 0, 1); +	GameObject obj1 = mgr.new_object("body", "person", vec2{0, 0}, 0, 1);  	vector<reference_wrapper<Metadata>> metadata = mgr.get_components_by_id<Metadata>(0);  	vector<reference_wrapper<Transform>> transform = mgr.get_components_by_id<Transform>(1); @@ -163,15 +163,15 @@ TEST_F(ECSTest, getComponentsByID) {  TEST_F(ECSTest, tooMuchComponents) {  	try { -		GameObject obj0 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); -		obj0.add_component<Transform>(Vector2{10, 10}, 0, 1); +		GameObject obj0 = mgr.new_object("body", "person", vec2{0, 0}, 0, 1); +		obj0.add_component<Transform>(vec2{10, 10}, 0, 1);  	} catch (const exception & e) {  		EXPECT_EQ(e.what(),  				  string("Exceeded maximum number of instances for this component type"));  	}  	try { -		GameObject obj1 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); +		GameObject obj1 = mgr.new_object("body", "person", vec2{0, 0}, 0, 1);  		obj1.add_component<Metadata>("body", "person");  	} catch (const exception & e) {  		EXPECT_EQ(e.what(), @@ -187,11 +187,11 @@ TEST_F(ECSTest, tooMuchComponents) {  TEST_F(ECSTest, partentChild) {  	{ -		GameObject body = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); -		GameObject right_leg = mgr.new_object("rightLeg", "person", Vector2{1, 1}, 0, 1); -		GameObject left_leg = mgr.new_object("leftLeg", "person", Vector2{1, 1}, 0, 1); -		GameObject right_foot = mgr.new_object("rightFoot", "person", Vector2{2, 2}, 0, 1); -		GameObject left_foot = mgr.new_object("leftFoot", "person", Vector2{2, 2}, 0, 1); +		GameObject body = mgr.new_object("body", "person", vec2{0, 0}, 0, 1); +		GameObject right_leg = mgr.new_object("rightLeg", "person", vec2{1, 1}, 0, 1); +		GameObject left_leg = mgr.new_object("leftLeg", "person", vec2{1, 1}, 0, 1); +		GameObject right_foot = mgr.new_object("rightFoot", "person", vec2{2, 2}, 0, 1); +		GameObject left_foot = mgr.new_object("leftFoot", "person", vec2{2, 2}, 0, 1);  		// Set the parent of each GameObject  		right_foot.set_parent(right_leg); diff --git a/src/test/ParticleTest.cpp b/src/test/ParticleTest.cpp index eee022f..8b81e74 100644 --- a/src/test/ParticleTest.cpp +++ b/src/test/ParticleTest.cpp @@ -25,7 +25,7 @@ public:  		std::vector<std::reference_wrapper<Transform>> transforms  			= mgr.get_components_by_id<Transform>(0);  		if (transforms.empty()) { -			GameObject game_object = mgr.new_object("", "", Vector2{0, 0}, 0, 0); +			GameObject game_object = mgr.new_object("", "", vec2{0, 0}, 0, 0);  			Color color(0, 0, 0, 0);  			Sprite & test_sprite = game_object.add_component<Sprite>( @@ -42,11 +42,11 @@ public:  				.max_angle = 0,  				.begin_lifespan = 0,  				.end_lifespan = 0, -				.force_over_time = Vector2{0, 0}, +				.force_over_time = vec2{0, 0},  				.boundary{  					.width = 0,  					.height = 0, -					.offset = Vector2{0, 0}, +					.offset = vec2{0, 0},  					.reset_on_exit = false,  				},  				.sprite = test_sprite, @@ -68,8 +68,8 @@ public:  		emitter.data.max_angle = 0;  		emitter.data.begin_lifespan = 0;  		emitter.data.end_lifespan = 0; -		emitter.data.force_over_time = Vector2{0, 0}; -		emitter.data.boundary = {0, 0, Vector2{0, 0}, false}; +		emitter.data.force_over_time = vec2{0, 0}; +		emitter.data.boundary = {0, 0, vec2{0, 0}, false};  		for (auto & particle : emitter.data.particles) {  			particle.active = false;  		} diff --git a/src/test/PhysicsTest.cpp b/src/test/PhysicsTest.cpp index 1e37c26..33b6020 100644 --- a/src/test/PhysicsTest.cpp +++ b/src/test/PhysicsTest.cpp @@ -20,12 +20,12 @@ public:  		vector<reference_wrapper<Transform>> transforms  			= mgr.get_components_by_id<Transform>(0);  		if (transforms.empty()) { -			auto entity = mgr.new_object("", "", Vector2{0, 0}, 0, 0); +			auto entity = mgr.new_object("", "", vec2{0, 0}, 0, 0);  			entity.add_component<Rigidbody>(Rigidbody::Data{  				.mass = 1,  				.gravity_scale = 1,  				.body_type = Rigidbody::BodyType::DYNAMIC, -				.max_linear_velocity = Vector2{10, 10}, +				.max_linear_velocity = vec2{10, 10},  				.max_angular_velocity = 10,  				.constraints = {0, 0},  				.use_gravity = true, diff --git a/src/test/SceneManagerTest.cpp b/src/test/SceneManagerTest.cpp index 1efcfb2..f3d2387 100644 --- a/src/test/SceneManagerTest.cpp +++ b/src/test/SceneManagerTest.cpp @@ -16,9 +16,9 @@ public:  	void load_scene() {  		auto & mgr = this->component_manager; -		GameObject object1 = mgr.new_object("scene_1", "tag_scene_1", Vector2{0, 0}, 0, 1); -		GameObject object2 = mgr.new_object("scene_1", "tag_scene_1", Vector2{1, 0}, 0, 1); -		GameObject object3 = mgr.new_object("scene_1", "tag_scene_1", Vector2{2, 0}, 0, 1); +		GameObject object1 = mgr.new_object("scene_1", "tag_scene_1", vec2{0, 0}, 0, 1); +		GameObject object2 = mgr.new_object("scene_1", "tag_scene_1", vec2{1, 0}, 0, 1); +		GameObject object3 = mgr.new_object("scene_1", "tag_scene_1", vec2{2, 0}, 0, 1);  	}  	string get_name() const { return "scene1"; } @@ -30,10 +30,10 @@ public:  	void load_scene() {  		auto & mgr = this->component_manager; -		GameObject object1 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 0}, 0, 1); -		GameObject object2 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 1}, 0, 1); -		GameObject object3 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 2}, 0, 1); -		GameObject object4 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 3}, 0, 1); +		GameObject object1 = mgr.new_object("scene_2", "tag_scene_2", vec2{0, 0}, 0, 1); +		GameObject object2 = mgr.new_object("scene_2", "tag_scene_2", vec2{0, 1}, 0, 1); +		GameObject object3 = mgr.new_object("scene_2", "tag_scene_2", vec2{0, 2}, 0, 1); +		GameObject object4 = mgr.new_object("scene_2", "tag_scene_2", vec2{0, 3}, 0, 1);  	}  	string get_name() const { return "scene2"; } diff --git a/src/test/ScriptTest.cpp b/src/test/ScriptTest.cpp index 19fef6d..78d5061 100644 --- a/src/test/ScriptTest.cpp +++ b/src/test/ScriptTest.cpp @@ -6,6 +6,8 @@  #include <crepe/ComponentManager.h>  #include <crepe/api/BehaviorScript.h> +#include <crepe/api/Event.h> +#include <crepe/api/EventManager.h>  #include <crepe/api/GameObject.h>  #include <crepe/api/Script.h>  #include <crepe/api/Vector2.h> @@ -15,58 +17,113 @@ using namespace std;  using namespace crepe;  using namespace testing; +class MyEvent : public Event {}; +  class ScriptTest : public Test {  public:  	ComponentManager component_manager{};  	ScriptSystem system{component_manager}; +	EventManager & event_manager = EventManager::get_instance();  	class MyScript : public Script {  		// NOTE: default (private) visibility of init and update shouldn't cause  		// issues! -		void init() { this->init_count++; } +		void init() { +			this->init_count++; + +			subscribe<MyEvent>([this](const MyEvent &) { +				this->event_count++; +				return true; +			}); + +			// init should never be called more than once +			EXPECT_LE(this->init_count, 1); +		}  		void update() { this->update_count++; }  	public:  		unsigned init_count = 0;  		unsigned update_count = 0; +		unsigned event_count = 0;  	}; -	BehaviorScript * behaviorscript_ref = nullptr; -	MyScript * script_ref = nullptr; +	OptionalRef<BehaviorScript> behaviorscript; +	OptionalRef<MyScript> script;  	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); +		this->behaviorscript = component; +		ASSERT_TRUE(this->behaviorscript); +		EXPECT_EQ(component.script.get(), nullptr);  		component.set_script<MyScript>(); -		ASSERT_NE(this->behaviorscript_ref->script.get(), nullptr); +		ASSERT_NE(component.script.get(), nullptr); -		this->script_ref = (MyScript *) this->behaviorscript_ref->script.get(); -		ASSERT_NE(this->script_ref, nullptr); +		this->script = *(MyScript *) component.script.get(); +		ASSERT_TRUE(this->script); + +		// sanity +		MyScript & script = this->script; +		ASSERT_EQ(script.init_count, 0); +		ASSERT_EQ(script.update_count, 0); +		ASSERT_EQ(script.event_count, 0);  	}  };  TEST_F(ScriptTest, Default) { -	EXPECT_EQ(0, this->script_ref->init_count); -	EXPECT_EQ(0, this->script_ref->update_count); +	MyScript & script = this->script; +	EXPECT_EQ(0, script.init_count); +	EXPECT_EQ(0, script.update_count); +	EXPECT_EQ(0, script.event_count);  }  TEST_F(ScriptTest, UpdateOnce) { -	EXPECT_EQ(0, this->script_ref->init_count); -	EXPECT_EQ(0, this->script_ref->update_count); +	MyScript & script = this->script; -	this->system.update(); -	EXPECT_EQ(1, this->script_ref->init_count); -	EXPECT_EQ(1, this->script_ref->update_count); +	system.update(); +	EXPECT_EQ(1, script.init_count); +	EXPECT_EQ(1, script.update_count); +	EXPECT_EQ(0, script.event_count);  } -TEST_F(ScriptTest, ListScripts) { -	size_t script_count = 0; -	for (auto & _ : this->system.get_scripts()) { -		script_count++; -	} -	ASSERT_EQ(1, script_count); +TEST_F(ScriptTest, UpdateInactive) { +	BehaviorScript & behaviorscript = this->behaviorscript; +	MyScript & script = this->script; + +	behaviorscript.active = false; +	system.update(); +	EXPECT_EQ(0, script.init_count); +	EXPECT_EQ(0, script.update_count); +	EXPECT_EQ(0, script.event_count); + +	behaviorscript.active = true; +	system.update(); +	EXPECT_EQ(1, script.init_count); +	EXPECT_EQ(1, script.update_count); +	EXPECT_EQ(0, script.event_count); +} + +TEST_F(ScriptTest, EventInactive) { +	BehaviorScript & behaviorscript = this->behaviorscript; +	MyScript & script = this->script; +	EventManager & evmgr = this->event_manager; + +	system.update(); +	behaviorscript.active = false; +	EXPECT_EQ(1, script.init_count); +	EXPECT_EQ(1, script.update_count); +	EXPECT_EQ(0, script.event_count); + +	evmgr.trigger_event<MyEvent>(); +	EXPECT_EQ(1, script.init_count); +	EXPECT_EQ(1, script.update_count); +	EXPECT_EQ(0, script.event_count); + +	behaviorscript.active = true; +	evmgr.trigger_event<MyEvent>(); +	EXPECT_EQ(1, script.init_count); +	EXPECT_EQ(1, script.update_count); +	EXPECT_EQ(1, script.event_count);  } diff --git a/src/test/Vector2Test.cpp b/src/test/Vector2Test.cpp new file mode 100644 index 0000000..17bca41 --- /dev/null +++ b/src/test/Vector2Test.cpp @@ -0,0 +1,384 @@ +#include <gtest/gtest.h> + +#include <crepe/api/Vector2.h> + +using namespace crepe; + +class Vector2Test : public ::testing::Test { +public: +	Vector2<int> int_vec1; +	Vector2<int> int_vec2; +	Vector2<double> double_vec1; +	Vector2<double> double_vec2; +	Vector2<long> long_vec1; +	Vector2<long> long_vec2; +	Vector2<float> float_vec1; +	Vector2<float> float_vec2; + +	void SetUp() override { +		int_vec1 = {1, 2}; +		int_vec2 = {3, 4}; +		double_vec1 = {1.0, 2.0}; +		double_vec2 = {3.0, 4.0}; +		long_vec1 = {1, 2}; +		long_vec2 = {3, 4}; +		float_vec1 = {1.0f, 2.0f}; +		float_vec2 = {3.0f, 4.0f}; +	} +}; + +TEST_F(Vector2Test, Subtract) { +	Vector2<int> result = int_vec1 - int_vec2; +	EXPECT_EQ(result.x, -2); +	EXPECT_EQ(result.y, -2); + +	Vector2<double> result2 = double_vec1 - double_vec2; +	EXPECT_FLOAT_EQ(result2.x, -2.0); +	EXPECT_FLOAT_EQ(result2.y, -2.0); + +	Vector2<long> result3 = long_vec1 - long_vec2; +	EXPECT_EQ(result3.x, -2); +	EXPECT_EQ(result3.y, -2); + +	Vector2<float> result4 = float_vec1 - float_vec2; +	EXPECT_FLOAT_EQ(result4.x, -2.0f); +	EXPECT_FLOAT_EQ(result4.y, -2.0f); +} + +TEST_F(Vector2Test, SubtractScalar) { +	Vector2<int> result = int_vec1 - 1; +	EXPECT_EQ(result.x, 0); +	EXPECT_EQ(result.y, 1); + +	Vector2<double> result2 = double_vec1 - 1.0; +	EXPECT_FLOAT_EQ(result2.x, 0.0); +	EXPECT_FLOAT_EQ(result2.y, 1.0); + +	Vector2<long> result3 = long_vec1 - 1; +	EXPECT_EQ(result3.x, 0); +	EXPECT_EQ(result3.y, 1); + +	Vector2<float> result4 = float_vec1 - 1.0f; +	EXPECT_FLOAT_EQ(result4.x, 0.0f); +	EXPECT_FLOAT_EQ(result4.y, 1.0f); +} + +TEST_F(Vector2Test, Add) { +	Vector2<int> result = int_vec1 + int_vec2; +	EXPECT_EQ(result.x, 4); +	EXPECT_EQ(result.y, 6); + +	Vector2<double> result2 = double_vec1 + double_vec2; +	EXPECT_FLOAT_EQ(result2.x, 4.0); +	EXPECT_FLOAT_EQ(result2.y, 6.0); + +	Vector2<long> result3 = long_vec1 + long_vec2; +	EXPECT_EQ(result3.x, 4); +	EXPECT_EQ(result3.y, 6); + +	Vector2<float> result4 = float_vec1 + float_vec2; +	EXPECT_FLOAT_EQ(result4.x, 4.0f); +	EXPECT_FLOAT_EQ(result4.y, 6.0f); +} + +TEST_F(Vector2Test, AddScalar) { +	Vector2<int> result = int_vec1 + 1; +	EXPECT_EQ(result.x, 2); +	EXPECT_EQ(result.y, 3); + +	Vector2<double> result2 = double_vec1 + 1.0; +	EXPECT_FLOAT_EQ(result2.x, 2.0); +	EXPECT_FLOAT_EQ(result2.y, 3.0); + +	Vector2<long> result3 = long_vec1 + 1; +	EXPECT_EQ(result3.x, 2); +	EXPECT_EQ(result3.y, 3); + +	Vector2<float> result4 = float_vec1 + 1.0f; +	EXPECT_FLOAT_EQ(result4.x, 2.0f); +	EXPECT_FLOAT_EQ(result4.y, 3.0f); +} + +TEST_F(Vector2Test, Multiply) { +	Vector2<int> result = int_vec1 * int_vec2; +	EXPECT_EQ(result.x, 3); +	EXPECT_EQ(result.y, 8); + +	Vector2<double> result2 = double_vec1 * double_vec2; +	EXPECT_FLOAT_EQ(result2.x, 3.0); +	EXPECT_FLOAT_EQ(result2.y, 8.0); + +	Vector2<long> result3 = long_vec1 * long_vec2; +	EXPECT_EQ(result3.x, 3); +	EXPECT_EQ(result3.y, 8); + +	Vector2<float> result4 = float_vec1 * float_vec2; +	EXPECT_FLOAT_EQ(result4.x, 3.0f); +	EXPECT_FLOAT_EQ(result4.y, 8.0f); +} + +TEST_F(Vector2Test, MultiplyScalar) { +	Vector2<int> result = int_vec1 * 2; +	EXPECT_EQ(result.x, 2); +	EXPECT_EQ(result.y, 4); + +	Vector2<double> result2 = double_vec1 * 2.0; +	EXPECT_FLOAT_EQ(result2.x, 2.0); +	EXPECT_FLOAT_EQ(result2.y, 4.0); + +	Vector2<long> result3 = long_vec1 * 2; +	EXPECT_EQ(result3.x, 2); +	EXPECT_EQ(result3.y, 4); + +	Vector2<float> result4 = float_vec1 * 2.0f; +	EXPECT_FLOAT_EQ(result4.x, 2.0f); +	EXPECT_FLOAT_EQ(result4.y, 4.0f); +} + +TEST_F(Vector2Test, Divide) { +	Vector2<int> result = int_vec1 / int_vec2; +	EXPECT_EQ(result.x, 0); +	EXPECT_EQ(result.y, 0); + +	Vector2<double> result2 = double_vec1 / double_vec2; +	EXPECT_FLOAT_EQ(result2.x, 0.33333333333333331); +	EXPECT_FLOAT_EQ(result2.y, 0.5); + +	Vector2<long> result3 = long_vec1 / long_vec2; +	EXPECT_EQ(result3.x, 0); +	EXPECT_EQ(result3.y, 0); + +	Vector2<float> result4 = float_vec1 / float_vec2; +	EXPECT_FLOAT_EQ(result4.x, 0.333333343f); +	EXPECT_FLOAT_EQ(result4.y, 0.5f); +} + +TEST_F(Vector2Test, DivideScalar) { +	Vector2<int> result = int_vec1 / 2; +	EXPECT_EQ(result.x, 0); +	EXPECT_EQ(result.y, 1); + +	Vector2<double> result2 = double_vec1 / 2.0; +	EXPECT_FLOAT_EQ(result2.x, 0.5); +	EXPECT_FLOAT_EQ(result2.y, 1.0); + +	Vector2<long> result3 = long_vec1 / 2; +	EXPECT_EQ(result3.x, 0); +	EXPECT_EQ(result3.y, 1); + +	Vector2<float> result4 = float_vec1 / 2.0f; +	EXPECT_FLOAT_EQ(result4.x, 0.5f); +	EXPECT_FLOAT_EQ(result4.y, 1.0f); +} + +TEST_F(Vector2Test, AddChain) { +	Vector2<int> result = int_vec1; +	result += int_vec2; +	EXPECT_EQ(result.x, 4); +	EXPECT_EQ(result.y, 6); + +	Vector2<double> result2 = double_vec1; +	result2 += double_vec2; +	EXPECT_FLOAT_EQ(result2.x, 4.0); +	EXPECT_FLOAT_EQ(result2.y, 6.0); + +	Vector2<long> result3 = long_vec1; +	result3 += long_vec2; +	EXPECT_EQ(result3.x, 4); +	EXPECT_EQ(result3.y, 6); + +	Vector2<float> result4 = float_vec1; +	result4 += float_vec2; +	EXPECT_FLOAT_EQ(result4.x, 4.0f); +	EXPECT_FLOAT_EQ(result4.y, 6.0f); +} + +TEST_F(Vector2Test, AddScalarChain) { +	Vector2<int> result = int_vec1; +	result += 1; +	EXPECT_EQ(result.x, 2); +	EXPECT_EQ(result.y, 3); + +	Vector2<double> result2 = double_vec1; +	result2 += 1.0; +	EXPECT_FLOAT_EQ(result2.x, 2.0); +	EXPECT_FLOAT_EQ(result2.y, 3.0); + +	Vector2<long> result3 = long_vec1; +	result3 += 1; +	EXPECT_EQ(result3.x, 2); +	EXPECT_EQ(result3.y, 3); + +	Vector2<float> result4 = float_vec1; +	result4 += 1.0f; +	EXPECT_FLOAT_EQ(result4.x, 2.0f); +	EXPECT_FLOAT_EQ(result4.y, 3.0f); +} + +TEST_F(Vector2Test, SubtractChain) { +	Vector2<int> result = int_vec1; +	result -= int_vec2; +	EXPECT_EQ(result.x, -2); +	EXPECT_EQ(result.y, -2); + +	Vector2<double> result2 = double_vec1; +	result2 -= double_vec2; +	EXPECT_FLOAT_EQ(result2.x, -2.0); +	EXPECT_FLOAT_EQ(result2.y, -2.0); + +	Vector2<long> result3 = long_vec1; +	result3 -= long_vec2; +	EXPECT_EQ(result3.x, -2); +	EXPECT_EQ(result3.y, -2); + +	Vector2<float> result4 = float_vec1; +	result4 -= float_vec2; +	EXPECT_FLOAT_EQ(result4.x, -2.0f); +	EXPECT_FLOAT_EQ(result4.y, -2.0f); +} + +TEST_F(Vector2Test, SubtractScalarChain) { +	Vector2<int> result = int_vec1; +	result -= 1; +	EXPECT_EQ(result.x, 0); +	EXPECT_EQ(result.y, 1); + +	Vector2<double> result2 = double_vec1; +	result2 -= 1.0; +	EXPECT_FLOAT_EQ(result2.x, 0.0); +	EXPECT_FLOAT_EQ(result2.y, 1.0); + +	Vector2<long> result3 = long_vec1; +	result3 -= 1; +	EXPECT_EQ(result3.x, 0); +	EXPECT_EQ(result3.y, 1); + +	Vector2<float> result4 = float_vec1; +	result4 -= 1.0f; +	EXPECT_FLOAT_EQ(result4.x, 0.0f); +	EXPECT_FLOAT_EQ(result4.y, 1.0f); +} + +TEST_F(Vector2Test, MultiplyChain) { +	Vector2<int> result = int_vec1; +	result *= int_vec2; +	EXPECT_EQ(result.x, 3); +	EXPECT_EQ(result.y, 8); + +	Vector2<double> result2 = double_vec1; +	result2 *= double_vec2; +	EXPECT_FLOAT_EQ(result2.x, 3.0); +	EXPECT_FLOAT_EQ(result2.y, 8.0); + +	Vector2<long> result3 = long_vec1; +	result3 *= long_vec2; +	EXPECT_EQ(result3.x, 3); +	EXPECT_EQ(result3.y, 8); + +	Vector2<float> result4 = float_vec1; +	result4 *= float_vec2; +	EXPECT_FLOAT_EQ(result4.x, 3.0f); +	EXPECT_FLOAT_EQ(result4.y, 8.0f); +} + +TEST_F(Vector2Test, MultiplyScalarChain) { +	Vector2<int> result = int_vec1; +	result *= 2; +	EXPECT_EQ(result.x, 2); +	EXPECT_EQ(result.y, 4); + +	Vector2<double> result2 = double_vec1; +	result2 *= 2.0; +	EXPECT_FLOAT_EQ(result2.x, 2.0); +	EXPECT_FLOAT_EQ(result2.y, 4.0); + +	Vector2<long> result3 = long_vec1; +	result3 *= 2; +	EXPECT_EQ(result3.x, 2); +	EXPECT_EQ(result3.y, 4); + +	Vector2<float> result4 = float_vec1; +	result4 *= 2.0f; +	EXPECT_FLOAT_EQ(result4.x, 2.0f); +	EXPECT_FLOAT_EQ(result4.y, 4.0f); +} + +TEST_F(Vector2Test, DivideChain) { +	Vector2<int> result = int_vec1; +	result /= int_vec2; +	EXPECT_EQ(result.x, 0); +	EXPECT_EQ(result.y, 0); + +	Vector2<double> result2 = double_vec1; +	result2 /= double_vec2; +	EXPECT_FLOAT_EQ(result2.x, 0.33333333333333331); +	EXPECT_FLOAT_EQ(result2.y, 0.5); + +	Vector2<long> result3 = long_vec1; +	result3 /= long_vec2; +	EXPECT_EQ(result3.x, 0); +	EXPECT_EQ(result3.y, 0); + +	Vector2<float> result4 = float_vec1; +	result4 /= float_vec2; +	EXPECT_FLOAT_EQ(result4.x, 0.333333343f); +	EXPECT_FLOAT_EQ(result4.y, 0.5f); +} + +TEST_F(Vector2Test, DivideScalarChain) { +	Vector2<int> result = int_vec1; +	result /= 2; +	EXPECT_EQ(result.x, 0); +	EXPECT_EQ(result.y, 1); + +	Vector2<double> result2 = double_vec1; +	result2 /= 2.0; +	EXPECT_FLOAT_EQ(result2.x, 0.5); +	EXPECT_FLOAT_EQ(result2.y, 1.0); + +	Vector2<long> result3 = long_vec1; +	result3 /= 2; +	EXPECT_EQ(result3.x, 0); +	EXPECT_EQ(result3.y, 1); + +	Vector2<float> result4 = float_vec1; +	result4 /= 2.0f; +	EXPECT_FLOAT_EQ(result4.x, 0.5f); +	EXPECT_FLOAT_EQ(result4.y, 1.0f); +} + +TEST_F(Vector2Test, Negatation) { +	Vector2<int> result = -int_vec1; +	EXPECT_EQ(result.x, -1); +	EXPECT_EQ(result.y, -2); + +	Vector2<double> result2 = -double_vec1; +	EXPECT_FLOAT_EQ(result2.x, -1.0); +	EXPECT_FLOAT_EQ(result2.y, -2.0); + +	Vector2<long> result3 = -long_vec1; +	EXPECT_EQ(result3.x, -1); +	EXPECT_EQ(result3.y, -2); + +	Vector2<float> result4 = -float_vec1; +	EXPECT_FLOAT_EQ(result4.x, -1.0f); +	EXPECT_FLOAT_EQ(result4.y, -2.0f); +} + +TEST_F(Vector2Test, Equals) { +	EXPECT_TRUE(int_vec1 == int_vec1); +	EXPECT_FALSE(int_vec1 == int_vec2); +	EXPECT_TRUE(double_vec1 == double_vec1); +	EXPECT_FALSE(double_vec1 == double_vec2); +	EXPECT_TRUE(long_vec1 == long_vec1); +	EXPECT_FALSE(long_vec1 == long_vec2); +} + +TEST_F(Vector2Test, NotEquals) { +	EXPECT_FALSE(int_vec1 != int_vec1); +	EXPECT_TRUE(int_vec1 != int_vec2); +	EXPECT_FALSE(double_vec1 != double_vec1); +	EXPECT_TRUE(double_vec1 != double_vec2); +	EXPECT_FALSE(long_vec1 != long_vec1); +	EXPECT_TRUE(long_vec1 != long_vec2); +} |