diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/crepe/Particle.cpp | 13 | ||||
| -rw-r--r-- | src/crepe/Particle.h | 14 | ||||
| -rw-r--r-- | src/crepe/api/LoopManager.cpp | 1 | ||||
| -rw-r--r-- | src/crepe/api/ParticleEmitter.cpp | 7 | ||||
| -rw-r--r-- | src/crepe/api/ParticleEmitter.h | 53 | ||||
| -rw-r--r-- | src/crepe/api/Rigidbody.h | 11 | ||||
| -rw-r--r-- | src/crepe/facade/SDLContext.cpp | 3 | ||||
| -rw-r--r-- | src/crepe/system/CollisionSystem.cpp | 235 | ||||
| -rw-r--r-- | src/crepe/system/CollisionSystem.h | 31 | ||||
| -rw-r--r-- | src/crepe/system/ParticleSystem.cpp | 90 | ||||
| -rw-r--r-- | src/crepe/system/ParticleSystem.h | 22 | ||||
| -rw-r--r-- | src/crepe/system/RenderSystem.cpp | 9 | ||||
| -rw-r--r-- | src/crepe/util/AbsoluutPosition.cpp | 20 | ||||
| -rw-r--r-- | src/crepe/util/AbsoluutPosition.h | 14 | ||||
| -rw-r--r-- | src/crepe/util/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/example/game.cpp | 71 | ||||
| -rw-r--r-- | src/example/rendering_particle.cpp | 22 | ||||
| -rw-r--r-- | src/test/CollisionTest.cpp | 23 | ||||
| -rw-r--r-- | src/test/ParticleTest.cpp | 98 | ||||
| -rw-r--r-- | src/test/Profiling.cpp | 25 | 
20 files changed, 467 insertions, 297 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/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 6900295..0f6be21 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -122,15 +122,8 @@ public:  		*/  		float elastisity_coefficient = 0.0; -		/** -		* \brief Offset of all colliders relative to the object's transform position. -		* -		* The `offset` defines a positional shift applied to all colliders associated with the object, relative to the object's -		* transform position. This allows for the colliders to be placed at a different position than the object's actual -		* position, without modifying the object's transform itself. -		* -		*/ -		vec2 offset; +		//! Enable collision handeling in collision system +		bool kinematic_collision = true;  		/**  		 * \brief Defines the collision layers of a GameObject. diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 20bb030..a1a6f97 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -235,8 +235,7 @@ SDL_FRect SDLContext::get_dst_rect(const DestinationRectangleData & ctx) const {  	}  	size *= cam_aux_data.render_scale * ctx.img_scale * data.scale_offset; -	vec2 screen_pos = (ctx.pos + data.position_offset - cam_aux_data.cam_pos -					   + (cam_aux_data.zoomed_viewport) / 2) +	vec2 screen_pos = (ctx.pos - cam_aux_data.cam_pos + (cam_aux_data.zoomed_viewport) / 2)  						  * cam_aux_data.render_scale  					  - size / 2 + cam_aux_data.bar_size; diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index af8adce..9604543 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -15,11 +15,12 @@  #include "api/Rigidbody.h"  #include "api/Transform.h"  #include "api/Vector2.h" +#include "util/AbsoluutPosition.h" +#include "util/OptionalRef.h"  #include "Collider.h"  #include "CollisionSystem.h"  #include "types.h" -#include "util/OptionalRef.h"  using namespace crepe; @@ -63,7 +64,7 @@ void CollisionSystem::update() {  	// For both objects call the collision handler  	for (auto & collision_pair : collided) {  		this->collision_handler_request(collision_pair.first, collision_pair.second); -		this->collision_handler_request(collision_pair.second, collision_pair.first); +		// this->collision_handler_request(collision_pair.second, collision_pair.first);  	}  } @@ -138,10 +139,11 @@ CollisionSystem::collision_handler(CollisionInternal & data1, CollisionInternal  				= std::get<std::reference_wrapper<BoxCollider>>(data1.collider);  			const BoxCollider & collider2  				= std::get<std::reference_wrapper<BoxCollider>>(data2.collider); -			vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, -															data1.rigidbody); -			vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, -															data2.rigidbody); + +			vec2 collider_pos1 +				= AbsoluutPosition::get_position(data1.transform, collider1.offset); +			vec2 collider_pos2 +				= AbsoluutPosition::get_position(data2.transform, collider2.offset);  			resolution = this->get_box_box_resolution(collider1, collider2, collider_pos1,  													  collider_pos2);  			break; @@ -151,10 +153,10 @@ CollisionSystem::collision_handler(CollisionInternal & data1, CollisionInternal  				= std::get<std::reference_wrapper<BoxCollider>>(data1.collider);  			const CircleCollider & collider2  				= std::get<std::reference_wrapper<CircleCollider>>(data2.collider); -			vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, -															data1.rigidbody); -			vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, -															data2.rigidbody); +			vec2 collider_pos1 +				= AbsoluutPosition::get_position(data1.transform, collider1.offset); +			vec2 collider_pos2 +				= AbsoluutPosition::get_position(data2.transform, collider2.offset);  			resolution = -this->get_circle_box_resolution(collider2, collider1, collider_pos2,  														  collider_pos1);  			break; @@ -164,10 +166,10 @@ CollisionSystem::collision_handler(CollisionInternal & data1, CollisionInternal  				= std::get<std::reference_wrapper<CircleCollider>>(data1.collider);  			const CircleCollider & collider2  				= std::get<std::reference_wrapper<CircleCollider>>(data2.collider); -			vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, -															data1.rigidbody); -			vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, -															data2.rigidbody); +			vec2 collider_pos1 +				= AbsoluutPosition::get_position(data1.transform, collider1.offset); +			vec2 collider_pos2 +				= AbsoluutPosition::get_position(data2.transform, collider2.offset);  			resolution = this->get_circle_circle_resolution(collider1, collider2,  															collider_pos1, collider_pos2);  			break; @@ -177,10 +179,10 @@ CollisionSystem::collision_handler(CollisionInternal & data1, CollisionInternal  				= std::get<std::reference_wrapper<CircleCollider>>(data1.collider);  			const BoxCollider & collider2  				= std::get<std::reference_wrapper<BoxCollider>>(data2.collider); -			vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, -															data1.rigidbody); -			vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, -															data2.rigidbody); +			vec2 collider_pos1 +				= AbsoluutPosition::get_position(data1.transform, collider1.offset); +			vec2 collider_pos2 +				= AbsoluutPosition::get_position(data2.transform, collider2.offset);  			resolution = this->get_circle_box_resolution(collider1, collider2, collider_pos1,  														 collider_pos2);  			break; @@ -302,16 +304,68 @@ vec2 CollisionSystem::get_circle_box_resolution(const CircleCollider & circle_co  }  void CollisionSystem::determine_collision_handler(CollisionInfo & info) { -	// Check rigidbody type for static -	if (info.this_rigidbody.data.body_type == Rigidbody::BodyType::STATIC) return; -	// If second body is static perform the static collision handler in this system -	if (info.other_rigidbody.data.body_type == Rigidbody::BodyType::STATIC) { -		this->static_collision_handler(info); +	// Inverted collision info +	CollisionInfo inverted = { +		.this_collider = info.other_collider, +		.this_transform = info.other_transform, +		.this_rigidbody = info.other_rigidbody, +		.this_metadata = info.other_metadata, +		.other_collider = info.this_collider, +		.other_transform = info.this_transform, +		.other_rigidbody = info.this_rigidbody, +		.other_metadata = info.this_metadata, +		.resolution = -info.resolution, +		.resolution_direction = info.resolution_direction,  	}; -	// Call collision event for user +	// If both objects are static skip handle call collision script +	if (info.this_rigidbody.data.body_type == Rigidbody::BodyType::STATIC +		&& info.other_rigidbody.data.body_type == Rigidbody::BodyType::STATIC) +		return; + +	//	First body is not dynamic +	if (info.this_rigidbody.data.body_type != Rigidbody::BodyType::DYNAMIC) { +		bool static_collision +			= info.this_rigidbody.data.body_type == Rigidbody::BodyType::STATIC +			  && info.other_rigidbody.data.body_type == Rigidbody::BodyType::DYNAMIC; +		bool kinematic_collision +			= info.this_rigidbody.data.body_type == Rigidbody::BodyType::KINEMATIC +			  && info.other_rigidbody.data.body_type == Rigidbody::BodyType::DYNAMIC +			  && info.this_rigidbody.data.kinematic_collision; + +		if (static_collision || kinematic_collision) { +			// Static collision +			this->static_collision_handler(inverted); +		}; +		// Call scripts +		this->call_collision_events(inverted, info); +		return; +	} + +	// Second body is not dynamic +	if (info.other_rigidbody.data.body_type != Rigidbody::BodyType::DYNAMIC) { +		bool static_collision +			= info.other_rigidbody.data.body_type == Rigidbody::BodyType::STATIC; +		bool kinematic_collision +			= info.other_rigidbody.data.body_type == Rigidbody::BodyType::KINEMATIC +			  && info.other_rigidbody.data.kinematic_collision; +		if (static_collision || kinematic_collision) this->static_collision_handler(info); +		this->call_collision_events(info, inverted); +		return; +	} + +	//dynamic +	this->dynamic_collision_handler(info); +	this->call_collision_events(info, inverted); +} + +void CollisionSystem::call_collision_events(CollisionInfo & info, +											CollisionInfo & info_inverted) {  	CollisionEvent data(info); +	CollisionEvent data_inverted(info_inverted);  	EventManager & emgr = this->mediator.event_manager;  	emgr.trigger_event<CollisionEvent>(data, info.this_collider.game_object_id); +	emgr.trigger_event<CollisionEvent>(data_inverted, +									   info_inverted.this_collider.game_object_id);  }  void CollisionSystem::static_collision_handler(CollisionInfo & info) { @@ -363,6 +417,80 @@ void CollisionSystem::static_collision_handler(CollisionInfo & info) {  	}  } +void CollisionSystem::dynamic_collision_handler(CollisionInfo & info) { +	info.this_transform.position += info.resolution / 2; +	info.other_transform.position += -(info.resolution / 2); + +	switch (info.resolution_direction) { +		case Direction::BOTH: +			if (info.this_rigidbody.data.elastisity_coefficient > 0) { +				info.this_rigidbody.data.linear_velocity +					= -info.this_rigidbody.data.linear_velocity +					  * info.this_rigidbody.data.elastisity_coefficient; +			} else { +				info.this_rigidbody.data.linear_velocity = {0, 0}; +			} + +			if (info.other_rigidbody.data.elastisity_coefficient > 0) { +				info.other_rigidbody.data.linear_velocity +					= -info.other_rigidbody.data.linear_velocity +					  * info.other_rigidbody.data.elastisity_coefficient; +			} else { +				info.other_rigidbody.data.linear_velocity = {0, 0}; +			} +			break; +		case Direction::Y_DIRECTION: +			if (info.this_rigidbody.data.elastisity_coefficient > 0) { +				info.this_rigidbody.data.linear_velocity.y +					= -info.this_rigidbody.data.linear_velocity.y +					  * info.this_rigidbody.data.elastisity_coefficient; +			} +			// Stop movement +			else { +				info.this_rigidbody.data.linear_velocity.y = 0; +				info.this_transform.position.x -= info.resolution.x; +			} + +			if (info.other_rigidbody.data.elastisity_coefficient > 0) { +				info.other_rigidbody.data.linear_velocity.y +					= -info.other_rigidbody.data.linear_velocity.y +					  * info.other_rigidbody.data.elastisity_coefficient; +			} +			// Stop movement +			else { +				info.other_rigidbody.data.linear_velocity.y = 0; +				info.other_transform.position.x -= info.resolution.x; +			} +			break; +		case Direction::X_DIRECTION: +			if (info.this_rigidbody.data.elastisity_coefficient > 0) { +				info.this_rigidbody.data.linear_velocity.x +					= -info.this_rigidbody.data.linear_velocity.x +					  * info.this_rigidbody.data.elastisity_coefficient; +			} +			// Stop movement +			else { +				info.this_rigidbody.data.linear_velocity.x = 0; +				info.this_transform.position.y -= info.resolution.y; +			} + +			if (info.other_rigidbody.data.elastisity_coefficient > 0) { +				info.other_rigidbody.data.linear_velocity.x +					= -info.other_rigidbody.data.linear_velocity.x +					  * info.other_rigidbody.data.elastisity_coefficient; +			} +			// Stop movement +			else { +				info.other_rigidbody.data.linear_velocity.x = 0; +				info.other_transform.position.y -= info.resolution.y; +			} +			break; +		case Direction::NONE: +			// Not possible +			break; +	} +} +  std::vector<std::pair<CollisionSystem::CollisionInternal, CollisionSystem::CollisionInternal>>  CollisionSystem::gather_collisions(std::vector<CollisionInternal> & colliders) { @@ -489,14 +617,18 @@ bool CollisionSystem::get_box_box_collision(const BoxCollider & box1, const BoxC  											const Rigidbody & rigidbody1,  											const Rigidbody & rigidbody2) const {  	// Get current positions of colliders -	vec2 final_position1 = this->get_current_position(box1.offset, transform1, rigidbody1); -	vec2 final_position2 = this->get_current_position(box2.offset, transform2, rigidbody2); +	vec2 final_position1 = AbsoluutPosition::get_position(transform1, box1.offset); +	vec2 final_position2 = AbsoluutPosition::get_position(transform2, box2.offset); + +	// Scale dimensions +	vec2 scaled_box1 = box1.dimensions * transform1.scale; +	vec2 scaled_box2 = box2.dimensions * transform2.scale;  	// Calculate half-extents (half width and half height) -	float half_width1 = box1.dimensions.x / 2.0; -	float half_height1 = box1.dimensions.y / 2.0; -	float half_width2 = box2.dimensions.x / 2.0; -	float half_height2 = box2.dimensions.y / 2.0; +	float half_width1 = scaled_box1.x / 2.0; +	float half_height1 = scaled_box1.y / 2.0; +	float half_width2 = scaled_box2.x / 2.0; +	float half_height2 = scaled_box2.y / 2.0;  	// Check if the boxes overlap along the X and Y axes  	return (final_position1.x + half_width1 > final_position2.x - half_width2 @@ -512,12 +644,16 @@ bool CollisionSystem::get_box_circle_collision(const BoxCollider & box1,  											   const Rigidbody & rigidbody1,  											   const Rigidbody & rigidbody2) const {  	// Get current positions of colliders -	vec2 final_position1 = this->get_current_position(box1.offset, transform1, rigidbody1); -	vec2 final_position2 = this->get_current_position(circle2.offset, transform2, rigidbody2); +	vec2 final_position1 = AbsoluutPosition::get_position(transform1, box1.offset); +	vec2 final_position2 = AbsoluutPosition::get_position(transform2, circle2.offset); + +	// Scale dimensions +	vec2 scaled_box = box1.dimensions * transform1.scale; +	float scaled_circle = circle2.radius * transform2.scale;  	// Calculate box half-extents -	float half_width = box1.dimensions.x / 2.0; -	float half_height = box1.dimensions.y / 2.0; +	float half_width = scaled_box.x / 2.0; +	float half_height = scaled_box.y / 2.0;  	// Find the closest point on the box to the circle's center  	float closest_x = std::max(final_position1.x - half_width, @@ -531,7 +667,7 @@ bool CollisionSystem::get_box_circle_collision(const BoxCollider & box1,  	float distance_squared = distance_x * distance_x + distance_y * distance_y;  	// Compare distance squared with the square of the circle's radius -	return distance_squared < circle2.radius * circle2.radius; +	return distance_squared < scaled_circle * scaled_circle;  }  bool CollisionSystem::get_circle_circle_collision(const CircleCollider & circle1, @@ -541,35 +677,20 @@ bool CollisionSystem::get_circle_circle_collision(const CircleCollider & circle1  												  const Rigidbody & rigidbody1,  												  const Rigidbody & rigidbody2) const {  	// Get current positions of colliders -	vec2 final_position1 = this->get_current_position(circle1.offset, transform1, rigidbody1); -	vec2 final_position2 = this->get_current_position(circle2.offset, transform2, rigidbody2); +	vec2 final_position1 = AbsoluutPosition::get_position(transform1, circle1.offset); +	vec2 final_position2 = AbsoluutPosition::get_position(transform2, circle2.offset); + +	// Scale dimensions +	float scaled_circle1 = circle1.radius * transform1.scale; +	float scaled_circle2 = circle2.radius * transform2.scale;  	float distance_x = final_position1.x - final_position2.x;  	float distance_y = final_position1.y - final_position2.y;  	float distance_squared = distance_x * distance_x + distance_y * distance_y;  	// Calculate the sum of the radii -	float radius_sum = circle1.radius + circle2.radius; +	float radius_sum = scaled_circle1 + scaled_circle2;  	// Check if the distance between the centers is less than or equal to the sum of the radii  	return distance_squared < radius_sum * radius_sum;  } - -vec2 CollisionSystem::get_current_position(const vec2 & collider_offset, -										   const Transform & transform, -										   const Rigidbody & rigidbody) const { -	// Get the rotation in radians -	float radians1 = transform.rotation * (M_PI / 180.0); - -	// Calculate total offset with scale -	vec2 total_offset = (rigidbody.data.offset + collider_offset) * transform.scale; - -	// Rotate -	float rotated_total_offset_x1 -		= total_offset.x * cos(radians1) - total_offset.y * sin(radians1); -	float rotated_total_offset_y1 -		= total_offset.x * sin(radians1) + total_offset.y * cos(radians1); - -	// Final positions considering scaling and rotation -	return (transform.position + vec2(rotated_total_offset_x1, rotated_total_offset_y1)); -} diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h index 5b136c6..23752e1 100644 --- a/src/crepe/system/CollisionSystem.h +++ b/src/crepe/system/CollisionSystem.h @@ -100,19 +100,6 @@ private:  	CollisionInternalType get_collider_type(const collider_variant & collider1,  											const collider_variant & collider2) const; -	/** -		* \brief Calculates the current position of a collider. -		* -		* Combines the Collider offset, Transform position, and Rigidbody offset to compute the position of the collider. -		* -		* \param collider_offset The offset of the collider. -		* \param transform The Transform of the associated game object. -		* \param rigidbody The Rigidbody of the associated game object. -		* \return The calculated position of the collider. -		*/ -	vec2 get_current_position(const vec2 & collider_offset, const Transform & transform, -							  const Rigidbody & rigidbody) const; -  private:  	/**  		* \brief Handles collision resolution between two colliders. @@ -195,6 +182,15 @@ private:  	void determine_collision_handler(CollisionInfo & info);  	/** +		* \brief Calls both collision script +		* +		* Calls both collision script to let user add additonal handeling or handle full collision. +		* +		* \param info Collision information containing data about both colliders. +		*/ +	void call_collision_events(CollisionInfo & info, CollisionInfo & info_inverted); + +	/**  		* \brief Handles collisions involving static objects.  		*  		* Resolves collisions by adjusting positions and modifying velocities if bounce is enabled. @@ -203,6 +199,15 @@ private:  		*/  	void static_collision_handler(CollisionInfo & info); +	/** +		* \brief Handles collisions involving dynamic objects. +		* +		* Resolves collisions by adjusting positions and modifying velocities if bounce is enabled. +		* +		* \param info Collision information containing data about both colliders. +		*/ +	void dynamic_collision_handler(CollisionInfo & info); +  private:  	/**  		* \brief Checks for collisions between colliders. diff --git a/src/crepe/system/ParticleSystem.cpp b/src/crepe/system/ParticleSystem.cpp index b14c52f..56f1dfd 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,8 @@  #include "../api/ParticleEmitter.h"  #include "../api/Transform.h"  #include "../manager/ComponentManager.h" +#include "../manager/LoopTimerManager.h" +#include "util/AbsoluutPosition.h"  #include "ParticleSystem.h" @@ -12,7 +15,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 +28,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 = AbsoluutPosition::get_position(transform, emitter.data.offset); +	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 +69,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 afd9548..c0717fc 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -13,6 +13,7 @@  #include "../facade/Texture.h"  #include "../manager/ComponentManager.h"  #include "../manager/ResourceManager.h" +#include "util/AbsoluutPosition.h"  #include "RenderSystem.h"  #include "types.h" @@ -83,11 +84,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{ @@ -105,11 +106,11 @@ void RenderSystem::render_normal(const Sprite & sprite, const Transform & tm) {  	SDLContext & ctx = this->mediator.sdl_context;  	ResourceManager & resource_manager = this->mediator.resource_manager;  	const Texture & res = resource_manager.get<Texture>(sprite.source); - +	vec2 pos = AbsoluutPosition::get_position(tm, sprite.data.position_offset);  	ctx.draw(SDLContext::RenderContext{  		.sprite = sprite,  		.texture = res, -		.pos = tm.position, +		.pos = pos,  		.angle = tm.rotation,  		.scale = tm.scale,  	}); diff --git a/src/crepe/util/AbsoluutPosition.cpp b/src/crepe/util/AbsoluutPosition.cpp new file mode 100644 index 0000000..296cc09 --- /dev/null +++ b/src/crepe/util/AbsoluutPosition.cpp @@ -0,0 +1,20 @@ +#include "AbsoluutPosition.h" + +using namespace crepe; + +vec2 AbsoluutPosition::get_position(const Transform & transform, const vec2 & offset) { +	// Get the rotation in radians +	float radians1 = transform.rotation * (M_PI / 180.0); + +	// Calculate total offset with scale +	vec2 total_offset = offset * transform.scale; + +	// Rotate +	float rotated_total_offset_x1 +		= total_offset.x * cos(radians1) - total_offset.y * sin(radians1); +	float rotated_total_offset_y1 +		= total_offset.x * sin(radians1) + total_offset.y * cos(radians1); + +	// Final positions considering scaling and rotation +	return (transform.position + vec2(rotated_total_offset_x1, rotated_total_offset_y1)); +} diff --git a/src/crepe/util/AbsoluutPosition.h b/src/crepe/util/AbsoluutPosition.h new file mode 100644 index 0000000..30a7f93 --- /dev/null +++ b/src/crepe/util/AbsoluutPosition.h @@ -0,0 +1,14 @@ +#pragma once + +#include "api/Transform.h" + +#include "types.h" + +namespace crepe { + +class AbsoluutPosition { +public: +	static vec2 get_position(const Transform & transform, const vec2 & offset); +}; + +} // namespace crepe diff --git a/src/crepe/util/CMakeLists.txt b/src/crepe/util/CMakeLists.txt index 94ed906..b4b9221 100644 --- a/src/crepe/util/CMakeLists.txt +++ b/src/crepe/util/CMakeLists.txt @@ -1,6 +1,7 @@  target_sources(crepe PUBLIC  	LogColor.cpp  	Log.cpp +	AbsoluutPosition.cpp  )  target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -11,5 +12,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES  	Proxy.hpp  	OptionalRef.h  	OptionalRef.hpp +	AbsoluutPosition.h  ) diff --git a/src/example/game.cpp b/src/example/game.cpp index 61f8760..a8b3d5d 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -1,8 +1,10 @@  #include "api/CircleCollider.h" +#include "api/ParticleEmitter.h"  #include "api/Scene.h"  #include "manager/ComponentManager.h"  #include "manager/Mediator.h"  #include "types.h" +#include <cmath>  #include <crepe/api/BoxCollider.h>  #include <crepe/api/Camera.h>  #include <crepe/api/Color.h> @@ -67,11 +69,6 @@ class MyScript1 : public Script {  				//add collider switch  				break;  			} -			case Keycode::Q: { -				Rigidbody & rg = this->get_component<Rigidbody>(); -				rg.data.angular_velocity = 1; -				break; -			}  			default:  				break;  		} @@ -140,6 +137,31 @@ class MyScript2 : public Script {  				//add collider switch  				break;  			} +			case Keycode::J: { +				Rigidbody & tf = this->get_component<Rigidbody>(); +				tf.data.linear_velocity.x = -10; +				break; +			} +			case Keycode::I: { +				Rigidbody & tf = this->get_component<Rigidbody>(); +				tf.data.linear_velocity.y -= 1; +				break; +			} +			case Keycode::K: { +				Rigidbody & tf = this->get_component<Rigidbody>(); +				tf.data.linear_velocity.y += 1; +				break; +			} +			case Keycode::L: { +				Rigidbody & tf = this->get_component<Rigidbody>(); +				tf.data.linear_velocity.x = 10; +				break; +			} +			case Keycode::O: { +				Rigidbody & tf = this->get_component<Rigidbody>(); +				tf.data.linear_velocity.x = 0; +				break; +			}  			default:  				break;  		} @@ -176,7 +198,6 @@ public:  			.mass = 0,  			.gravity_scale = 0,  			.body_type = Rigidbody::BodyType::STATIC, -			.offset = {0, 0},  		});  		world.add_component<BoxCollider>(  			vec2{world_collider, world_collider}, @@ -199,23 +220,25 @@ public:  			});  		GameObject game_object1 = new_object( -			"Name", "Tag", vec2{screen_size_width / 2, screen_size_height / 2}, 0, 1); +			"Name", "Tag", vec2{screen_size_width / 2, screen_size_height / 2}, 45, 1);  		game_object1.add_component<Rigidbody>(Rigidbody::Data{  			.mass = 1, -			.gravity_scale = 1, -			.body_type = Rigidbody::BodyType::DYNAMIC, +			.gravity_scale = 0, +			.body_type = Rigidbody::BodyType::KINEMATIC,  			.linear_velocity = {0, 1},  			.constraints = {0, 0, 0}, -			.elastisity_coefficient = 0, -			.offset = {0, 0}, +			.elastisity_coefficient = 1,  		});  		// add box with boxcollider  		game_object1.add_component<BoxCollider>(vec2{20, 20});  		game_object1.add_component<BehaviorScript>().set_script<MyScript1>(); -		Asset img1{"asset/texture/square.png"}; +		Asset img1{"asset/texture/test_ap43.png"};  		game_object1.add_component<Sprite>(img1, Sprite::Data{ +													 .sorting_in_layer = 2, +													 .order_in_layer = 2,  													 .size = {20, 20}, +													 .position_offset = {0, -10},  												 });  		//add circle with cirlcecollider deactiveated @@ -233,12 +256,11 @@ public:  			"Name", "Tag", vec2{screen_size_width / 2, screen_size_height / 2}, 0, 1);  		game_object2.add_component<Rigidbody>(Rigidbody::Data{  			.mass = 1, -			.gravity_scale = 0, -			.body_type = Rigidbody::BodyType::STATIC, +			.gravity_scale = 1, +			.body_type = Rigidbody::BodyType::KINEMATIC,  			.linear_velocity = {0, 0},  			.constraints = {0, 0, 0},  			.elastisity_coefficient = 1, -			.offset = {0, 0},  		});  		// add box with boxcollider  		game_object2.add_component<BoxCollider>(vec2{20, 20}); @@ -258,6 +280,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 ff9e7cc..50e862d 100644 --- a/src/test/CollisionTest.cpp +++ b/src/test/CollisionTest.cpp @@ -66,7 +66,6 @@ public:  		world.add_component<Rigidbody>(Rigidbody::Data{  			// TODO: remove unrelated properties:  			.body_type = Rigidbody::BodyType::STATIC, -			.offset = {0, 0},  		});  		// Create a box with an inner size of 10x10 units  		world.add_component<BoxCollider>(vec2{100, 100}, vec2{0, -100}); // Top @@ -81,7 +80,6 @@ public:  			.linear_velocity = {0, 0},  			.constraints = {0, 0, 0},  			.elastisity_coefficient = 1, -			.offset = {0, 0},  			.collision_layers = {0},  		});  		game_object1.add_component<BoxCollider>(vec2{10, 10}, vec2{0, 0}); @@ -97,7 +95,6 @@ public:  			.linear_velocity = {0, 0},  			.constraints = {0, 0, 0},  			.elastisity_coefficient = 1, -			.offset = {0, 0},  			.collision_layers = {0},  		});  		game_object2.add_component<BoxCollider>(vec2{10, 10}, vec2{0, 0}); @@ -138,8 +135,8 @@ TEST_F(CollisionTest, collision_box_box_dynamic_both_no_velocity) {  	script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) {  		collision_happend = true;  		EXPECT_EQ(ev.info.this_collider.game_object_id, 2); -		EXPECT_EQ(ev.info.resolution.x, 10); -		EXPECT_EQ(ev.info.resolution.y, 10); +		EXPECT_EQ(ev.info.resolution.x, -10); +		EXPECT_EQ(ev.info.resolution.y, -10);  		EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::BOTH);  	};  	EXPECT_FALSE(collision_happend); @@ -211,8 +208,8 @@ TEST_F(CollisionTest, collision_box_box_dynamic_both) {  	script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) {  		collision_happend = true;  		EXPECT_EQ(ev.info.this_collider.game_object_id, 2); -		EXPECT_EQ(ev.info.resolution.x, 10); -		EXPECT_EQ(ev.info.resolution.y, 10); +		EXPECT_EQ(ev.info.resolution.x, -10); +		EXPECT_EQ(ev.info.resolution.y, -10);  		EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::BOTH);  	};  	EXPECT_FALSE(collision_happend); @@ -293,10 +290,8 @@ TEST_F(CollisionTest, collision_box_box_static_both) {  		EXPECT_EQ(ev.info.resolution.y, 10);  		EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::BOTH);  	}; -	script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { -		// is static should not be called -		FAIL(); -	}; +	script_object2_ref->test_fn +		= [&collision_happend](const CollisionEvent & ev) { collision_happend = true; };  	EXPECT_FALSE(collision_happend);  	Transform & tf = this->mgr.get_components_by_id<Transform>(1).front().get();  	tf.position = {50, 30}; @@ -318,7 +313,7 @@ TEST_F(CollisionTest, collision_box_box_static_x_direction) {  	};  	script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) {  		// is static should not be called -		FAIL(); +		//FAIL();  	};  	EXPECT_FALSE(collision_happend);  	Transform & tf = this->mgr.get_components_by_id<Transform>(1).front().get(); @@ -343,7 +338,7 @@ TEST_F(CollisionTest, collision_box_box_static_y_direction) {  	};  	script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) {  		// is static should not be called -		FAIL(); +		//FAIL();  	};  	EXPECT_FALSE(collision_happend);  	Transform & tf = this->mgr.get_components_by_id<Transform>(1).front().get(); @@ -368,7 +363,7 @@ TEST_F(CollisionTest, collision_box_box_static_multiple) { //todo check visually  	};  	script_object2_ref->test_fn = [&](const CollisionEvent & ev) {  		// is static should not be called -		FAIL(); +		//FAIL();  	};  	EXPECT_FALSE(collision_happend);  	Transform & tf = this->mgr.get_components_by_id<Transform>(1).front().get(); 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++;  |