diff options
Diffstat (limited to 'src')
33 files changed, 847 insertions, 639 deletions
| diff --git a/src/crepe/Particle.cpp b/src/crepe/Particle.cpp index 485a0d4..b340826 100644 --- a/src/crepe/Particle.cpp +++ b/src/crepe/Particle.cpp @@ -2,8 +2,8 @@  using namespace crepe; -void Particle::reset(uint32_t lifespan, const vec2 & position, const vec2 & velocity, -					 double angle) { +void Particle::reset(unsigned int lifespan, const vec2 & position, const vec2 & velocity, +					 float angle) {  	// Initialize the particle state  	this->time_in_life = 0;  	this->lifespan = lifespan; @@ -15,16 +15,17 @@ void Particle::reset(uint32_t lifespan, const vec2 & position, const vec2 & velo  	this->force_over_time = {0, 0};  } -void Particle::update() { +void Particle::update(double dt) {  	// Deactivate particle if it has exceeded its lifespan -	if (++time_in_life >= lifespan) { +	time_in_life += dt; +	if (time_in_life >= lifespan) {  		this->active = false;  		return;  	}  	// Update velocity based on accumulated force and update position -	this->velocity += force_over_time; -	this->position += velocity; +	this->velocity += force_over_time * dt; +	this->position += velocity * dt;  }  void Particle::stop_movement() { diff --git a/src/crepe/Particle.h b/src/crepe/Particle.h index d0397c9..ee0cd66 100644 --- a/src/crepe/Particle.h +++ b/src/crepe/Particle.h @@ -14,8 +14,6 @@ namespace crepe {   * can also be reset or stopped.   */  class Particle { -	// TODO: add friend particleSsytem and rendersystem. Unit test will fail. -  public:  	//! Position of the particle in 2D space.  	vec2 position; @@ -24,13 +22,13 @@ public:  	//! Accumulated force affecting the particle over time.  	vec2 force_over_time;  	//! Total lifespan of the particle in milliseconds. -	uint32_t lifespan; +	float lifespan;  	//! Active state of the particle; true if it is in use, false otherwise.  	bool active = false;  	//! The time the particle has been alive, in milliseconds. -	uint32_t time_in_life = 0; +	float time_in_life = 0;  	//! The angle at which the particle is oriented or moving. -	double angle = 0; +	float angle = 0;  	/**  	 * \brief Resets the particle with new properties. @@ -43,14 +41,16 @@ 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 vec2 & position, const vec2 & velocity, double angle); +	void reset(unsigned int lifespan, const vec2 & position, const vec2 & velocity, +			   float angle);  	/**  	 * \brief Updates the particle's state.  	 *  	 * Advances the particle's position based on its velocity and applies accumulated forces.  	 * Deactivates the particle if its lifespan has expired. +	 * \param dt The amount of fixed delta time that has passed.  	 */ -	void update(); +	void update(double dt);  	/**  	 * \brief Stops the particle's movement.  	 * diff --git a/src/crepe/api/BoxCollider.cpp b/src/crepe/api/BoxCollider.cpp index c097a24..a893d41 100644 --- a/src/crepe/api/BoxCollider.cpp +++ b/src/crepe/api/BoxCollider.cpp @@ -4,7 +4,7 @@  using namespace crepe; -BoxCollider::BoxCollider(game_object_id_t game_object_id, const vec2 & offset, -						 const vec2 & dimensions) +BoxCollider::BoxCollider(game_object_id_t game_object_id, const vec2 & dimensions, +						 const vec2 & offset)  	: Collider(game_object_id, offset),  	  dimensions(dimensions) {} diff --git a/src/crepe/api/BoxCollider.h b/src/crepe/api/BoxCollider.h index 1ac4d46..d643e7f 100644 --- a/src/crepe/api/BoxCollider.h +++ b/src/crepe/api/BoxCollider.h @@ -13,7 +13,8 @@ namespace crepe {   */  class BoxCollider : public Collider {  public: -	BoxCollider(game_object_id_t game_object_id, const vec2 & offset, const vec2 & dimensions); +	BoxCollider(game_object_id_t game_object_id, const vec2 & dimensions, +				const vec2 & offset = {0, 0});  	//! Width and height of the box collider  	vec2 dimensions; diff --git a/src/crepe/api/Button.cpp b/src/crepe/api/Button.cpp index 76f74f0..305922c 100644 --- a/src/crepe/api/Button.cpp +++ b/src/crepe/api/Button.cpp @@ -3,9 +3,8 @@  namespace crepe {  Button::Button(game_object_id_t id, const vec2 & dimensions, const vec2 & offset, -			   const std::function<void()> & on_click, bool is_toggle) +			   const std::function<void()> & on_click)  	: UIObject(id, dimensions, offset), -	  is_toggle(is_toggle),  	  on_click(on_click) {}  } // namespace crepe diff --git a/src/crepe/api/Button.h b/src/crepe/api/Button.h index 61b18d7..08f5dec 100644 --- a/src/crepe/api/Button.h +++ b/src/crepe/api/Button.h @@ -15,19 +15,11 @@ public:  	 * \param id The unique ID of the game object associated with this button.  	 * \param dimensions The width and height of the UIObject  	 * \param offset The offset relative this GameObjects Transform -	 * \param is_toggle Optional flag to indicate if the button is a toggle button. Defaults to false.  	 * \param on_click callback function that will be invoked when the button is clicked.  	 */  	Button(game_object_id_t id, const vec2 & dimensions, const vec2 & offset, -		   const std::function<void()> & on_click, bool is_toggle = false); +		   const std::function<void()> & on_click); -	/** -	 * \brief Indicates if the button is a toggle button (can be pressed and released). -	 * -	 * A toggle button allows for a pressed/released state, whereas a regular button -	 * typically only has an on-click state. -	 */ -	bool is_toggle = false;  	// TODO: create separate toggle button class  	/**  	 * \brief The callback function to be executed when the button is clicked. @@ -56,8 +48,6 @@ public:  private:  	//! friend relation for is_pressed and hover variables  	friend class InputSystem; -	//! Indicates whether the toggle button is pressed -	bool is_pressed = false;  	//! Indicates whether the mouse is currently hovering over the button  	bool hover = false; diff --git a/src/crepe/api/CircleCollider.cpp b/src/crepe/api/CircleCollider.cpp index a4271e9..90ab5e7 100644 --- a/src/crepe/api/CircleCollider.cpp +++ b/src/crepe/api/CircleCollider.cpp @@ -2,7 +2,7 @@  using namespace crepe; -CircleCollider::CircleCollider(game_object_id_t game_object_id, const vec2 & offset, -							   float radius) +CircleCollider::CircleCollider(game_object_id_t game_object_id, float radius, +							   const vec2 & offset)  	: Collider(game_object_id, offset),  	  radius(radius) {} diff --git a/src/crepe/api/CircleCollider.h b/src/crepe/api/CircleCollider.h index c7bf66e..22da836 100644 --- a/src/crepe/api/CircleCollider.h +++ b/src/crepe/api/CircleCollider.h @@ -13,7 +13,8 @@ namespace crepe {   */  class CircleCollider : public Collider {  public: -	CircleCollider(game_object_id_t game_object_id, const vec2 & offset, float radius); +	CircleCollider(game_object_id_t game_object_id, float radius, +				   const vec2 & offset = {0, 0});  	//! Radius of the circle collider.  	float radius; diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 47a81b7..6b9e3ca 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -87,6 +87,11 @@ struct Config final {  		 */  		unsigned int size = 16;  	} font; +	//! Configuration for click tolerance. +	struct { +		//! The maximum number of pixels the mouse can move between MouseDown and MouseUp events to be considered a click. +		int click_tolerance = 5; +	} input;  	//! Audio system settings  	struct { diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h index f2f3daf..73bf461 100644 --- a/src/crepe/api/Event.h +++ b/src/crepe/api/Event.h @@ -3,7 +3,8 @@  #include <string> -#include "KeyCodes.h" +#include "api/KeyCodes.h" +#include "types.h"  namespace crepe { @@ -38,11 +39,8 @@ public:   */  class MousePressEvent : public Event {  public: -	//! X-coordinate of the mouse position at the time of the event. -	int mouse_x = 0; - -	//! Y-coordinate of the mouse position at the time of the event. -	int mouse_y = 0; +	//! mouse position in world coordinates (game units). +	vec2 mouse_pos = {0, 0};  	//! The mouse button that was pressed.  	MouseButton button = MouseButton::NONE; @@ -53,11 +51,8 @@ public:   */  class MouseClickEvent : public Event {  public: -	//! X-coordinate of the mouse position at the time of the event. -	int mouse_x = 0; - -	//! Y-coordinate of the mouse position at the time of the event. -	int mouse_y = 0; +	//! mouse position in world coordinates (game units). +	vec2 mouse_pos = {0, 0};  	//! The mouse button that was clicked.  	MouseButton button = MouseButton::NONE; @@ -68,11 +63,8 @@ public:   */  class MouseReleaseEvent : public Event {  public: -	//! X-coordinate of the mouse position at the time of the event. -	int mouse_x = 0; - -	//! Y-coordinate of the mouse position at the time of the event. -	int mouse_y = 0; +	//! mouse position in world coordinates (game units). +	vec2 mouse_pos = {0, 0};  	//! The mouse button that was released.  	MouseButton button = MouseButton::NONE; @@ -83,17 +75,10 @@ public:   */  class MouseMoveEvent : public Event {  public: -	//! X-coordinate of the mouse position at the time of the event. -	int mouse_x = 0; - -	//! Y-coordinate of the mouse position at the time of the event. -	int mouse_y = 0; - -	// Movement since last event in x -	int delta_x = 0; - -	// Movement since last event in y -	int delta_y = 0; +	//! mouse position in world coordinates (game units). +	vec2 mouse_pos = {0, 0}; +	//! The change in mouse position relative to the last position (in pixels). +	ivec2 mouse_delta = {0, 0};  };  /** @@ -101,12 +86,8 @@ public:   */  class MouseScrollEvent : public Event {  public: -	//! X-coordinate of the mouse position at the time of the event. -	int mouse_x = 0; - -	//! Y-coordinate of the mouse position at the time of the event. -	int mouse_y = 0; - +	//! mouse position in world coordinates (game units) when the scroll happened. +	vec2 mouse_pos = {0, 0};  	//! scroll direction (-1 = down, 1 = up)  	int scroll_direction = 0;  	//! scroll amount in y axis (from and away from the person). @@ -127,4 +108,55 @@ public:   */  class ShutDownEvent : public Event {}; +/** + * \brief Event triggered to indicate the window is overlapped by another window. + *  + * When two windows overlap the bottom window gets distorted and that window has to be redrawn. + */ +class WindowExposeEvent : public Event {}; + +/** + * \brief Event triggered to indicate the window is resized. + */ +class WindowResizeEvent : public Event { +public: +	//! new window dimensions +	ivec2 dimensions = {0, 0}; +}; + +/** + * \brief Event triggered to indicate the window is moved. + */ +class WindowMoveEvent : public Event { +public: +	//! The change in position relative to the last position (in pixels). +	ivec2 delta_move = {0, 0}; +}; + +/** + * \brief Event triggered to indicate the window is minimized. + */ +class WindowMinimizeEvent : public Event {}; + +/** + * \brief Event triggered to indicate the window is maximized + */ +class WindowMaximizeEvent : public Event {}; + +/** + * \brief Event triggered to indicate the window gained focus + *  + * This event is triggered when the window receives focus, meaning it becomes the active window + * for user interaction. + */ +class WindowFocusGainEvent : public Event {}; + +/** + * \brief Event triggered to indicate the window lost focus + *  + * This event is triggered when the window loses focus, meaning it is no longer the active window + * for user interaction. + */ +class WindowFocusLostEvent : public Event {}; +  } // namespace crepe diff --git a/src/crepe/api/KeyCodes.h b/src/crepe/api/KeyCodes.h index fcfc080..1b9573a 100644 --- a/src/crepe/api/KeyCodes.h +++ b/src/crepe/api/KeyCodes.h @@ -1,5 +1,9 @@  #pragma once + +#include <unordered_map> +  namespace crepe { +  //! Enumeration for mouse button inputs, including standard and extended buttons.  enum class MouseButton {  	NONE = 0, //!< No mouse button input. @@ -151,4 +155,6 @@ enum class Keycode {  	/// \}  	MENU = 348, //!< Menu key.  }; +//! Typedef for keyboard state. +typedef std::unordered_map<Keycode, bool> keyboard_state_t;  } // namespace crepe diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index b5e5ff7..7a78019 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -65,6 +65,7 @@ void LoopManager::fixed_update() {  	this->get_system<InputSystem>().update();  	this->event_manager.dispatch_events();  	this->get_system<ScriptSystem>().update(); +	this->get_system<ParticleSystem>().update();  	this->get_system<AISystem>().update();  	this->get_system<PhysicsSystem>().update();  	this->get_system<CollisionSystem>().update(); diff --git a/src/crepe/api/ParticleEmitter.cpp b/src/crepe/api/ParticleEmitter.cpp index 90b77a0..4f54bbd 100644 --- a/src/crepe/api/ParticleEmitter.cpp +++ b/src/crepe/api/ParticleEmitter.cpp @@ -1,11 +1,14 @@  #include "ParticleEmitter.h" +#include "api/Sprite.h"  using namespace crepe; -ParticleEmitter::ParticleEmitter(game_object_id_t game_object_id, const Data & data) +ParticleEmitter::ParticleEmitter(game_object_id_t game_object_id, const Sprite & sprite, +								 const Data & data)  	: Component(game_object_id), +	  sprite(sprite),  	  data(data) {  	for (size_t i = 0; i < this->data.max_particles; i++) { -		this->data.particles.emplace_back(); +		this->particles.emplace_back();  	}  } diff --git a/src/crepe/api/ParticleEmitter.h b/src/crepe/api/ParticleEmitter.h index b83fd61..8ac2e72 100644 --- a/src/crepe/api/ParticleEmitter.h +++ b/src/crepe/api/ParticleEmitter.h @@ -1,7 +1,11 @@  #pragma once +#include <cmath>  #include <vector> +#include "system/ParticleSystem.h" +#include "system/RenderSystem.h" +  #include "Component.h"  #include "Particle.h"  #include "types.h" @@ -26,15 +30,18 @@ public:  	 */  	struct Boundary {  		//! boundary width (midpoint is emitter location) -		double width = 0.0; +		float width = INFINITY;  		//! boundary height (midpoint is emitter location) -		double height = 0.0; +		float height = INFINITY;  		//! boundary offset from particle emitter location  		vec2 offset;  		//! reset on exit or stop velocity and set max postion  		bool reset_on_exit = false;  	}; +	//! sprite reference of displayed sprite +	const Sprite & sprite; +  	/**  	 * \brief Holds parameters that control particle emission.  	 * @@ -42,32 +49,28 @@ public:  	 * and the sprite used for rendering particles.  	 */  	struct Data { -		//! position of the emitter -		vec2 position; +		//! offset of the emitter relative to transform +		vec2 offset;  		//! maximum number of particles -		const unsigned int max_particles = 0; -		//! rate of particle emission per update (Lowest value = 0.001 any lower is ignored) -		double emission_rate = 0; +		const unsigned int max_particles = 256; +		//! rate of particle emission per second +		float emission_rate = 50;  		//! min speed of the particles -		double min_speed = 0; +		float min_speed = 100;  		//! min speed of the particles -		double max_speed = 0; +		float max_speed = 100;  		//! min angle of particle emission -		double min_angle = 0; +		float min_angle = 0;  		//! max angle of particle emission -		double max_angle = 0; -		//! begin Lifespan of particle (only visual) -		double begin_lifespan = 0.0; -		//! end Lifespan of particle -		double end_lifespan = 0.0; +		float max_angle = 0; +		//! begin Lifespan of particle in seconds (only visual) +		float begin_lifespan = 0.0; +		//! end Lifespan of particle in seconds +		float end_lifespan = 10.0;  		//! force over time (physics)  		vec2 force_over_time;  		//! particle boundary  		Boundary boundary; -		//! collection of particles -		std::vector<Particle> particles; -		//! sprite reference -		const Sprite & sprite;  	};  public: @@ -75,11 +78,21 @@ public:  	 * \param game_object_id  Identifier for the game object using this emitter.  	 * \param data            Configuration data defining particle properties.  	 */ -	ParticleEmitter(game_object_id_t game_object_id, const Data & data); +	ParticleEmitter(game_object_id_t game_object_id, const Sprite & sprite, const Data & data);  public:  	//! Configuration data for particle emission settings.  	Data data; + +private: +	//! Only ParticleSystem can move and read particles +	friend ParticleSystem; +	//! Only RenderSystem can read particles +	friend RenderSystem; +	//! Saves time left over from last update event. +	float spawn_accumulator = 0; +	//! collection of particles +	std::vector<Particle> particles;  };  } // namespace crepe diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index b08c8db..6900295 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -139,7 +139,7 @@ public:  		 * Each element represents a layer ID, and the GameObject will only detect  		 * collisions with other GameObjects that belong to these layers.  		 */ -		std::set<int> collision_layers; +		std::set<int> collision_layers = {0};  	};  public: diff --git a/src/crepe/api/Script.cpp b/src/crepe/api/Script.cpp index 753a9e3..583c04f 100644 --- a/src/crepe/api/Script.cpp +++ b/src/crepe/api/Script.cpp @@ -1,7 +1,7 @@  #include <string> +#include "../facade/SDLContext.h"  #include "../manager/SceneManager.h" -  #include "Script.h"  using namespace crepe; @@ -25,3 +25,16 @@ void Script::set_next_scene(const string & name) {  }  SaveManager & Script::get_save_manager() const { return this->mediator->save_manager; } + +const keyboard_state_t & Script::get_keyboard_state() const { +	SDLContext & sdl_context = this->mediator->sdl_context; +	return sdl_context.get_keyboard_state(); +} + +bool Script::get_key_state(Keycode key) const noexcept { +	try { +		return this->get_keyboard_state().at(key); +	} catch (...) { +		return false; +	} +} diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 668e5d1..65306cd 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -2,6 +2,7 @@  #include <vector> +#include "../api/KeyCodes.h"  #include "../manager/EventManager.h"  #include "../manager/Mediator.h"  #include "../system/CollisionSystem.h" @@ -134,7 +135,22 @@ protected:  	//! Retrieve SaveManager reference  	SaveManager & get_save_manager() const; - +	/** +	 * \brief Utility function to retrieve the keyboard state +	 * \see SDLContext::get_keyboard_state +	 *  +	 * \return current keyboard state map with Keycode as key and bool as value(true = pressed, false = not pressed) +	 *  +	 */ +	const keyboard_state_t & get_keyboard_state() const; +	/** +	 * \brief Utility function to retrieve a single key state. +	 * \see SDLContext::get_keyboard_state +	 *  +	 * \return Keycode state (true if pressed, false if not pressed). +	 *  +	 */ +	bool get_key_state(Keycode key) const noexcept;  	//! \}  private: diff --git a/src/crepe/facade/EventData.h b/src/crepe/facade/EventData.h new file mode 100644 index 0000000..a7526b4 --- /dev/null +++ b/src/crepe/facade/EventData.h @@ -0,0 +1,54 @@ +#pragma once +#include "../api/KeyCodes.h" +#include "../types.h" +namespace crepe { +//! EventType enum for passing eventType +enum EventType { +	NONE = 0, +	MOUSE_DOWN, +	MOUSE_UP, +	MOUSE_MOVE, +	MOUSE_WHEEL, +	KEY_UP, +	KEY_DOWN, +	SHUTDOWN, +	WINDOW_MINIMIZE, +	WINDOW_MAXIMIZE, +	WINDOW_FOCUS_GAIN, +	WINDOW_FOCUS_LOST, +	WINDOW_MOVE, +	WINDOW_RESIZE, +	WINDOW_EXPOSE, +}; + +//! Struct for storing key data. +struct KeyData { +	Keycode key = Keycode::NONE; +	bool key_repeat = false; +}; + +//! Struct for storing mouse data. +struct MouseData { +	MouseButton mouse_button = MouseButton::NONE; +	ivec2 mouse_position = {-1, -1}; +	int scroll_direction = -1; +	float scroll_delta = INFINITY; +	ivec2 rel_mouse_move = {-1, -1}; +}; + +//! Struct for storing window data. +struct WindowData { +	ivec2 move_delta; +	ivec2 resize_dimension; +}; + +//! EventData struct for passing event data from facade +struct EventData { +	EventType event_type = EventType::NONE; +	union { +		KeyData key_data; +		MouseData mouse_data; +		WindowData window_data; +	} data; +}; +} // namespace crepe diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index c88687e..fffbe34 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -80,118 +80,23 @@ SDLContext::~SDLContext() {  	SDL_Quit();  } -Keycode SDLContext::sdl_to_keycode(SDL_Keycode sdl_key) { -	static const std::array<Keycode, SDL_NUM_SCANCODES> LOOKUP_TABLE = [] { -		std::array<Keycode, SDL_NUM_SCANCODES> table{}; -		table.fill(Keycode::NONE); - -		table[SDL_SCANCODE_SPACE] = Keycode::SPACE; -		table[SDL_SCANCODE_APOSTROPHE] = Keycode::APOSTROPHE; -		table[SDL_SCANCODE_COMMA] = Keycode::COMMA; -		table[SDL_SCANCODE_MINUS] = Keycode::MINUS; -		table[SDL_SCANCODE_PERIOD] = Keycode::PERIOD; -		table[SDL_SCANCODE_SLASH] = Keycode::SLASH; -		table[SDL_SCANCODE_0] = Keycode::D0; -		table[SDL_SCANCODE_1] = Keycode::D1; -		table[SDL_SCANCODE_2] = Keycode::D2; -		table[SDL_SCANCODE_3] = Keycode::D3; -		table[SDL_SCANCODE_4] = Keycode::D4; -		table[SDL_SCANCODE_5] = Keycode::D5; -		table[SDL_SCANCODE_6] = Keycode::D6; -		table[SDL_SCANCODE_7] = Keycode::D7; -		table[SDL_SCANCODE_8] = Keycode::D8; -		table[SDL_SCANCODE_9] = Keycode::D9; -		table[SDL_SCANCODE_SEMICOLON] = Keycode::SEMICOLON; -		table[SDL_SCANCODE_EQUALS] = Keycode::EQUAL; -		table[SDL_SCANCODE_A] = Keycode::A; -		table[SDL_SCANCODE_B] = Keycode::B; -		table[SDL_SCANCODE_C] = Keycode::C; -		table[SDL_SCANCODE_D] = Keycode::D; -		table[SDL_SCANCODE_E] = Keycode::E; -		table[SDL_SCANCODE_F] = Keycode::F; -		table[SDL_SCANCODE_G] = Keycode::G; -		table[SDL_SCANCODE_H] = Keycode::H; -		table[SDL_SCANCODE_I] = Keycode::I; -		table[SDL_SCANCODE_J] = Keycode::J; -		table[SDL_SCANCODE_K] = Keycode::K; -		table[SDL_SCANCODE_L] = Keycode::L; -		table[SDL_SCANCODE_M] = Keycode::M; -		table[SDL_SCANCODE_N] = Keycode::N; -		table[SDL_SCANCODE_O] = Keycode::O; -		table[SDL_SCANCODE_P] = Keycode::P; -		table[SDL_SCANCODE_Q] = Keycode::Q; -		table[SDL_SCANCODE_R] = Keycode::R; -		table[SDL_SCANCODE_S] = Keycode::S; -		table[SDL_SCANCODE_T] = Keycode::T; -		table[SDL_SCANCODE_U] = Keycode::U; -		table[SDL_SCANCODE_V] = Keycode::V; -		table[SDL_SCANCODE_W] = Keycode::W; -		table[SDL_SCANCODE_X] = Keycode::X; -		table[SDL_SCANCODE_Y] = Keycode::Y; -		table[SDL_SCANCODE_Z] = Keycode::Z; -		table[SDL_SCANCODE_LEFTBRACKET] = Keycode::LEFT_BRACKET; -		table[SDL_SCANCODE_BACKSLASH] = Keycode::BACKSLASH; -		table[SDL_SCANCODE_RIGHTBRACKET] = Keycode::RIGHT_BRACKET; -		table[SDL_SCANCODE_GRAVE] = Keycode::GRAVE_ACCENT; -		table[SDL_SCANCODE_ESCAPE] = Keycode::ESCAPE; -		table[SDL_SCANCODE_RETURN] = Keycode::ENTER; -		table[SDL_SCANCODE_TAB] = Keycode::TAB; -		table[SDL_SCANCODE_BACKSPACE] = Keycode::BACKSPACE; -		table[SDL_SCANCODE_INSERT] = Keycode::INSERT; -		table[SDL_SCANCODE_DELETE] = Keycode::DELETE; -		table[SDL_SCANCODE_RIGHT] = Keycode::RIGHT; -		table[SDL_SCANCODE_LEFT] = Keycode::LEFT; -		table[SDL_SCANCODE_DOWN] = Keycode::DOWN; -		table[SDL_SCANCODE_UP] = Keycode::UP; -		table[SDL_SCANCODE_PAGEUP] = Keycode::PAGE_UP; -		table[SDL_SCANCODE_PAGEDOWN] = Keycode::PAGE_DOWN; -		table[SDL_SCANCODE_HOME] = Keycode::HOME; -		table[SDL_SCANCODE_END] = Keycode::END; -		table[SDL_SCANCODE_CAPSLOCK] = Keycode::CAPS_LOCK; -		table[SDL_SCANCODE_SCROLLLOCK] = Keycode::SCROLL_LOCK; -		table[SDL_SCANCODE_NUMLOCKCLEAR] = Keycode::NUM_LOCK; -		table[SDL_SCANCODE_PRINTSCREEN] = Keycode::PRINT_SCREEN; -		table[SDL_SCANCODE_PAUSE] = Keycode::PAUSE; -		table[SDL_SCANCODE_F1] = Keycode::F1; -		table[SDL_SCANCODE_F2] = Keycode::F2; -		table[SDL_SCANCODE_F3] = Keycode::F3; -		table[SDL_SCANCODE_F4] = Keycode::F4; -		table[SDL_SCANCODE_F5] = Keycode::F5; -		table[SDL_SCANCODE_F6] = Keycode::F6; -		table[SDL_SCANCODE_F7] = Keycode::F7; -		table[SDL_SCANCODE_F8] = Keycode::F8; -		table[SDL_SCANCODE_F9] = Keycode::F9; -		table[SDL_SCANCODE_F10] = Keycode::F10; -		table[SDL_SCANCODE_F11] = Keycode::F11; -		table[SDL_SCANCODE_F12] = Keycode::F12; -		table[SDL_SCANCODE_KP_0] = Keycode::KP0; -		table[SDL_SCANCODE_KP_1] = Keycode::KP1; -		table[SDL_SCANCODE_KP_2] = Keycode::KP2; -		table[SDL_SCANCODE_KP_3] = Keycode::KP3; -		table[SDL_SCANCODE_KP_4] = Keycode::KP4; -		table[SDL_SCANCODE_KP_5] = Keycode::KP5; -		table[SDL_SCANCODE_KP_6] = Keycode::KP6; -		table[SDL_SCANCODE_KP_7] = Keycode::KP7; -		table[SDL_SCANCODE_KP_8] = Keycode::KP8; -		table[SDL_SCANCODE_KP_9] = Keycode::KP9; -		table[SDL_SCANCODE_LSHIFT] = Keycode::LEFT_SHIFT; -		table[SDL_SCANCODE_LCTRL] = Keycode::LEFT_CONTROL; -		table[SDL_SCANCODE_LALT] = Keycode::LEFT_ALT; -		table[SDL_SCANCODE_LGUI] = Keycode::LEFT_SUPER; -		table[SDL_SCANCODE_RSHIFT] = Keycode::RIGHT_SHIFT; -		table[SDL_SCANCODE_RCTRL] = Keycode::RIGHT_CONTROL; -		table[SDL_SCANCODE_RALT] = Keycode::RIGHT_ALT; -		table[SDL_SCANCODE_RGUI] = Keycode::RIGHT_SUPER; -		table[SDL_SCANCODE_MENU] = Keycode::MENU; +Keycode SDLContext::sdl_to_keycode(SDL_Scancode sdl_key) { +	if (!lookup_table.contains(sdl_key)) return Keycode::NONE; +	return lookup_table.at(sdl_key); +} -		return table; -	}(); +const keyboard_state_t & SDLContext::get_keyboard_state() { +	SDL_PumpEvents(); +	const Uint8 * current_state = SDL_GetKeyboardState(nullptr); -	if (sdl_key < 0 || sdl_key >= SDL_NUM_SCANCODES) { -		return Keycode::NONE; -	} +	for (int i = 0; i < SDL_NUM_SCANCODES; ++i) { -	return LOOKUP_TABLE[sdl_key]; +		Keycode key = sdl_to_keycode(static_cast<SDL_Scancode>(i)); +		if (key != Keycode::NONE) { +			this->keyboard_state[key] = current_state[i] != 0; +		} +	} +	return this->keyboard_state;  }  MouseButton SDLContext::sdl_to_mousebutton(Uint8 sdl_button) { @@ -370,8 +275,8 @@ ivec2 SDLContext::get_size(const Texture & ctx) {  	return size;  } -std::vector<SDLContext::EventData> SDLContext::get_events() { -	std::vector<SDLContext::EventData> event_list; +std::vector<EventData> SDLContext::get_events() { +	std::vector<EventData> event_list;  	SDL_Event event;  	const CameraAuxiliaryData & cam = this->cam_aux_data;  	while (SDL_PollEvent(&event)) { @@ -380,61 +285,130 @@ std::vector<SDLContext::EventData> SDLContext::get_events() {  		mouse_pos.y = (event.button.y - cam.bar_size.y) / cam.render_scale.y;  		switch (event.type) {  			case SDL_QUIT: -				event_list.push_back(EventData{ -					.event_type = SDLContext::EventType::SHUTDOWN, -				}); +				event_list.push_back({.event_type = EventType::SHUTDOWN});  				break;  			case SDL_KEYDOWN:  				event_list.push_back(EventData{ -					.event_type = SDLContext::EventType::KEYDOWN, -					.key = sdl_to_keycode(event.key.keysym.scancode), -					.key_repeat = (event.key.repeat != 0), +					.event_type = EventType::KEY_DOWN, +					.data = { +						.key_data = { +							.key = this->sdl_to_keycode(event.key.keysym.scancode), +							.key_repeat = event.key.repeat != 0, +						}, +					},  				});  				break; +  			case SDL_KEYUP:  				event_list.push_back(EventData{ -					.event_type = SDLContext::EventType::KEYUP, -					.key = sdl_to_keycode(event.key.keysym.scancode), +					.event_type = EventType::KEY_UP, +					.data = { +						.key_data = { +							.key = this->sdl_to_keycode(event.key.keysym.scancode), +							.key_repeat = event.key.repeat != 0, +						}, +					},  				});  				break; +  			case SDL_MOUSEBUTTONDOWN:  				event_list.push_back(EventData{ -					.event_type = SDLContext::EventType::MOUSEDOWN, -					.mouse_button = sdl_to_mousebutton(event.button.button), -					.mouse_position = mouse_pos, +					.event_type = EventType::MOUSE_DOWN, +					.data = { +						.mouse_data = { +							.mouse_button = this->sdl_to_mousebutton(event.button.button), +							.mouse_position = mouse_pos, +						}, +					},  				});  				break; -			case SDL_MOUSEBUTTONUP: { -				int x, y; -				SDL_GetMouseState(&x, &y); +			case SDL_MOUSEBUTTONUP:  				event_list.push_back(EventData{ -					.event_type = SDLContext::EventType::MOUSEUP, -					.mouse_button = sdl_to_mousebutton(event.button.button), -					.mouse_position = mouse_pos, +					.event_type = EventType::MOUSE_UP, +					.data = { +						.mouse_data = { +							.mouse_button = this->sdl_to_mousebutton(event.button.button), +							.mouse_position = mouse_pos, +						}, +					},  				}); -			} break; +				break; -			case SDL_MOUSEMOTION: { -				event_list.push_back( -					EventData{.event_type = SDLContext::EventType::MOUSEMOVE, -							  .mouse_position = mouse_pos, -							  .rel_mouse_move = {event.motion.xrel, event.motion.yrel}}); -			} break; +			case SDL_MOUSEMOTION: +				event_list.push_back(EventData{ +					.event_type = EventType::MOUSE_MOVE, +					.data = { +						.mouse_data = { +							.mouse_position = mouse_pos, +							.rel_mouse_move = {event.motion.xrel, event.motion.yrel}, +						}, +					}, +				}); +				break; -			case SDL_MOUSEWHEEL: { +			case SDL_MOUSEWHEEL:  				event_list.push_back(EventData{ -					.event_type = SDLContext::EventType::MOUSEWHEEL, -					.mouse_position = mouse_pos, -					// TODO: why is this needed? -					.scroll_direction = event.wheel.y < 0 ? -1 : 1, -					.scroll_delta = event.wheel.preciseY, +					.event_type = EventType::MOUSE_WHEEL, +					.data = { +						.mouse_data = { +							.mouse_position = mouse_pos, +							.scroll_direction = event.wheel.y < 0 ? -1 : 1, +							.scroll_delta = event.wheel.preciseY, +						}, +					},  				}); -			} break; +				break; +			case SDL_WINDOWEVENT: +				this->handle_window_event(event.window, event_list); +				break;  		}  	} +  	return event_list;  } +void SDLContext::handle_window_event(const SDL_WindowEvent & window_event, +									 std::vector<EventData> & event_list) { +	switch (window_event.event) { +		case SDL_WINDOWEVENT_EXPOSED: +			event_list.push_back(EventData{EventType::WINDOW_EXPOSE}); +			break; +		case SDL_WINDOWEVENT_RESIZED: +			event_list.push_back(EventData{ +					.event_type = EventType::WINDOW_RESIZE, +					.data = { +						.window_data = { +							.resize_dimension = {window_event.data1, window_event.data2} +						}, +					}, +				}); +			break; +		case SDL_WINDOWEVENT_MOVED: +			event_list.push_back(EventData{ +					.event_type = EventType::WINDOW_MOVE, +					.data = { +						.window_data = { +							.move_delta = {window_event.data1, window_event.data2} +						}, +					}, +				}); +			break; + +		case SDL_WINDOWEVENT_MINIMIZED: +			event_list.push_back(EventData{EventType::WINDOW_MINIMIZE}); +			break; +		case SDL_WINDOWEVENT_MAXIMIZED: +			event_list.push_back(EventData{EventType::WINDOW_MAXIMIZE}); +			break; +		case SDL_WINDOWEVENT_FOCUS_GAINED: +			event_list.push_back(EventData{EventType::WINDOW_FOCUS_GAIN}); +			break; +		case SDL_WINDOWEVENT_FOCUS_LOST: +			event_list.push_back(EventData{EventType::WINDOW_FOCUS_LOST}); +			break; +	} +} +  void SDLContext::set_color_texture(const Texture & texture, const Color & color) {  	SDL_SetTextureColorMod(texture.get_img(), color.r, color.g, color.b);  	SDL_SetTextureAlphaMod(texture.get_img(), color.a); diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index 6f6eddb..b687f87 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -9,7 +9,9 @@  #include <functional>  #include <memory>  #include <string> +#include <unordered_map> +#include "../types.h"  #include "api/Camera.h"  #include "api/Color.h"  #include "api/KeyCodes.h" @@ -17,10 +19,10 @@  #include "api/Transform.h"  #include "types.h" +#include "EventData.h"  #include "FontFacade.h"  namespace crepe { -  class Texture;  class Mediator; @@ -70,29 +72,11 @@ public:  	};  public: -	//! EventType enum for passing eventType -	enum EventType { -		NONE = 0, -		MOUSEDOWN, -		MOUSEUP, -		MOUSEMOVE, -		MOUSEWHEEL, -		KEYUP, -		KEYDOWN, -		SHUTDOWN, - -	}; -	//! EventData struct for passing event data from facade -	struct EventData { -		SDLContext::EventType event_type = SDLContext::EventType::NONE; -		Keycode key = Keycode::NONE; -		bool key_repeat = false; -		MouseButton mouse_button = MouseButton::NONE; -		ivec2 mouse_position = {-1, -1}; -		int scroll_direction = -1; -		float scroll_delta = INFINITY; -		ivec2 rel_mouse_move = {-1, -1}; -	}; +	/** +	 * \brief Gets the singleton instance of SDLContext. +	 * \return Reference to the SDLContext instance. +	 */ +	static SDLContext & get_instance();  public:  	SDLContext(const SDLContext &) = delete; @@ -123,18 +107,25 @@ public:  	 *  	 * \return Events that occurred since last call to `get_events()`  	 */ -	std::vector<SDLContext::EventData> get_events(); - +	std::vector<EventData> get_events();  	/** -	 * \brief Converts an SDL key code to the custom Keycode type. +	 * \brief Fills event_list with triggered window events +	 * +	 * This method checks if any window events are triggered and adds them to the event_list.  	 * -	 * This method maps an SDL key code to the corresponding `Keycode` enum value, +	 */ +	void handle_window_event(const SDL_WindowEvent & window_event, +							 std::vector<EventData> & event_list); +	/** +	 * \brief Converts an SDL scan code to the custom Keycode type. +	 * +	 * This method maps an SDL scan code to the corresponding `Keycode` enum value,  	 * which is used internally by the system to identify the keys.  	 * -	 * \param sdl_key The SDL key code to convert. +	 * \param sdl_key The SDL scan code to convert.  	 * \return The corresponding `Keycode` value or `Keycode::NONE` if the key is unrecognized.  	 */ -	Keycode sdl_to_keycode(SDL_Keycode sdl_key); +	Keycode sdl_to_keycode(SDL_Scancode sdl_key);  	/**  	 * \brief Converts an SDL mouse button code to the custom MouseButton type. @@ -146,6 +137,16 @@ public:  	 * \return The corresponding `MouseButton` value or `MouseButton::NONE` if the key is unrecognized  	 */  	MouseButton sdl_to_mousebutton(Uint8 sdl_button); +	/** +	 * \brief Gets the current state of the keyboard. +	 * +	 * Updates the internal keyboard state by checking the current key states using +	 * SDL's `SDL_GetKeyboardState()`, and returns a reference to the `keyboard_state_t`. +	 * +	 * \return A constant reference to the `keyboard_state_t`, which holds the state +	 *         of each key (true = pressed, false = not pressed). +	 */ +	const keyboard_state_t & get_keyboard_state();  public:  	/** @@ -257,6 +258,108 @@ public:  	 * \return asset with the font style absolute path  	 */  	Asset get_font_from_name(const std::string & font_family); +	//! variable to store the state of each key (true = pressed, false = not pressed) +	keyboard_state_t keyboard_state; +	//! lookup table for converting SDL_SCANCODES to Keycodes +	const std::unordered_map<SDL_Scancode, Keycode> lookup_table +		= {{SDL_SCANCODE_SPACE, Keycode::SPACE}, +		   {SDL_SCANCODE_APOSTROPHE, Keycode::APOSTROPHE}, +		   {SDL_SCANCODE_COMMA, Keycode::COMMA}, +		   {SDL_SCANCODE_MINUS, Keycode::MINUS}, +		   {SDL_SCANCODE_PERIOD, Keycode::PERIOD}, +		   {SDL_SCANCODE_SLASH, Keycode::SLASH}, +		   {SDL_SCANCODE_0, Keycode::D0}, +		   {SDL_SCANCODE_1, Keycode::D1}, +		   {SDL_SCANCODE_2, Keycode::D2}, +		   {SDL_SCANCODE_3, Keycode::D3}, +		   {SDL_SCANCODE_4, Keycode::D4}, +		   {SDL_SCANCODE_5, Keycode::D5}, +		   {SDL_SCANCODE_6, Keycode::D6}, +		   {SDL_SCANCODE_7, Keycode::D7}, +		   {SDL_SCANCODE_8, Keycode::D8}, +		   {SDL_SCANCODE_9, Keycode::D9}, +		   {SDL_SCANCODE_SEMICOLON, Keycode::SEMICOLON}, +		   {SDL_SCANCODE_EQUALS, Keycode::EQUAL}, +		   {SDL_SCANCODE_A, Keycode::A}, +		   {SDL_SCANCODE_B, Keycode::B}, +		   {SDL_SCANCODE_C, Keycode::C}, +		   {SDL_SCANCODE_D, Keycode::D}, +		   {SDL_SCANCODE_E, Keycode::E}, +		   {SDL_SCANCODE_F, Keycode::F}, +		   {SDL_SCANCODE_G, Keycode::G}, +		   {SDL_SCANCODE_H, Keycode::H}, +		   {SDL_SCANCODE_I, Keycode::I}, +		   {SDL_SCANCODE_J, Keycode::J}, +		   {SDL_SCANCODE_K, Keycode::K}, +		   {SDL_SCANCODE_L, Keycode::L}, +		   {SDL_SCANCODE_M, Keycode::M}, +		   {SDL_SCANCODE_N, Keycode::N}, +		   {SDL_SCANCODE_O, Keycode::O}, +		   {SDL_SCANCODE_P, Keycode::P}, +		   {SDL_SCANCODE_Q, Keycode::Q}, +		   {SDL_SCANCODE_R, Keycode::R}, +		   {SDL_SCANCODE_S, Keycode::S}, +		   {SDL_SCANCODE_T, Keycode::T}, +		   {SDL_SCANCODE_U, Keycode::U}, +		   {SDL_SCANCODE_V, Keycode::V}, +		   {SDL_SCANCODE_W, Keycode::W}, +		   {SDL_SCANCODE_X, Keycode::X}, +		   {SDL_SCANCODE_Y, Keycode::Y}, +		   {SDL_SCANCODE_Z, Keycode::Z}, +		   {SDL_SCANCODE_LEFTBRACKET, Keycode::LEFT_BRACKET}, +		   {SDL_SCANCODE_BACKSLASH, Keycode::BACKSLASH}, +		   {SDL_SCANCODE_RIGHTBRACKET, Keycode::RIGHT_BRACKET}, +		   {SDL_SCANCODE_GRAVE, Keycode::GRAVE_ACCENT}, +		   {SDL_SCANCODE_ESCAPE, Keycode::ESCAPE}, +		   {SDL_SCANCODE_RETURN, Keycode::ENTER}, +		   {SDL_SCANCODE_TAB, Keycode::TAB}, +		   {SDL_SCANCODE_BACKSPACE, Keycode::BACKSPACE}, +		   {SDL_SCANCODE_INSERT, Keycode::INSERT}, +		   {SDL_SCANCODE_DELETE, Keycode::DELETE}, +		   {SDL_SCANCODE_RIGHT, Keycode::RIGHT}, +		   {SDL_SCANCODE_LEFT, Keycode::LEFT}, +		   {SDL_SCANCODE_DOWN, Keycode::DOWN}, +		   {SDL_SCANCODE_UP, Keycode::UP}, +		   {SDL_SCANCODE_PAGEUP, Keycode::PAGE_UP}, +		   {SDL_SCANCODE_PAGEDOWN, Keycode::PAGE_DOWN}, +		   {SDL_SCANCODE_HOME, Keycode::HOME}, +		   {SDL_SCANCODE_END, Keycode::END}, +		   {SDL_SCANCODE_CAPSLOCK, Keycode::CAPS_LOCK}, +		   {SDL_SCANCODE_SCROLLLOCK, Keycode::SCROLL_LOCK}, +		   {SDL_SCANCODE_NUMLOCKCLEAR, Keycode::NUM_LOCK}, +		   {SDL_SCANCODE_PRINTSCREEN, Keycode::PRINT_SCREEN}, +		   {SDL_SCANCODE_PAUSE, Keycode::PAUSE}, +		   {SDL_SCANCODE_F1, Keycode::F1}, +		   {SDL_SCANCODE_F2, Keycode::F2}, +		   {SDL_SCANCODE_F3, Keycode::F3}, +		   {SDL_SCANCODE_F4, Keycode::F4}, +		   {SDL_SCANCODE_F5, Keycode::F5}, +		   {SDL_SCANCODE_F6, Keycode::F6}, +		   {SDL_SCANCODE_F7, Keycode::F7}, +		   {SDL_SCANCODE_F8, Keycode::F8}, +		   {SDL_SCANCODE_F9, Keycode::F9}, +		   {SDL_SCANCODE_F10, Keycode::F10}, +		   {SDL_SCANCODE_F11, Keycode::F11}, +		   {SDL_SCANCODE_F12, Keycode::F12}, +		   {SDL_SCANCODE_KP_0, Keycode::KP0}, +		   {SDL_SCANCODE_KP_1, Keycode::KP1}, +		   {SDL_SCANCODE_KP_2, Keycode::KP2}, +		   {SDL_SCANCODE_KP_3, Keycode::KP3}, +		   {SDL_SCANCODE_KP_4, Keycode::KP4}, +		   {SDL_SCANCODE_KP_5, Keycode::KP5}, +		   {SDL_SCANCODE_KP_6, Keycode::KP6}, +		   {SDL_SCANCODE_KP_7, Keycode::KP7}, +		   {SDL_SCANCODE_KP_8, Keycode::KP8}, +		   {SDL_SCANCODE_KP_9, Keycode::KP9}, +		   {SDL_SCANCODE_LSHIFT, Keycode::LEFT_SHIFT}, +		   {SDL_SCANCODE_LCTRL, Keycode::LEFT_CONTROL}, +		   {SDL_SCANCODE_LALT, Keycode::LEFT_ALT}, +		   {SDL_SCANCODE_LGUI, Keycode::LEFT_SUPER}, +		   {SDL_SCANCODE_RSHIFT, Keycode::RIGHT_SHIFT}, +		   {SDL_SCANCODE_RCTRL, Keycode::RIGHT_CONTROL}, +		   {SDL_SCANCODE_RALT, Keycode::RIGHT_ALT}, +		   {SDL_SCANCODE_RGUI, Keycode::RIGHT_SUPER}, +		   {SDL_SCANCODE_MENU, Keycode::MENU}};  };  } // namespace crepe diff --git a/src/crepe/system/InputSystem.cpp b/src/crepe/system/InputSystem.cpp index a710ae2..fca540f 100644 --- a/src/crepe/system/InputSystem.cpp +++ b/src/crepe/system/InputSystem.cpp @@ -1,7 +1,7 @@  #include "../api/Button.h" +#include "../facade/SDLContext.h"  #include "../manager/ComponentManager.h"  #include "../manager/EventManager.h" -#include "facade/SDLContext.h"  #include "util/Log.h"  #include "InputSystem.h" @@ -10,12 +10,13 @@ using namespace crepe;  void InputSystem::update() {  	ComponentManager & mgr = this->mediator.component_manager; -	EventManager & event_mgr = this->mediator.event_manager; +  	SDLContext & context = this->mediator.sdl_context; -	std::vector<SDLContext::EventData> event_list = context.get_events(); +	std::vector<EventData> event_list = context.get_events();  	RefVector<Button> buttons = mgr.get_components_by_type<Button>();  	RefVector<Camera> cameras = mgr.get_components_by_type<Camera>();  	OptionalRef<Camera> curr_cam_ref; +  	// Find the active camera  	for (Camera & cam : cameras) {  		if (!cam.active) continue; @@ -23,150 +24,185 @@ void InputSystem::update() {  		break;  	}  	if (!curr_cam_ref) return; +  	Camera & current_cam = curr_cam_ref;  	RefVector<Transform> transform_vec  		= mgr.get_components_by_id<Transform>(current_cam.game_object_id);  	Transform & cam_transform = transform_vec.front().get(); -	int camera_origin_x = cam_transform.position.x + current_cam.data.postion_offset.x -						  - (current_cam.viewport_size.x / 2); -	int camera_origin_y = cam_transform.position.y + current_cam.data.postion_offset.y -						  - (current_cam.viewport_size.y / 2); - -	for (const SDLContext::EventData & event : event_list) { -		int world_mouse_x = event.mouse_position.x + camera_origin_x; -		int world_mouse_y = event.mouse_position.y + camera_origin_y; -		// check if the mouse is within the viewport -		bool mouse_in_viewport -			= !(world_mouse_x < camera_origin_x -				|| world_mouse_x > camera_origin_x + current_cam.viewport_size.x -				|| world_mouse_y < camera_origin_y -				|| world_mouse_y > camera_origin_y + current_cam.viewport_size.y); - -		switch (event.event_type) { -			case SDLContext::EventType::KEYDOWN: -				event_mgr.queue_event<KeyPressEvent>(KeyPressEvent{ -					.repeat = event.key_repeat, -					.key = event.key, -				}); -				break; -			case SDLContext::EventType::KEYUP: -				event_mgr.queue_event<KeyReleaseEvent>(KeyReleaseEvent{ -					.key = event.key, -				}); -				break; -			case SDLContext::EventType::MOUSEDOWN: -				if (!mouse_in_viewport) { -					break; -				} -				event_mgr.queue_event<MousePressEvent>(MousePressEvent{ -					.mouse_x = world_mouse_x, -					.mouse_y = world_mouse_y, -					.button = event.mouse_button, -				}); -				this->last_mouse_down_position = {world_mouse_x, world_mouse_y}; -				this->last_mouse_button = event.mouse_button; -				break; -			case SDLContext::EventType::MOUSEUP: { -				if (!mouse_in_viewport) { -					break; -				} -				event_mgr.queue_event<MouseReleaseEvent>(MouseReleaseEvent{ -					.mouse_x = world_mouse_x, -					.mouse_y = world_mouse_y, -					.button = event.mouse_button, -				}); -				//check if its a click by checking the last button down -				int delta_x = world_mouse_x - this->last_mouse_down_position.x; -				int delta_y = world_mouse_y - this->last_mouse_down_position.y; - -				if (this->last_mouse_button == event.mouse_button -					&& std::abs(delta_x) <= click_tolerance -					&& std::abs(delta_y) <= click_tolerance) { -					event_mgr.queue_event<MouseClickEvent>(MouseClickEvent{ -						.mouse_x = world_mouse_x, -						.mouse_y = world_mouse_y, -						.button = event.mouse_button, -					}); - -					this->handle_click(event.mouse_button, world_mouse_x, world_mouse_y); -				} -			} break; -			case SDLContext::EventType::MOUSEMOVE: -				if (!mouse_in_viewport) { -					break; -				} -				event_mgr.queue_event<MouseMoveEvent>(MouseMoveEvent{ -					.mouse_x = world_mouse_x, -					.mouse_y = world_mouse_y, -					.delta_x = event.rel_mouse_move.x, -					.delta_y = event.rel_mouse_move.y, -				}); -				this->handle_move(event, world_mouse_x, world_mouse_y); -				break; -			case SDLContext::EventType::MOUSEWHEEL: -				event_mgr.queue_event<MouseScrollEvent>(MouseScrollEvent{ -					.mouse_x = world_mouse_x, -					.mouse_y = world_mouse_y, -					.scroll_direction = event.scroll_direction, -					.scroll_delta = event.scroll_delta, + +	vec2 camera_origin = cam_transform.position + current_cam.data.postion_offset +						 - (current_cam.viewport_size / 2); + +	for (const EventData & event : event_list) { +		// Only calculate mouse coordinates for relevant events +		if (event.event_type == EventType::MOUSE_DOWN +			|| event.event_type == EventType::MOUSE_UP +			|| event.event_type == EventType::MOUSE_MOVE +			|| event.event_type == EventType::MOUSE_WHEEL) { +			this->handle_mouse_event(event, camera_origin, current_cam); + +		} else { +			this->handle_non_mouse_event(event); +		} +	} +} + +void InputSystem::handle_mouse_event(const EventData & event, const vec2 & camera_origin, +									 const Camera & current_cam) { +	EventManager & event_mgr = this->mediator.event_manager; +	vec2 adjusted_mouse; +	adjusted_mouse.x = event.data.mouse_data.mouse_position.x + camera_origin.x; +	adjusted_mouse.x = event.data.mouse_data.mouse_position.y + camera_origin.y; +	// Check if the mouse is within the viewport +	if ((adjusted_mouse.x < camera_origin.x +		 || adjusted_mouse.x > camera_origin.x + current_cam.viewport_size.x +		 || adjusted_mouse.y < camera_origin.y +		 || adjusted_mouse.y > camera_origin.y + current_cam.viewport_size.y)) +		return; + +	// Handle mouse-specific events +	switch (event.event_type) { +		case EventType::MOUSE_DOWN: +			event_mgr.queue_event<MousePressEvent>({ +				.mouse_pos = adjusted_mouse, +				.button = event.data.mouse_data.mouse_button, +			}); +			this->last_mouse_down_position = adjusted_mouse; +			this->last_mouse_button = event.data.mouse_data.mouse_button; +			break; + +		case EventType::MOUSE_UP: { +			event_mgr.queue_event<MouseReleaseEvent>({ +				.mouse_pos = adjusted_mouse, +				.button = event.data.mouse_data.mouse_button, +			}); +			vec2 delta_move = adjusted_mouse - this->last_mouse_down_position; +			int click_tolerance = Config::get_instance().input.click_tolerance; +			if (this->last_mouse_button == event.data.mouse_data.mouse_button +				&& std::abs(delta_move.x) <= click_tolerance +				&& std::abs(delta_move.y) <= click_tolerance) { +				event_mgr.queue_event<MouseClickEvent>({ +					.mouse_pos = adjusted_mouse, +					.button = event.data.mouse_data.mouse_button,  				}); -				break; -			case SDLContext::EventType::SHUTDOWN: -				event_mgr.queue_event<ShutDownEvent>(ShutDownEvent{}); -				break; -			default: -				break; +				this->handle_click(event.data.mouse_data.mouse_button, adjusted_mouse); +			} +			break;  		} + +		case EventType::MOUSE_MOVE: +			event_mgr.queue_event<MouseMoveEvent>({ +				.mouse_pos = adjusted_mouse, +				.mouse_delta = event.data.mouse_data.rel_mouse_move, +			}); +			this->handle_move(event, adjusted_mouse); +			break; + +		case EventType::MOUSE_WHEEL: +			event_mgr.queue_event<MouseScrollEvent>({ +				.mouse_pos = adjusted_mouse, +				.scroll_direction = event.data.mouse_data.scroll_direction, +				.scroll_delta = event.data.mouse_data.scroll_delta, +			}); +			break; + +		default: +			break; +	} +} + +void InputSystem::handle_non_mouse_event(const EventData & event) { +	EventManager & event_mgr = this->mediator.event_manager; +	switch (event.event_type) { +		case EventType::KEY_DOWN: + +			event_mgr.queue_event<KeyPressEvent>( +				{.repeat = event.data.key_data.key_repeat, .key = event.data.key_data.key}); +			break; +		case EventType::KEY_UP: +			event_mgr.queue_event<KeyReleaseEvent>({.key = event.data.key_data.key}); +			break; +		case EventType::SHUTDOWN: +			event_mgr.queue_event<ShutDownEvent>({}); +			break; +		case EventType::WINDOW_EXPOSE: +			event_mgr.queue_event<WindowExposeEvent>({}); +			break; +		case EventType::WINDOW_RESIZE: +			event_mgr.queue_event<WindowResizeEvent>( +				WindowResizeEvent{.dimensions = event.data.window_data.resize_dimension}); +			break; +		case EventType::WINDOW_MOVE: +			event_mgr.queue_event<WindowMoveEvent>( +				{.delta_move = event.data.window_data.move_delta}); +			break; +		case EventType::WINDOW_MINIMIZE: +			event_mgr.queue_event<WindowMinimizeEvent>({}); +			break; +		case EventType::WINDOW_MAXIMIZE: +			event_mgr.queue_event<WindowMaximizeEvent>({}); +			break; +		case EventType::WINDOW_FOCUS_GAIN: +			event_mgr.queue_event<WindowFocusGainEvent>({}); +			break; +		case EventType::WINDOW_FOCUS_LOST: +			event_mgr.queue_event<WindowFocusLostEvent>({}); +			break; +		default: +			break;  	}  } -void InputSystem::handle_move(const SDLContext::EventData & event_data, -							  const int world_mouse_x, const int world_mouse_y) { + +void InputSystem::handle_move(const EventData & event_data, const vec2 & mouse_pos) {  	ComponentManager & mgr = this->mediator.component_manager;  	RefVector<Button> buttons = mgr.get_components_by_type<Button>();  	for (Button & button : buttons) { +		if (!button.active) continue;  		RefVector<Transform> transform_vec  			= mgr.get_components_by_id<Transform>(button.game_object_id);  		Transform & transform(transform_vec.front().get());  		bool was_hovering = button.hover; -		if (button.active -			&& this->is_mouse_inside_button(world_mouse_x, world_mouse_y, button, transform)) { +		if (this->is_mouse_inside_button(mouse_pos, button, transform)) {  			button.hover = true; -			if (!was_hovering && button.on_mouse_enter) { +			if (!button.on_mouse_enter) continue; +			if (!was_hovering) {  				button.on_mouse_enter();  			}  		} else {  			button.hover = false;  			// Trigger the on_exit callback if the hover state just changed to false -			if (was_hovering && button.on_mouse_exit) { +			if (!button.on_mouse_exit) continue; +			if (was_hovering) {  				button.on_mouse_exit();  			}  		}  	}  } -void InputSystem::handle_click(const MouseButton & mouse_button, const int world_mouse_x, -							   const int world_mouse_y) { +void InputSystem::handle_click(const MouseButton & mouse_button, const vec2 & mouse_pos) {  	ComponentManager & mgr = this->mediator.component_manager;  	RefVector<Button> buttons = mgr.get_components_by_type<Button>();  	for (Button & button : buttons) { +		if (!button.active) continue; +		if (!button.on_click) continue;  		RefVector<Transform> transform_vec  			= mgr.get_components_by_id<Transform>(button.game_object_id);  		Transform & transform = transform_vec.front().get(); -		if (button.active -			&& this->is_mouse_inside_button(world_mouse_x, world_mouse_y, button, transform)) { -			this->handle_button_press(button); +		if (this->is_mouse_inside_button(mouse_pos, button, transform)) { + +			button.on_click();  		}  	}  } -bool InputSystem::is_mouse_inside_button(const int mouse_x, const int mouse_y, -										 const Button & button, const Transform & transform) { +bool InputSystem::is_mouse_inside_button(const vec2 & mouse_pos, const Button & button, +										 const Transform & transform) {  	int actual_x = transform.position.x + button.offset.x;  	int actual_y = transform.position.y + button.offset.y; @@ -174,17 +210,6 @@ bool InputSystem::is_mouse_inside_button(const int mouse_x, const int mouse_y,  	int half_height = button.dimensions.y / 2;  	// Check if the mouse is within the button's boundaries -	return mouse_x >= actual_x - half_width && mouse_x <= actual_x + half_width -		   && mouse_y >= actual_y - half_height && mouse_y <= actual_y + half_height; -} - -void InputSystem::handle_button_press(Button & button) { -	if (button.is_toggle) { -		if (!button.is_pressed && button.on_click) { -			button.on_click(); -		} -		button.is_pressed = !button.is_pressed; -	} else if (button.on_click) { -		button.on_click(); -	} +	return mouse_pos.x >= actual_x - half_width && mouse_pos.x <= actual_x + half_width +		   && mouse_pos.y >= actual_y - half_height && mouse_pos.y <= actual_y + half_height;  } diff --git a/src/crepe/system/InputSystem.h b/src/crepe/system/InputSystem.h index 87e86f8..eefd9fe 100644 --- a/src/crepe/system/InputSystem.h +++ b/src/crepe/system/InputSystem.h @@ -1,6 +1,8 @@  #pragma once -#include "../facade/SDLContext.h" +#include "../api/Config.h" +#include "../facade/EventData.h" +  #include "../types.h"  #include "../util/OptionalRef.h" @@ -11,7 +13,6 @@ namespace crepe {  class Camera;  class Button;  class Transform; -  /**   * \brief Handles the processing of input events created by SDLContext   * @@ -31,15 +32,30 @@ public:  private:  	//! Stores the last position of the mouse when the button was pressed. -	ivec2 last_mouse_down_position; +	vec2 last_mouse_down_position;  	// TODO: specify world/hud space and make regular `vec2`  	//! Stores the last mouse button pressed.  	MouseButton last_mouse_button = MouseButton::NONE; - -	//! The maximum allowable distance between mouse down and mouse up to register as a click. -	const int click_tolerance = 5; - +	/** +	 * \brief Handles mouse-related events. +	 * \param event The event data for the mouse event. +	 * \param camera_origin The origin position of the camera in world space. +	 * \param current_cam The currently active camera. +	 * +	 * This method processes mouse events, adjusts the mouse position to world coordinates, +	 * and triggers the appropriate mouse-specific event handling logic. +	 */ +	void handle_mouse_event(const EventData & event, const vec2 & camera_origin, +							const Camera & current_cam); +	/** +	 * \brief Handles non-mouse-related events. +	 * \param event The event data for the non-mouse event. +	 * +	 * This method processes events that do not involve the mouse, such as keyboard events, +	 * window events, and shutdown events, and triggers the corresponding event actions. +	 */ +	void handle_non_mouse_event(const EventData & event);  	/**  	* \brief Handles the mouse click event.  	* \param mouse_button The mouse button involved in the click. @@ -48,8 +64,7 @@ private:  	*  	* This method processes the mouse click event and triggers the corresponding button action.  	*/ -	void handle_click(const MouseButton & mouse_button, const int world_mouse_x, -					  const int world_mouse_y); +	void handle_click(const MouseButton & mouse_button, const vec2 & mouse_pos);  	/**  	* \brief Handles the mouse movement event. @@ -59,8 +74,7 @@ private:  	*  	* This method processes the mouse movement event and updates the button hover state.  	*/ -	void handle_move(const SDLContext::EventData & event_data, const int world_mouse_x, -					 const int world_mouse_y); +	void handle_move(const EventData & event_data, const vec2 & mouse_pos);  	/**  	* \brief Checks if the mouse position is inside the bounds of the button. @@ -70,8 +84,8 @@ private:  	* \param transform The transform component of the button.  	* \return True if the mouse is inside the button, false otherwise.  	*/ -	bool is_mouse_inside_button(const int world_mouse_x, const int world_mouse_y, -								const Button & button, const Transform & transform); +	bool is_mouse_inside_button(const vec2 & mouse_pos, const Button & button, +								const Transform & transform);  	/**  	* \brief Handles the button press event, calling the on_click callback if necessary. diff --git a/src/crepe/system/ParticleSystem.cpp b/src/crepe/system/ParticleSystem.cpp index b14c52f..35a1d41 100644 --- a/src/crepe/system/ParticleSystem.cpp +++ b/src/crepe/system/ParticleSystem.cpp @@ -1,3 +1,4 @@ +#include <chrono>  #include <cmath>  #include <cstdlib>  #include <ctime> @@ -5,6 +6,7 @@  #include "../api/ParticleEmitter.h"  #include "../api/Transform.h"  #include "../manager/ComponentManager.h" +#include "../manager/LoopTimerManager.h"  #include "ParticleSystem.h" @@ -12,7 +14,11 @@ using namespace crepe;  void ParticleSystem::update() {  	// Get all emitters -	ComponentManager & mgr = this->mediator.component_manager; +	const Mediator & mediator = this->mediator; +	LoopTimerManager & loop_timer = mediator.loop_timer; +	ComponentManager & mgr = mediator.component_manager; +	float dt = loop_timer.get_scaled_fixed_delta_time().count(); +  	RefVector<ParticleEmitter> emitters = mgr.get_components_by_type<ParticleEmitter>();  	for (ParticleEmitter & emitter : emitters) { @@ -21,38 +27,39 @@ void ParticleSystem::update() {  			= mgr.get_components_by_id<Transform>(emitter.game_object_id).front().get();  		// Emit particles based on emission_rate -		int updates = calculate_update(this->update_count, emitter.data.emission_rate); -		for (size_t i = 0; i < updates; i++) { -			emit_particle(emitter, transform); +		emitter.spawn_accumulator += emitter.data.emission_rate * dt; +		while (emitter.spawn_accumulator >= 1.0) { +			this->emit_particle(emitter, transform); +			emitter.spawn_accumulator -= 1.0;  		}  		// Update all particles -		for (Particle & particle : emitter.data.particles) { +		for (Particle & particle : emitter.particles) {  			if (particle.active) { -				particle.update(); +				particle.update(dt);  			}  		}  		// Check if within boundary -		check_bounds(emitter, transform); +		this->check_bounds(emitter, transform);  	} - -	this->update_count = (this->update_count + 1) % this->MAX_UPDATE_COUNT;  }  void ParticleSystem::emit_particle(ParticleEmitter & emitter, const Transform & transform) {  	constexpr float DEG_TO_RAD = M_PI / 180.0; -	vec2 initial_position = emitter.data.position + transform.position; -	float random_angle = generate_random_angle(emitter.data.min_angle, emitter.data.max_angle); +	vec2 initial_position = emitter.data.offset + transform.position; +	float random_angle +		= this->generate_random_angle(emitter.data.min_angle, emitter.data.max_angle); -	float random_speed = generate_random_speed(emitter.data.min_speed, emitter.data.max_speed); +	float random_speed +		= this->generate_random_speed(emitter.data.min_speed, emitter.data.max_speed);  	float angle_radians = random_angle * DEG_TO_RAD;  	vec2 velocity  		= {random_speed * std::cos(angle_radians), random_speed * std::sin(angle_radians)}; -	for (Particle & particle : emitter.data.particles) { +	for (Particle & particle : emitter.particles) {  		if (!particle.active) {  			particle.reset(emitter.data.end_lifespan, initial_position, velocity,  						   random_angle); @@ -61,66 +68,54 @@ void ParticleSystem::emit_particle(ParticleEmitter & emitter, const Transform &  	}  } -int ParticleSystem::calculate_update(int count, double emission) const { -	double integer_part = std::floor(emission); -	double fractional_part = emission - integer_part; - -	if (fractional_part > 0) { -		int denominator = static_cast<int>(1.0 / fractional_part); -		return (count % denominator == 0) ? 1 : 0; -	} - -	return static_cast<int>(emission); -} -  void ParticleSystem::check_bounds(ParticleEmitter & emitter, const Transform & transform) { -	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; +	vec2 offset = emitter.data.boundary.offset + transform.position + emitter.data.offset; +	float half_width = emitter.data.boundary.width / 2.0; +	float half_height = emitter.data.boundary.height / 2.0; -	const double LEFT = offset.x - half_width; -	const double RIGHT = offset.x + half_width; -	const double TOP = offset.y - half_height; -	const double BOTTOM = offset.y + half_height; +	float left = offset.x - half_width; +	float right = offset.x + half_width; +	float top = offset.y - half_height; +	float bottom = offset.y + half_height; -	for (Particle & particle : emitter.data.particles) { +	for (Particle & particle : emitter.particles) {  		const vec2 & position = particle.position; -		bool within_bounds = (position.x >= LEFT && position.x <= RIGHT && position.y >= TOP -							  && position.y <= BOTTOM); - +		bool within_bounds = (position.x >= left && position.x <= right && position.y >= top +							  && position.y <= bottom); +		//if not within bounds do a reset or stop velocity  		if (!within_bounds) {  			if (emitter.data.boundary.reset_on_exit) {  				particle.active = false;  			} else {  				particle.velocity = {0, 0}; -				if (position.x < LEFT) particle.position.x = LEFT; -				else if (position.x > RIGHT) particle.position.x = RIGHT; -				if (position.y < TOP) particle.position.y = TOP; -				else if (position.y > BOTTOM) particle.position.y = BOTTOM; +				if (position.x < left) particle.position.x = left; +				else if (position.x > right) particle.position.x = right; +				if (position.y < top) particle.position.y = top; +				else if (position.y > bottom) particle.position.y = bottom;  			}  		}  	}  } -double ParticleSystem::generate_random_angle(double min_angle, double max_angle) const { +float ParticleSystem::generate_random_angle(float min_angle, float max_angle) const {  	if (min_angle == max_angle) {  		return min_angle;  	} else if (min_angle < max_angle) {  		return min_angle -			   + static_cast<double>(std::rand() % static_cast<int>(max_angle - min_angle)); +			   + static_cast<float>(std::rand() % static_cast<int>(max_angle - min_angle));  	} else { -		double angle_offset = (360 - min_angle) + max_angle; -		double random_angle -			= min_angle + static_cast<double>(std::rand() % static_cast<int>(angle_offset)); +		float angle_offset = (360 - min_angle) + max_angle; +		float random_angle +			= min_angle + static_cast<float>(std::rand() % static_cast<int>(angle_offset));  		return (random_angle >= 360) ? random_angle - 360 : random_angle;  	}  } -double ParticleSystem::generate_random_speed(double min_speed, double max_speed) const { +float ParticleSystem::generate_random_speed(float min_speed, float max_speed) const {  	if (min_speed == max_speed) {  		return min_speed;  	} else {  		return min_speed -			   + static_cast<double>(std::rand() % static_cast<int>(max_speed - min_speed)); +			   + static_cast<float>(std::rand() % static_cast<int>(max_speed - min_speed));  	}  } diff --git a/src/crepe/system/ParticleSystem.h b/src/crepe/system/ParticleSystem.h index 068f01c..154521d 100644 --- a/src/crepe/system/ParticleSystem.h +++ b/src/crepe/system/ParticleSystem.h @@ -32,16 +32,6 @@ private:  	void emit_particle(ParticleEmitter & emitter, const Transform & transform);  	/** -	 * \brief Calculates the number of times particles should be emitted based on emission rate -	 * and update count. -	 * -	 * \param count Current update count. -	 * \param emission Emission rate. -	 * \return The number of particles to emit. -	 */ -	int calculate_update(int count, double emission) const; - -	/**  	 * \brief Checks whether particles are within the emitter’s boundary, resets or stops  	 * particles if they exit.  	 * @@ -57,7 +47,7 @@ private:  	 * \param max_angle Maximum emission angle in degrees.  	 * \return Random angle in degrees.  	 */ -	double generate_random_angle(double min_angle, double max_angle) const; +	float generate_random_angle(float min_angle, float max_angle) const;  	/**  	 * \brief Generates a random speed for particle emission within the specified range. @@ -66,15 +56,7 @@ private:  	 * \param max_speed Maximum emission speed.  	 * \return Random speed.  	 */ -	double generate_random_speed(double min_speed, double max_speed) const; - -private: -	//! Counter to count updates to determine how many times emit_particle is -	// called. -	unsigned int update_count = 0; -	//! Determines the lowest amount of emission rate (1000 = 0.001 = 1 particle per 1000 -	// updates). -	static constexpr unsigned int MAX_UPDATE_COUNT = 100; +	float generate_random_speed(float min_speed, float max_speed) const;  };  } // namespace crepe diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index 5b2528a..62d42ec 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -86,11 +86,11 @@ bool RenderSystem::render_particle(const Sprite & sprite, const double & scale)  	bool rendering_particles = false;  	for (const ParticleEmitter & em : emitters) { -		if (&em.data.sprite != &sprite) continue; +		if (&em.sprite != &sprite) continue;  		rendering_particles = true;  		if (!em.active) continue; -		for (const Particle & p : em.data.particles) { +		for (const Particle & p : em.particles) {  			if (!p.active) continue;  			ctx.draw(SDLContext::RenderContext{ diff --git a/src/example/button.cpp b/src/example/button.cpp index 00bdc28..4220588 100644 --- a/src/example/button.cpp +++ b/src/example/button.cpp @@ -1,52 +1,39 @@  #include <SDL2/SDL_timer.h>  #include <chrono>  #include <crepe/Component.h> -#include <crepe/ComponentManager.h>  #include <crepe/api/Animator.h>  #include <crepe/api/Button.h>  #include <crepe/api/Camera.h>  #include <crepe/api/Color.h> -#include <crepe/api/EventManager.h>  #include <crepe/api/GameObject.h>  #include <crepe/api/Sprite.h>  #include <crepe/api/Texture.h>  #include <crepe/api/Transform.h> +#include <crepe/facade/SDLContext.h> +#include <crepe/manager/ComponentManager.h> +#include <crepe/manager/EventManager.h>  #include <crepe/system/AnimatorSystem.h>  #include <crepe/system/InputSystem.h>  #include <crepe/system/RenderSystem.h>  #include <crepe/types.h> -#include <iostream>  using namespace crepe;  using namespace std;  int main(int argc, char * argv[]) { -	ComponentManager mgr; -	RenderSystem sys{mgr}; -	EventManager & event_mgr = EventManager::get_instance(); -	InputSystem input_sys{mgr}; -	AnimatorSystem asys{mgr}; -	GameObject camera_obj = mgr.new_object("", "", vec2{1000, 1000}, 0, 1); -	camera_obj.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{2000, 2000}, 1.0f); - -	GameObject button_obj = mgr.new_object("body", "person", vec2{0, 0}, 0, 1); -	auto s2 = Texture("asset/texture/test_ap43.png"); -	bool button_clicked = false; -	auto & sprite2 = button_obj.add_component<Sprite>( -		s2, Color::GREEN, Sprite::FlipSettings{false, false}, 2, 1, 100); -	std::function<void()> on_click = [&]() { std::cout << "button clicked" << std::endl; }; -	std::function<void()> on_enter = [&]() { std::cout << "enter" << std::endl; }; -	std::function<void()> on_exit = [&]() { std::cout << "exit" << std::endl; }; -	auto & button -		= button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click, false); -	button.on_mouse_enter = on_enter; -	button.on_mouse_exit = on_exit; -	button.is_toggle = true; -	button.active = true; +	Mediator mediator; +	ComponentManager mgr{mediator}; +	RenderSystem sys{mediator}; +	EventManager event_mgr{mediator}; +	InputSystem input_sys{mediator}; +	SDLContext sdl_context{mediator}; +	GameObject obj = mgr.new_object("camera", "camera", vec2{0, 0}, 0, 1); +	auto & camera = obj.add_component<Camera>( +		ivec2{500, 500}, vec2{500, 500}, Camera::Data{.bg_color = Color::WHITE, .zoom = 1.0f});  	auto start = std::chrono::steady_clock::now();  	while (true) { +		const keyboard_state_t & keyboard_state = sdl_context.get_keyboard_state();  		input_sys.update();  		sys.update(); -		asys.update();  		event_mgr.dispatch_events();  		SDL_Delay(30);  	} diff --git a/src/example/game.cpp b/src/example/game.cpp index 8ea50ea..22effd2 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -1,4 +1,5 @@  #include "api/CircleCollider.h" +#include "api/ParticleEmitter.h"  #include "api/Scene.h"  #include "manager/ComponentManager.h"  #include "manager/Mediator.h" @@ -35,7 +36,8 @@ class MyScript1 : public Script {  			}  			case Keycode::W: {  				Rigidbody & tf = this->get_component<Rigidbody>(); -				tf.data.linear_velocity.y -= 1; +				// tf.data.linear_velocity.y -= 1; +				tf.add_force_linear({0, -1});  				break;  			}  			case Keycode::S: { @@ -176,19 +178,19 @@ public:  			.gravity_scale = 0,  			.body_type = Rigidbody::BodyType::STATIC,  			.offset = {0, 0}, -			.collision_layers = {0},  		});  		world.add_component<BoxCollider>( -			vec2{0, 0 - (screen_size_height / 2 + world_collider / 2)}, -			vec2{world_collider, world_collider}); -		; // Top -		world.add_component<BoxCollider>(vec2{0, screen_size_height / 2 + world_collider / 2}, -										 vec2{world_collider, world_collider}); // Bottom +			vec2{world_collider, world_collider}, +			vec2{0, 0 - (screen_size_height / 2 + world_collider / 2)}); // Top  		world.add_component<BoxCollider>( -			vec2{0 - (screen_size_width / 2 + world_collider / 2), 0}, -			vec2{world_collider, world_collider}); // Left -		world.add_component<BoxCollider>(vec2{screen_size_width / 2 + world_collider / 2, 0}, -										 vec2{world_collider, world_collider}); // right +			vec2{world_collider, world_collider}, +			vec2{0, screen_size_height / 2 + world_collider / 2}); // Bottom +		world.add_component<BoxCollider>( +			vec2{world_collider, world_collider}, +			vec2{0 - (screen_size_width / 2 + world_collider / 2), 0}); // Left +		world.add_component<BoxCollider>( +			vec2{world_collider, world_collider}, +			vec2{screen_size_width / 2 + world_collider / 2, 0}); // right  		world.add_component<Camera>(  			ivec2{static_cast<int>(screen_size_width), static_cast<int>(screen_size_height)},  			vec2{screen_size_width, screen_size_height}, @@ -205,12 +207,11 @@ public:  			.body_type = Rigidbody::BodyType::DYNAMIC,  			.linear_velocity = {0, 1},  			.constraints = {0, 0, 0}, -			.elastisity_coefficient = 1, +			.elastisity_coefficient = 0,  			.offset = {0, 0}, -			.collision_layers = {0},  		});  		// add box with boxcollider -		game_object1.add_component<BoxCollider>(vec2{0, 0}, vec2{20, 20}); +		game_object1.add_component<BoxCollider>(vec2{20, 20});  		game_object1.add_component<BehaviorScript>().set_script<MyScript1>();  		Asset img1{"asset/texture/square.png"}; @@ -219,7 +220,7 @@ public:  												 });  		//add circle with cirlcecollider deactiveated -		game_object1.add_component<CircleCollider>(vec2{0, 0}, 10).active = false; +		game_object1.add_component<CircleCollider>(10).active = false;  		Asset img2{"asset/texture/circle.png"};  		game_object1  			.add_component<Sprite>(img2, @@ -239,10 +240,9 @@ public:  			.constraints = {0, 0, 0},  			.elastisity_coefficient = 1,  			.offset = {0, 0}, -			.collision_layers = {0},  		});  		// add box with boxcollider -		game_object2.add_component<BoxCollider>(vec2{0, 0}, vec2{20, 20}); +		game_object2.add_component<BoxCollider>(vec2{20, 20});  		game_object2.add_component<BehaviorScript>().set_script<MyScript2>();  		game_object2.add_component<Sprite>(img1, Sprite::Data{ @@ -250,7 +250,7 @@ public:  												 });  		//add circle with cirlcecollider deactiveated -		game_object2.add_component<CircleCollider>(vec2{0, 0}, 10).active = false; +		game_object2.add_component<CircleCollider>(10).active = false;  		game_object2  			.add_component<Sprite>(img2, @@ -259,6 +259,25 @@ public:  								   })  			.active  			= false; +		Asset img5{"asset/texture/square.png"}; + +		GameObject particle = new_object( +			"Name", "Tag", vec2{screen_size_width / 2, screen_size_height / 2}, 0, 1); +		auto & particle_image = particle.add_component<Sprite>(img5, Sprite::Data{ +																		 .size = {5, 5}, +																	 }); +		auto & test +			= particle.add_component<ParticleEmitter>(particle_image, ParticleEmitter::Data{ +																		  .offset = {0, 0}, +																		  .max_particles = 256, +																		  .emission_rate = 1, +																		  .min_speed = 10, +																		  .max_speed = 20, +																		  .min_angle = -20, +																		  .max_angle = 20, +																		  .begin_lifespan = 0, +																		  .end_lifespan = 5, +																	  });  	}  	string get_name() const { return "scene1"; } diff --git a/src/example/rendering_particle.cpp b/src/example/rendering_particle.cpp index 13e625f..add43f4 100644 --- a/src/example/rendering_particle.cpp +++ b/src/example/rendering_particle.cpp @@ -18,28 +18,6 @@  using namespace crepe;  using namespace std; -/* -	auto & test = game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{ -		.position = {0, 0}, -		.max_particles = 10, -		.emission_rate = 0.1, -		.min_speed = 6, -		.max_speed = 20, -		.min_angle = -20, -		.max_angle = 20, -		.begin_lifespan = 0, -		.end_lifespan = 60, -		.force_over_time = vec2{0, 0}, -		.boundary{ -			.width = 1000, -			.height = 1000, -			.offset = vec2{0, 0}, -			.reset_on_exit = false, -		}, -		.sprite = test_sprite, -	}); -	*/ -  class TestScene : public Scene {  public:  	void load_scene() { diff --git a/src/test/CollisionTest.cpp b/src/test/CollisionTest.cpp index 2ad65fa..ff9e7cc 100644 --- a/src/test/CollisionTest.cpp +++ b/src/test/CollisionTest.cpp @@ -69,10 +69,10 @@ public:  			.offset = {0, 0},  		});  		// Create a box with an inner size of 10x10 units -		world.add_component<BoxCollider>(vec2{0, -100}, vec2{100, 100}); // Top -		world.add_component<BoxCollider>(vec2{0, 100}, vec2{100, 100}); // Bottom -		world.add_component<BoxCollider>(vec2{-100, 0}, vec2{100, 100}); // Left -		world.add_component<BoxCollider>(vec2{100, 0}, vec2{100, 100}); // right +		world.add_component<BoxCollider>(vec2{100, 100}, vec2{0, -100}); // Top +		world.add_component<BoxCollider>(vec2{100, 100}, vec2{0, 100}); // Bottom +		world.add_component<BoxCollider>(vec2{100, 100}, vec2{-100, 0}); // Left +		world.add_component<BoxCollider>(vec2{100, 100}, vec2{100, 0}); // right  		game_object1.add_component<Rigidbody>(Rigidbody::Data{  			.mass = 1, @@ -84,7 +84,7 @@ public:  			.offset = {0, 0},  			.collision_layers = {0},  		}); -		game_object1.add_component<BoxCollider>(vec2{0, 0}, vec2{10, 10}); +		game_object1.add_component<BoxCollider>(vec2{10, 10}, vec2{0, 0});  		BehaviorScript & script_object1  			= game_object1.add_component<BehaviorScript>().set_script<CollisionHandler>(1);  		script_object1_ref = static_cast<CollisionHandler *>(script_object1.script.get()); @@ -100,7 +100,7 @@ public:  			.offset = {0, 0},  			.collision_layers = {0},  		}); -		game_object2.add_component<BoxCollider>(vec2{0, 0}, vec2{10, 10}); +		game_object2.add_component<BoxCollider>(vec2{10, 10}, vec2{0, 0});  		BehaviorScript & script_object2  			= game_object2.add_component<BehaviorScript>().set_script<CollisionHandler>(2);  		script_object2_ref = static_cast<CollisionHandler *>(script_object2.script.get()); diff --git a/src/test/EventTest.cpp b/src/test/EventTest.cpp index 82272b5..f8be3fe 100644 --- a/src/test/EventTest.cpp +++ b/src/test/EventTest.cpp @@ -48,15 +48,14 @@ TEST_F(EventManagerTest, EventManagerTest_trigger_all_channels) {  	EventHandler<MouseClickEvent> mouse_handler = [&](const MouseClickEvent & e) {  		triggered = true; -		EXPECT_EQ(e.mouse_x, 100); -		EXPECT_EQ(e.mouse_y, 200); +		EXPECT_EQ(e.mouse_pos.x, 100); +		EXPECT_EQ(e.mouse_pos.y, 200);  		EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);  		return false;  	};  	event_mgr.subscribe<MouseClickEvent>(mouse_handler, EventManager::CHANNEL_ALL); -	MouseClickEvent click_event{ -		.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}; +	MouseClickEvent click_event{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE};  	event_mgr.trigger_event<MouseClickEvent>(click_event, EventManager::CHANNEL_ALL);  	EXPECT_TRUE(triggered); @@ -66,15 +65,14 @@ TEST_F(EventManagerTest, EventManagerTest_trigger_one_channel) {  	int test_channel = 1;  	EventHandler<MouseClickEvent> mouse_handler = [&](const MouseClickEvent & e) {  		triggered = true; -		EXPECT_EQ(e.mouse_x, 100); -		EXPECT_EQ(e.mouse_y, 200); +		EXPECT_EQ(e.mouse_pos.x, 100); +		EXPECT_EQ(e.mouse_pos.y, 200);  		EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);  		return false;  	};  	event_mgr.subscribe<MouseClickEvent>(mouse_handler, test_channel); -	MouseClickEvent click_event{ -		.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}; +	MouseClickEvent click_event{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE};  	event_mgr.trigger_event<MouseClickEvent>(click_event, EventManager::CHANNEL_ALL);  	EXPECT_FALSE(triggered); @@ -90,23 +88,22 @@ TEST_F(EventManagerTest, EventManagerTest_callback_propagation) {  	// Handlers  	EventHandler<MouseClickEvent> mouse_handler_true = [&](const MouseClickEvent & e) {  		triggered_true = true; -		EXPECT_EQ(e.mouse_x, 100); -		EXPECT_EQ(e.mouse_y, 200); +		EXPECT_EQ(e.mouse_pos.x, 100); +		EXPECT_EQ(e.mouse_pos.y, 200);  		EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);  		return true; // Stops propagation  	};  	EventHandler<MouseClickEvent> mouse_handler_false = [&](const MouseClickEvent & e) {  		triggered_false = true; -		EXPECT_EQ(e.mouse_x, 100); -		EXPECT_EQ(e.mouse_y, 200); +		EXPECT_EQ(e.mouse_pos.x, 100); +		EXPECT_EQ(e.mouse_pos.y, 200);  		EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);  		return false; // Allows propagation  	};  	// Test event -	MouseClickEvent click_event{ -		.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}; +	MouseClickEvent click_event{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE};  	event_mgr.subscribe<MouseClickEvent>(mouse_handler_true, EventManager::CHANNEL_ALL);  	event_mgr.subscribe<MouseClickEvent>(mouse_handler_false, EventManager::CHANNEL_ALL); @@ -138,15 +135,15 @@ TEST_F(EventManagerTest, EventManagerTest_queue_dispatch) {  	int test_channel = 1;  	EventHandler<MouseClickEvent> mouse_handler1 = [&](const MouseClickEvent & e) {  		triggered1 = true; -		EXPECT_EQ(e.mouse_x, 100); -		EXPECT_EQ(e.mouse_y, 200); +		EXPECT_EQ(e.mouse_pos.x, 100); +		EXPECT_EQ(e.mouse_pos.y, 200);  		EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);  		return false; // Allows propagation  	};  	EventHandler<MouseClickEvent> mouse_handler2 = [&](const MouseClickEvent & e) {  		triggered2 = true; -		EXPECT_EQ(e.mouse_x, 100); -		EXPECT_EQ(e.mouse_y, 200); +		EXPECT_EQ(e.mouse_pos.x, 100); +		EXPECT_EQ(e.mouse_pos.y, 200);  		EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);  		return false; // Allows propagation  	}; @@ -154,9 +151,9 @@ TEST_F(EventManagerTest, EventManagerTest_queue_dispatch) {  	event_mgr.subscribe<MouseClickEvent>(mouse_handler2, test_channel);  	event_mgr.queue_event<MouseClickEvent>( -		MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}); +		MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE});  	event_mgr.queue_event<MouseClickEvent>( -		MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}, +		MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE},  		test_channel);  	event_mgr.dispatch_events();  	EXPECT_TRUE(triggered1); @@ -172,16 +169,16 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {  	// Define EventHandlers  	EventHandler<MouseClickEvent> mouse_handler1 = [&](const MouseClickEvent & e) {  		triggered1 = true; -		EXPECT_EQ(e.mouse_x, 100); -		EXPECT_EQ(e.mouse_y, 200); +		EXPECT_EQ(e.mouse_pos.x, 100); +		EXPECT_EQ(e.mouse_pos.y, 200);  		EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);  		return false; // Allows propagation  	};  	EventHandler<MouseClickEvent> mouse_handler2 = [&](const MouseClickEvent & e) {  		triggered2 = true; -		EXPECT_EQ(e.mouse_x, 100); -		EXPECT_EQ(e.mouse_y, 200); +		EXPECT_EQ(e.mouse_pos.x, 100); +		EXPECT_EQ(e.mouse_pos.y, 200);  		EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);  		return false; // Allows propagation  	}; @@ -191,7 +188,7 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {  	// Queue events  	event_mgr.queue_event<MouseClickEvent>( -		MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}); +		MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE});  	// Dispatch events - both handlers should be triggered  	event_mgr.dispatch_events(); @@ -207,7 +204,7 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {  	// Queue the same event again  	event_mgr.queue_event<MouseClickEvent>( -		MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}); +		MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE});  	// Dispatch events - only handler 2 should be triggered, handler 1 should NOT  	event_mgr.dispatch_events(); @@ -222,7 +219,7 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {  	// Queue the event again  	event_mgr.queue_event<MouseClickEvent>( -		MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}); +		MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE});  	// Dispatch events - no handler should be triggered  	event_mgr.dispatch_events(); diff --git a/src/test/InputTest.cpp b/src/test/InputTest.cpp index 8b40cea..d893276 100644 --- a/src/test/InputTest.cpp +++ b/src/test/InputTest.cpp @@ -15,6 +15,7 @@  #include <crepe/api/Metadata.h>  #include <crepe/api/Transform.h>  #include <crepe/api/Vector2.h> +#include <crepe/facade/SDLContext.h>  #include <gmock/gmock.h>  using namespace std; @@ -43,7 +44,7 @@ protected:  		//mediator.component_manager = mgr;  		//event_manager.clear();  	} - +	void TearDown() override {}  	void simulate_mouse_click(int mouse_x, int mouse_y, Uint8 mouse_button) {  		SDL_Event event; @@ -70,8 +71,8 @@ TEST_F(InputTest, MouseDown) {  	EventHandler<MousePressEvent> on_mouse_down = [&](const MousePressEvent & event) {  		mouse_triggered = true;  		//middle of the screen = 0,0 -		EXPECT_EQ(event.mouse_x, 0); -		EXPECT_EQ(event.mouse_y, 0); +		EXPECT_EQ(event.mouse_pos.x, 0); +		EXPECT_EQ(event.mouse_pos.y, 0);  		EXPECT_EQ(event.button, MouseButton::LEFT_MOUSE);  		return false;  	}; @@ -95,8 +96,8 @@ TEST_F(InputTest, MouseUp) {  	bool function_triggered = false;  	EventHandler<MouseReleaseEvent> on_mouse_release = [&](const MouseReleaseEvent & e) {  		function_triggered = true; -		EXPECT_EQ(e.mouse_x, 0); -		EXPECT_EQ(e.mouse_y, 0); +		EXPECT_EQ(e.mouse_pos.x, 0); +		EXPECT_EQ(e.mouse_pos.y, 0);  		EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);  		return false;  	}; @@ -119,10 +120,10 @@ TEST_F(InputTest, MouseMove) {  	bool function_triggered = false;  	EventHandler<MouseMoveEvent> on_mouse_move = [&](const MouseMoveEvent & e) {  		function_triggered = true; -		EXPECT_EQ(e.mouse_x, 0); -		EXPECT_EQ(e.mouse_y, 0); -		EXPECT_EQ(e.delta_x, 10); -		EXPECT_EQ(e.delta_y, 10); +		EXPECT_EQ(e.mouse_pos.x, 0); +		EXPECT_EQ(e.mouse_pos.y, 0); +		EXPECT_EQ(e.mouse_delta.x, 10); +		EXPECT_EQ(e.mouse_delta.y, 10);  		return false;  	};  	event_manager.subscribe<MouseMoveEvent>(on_mouse_move); @@ -193,8 +194,8 @@ TEST_F(InputTest, MouseClick) {  	EventHandler<MouseClickEvent> on_mouse_click = [&](const MouseClickEvent & event) {  		on_click_triggered = true;  		EXPECT_EQ(event.button, MouseButton::LEFT_MOUSE); -		EXPECT_EQ(event.mouse_x, 0); -		EXPECT_EQ(event.mouse_y, 0); +		EXPECT_EQ(event.mouse_pos.x, 0); +		EXPECT_EQ(event.mouse_pos.y, 0);  		return false;  	};  	event_manager.subscribe<MouseClickEvent>(on_mouse_click); @@ -209,14 +210,10 @@ TEST_F(InputTest, testButtonClick) {  	GameObject button_obj = mgr.new_object("body", "person", vec2{0, 0}, 0, 1);  	bool button_clicked = false;  	std::function<void()> on_click = [&]() { button_clicked = true; }; -	auto & button -		= button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click, false); +	auto & button = button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click);  	bool hover = false;  	button.active = true; - -	button.is_pressed = false; -	button.is_toggle = false;  	this->simulate_mouse_click(999, 999, SDL_BUTTON_LEFT);  	input_system.update();  	event_manager.dispatch_events(); @@ -232,11 +229,8 @@ TEST_F(InputTest, testButtonHover) {  	GameObject button_obj = mgr.new_object("body", "person", vec2{0, 0}, 0, 1);  	bool button_clicked = false;  	std::function<void()> on_click = [&]() { button_clicked = true; }; -	auto & button -		= button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click, false); +	auto & button = button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click);  	button.active = true; -	button.is_pressed = false; -	button.is_toggle = false;  	// Mouse not on button  	SDL_Event event; diff --git a/src/test/ParticleTest.cpp b/src/test/ParticleTest.cpp index 9112a3f..9263e00 100644 --- a/src/test/ParticleTest.cpp +++ b/src/test/ParticleTest.cpp @@ -1,15 +1,18 @@  #include "api/Asset.h" -#include <crepe/Particle.h>  #include <crepe/api/Config.h>  #include <crepe/api/GameObject.h> -#include <crepe/api/ParticleEmitter.h>  #include <crepe/api/Rigidbody.h>  #include <crepe/api/Sprite.h>  #include <crepe/api/Transform.h>  #include <crepe/manager/ComponentManager.h> -#include <crepe/system/ParticleSystem.h> +#include <crepe/manager/LoopTimerManager.h>  #include <gtest/gtest.h>  #include <math.h> +#define protected public +#define private public +#include <crepe/Particle.h> +#include <crepe/api/ParticleEmitter.h> +#include <crepe/system/ParticleSystem.h>  using namespace std;  using namespace std::chrono_literals; @@ -21,6 +24,7 @@ class ParticlesTest : public ::testing::Test {  public:  	ComponentManager component_manager{m};  	ParticleSystem particle_system{m}; +	LoopTimerManager loop_timer{m};  	void SetUp() override {  		ComponentManager & mgr = this->component_manager; @@ -38,25 +42,25 @@ public:  						.size = {10, 10},  					}); -			game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{ -				.position = {0, 0}, -				.max_particles = 100, -				.emission_rate = 0, -				.min_speed = 0, -				.max_speed = 0, -				.min_angle = 0, -				.max_angle = 0, -				.begin_lifespan = 0, -				.end_lifespan = 0, -				.force_over_time = vec2{0, 0}, -				.boundary{ -					.width = 0, -					.height = 0, -					.offset = vec2{0, 0}, -					.reset_on_exit = false, -				}, -				.sprite = test_sprite, -			}); +			game_object.add_component<ParticleEmitter>(test_sprite, +													   ParticleEmitter::Data{ +														   .offset = {0, 0}, +														   .max_particles = 100, +														   .emission_rate = 0, +														   .min_speed = 0, +														   .max_speed = 0, +														   .min_angle = 0, +														   .max_angle = 0, +														   .begin_lifespan = 0, +														   .end_lifespan = 0, +														   .force_over_time = vec2{0, 0}, +														   .boundary{ +															   .width = 0, +															   .height = 0, +															   .offset = vec2{0, 0}, +															   .reset_on_exit = false, +														   }, +													   });  		}  		transforms = mgr.get_components_by_id<Transform>(0);  		Transform & transform = transforms.front().get(); @@ -66,7 +70,7 @@ public:  		std::vector<std::reference_wrapper<ParticleEmitter>> rigidbodies  			= mgr.get_components_by_id<ParticleEmitter>(0);  		ParticleEmitter & emitter = rigidbodies.front().get(); -		emitter.data.position = {0, 0}; +		emitter.data.offset = {0, 0};  		emitter.data.emission_rate = 0;  		emitter.data.min_speed = 0;  		emitter.data.max_speed = 0; @@ -76,7 +80,7 @@ public:  		emitter.data.end_lifespan = 0;  		emitter.data.force_over_time = vec2{0, 0};  		emitter.data.boundary = {0, 0, vec2{0, 0}, false}; -		for (auto & particle : emitter.data.particles) { +		for (auto & particle : emitter.particles) {  			particle.active = false;  		}  	} @@ -95,19 +99,19 @@ TEST_F(ParticlesTest, spawnParticle) {  	emitter.data.max_angle = 10;  	particle_system.update();  	//check if nothing happend -	EXPECT_EQ(emitter.data.particles[0].active, false); -	emitter.data.emission_rate = 1; +	EXPECT_EQ(emitter.particles[0].active, false); +	emitter.data.emission_rate = 50;  	//check particle spawnes  	particle_system.update(); -	EXPECT_EQ(emitter.data.particles[0].active, true); +	EXPECT_EQ(emitter.particles[0].active, true);  	particle_system.update(); -	EXPECT_EQ(emitter.data.particles[1].active, true); +	EXPECT_EQ(emitter.particles[1].active, true);  	particle_system.update(); -	EXPECT_EQ(emitter.data.particles[2].active, true); +	EXPECT_EQ(emitter.particles[2].active, true);  	particle_system.update(); -	EXPECT_EQ(emitter.data.particles[3].active, true); +	EXPECT_EQ(emitter.particles[3].active, true); -	for (auto & particle : emitter.data.particles) { +	for (auto & particle : emitter.particles) {  		// Check velocity range  		EXPECT_GE(particle.velocity.x, emitter.data.min_speed);  		// Speed should be greater than or equal to min_speed @@ -133,13 +137,13 @@ TEST_F(ParticlesTest, moveParticleHorizontal) {  	emitter.data.end_lifespan = 100;  	emitter.data.boundary.height = 100;  	emitter.data.boundary.width = 100; -	emitter.data.min_speed = 1; -	emitter.data.max_speed = 1; +	emitter.data.min_speed = 50; +	emitter.data.max_speed = 50;  	emitter.data.max_angle = 0; -	emitter.data.emission_rate = 1; +	emitter.data.emission_rate = 50;  	for (int a = 1; a < emitter.data.boundary.width / 2; a++) {  		particle_system.update(); -		EXPECT_EQ(emitter.data.particles[0].position.x, a); +		EXPECT_EQ(emitter.particles[0].position.x, a);  	}  } @@ -150,14 +154,14 @@ TEST_F(ParticlesTest, moveParticleVertical) {  	emitter.data.end_lifespan = 100;  	emitter.data.boundary.height = 100;  	emitter.data.boundary.width = 100; -	emitter.data.min_speed = 1; -	emitter.data.max_speed = 1; +	emitter.data.min_speed = 50; +	emitter.data.max_speed = 50;  	emitter.data.min_angle = 90;  	emitter.data.max_angle = 90; -	emitter.data.emission_rate = 1; +	emitter.data.emission_rate = 50;  	for (int a = 1; a < emitter.data.boundary.width / 2; a++) {  		particle_system.update(); -		EXPECT_EQ(emitter.data.particles[0].position.y, a); +		EXPECT_EQ(emitter.particles[0].position.y, a);  	}  } @@ -177,7 +181,7 @@ TEST_F(ParticlesTest, boundaryParticleReset) {  	for (int a = 0; a < emitter.data.boundary.width / 2 + 1; a++) {  		particle_system.update();  	} -	EXPECT_EQ(emitter.data.particles[0].active, false); +	EXPECT_EQ(emitter.particles[0].active, false);  }  TEST_F(ParticlesTest, boundaryParticleStop) { @@ -197,12 +201,12 @@ TEST_F(ParticlesTest, boundaryParticleStop) {  		particle_system.update();  	}  	const double TOLERANCE = 0.01; -	EXPECT_NEAR(emitter.data.particles[0].velocity.x, 0, TOLERANCE); -	EXPECT_NEAR(emitter.data.particles[0].velocity.y, 0, TOLERANCE); -	if (emitter.data.particles[0].velocity.x != 0) -		EXPECT_NEAR(std::abs(emitter.data.particles[0].position.x), +	EXPECT_NEAR(emitter.particles[0].velocity.x, 0, TOLERANCE); +	EXPECT_NEAR(emitter.particles[0].velocity.y, 0, TOLERANCE); +	if (emitter.particles[0].velocity.x != 0) +		EXPECT_NEAR(std::abs(emitter.particles[0].position.x),  					emitter.data.boundary.height / 2, TOLERANCE); -	if (emitter.data.particles[0].velocity.y != 0) -		EXPECT_NEAR(std::abs(emitter.data.particles[0].position.y), -					emitter.data.boundary.width / 2, TOLERANCE); +	if (emitter.particles[0].velocity.y != 0) +		EXPECT_NEAR(std::abs(emitter.particles[0].position.y), emitter.data.boundary.width / 2, +					TOLERANCE);  } diff --git a/src/test/Profiling.cpp b/src/test/Profiling.cpp index 35f52dc..16736b8 100644 --- a/src/test/Profiling.cpp +++ b/src/test/Profiling.cpp @@ -219,18 +219,19 @@ TEST_F(DISABLED_ProfilingTest, Profiling_3) {  					.order_in_layer = 1,  					.size = {.y = 500},  				}); -			auto & test = gameobject.add_component<ParticleEmitter>(ParticleEmitter::Data{ -				.max_particles = 10, -				.emission_rate = 100, -				.end_lifespan = 100000, -				.boundary{ -					.width = 1000, -					.height = 1000, -					.offset = vec2{0, 0}, -					.reset_on_exit = false, -				}, -				.sprite = test_sprite, -			}); +			auto & test = gameobject.add_component<ParticleEmitter>( +				test_sprite, ParticleEmitter::Data{ +								 .max_particles = 10, +								 .emission_rate = 100, +								 .end_lifespan = 100000, +								 .boundary{ +									 .width = 1000, +									 .height = 1000, +									 .offset = vec2{0, 0}, +									 .reset_on_exit = false, +								 }, + +							 });  		}  		render_sys.update();  		this->game_object_count++; |