diff options
Diffstat (limited to 'src/crepe')
| -rw-r--r-- | src/crepe/Collider.cpp | 2 | ||||
| -rw-r--r-- | src/crepe/Collider.h | 7 | ||||
| -rw-r--r-- | src/crepe/api/BehaviorScript.h | 7 | ||||
| -rw-r--r-- | src/crepe/api/BehaviorScript.hpp | 6 | ||||
| -rw-r--r-- | src/crepe/api/BoxCollider.cpp | 7 | ||||
| -rw-r--r-- | src/crepe/api/BoxCollider.h | 24 | ||||
| -rw-r--r-- | src/crepe/api/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/crepe/api/CircleCollider.cpp | 6 | ||||
| -rw-r--r-- | src/crepe/api/CircleCollider.h | 17 | ||||
| -rw-r--r-- | src/crepe/api/Event.h | 7 | ||||
| -rw-r--r-- | src/crepe/api/LoopManager.cpp | 11 | ||||
| -rw-r--r-- | src/crepe/api/Rigidbody.h | 10 | ||||
| -rw-r--r-- | src/crepe/api/Script.h | 7 | ||||
| -rw-r--r-- | src/crepe/api/Vector2.h | 3 | ||||
| -rw-r--r-- | src/crepe/system/CollisionSystem.cpp | 356 | ||||
| -rw-r--r-- | src/crepe/system/CollisionSystem.h | 179 | ||||
| -rw-r--r-- | src/crepe/system/RenderSystem.cpp | 2 | 
17 files changed, 635 insertions, 20 deletions
diff --git a/src/crepe/Collider.cpp b/src/crepe/Collider.cpp index bbec488..0706371 100644 --- a/src/crepe/Collider.cpp +++ b/src/crepe/Collider.cpp @@ -2,4 +2,4 @@  using namespace crepe; -Collider::Collider(game_object_id_t id) : Component(id) {} +Collider::Collider(game_object_id_t id, Vector2 offset) : Component(id), offset(offset) {} diff --git a/src/crepe/Collider.h b/src/crepe/Collider.h index 827f83d..e910ae4 100644 --- a/src/crepe/Collider.h +++ b/src/crepe/Collider.h @@ -1,14 +1,17 @@  #pragma once +#include "api/Vector2.h" +  #include "Component.h"  namespace crepe {  class Collider : public Component {  public: -	Collider(game_object_id_t id); +	Collider(game_object_id_t id, Vector2 offset); -	int size; +	//! Offset of the collider relative to rigidbody position  +	Vector2 offset;  };  } // namespace crepe diff --git a/src/crepe/api/BehaviorScript.h b/src/crepe/api/BehaviorScript.h index 9d85d4c..d556fe5 100644 --- a/src/crepe/api/BehaviorScript.h +++ b/src/crepe/api/BehaviorScript.h @@ -39,11 +39,14 @@ public:  	 * \brief Set the concrete script of this component  	 *  	 * \tparam T Concrete script type (derived from \c crepe::Script) +	 * \tparam Args Arguments for concrete script constructor +	 * +	 * \param args Arguments for concrete script constructor (forwarded using perfect forwarding)  	 *  	 * \returns Reference to BehaviorScript component (`*this`)  	 */ -	template <class T> -	BehaviorScript & set_script(); +	template <class T, typename... Args> +	BehaviorScript & set_script(Args &&... args);  protected:  	//! Script instance diff --git a/src/crepe/api/BehaviorScript.hpp b/src/crepe/api/BehaviorScript.hpp index d80321d..6bd123d 100644 --- a/src/crepe/api/BehaviorScript.hpp +++ b/src/crepe/api/BehaviorScript.hpp @@ -9,11 +9,11 @@  namespace crepe { -template <class T> -BehaviorScript & BehaviorScript::set_script() { +template <class T, typename... Args> +BehaviorScript & BehaviorScript::set_script(Args &&... args) {  	dbg_trace();  	static_assert(std::is_base_of<Script, T>::value); -	Script * s = new T(); +	Script * s = new T(std::forward<Args>(args)...);  	s->game_object_id = this->game_object_id;  	s->component_manager_ref = &this->component_manager;  	this->script = std::unique_ptr<Script>(s); diff --git a/src/crepe/api/BoxCollider.cpp b/src/crepe/api/BoxCollider.cpp new file mode 100644 index 0000000..eafbdb2 --- /dev/null +++ b/src/crepe/api/BoxCollider.cpp @@ -0,0 +1,7 @@ +#include "BoxCollider.h" +#include "../Collider.h"  + +using namespace crepe; + + +BoxCollider::BoxCollider(game_object_id_t game_object_id,Vector2 offset, double width, double height) : Collider(game_object_id,offset), width(width), height(height) {} diff --git a/src/crepe/api/BoxCollider.h b/src/crepe/api/BoxCollider.h new file mode 100644 index 0000000..7f51cba --- /dev/null +++ b/src/crepe/api/BoxCollider.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Vector2.h" +#include "../Collider.h" + +namespace crepe { + +/** + * \brief A class representing a box-shaped collider. + *  + * This class is used for collision detection with other colliders (e.g., CircleCollider). + */ +class BoxCollider : public Collider { +public: +	BoxCollider(game_object_id_t game_object_id,Vector2 offset, double width, double height); + +	//! Width of box collider  +	double width; + +	//! Height of box collider +	double height; +}; + +} // namespace crepe diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index d6b6801..830f5bd 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -17,6 +17,8 @@ target_sources(crepe PUBLIC  	Vector2.cpp  	Camera.cpp  	Animator.cpp +	BoxCollider.cpp +	CircleCollider.cpp  	EventManager.cpp  	IKeyListener.cpp  	IMouseListener.cpp @@ -48,6 +50,8 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES  	SceneManager.hpp  	Camera.h  	Animator.h +	BoxCollider.h +	CircleCollider.h  	EventManager.h  	EventManager.hpp  	EventHandler.h diff --git a/src/crepe/api/CircleCollider.cpp b/src/crepe/api/CircleCollider.cpp new file mode 100644 index 0000000..04a4995 --- /dev/null +++ b/src/crepe/api/CircleCollider.cpp @@ -0,0 +1,6 @@ +#include "CircleCollider.h" + +using namespace crepe; + + +CircleCollider::CircleCollider(game_object_id_t game_object_id,Vector2 offset, int radius) : Collider(game_object_id,offset), radius(radius) {} diff --git a/src/crepe/api/CircleCollider.h b/src/crepe/api/CircleCollider.h index e77a592..4e04fa4 100644 --- a/src/crepe/api/CircleCollider.h +++ b/src/crepe/api/CircleCollider.h @@ -1,14 +1,23 @@  #pragma once + +#include "Vector2.h" +  #include "../Collider.h"  namespace crepe { +/** + * \brief A class representing a circle-shaped collider. + *  + * This class is used for collision detection with other colliders (e.g., BoxCollider). + */  class CircleCollider : public Collider {  public: -	CircleCollider(game_object_id_t game_object_id, int radius) -		: Collider(game_object_id), -		  radius(radius) {} -	int radius; + +	CircleCollider(game_object_id_t game_object_id,Vector2 offset, int radius); + +	//! Radius of the circle collider. +	double radius;  };  } // namespace crepe diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h index 06cf7f3..8a6b931 100644 --- a/src/crepe/api/Event.h +++ b/src/crepe/api/Event.h @@ -3,6 +3,8 @@  #include <string> +#include "system/CollisionSystem.h" +  #include "KeyCodes.h"  /** @@ -93,8 +95,9 @@ public:   */  class CollisionEvent : public Event {  public: -	//! Data describing the collision (currently not implemented). -	// Collision collisionData; +	crepe::CollisionSystem::CollisionInfo info; +	CollisionEvent(const crepe::CollisionSystem::CollisionInfo& collisionInfo) +        : info(collisionInfo) {}  };  /** diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index a64366f..586919d 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -6,6 +6,8 @@  #include "../system/PhysicsSystem.h"  #include "../system/RenderSystem.h"  #include "../system/ScriptSystem.h" +#include "..//system/PhysicsSystem.h" +#include "..//system/CollisionSystem.h"  #include "LoopManager.h"  #include "LoopTimer.h" @@ -32,7 +34,10 @@ void LoopManager::start() {  }  void LoopManager::set_running(bool running) { this->game_running = running; } -void LoopManager::fixed_update() {} +void LoopManager::fixed_update() { +	this->get_system<PhysicsSystem>().update(); +	this->get_system<CollisionSystem>().update(); +}  void LoopManager::loop() {  	LoopTimer & timer = LoopTimer::get_instance(); @@ -41,11 +46,11 @@ void LoopManager::loop() {  	while (game_running) {  		timer.update(); -		while (timer.get_lag() >= timer.get_fixed_delta_time()) { +		//while (timer.get_lag() >= timer.get_fixed_delta_time()) {  			this->process_input();  			this->fixed_update();  			timer.advance_fixed_update(); -		} +		//}  		this->update();  		this->render(); diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index 3e5c7a3..fddbf5c 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -1,5 +1,7 @@  #pragma once +#include <cmath> +  #include "../Component.h"  #include "Vector2.h" @@ -58,13 +60,13 @@ public:  		//! linear velocity of object  		Vector2 linear_velocity;  		//! maximum linear velocity of object -		Vector2 max_linear_velocity; +		Vector2 max_linear_velocity = {INFINITY ,INFINITY};  		//! linear damping of object  		Vector2 linear_damping;  		//! angular velocity of object  		double angular_velocity = 0.0;  		//! max angular velocity of object -		double max_angular_velocity = 0.0; +		double max_angular_velocity = INFINITY;  		//! angular damping of object  		double angular_damping = 0.0;  		//! movements constraints of object @@ -73,6 +75,10 @@ public:  		bool use_gravity = true;  		//! if object bounces  		bool bounce = false; +		//! bounce factor of material +		double elastisity = 0.0; +		//! offset of all colliders relative to transform position +		Vector2 offset;  	};  public: diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 839d937..0702e36 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -64,6 +64,13 @@ protected:  	template <typename T>  	RefVector<T> get_components() const; +	/** +	 * \brief Gets game object id this script is attached to +	 * +	 * \returns game object id +	 */ +	game_object_id_t get_game_object_id() const {return this->game_object_id;}; +  protected:  	// NOTE: Script must have a constructor without arguments so the game programmer doesn't need  	// to manually add `using Script::Script` to their concrete script class. diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h index 2fb6136..438fde6 100644 --- a/src/crepe/api/Vector2.h +++ b/src/crepe/api/Vector2.h @@ -35,6 +35,9 @@ struct Vector2 {  	//! Checks if this vector is not equal to another vector.  	bool operator!=(const Vector2 & other) const; + +	//! +	double dot(const Vector2& other) const;  };  } // namespace crepe diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index c74ca1d..b23e779 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -1,5 +1,359 @@ +#include <cmath> +#include <algorithm> +#include <cstddef> +#include <utility> +#include <variant> + +#include "api/Event.h" +#include "api/EventManager.h" +#include "api/BoxCollider.h" +#include "api/CircleCollider.h" +#include "api/Vector2.h" +#include "api/Rigidbody.h" +#include "api/Transform.h" + +#include "ComponentManager.h"  #include "CollisionSystem.h" +#include "Collider.h"  using namespace crepe; -void CollisionSystem::update() {} +void CollisionSystem::update() { +	// Get collider components and keep them seperate +	ComponentManager & mgr = this->component_manager; +	std::vector<std::reference_wrapper<BoxCollider>> boxcolliders	= mgr.get_components_by_type<BoxCollider>(); +	std::vector<std::reference_wrapper<CircleCollider>> circlecolliders	= mgr.get_components_by_type<CircleCollider>(); +	 +	// Check between all colliders if there is a collision +	std::vector<std::pair<CollidedInfoStor,CollidedInfoStor>> collided = check_collisions(boxcolliders,circlecolliders); + +	// For both objects call the collision handler  +	for (auto& collision_pair : collided) { +		collision_handler(collision_pair.first,collision_pair.second); +		collision_handler(collision_pair.second,collision_pair.first); +	} +} + +void CollisionSystem::collision_handler(CollidedInfoStor& data1,CollidedInfoStor& data2){ + +	// Data needed for collision handler info +	const Collider* collider1 = nullptr; +	const Collider* collider2 = nullptr; +	Vector2 move_back; + +	// Check collision type and get values for handler +	if (std::holds_alternative<BoxCollider>(data1.collider)) { +		if (std::holds_alternative<BoxCollider>(data2.collider)) { +			 +			// Get colliders from variant to be used to determine collision handler info +			const BoxCollider& box_collider1 = std::get<BoxCollider>(data1.collider); +			const BoxCollider& box_collider2 = std::get<BoxCollider>(data2.collider); +			collider1 = &box_collider1; +			collider2 = &box_collider2; + +			// TODO: send with the collider info to this function because this is calculated previously +			// Get the current position of the collider +			Vector2 final_position1 = current_position(box_collider1,data1.transform,data1.rigidbody); +			Vector2 final_position2 = current_position(box_collider2,data2.transform,data2.rigidbody); + +			// Determine move_back value for smallest overlap (x or y) +			move_back = box_box_collision_move_back(box_collider1,box_collider2,final_position1,final_position2); +			 +		} +		else { +			// TODO: calcualte Box - Circle collision info +			const BoxCollider& box_collider = std::get<BoxCollider>(data1.collider); +			const CircleCollider& circle_collider = std::get<CircleCollider>(data2.collider); +			collider1 = &box_collider; +			collider2 = &circle_collider; +		} +	} +	else { +		if (std::holds_alternative<CircleCollider>(data2.collider)) { +			// TODO: calcualte Circle - Circle collision info +			const CircleCollider& circle_collider1 = std::get<CircleCollider>(data1.collider); +			const CircleCollider& circle_collider2 = std::get<CircleCollider>(data2.collider); +			collider1 = &circle_collider1; +			collider2 = &circle_collider2; +		} +		else { +			// TODO: calcualte Circle - Box collision info +			const CircleCollider& circle_collider = std::get<CircleCollider>(data1.collider); +			const BoxCollider& box_collider = std::get<BoxCollider>(data2.collider); +			collider1 = &circle_collider; +			collider2 = &box_collider; +		} +	} + +	// One vaue is calculated for moving back. Calculate the other value (x or y) relateive to the move_back value. +	Direction move_back_direction = Direction::NONE; +	if(move_back.x != 0 && move_back.y > 0) { +		move_back_direction = Direction::BOTH; +	} else if (move_back.x != 0) { +		move_back_direction = Direction::X_DIRECTION; +		if(data1.rigidbody.data.linear_velocity.y != 0)	 +		move_back.y = data1.rigidbody.data.linear_velocity.y * (move_back.x/data1.rigidbody.data.linear_velocity.x); +	} else if (move_back.y != 0) { +		move_back_direction = Direction::Y_DIRECTION; +		if(data1.rigidbody.data.linear_velocity.x != 0)  +		move_back.x = data1.rigidbody.data.linear_velocity.x * (move_back.y/data1.rigidbody.data.linear_velocity.y); +	} + +	// collision info +	crepe::CollisionSystem::CollisionInfo collision_info{ +            .first={ *collider1, data1.transform, data1.rigidbody }, +            .second={ *collider2, data2.transform, data2.rigidbody }, +						.move_back_value = move_back, +						.move_back_direction = move_back_direction, +        }; + +	// Determine if static needs to be called +	determine_collision_handler(collision_info);	 +} + + +Vector2 CollisionSystem::box_box_collision_move_back(const BoxCollider& box_collider1,const BoxCollider& box_collider2,Vector2 final_position1,Vector2 final_position2) +{ +	Vector2 resolution; // Default resolution vector +	Vector2 delta = final_position2 - final_position1; + +	// Compute half-dimensions of the boxes +	double half_width1 = box_collider1.width / 2.0; +	double half_height1 = box_collider1.height / 2.0; +	double half_width2 = box_collider2.width / 2.0; +	double half_height2 = box_collider2.height / 2.0; + +	// Calculate overlaps along X and Y axes +	double overlap_x = (half_width1 + half_width2) - std::abs(delta.x); +	double overlap_y = (half_height1 + half_height2) - std::abs(delta.y); + +	// Check if there is a collision +	if (overlap_x > 0 && overlap_y > 0) {//should always be true check if this can be removed +		// Determine the direction of resolution +		if (overlap_x < overlap_y) { +			// Resolve along the X-axis (smallest overlap) +			resolution.x = (delta.x > 0) ? -overlap_x : overlap_x; +		} else if (overlap_y < overlap_x) { +			// Resolve along the Y-axis (smallest overlap) +			resolution.y = (delta.y > 0) ? -overlap_y : overlap_y; +		} else { +			// Equal overlap, resolve both directions with preference +			resolution.x = (delta.x > 0) ? -overlap_x : overlap_x; +			resolution.y = (delta.y > 0) ? -overlap_y : overlap_y; +		} +	} + +	return resolution; +} + +void CollisionSystem::determine_collision_handler(CollisionInfo& info){ +	// Check rigidbody type for static +	if(info.first.rigidbody.data.body_type != Rigidbody::BodyType::STATIC) +	{ +		// If second body is static perform the static collision handler in this system +		if(info.second.rigidbody.data.body_type == Rigidbody::BodyType::STATIC){ +			static_collision_handler(info); +		};  +		// Call collision event for user +		CollisionEvent data(info); +		EventManager::get_instance().trigger_event<CollisionEvent>(data, info.first.collider.game_object_id); +	}		 +} + +void CollisionSystem::static_collision_handler(CollisionInfo& info){ +	// Move object back using calculate move back value  +	info.first.transform.position += info.move_back_value; + +	// If bounce is enabled mirror velocity +	if(info.first.rigidbody.data.bounce) { +		if(info.move_back_direction == Direction::BOTH) +		{ +			info.first.rigidbody.data.linear_velocity.y = -info.first.rigidbody.data.linear_velocity.y * info.first.rigidbody.data.elastisity; +			info.first.rigidbody.data.linear_velocity.x = -info.first.rigidbody.data.linear_velocity.x * info.first.rigidbody.data.elastisity; +		} +		else if(info.move_back_direction == Direction::Y_DIRECTION) { +			info.first.rigidbody.data.linear_velocity.y = -info.first.rigidbody.data.linear_velocity.y * info.first.rigidbody.data.elastisity; +		} +		else if(info.move_back_direction == Direction::X_DIRECTION){ +			info.first.rigidbody.data.linear_velocity.x = -info.first.rigidbody.data.linear_velocity.x * info.first.rigidbody.data.elastisity; +		} +	} +	// Stop movement if bounce is disabled +	else { +		info.first.rigidbody.data.linear_velocity = {0,0}; +	} +} + +std::vector<std::pair<CollisionSystem::CollidedInfoStor,CollisionSystem::CollidedInfoStor>> CollisionSystem::check_collisions(const std::vector<std::reference_wrapper<BoxCollider>>& boxcolliders, const std::vector<std::reference_wrapper<CircleCollider>>& circlecolliders) { +	ComponentManager & mgr = this->component_manager; +	std::vector<std::pair<CollidedInfoStor,CollidedInfoStor>> collisions_ret; + +	// TODO: +	// If no colliders skip +	// Check if colliders has rigidbody if not skip + +	// TODO: +	// If amount is higer than lets say 16 for now use quadtree otwerwise skip +	// Quadtree code +	// Quadtree is placed over the input vector + +	// Check collisions for each collider +	for (size_t i = 0; i < boxcolliders.size(); ++i) { +		// Fetch components for the first box collider +		if(!boxcolliders[i].get().active) continue; +		int game_object_id_1 = boxcolliders[i].get().game_object_id; +		Transform& transform1 = mgr.get_components_by_id<Transform>(game_object_id_1).front().get(); +		if(!transform1.active) continue; +		Rigidbody& rigidbody1 = mgr.get_components_by_id<Rigidbody>(game_object_id_1).front().get(); +		if(!rigidbody1.active) continue; +		 +		// Check BoxCollider vs BoxCollider +		for (size_t j = i + 1; j < boxcolliders.size(); ++j) { +			if(!boxcolliders[j].get().active) continue; +			// Skip self collision +			int game_object_id_2 = boxcolliders[j].get().game_object_id; +			if (game_object_id_1 == game_object_id_2) continue; + +			// Fetch components for the second box collider +			Transform & transform2 = mgr.get_components_by_id<Transform>(boxcolliders[j].get().game_object_id).front().get(); +			if(!transform2.active) continue; +			Rigidbody & rigidbody2 = mgr.get_components_by_id<Rigidbody>(boxcolliders[j].get().game_object_id).front().get(); +			if(!rigidbody2.active) continue; +			// Check collision +			if (check_box_box_collision(boxcolliders[i], boxcolliders[j], transform1, transform2, rigidbody1, rigidbody2)) { +				collisions_ret.emplace_back(std::make_pair( +				CollidedInfoStor{boxcolliders[i], transform1, rigidbody1},  +				CollidedInfoStor{boxcolliders[j], transform2, rigidbody2} +				)); +			} +		} + +		// Check BoxCollider vs CircleCollider +		for (size_t j = 0; j < circlecolliders.size(); ++j) { +			if(!circlecolliders[j].get().active) continue; +			// Skip self collision +			int game_object_id_2 = circlecolliders[j].get().game_object_id; +			if (game_object_id_1 == game_object_id_2) continue; + +			// Fetch components for the second collider (circle) +			Transform & transform2 = mgr.get_components_by_id<Transform>(circlecolliders[j].get().game_object_id).front().get(); +			if(!transform2.active) continue; +			Rigidbody & rigidbody2 = mgr.get_components_by_id<Rigidbody>(circlecolliders[j].get().game_object_id).front().get(); +			if(!rigidbody2.active) continue; + +			// Check collision +			if (check_box_circle_collision(boxcolliders[i], circlecolliders[j], transform1, transform2, rigidbody1, rigidbody2)) { +				 +				collisions_ret.emplace_back(std::make_pair( +				CollidedInfoStor{boxcolliders[i], transform1, rigidbody1},  +				CollidedInfoStor{circlecolliders[j], transform2, rigidbody2} +				)); +			} +		} +	} +	// Check CircleCollider vs CircleCollider +	for (size_t i = 0; i < circlecolliders.size(); ++i) { +		if(!circlecolliders[i].get().active) continue; +		// Fetch components for the first circle collider +		int game_object_id_1 = circlecolliders[i].get().game_object_id; +		Transform & transform1 = mgr.get_components_by_id<Transform>(circlecolliders[i].get().game_object_id).front().get(); +		if(!transform1.active) continue; +		Rigidbody & rigidbody1 = mgr.get_components_by_id<Rigidbody>(circlecolliders[i].get().game_object_id).front().get(); +		if(!rigidbody1.active) continue; + +		for (size_t j = i + 1; j < circlecolliders.size(); ++j) { +			if(!circlecolliders[j].get().active) continue; +			// Skip self collision +			int game_object_id_2 = circlecolliders[j].get().game_object_id; +			if (game_object_id_1 == game_object_id_2) continue; + +			// Fetch components for the second circle collider +			Transform & transform2 = mgr.get_components_by_id<Transform>(circlecolliders[j].get().game_object_id).front().get(); +			if(!transform2.active) continue; +			Rigidbody & rigidbody2 = mgr.get_components_by_id<Rigidbody>(circlecolliders[j].get().game_object_id).front().get(); +			if(!rigidbody2.active) continue; + +			// Check collision +			if (check_circle_circle_collision(circlecolliders[i], circlecolliders[j], transform1, transform2, rigidbody1, rigidbody2)) { +				collisions_ret.emplace_back(std::make_pair( +				CollidedInfoStor{circlecolliders[i], transform1, rigidbody1},  +				CollidedInfoStor{circlecolliders[j], transform2, rigidbody2} +				)); +			} +		} +	} +	return collisions_ret; +} + +bool CollisionSystem::check_box_box_collision(const BoxCollider& box1, const BoxCollider& box2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) +{ +	// Get current positions of colliders +	Vector2 final_position1 = current_position(box1,transform1,rigidbody1); +	Vector2 final_position2 = current_position(box2,transform2,rigidbody2); + +	// Calculate half-extents (half width and half height) +	double half_width1 = box1.width / 2.0; +	double half_height1 = box1.height / 2.0; +	double half_width2 = box2.width / 2.0; +	double half_height2 = box2.height / 2.0; + +	// Check if the boxes overlap along the X and Y axes +	return !(final_position1.x + half_width1 <= final_position2.x - half_width2 ||  // box1 is left of box2 +						final_position1.x - half_width1 >= final_position2.x + half_width2 ||  // box1 is right of box2 +						final_position1.y + half_height1 <= final_position2.y - half_height2 || // box1 is above box2 +						final_position1.y - half_height1 >= final_position2.y + half_height2);  // box1 is below box2 +} + +bool CollisionSystem::check_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) { +	// Get current positions of colliders +	Vector2 final_position1 = current_position(box1, transform1, rigidbody1); +	Vector2 final_position2 = current_position(circle2, transform2, rigidbody2); + +	// Calculate box half-extents +	double half_width = box1.width / 2.0; +	double half_height = box1.height / 2.0; + +	// Find the closest point on the box to the circle's center +	double closest_x = std::max(final_position1.x - half_width, std::min(final_position2.x, final_position1.x + half_width)); +	double closest_y = std::max(final_position1.y - half_height, std::min(final_position2.y, final_position1.y + half_height)); + +	// Calculate the distance squared between the circle's center and the closest point on the box +	double distance_x = final_position2.x - closest_x; +	double distance_y = final_position2.y - closest_y; +	double 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; +} + +bool CollisionSystem::check_circle_circle_collision(const CircleCollider& circle1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) { +	// Get current positions of colliders +	Vector2 final_position1 = current_position(circle1,transform1,rigidbody1); +	Vector2 final_position2 = current_position(circle2,transform2,rigidbody2); + +	double distance_x = final_position1.x - final_position2.x; +	double distance_y = final_position1.y - final_position2.y; +	double distance_squared = distance_x * distance_x + distance_y * distance_y; + +	// Calculate the sum of the radii +	double radius_sum = circle1.radius + circle2.radius; + +	// 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; +} + +Vector2 CollisionSystem::current_position(const Collider& collider, const Transform& transform, const Rigidbody& rigidbody) { +	// Get the rotation in radians +	double radians1 = transform.rotation * (M_PI / 180.0); + +	// Calculate total offset with scale +	Vector2 total_offset = (rigidbody.data.offset + collider.offset) * transform.scale; + +	// Rotate +	double rotated_total_offset_x1 = total_offset.x * cos(radians1) - total_offset.y * sin(radians1); +	double rotated_total_offset_y1 = total_offset.x * sin(radians1) + total_offset.y * cos(radians1); + +	// Final positions considering scaling and rotation +	return(transform.position + Vector2(rotated_total_offset_x1, rotated_total_offset_y1)); + +} diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h index c1a70d8..d94f6bc 100644 --- a/src/crepe/system/CollisionSystem.h +++ b/src/crepe/system/CollisionSystem.h @@ -1,13 +1,192 @@  #pragma once +#include <vector> +#include <variant> + +#include "api/Rigidbody.h" +#include "api/Transform.h" +#include "api/BoxCollider.h" +#include "api/CircleCollider.h" +#include "api/Vector2.h" + +#include "Collider.h"  #include "System.h"  namespace crepe { + +//! A system responsible for detecting and handling collisions between colliders.  class CollisionSystem : public System {  public:  	using System::System; +private: +	 +	//! A variant type that can hold either a BoxCollider or a CircleCollider. +	using collider_stor = std::variant<BoxCollider, CircleCollider>; + +	/** +		* \brief A structure to store the collision data of a single collider. +		*  +		* This structure stores the collider type, its associated transform, and its rigidbody. +		*/ +	struct CollidedInfoStor { +		//! Store either BoxCollider or CircleCollider +		collider_stor collider;  +		Transform& transform; +		Rigidbody& rigidbody; +	}; +	 +	//! Enum representing movement directions during collision resolution. +	enum class Direction { +    NONE, +    X_DIRECTION, +    Y_DIRECTION, +    BOTH +	}; + +public: +	/** +		* \brief A structure representing the collision information between two colliders. +		*  +		* This structure contains both colliders, their associated transforms and rigidbodies, +		* as well as the movement vector to resolve the collision. +		*/ +	struct ColliderInfo { +		const Collider& collider; +		Transform& transform; +		Rigidbody& rigidbody; +	}; +	/** +		* \brief A structure representing detailed collision information between two colliders. +		*  +		* This includes the movement data required to resolve the collision. +		*/ +	struct CollisionInfo{ +    ColliderInfo first; +    ColliderInfo second; +		Vector2 move_back_value; +		Direction move_back_direction = Direction::NONE; +	}; + +public: + +	//! Updates the collision system by checking for collisions between colliders and handling them.  	void update() override; + +private: +	/** +		* \brief Handles a collision between two colliders. +		*  +		* This function calculates the necessary response to resolve the collision, including +		* moving the objects back to prevent overlap and applying any velocity changes. +		* +		* \param data1 The collision data for the first collider. +		* \param data2 The collision data for the second collider. +		*/ +	void collision_handler(CollidedInfoStor& data1,CollidedInfoStor& data2); +	 +	/** +		* \brief Resolves the movement of two box colliders that are colliding. +		*  +		* This function calculates the smallest overlap (along the X or Y axis) and determines +		* the move-back vector to prevent overlap. +		* +		* \param box_collider1 The first box collider. +		* \param box_collider2 The second box collider. +		* \param final_position1 The final position of the first box collider. +		* \param final_position2 The final position of the second box collider. +		* \return The move-back vector to resolve the collision. +		*/ +	Vector2 box_box_collision_move_back(const BoxCollider& box_collider1,const BoxCollider& box_collider2,Vector2 position1,Vector2 position2); + +	/** +		* \brief Determines the appropriate collision handler based on the rigidbody types of the colliding objects. +		*  +		* This function checks if the second object is static, and if so, it calls the static collision handler. +		* Otherwise, it triggers a collision event. +		* +		* \param info The collision information containing the colliders, transforms, rigidbodies, and move-back data. +		*/ +	void determine_collision_handler(CollisionInfo& info); + +	/** +		* \brief Handles the collision with a static object. +		*  +		* This function resolves the collision by moving the object back and applying any bounce or stop behavior. +		* +		* \param info The collision information containing the colliders, transforms, rigidbodies, and move-back data. +		*/ +	void static_collision_handler(CollisionInfo& info); +private: //detection +	 +	/** +		* \brief Checks for collisions between box colliders and circle colliders +		* and returns the collision pairs that need to be resolved. +		*  +		* \param boxcolliders A vector of references to all box colliders. +		* \param circlecolliders A vector of references to all circle colliders. +		* \return A vector of pairs containing collision information for the detected collisions. +		*/ +	std::vector<std::pair<CollidedInfoStor,CollidedInfoStor>> check_collisions(const std::vector<std::reference_wrapper<BoxCollider>>& boxcolliders, const std::vector<std::reference_wrapper<CircleCollider>>& circlecolliders); +	 +	/** +		* \brief Checks for a collision between two box colliders. +		*  +		* This function checks if two box colliders overlap based on their positions and dimensions. +		* +		* \param box1 The first box collider. +		* \param box2 The second box collider. +		* \param transform1 The transform component of the first box collider. +		* \param transform2 The transform component of the second box collider. +		* \param rigidbody1 The rigidbody component of the first box collider. +		* \param rigidbody2 The rigidbody component of the second box collider. +		* \return True if the two box colliders overlap, otherwise false. +		*/ +	bool check_box_box_collision(const BoxCollider& box1, const BoxCollider& box2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); +	 +	/** +		* \brief Checks for a collision between a box collider and a circle collider. +		*  +		* This function checks if a box collider overlaps with a circle collider based on their positions +		* and dimensions. +		* +		* \param box1 The box collider. +		* \param circle2 The circle collider. +		* \param transform1 The transform component of the box collider. +		* \param transform2 The transform component of the circle collider. +		* \param rigidbody1 The rigidbody component of the box collider. +		* \param rigidbody2 The rigidbody component of the circle collider. +		* \return True if the box collider and circle collider overlap, otherwise false. +		*/ +	bool check_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); +	 +	/** +		* \brief Checks for a collision between two circle colliders. +		*  +		* This function checks if two circle colliders overlap based on their positions and radii. +		* +		* \param circle1 The first circle collider. +		* \param circle2 The second circle collider. +		* \param transform1 The transform component of the first circle collider. +		* \param transform2 The transform component of the second circle collider. +		* \param rigidbody1 The rigidbody component of the first circle collider. +		* \param rigidbody2 The rigidbody component of the second circle collider. +		* \return True if the two circle colliders overlap, otherwise false. +		*/ +	bool check_circle_circle_collision(const CircleCollider& circle1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); +	 +	/** +		* \brief Gets the current position of a collider by combining its transform and rigidbody data. +		*  +		* This function calculates the current position of the collider by considering its transform and  +		* rigidbody velocity. +		* +		* \param collider The collider whose position is being determined. +		* \param transform The transform component associated with the collider. +		* \param rigidbody The rigidbody component associated with the collider. +		* \return The current position of the collider as a Vector2. +		*/ +	Vector2 current_position(const Collider& collider, const Transform& transform, const Rigidbody& rigidbody);  };  } // namespace crepe diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index ad510f5..8f9467e 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -28,6 +28,8 @@ void RenderSystem::update_camera() {  	if (cameras.size() == 0) throw std::runtime_error("No cameras in current scene"); +	if (cameras.size() == 0) throw std::runtime_error("No cameras in current scene"); +  	for (Camera & cam : cameras) {  		if (!cam.active) continue;  		this->context.set_camera(cam);  |