Collision and Physics System Structure


Overview

(1) The in-game collision and physics system minimizes unnecessary collision checks by utilizing collision channels and profiles within a CQuadTree based spatial partitioning algorithm. The CCollisionManager provides collision detection algorithms to determine if selected colliders actually collide.


(2) Collisions are handled between collider pairs and collision events (ENTER/STAY/EXIT) are notified. When physics processing is required, CPhysicsManager and CRigidbody resolve overlaps and handle physical responses to ensure stable collision handling.


Collision and Physics System Flowchart

1. Initialization Flowchart | Full View

This diagram briefly illustrates the initialization process of the collision and physics system.


2. Update Flowchart | Full View

This diagram briefly illustrates the update process of the collision and physics system.


1. CCollisionManager Class | View Repository

class CCollisionManager
{
private:
	CCollisionManager();
	~CCollisionManager();
	
private:
	static CCollisionManager* mInst;
	
	std::unordered_map<std::string, FCollisionProfile*>	mProfileMap;
	
public:
	bool Init();
	
	bool CreateProfile(const std::string& name, 
		ECollision::Channel myChannel, ECollision::Interaction interaction);
	
	bool SetCollisionInteraction(const std::string& name,
		ECollision::Channel otherChannel, ECollision::Interaction interaction);
	
	FCollisionProfile* FindProfile(const std::string& name);
	
public:
	bool AABBCollision(CBoxCollider* collider1, CBoxCollider* collider2);
	bool CircleCircleCollision(CCircleCollider* collider1, CCircleCollider* collider2);
	bool AABBCircleCollision(CBoxCollider* collider1, CCircleCollider* collider2);
	bool AABBPointCollision(CBoxCollider* collider, const FVector2D& point);
	bool CirclePointCollision(CCircleCollider* collider, const FVector2D& point);
	
	bool AABBPointCollision(const SDL_Rect& rect, const FVector2D& point);
	
public:
	static CCollisionManager* GetInst();
	static void DestroyInst();
};


2. CSceneCollision Class | View Repository

class CSceneCollision
{
	friend class CScene;
	
public:
	CSceneCollision() = delete;
	CSceneCollision(CCamera* camera);
	~CSceneCollision();
	
private:
	CQuadTree* mQuadTree;
	std::unordered_map<FColliderPair, EPair::Status> mPairs;
	
public:
	void Update(float deltaTime);
	void LateUpdate(float deltaTime);
	
public:
	void AddCollider(CCollider* collider);
	void HandleCollision(CCollider* collider1, CCollider* collider2);
	
private:
	void CleanPairs();
};

  • Role:
    • Scene-level collision management system, using CQuadTree to manage registered collider pairs and track their states (ENTER/STAY/EXIT).
    • Delivers collision events to each collider and performs physical collision handling via CPhysicsManager if needed.
  • Key Variables:
    • mQuadTree:
      • Pointer to CQuadTree, which manages the scene’s colliders through spatial partitioning.
    • mPairs:
      • Manages all collider pairs (FColliderPair) and their collision states (EPair::Status).
  • Key Methods:
    • void HandleCollision(CCollider* collider1, CCollider* collider2):
      • Determines whether two colliders intersect and updates their states.
        • On collision enter, performs OnCollisionEnter(CCollider* other).
        • On collision stay, performs OnCollisionStay(CCollider* other).
          • resolves physical interactions via CPhysicsManager if needed.
        • On collision exit, performs OnCollisionExit(CCollider* other).
    • void CleanPairs():
      • If any collider pairs are inactive, triggers exit events and removes the pair from mPairs.

3. CQuadTree Class | View Repository

class CQuadTree
{
	friend class CSceneCollision;
	
private:
	CQuadTree() = delete;
	CQuadTree(CCamera* camera);
	~CQuadTree();
	
private:
	CQTNode* mRoot = nullptr;
	std::vector<CCollider*> mColliders;
	
public:
	void Update(float deltaTime);
	void LateUpdate(float deltaTime);
	
public:
	void AddCollider(CCollider* collider);
	
private:
	void UpdateBoundary();
};

  • Role:
    • Manages all colliders in the scene and manages the root node of the quadtree according to the camera’s view.
  • Key Variables:
    • mRoot:
      • The root node of the quadtree (CQTNode). All colliders are distributed based on this node.
    • mColliders:
      • A container that stores all colliders in the scene.
  • Key Methods:
    • CQuadTree(CCamera* camera):
      • Parameterized constructor, which calculates the total number of nodes based on MAX_SPLIT, creates a memory pool for CQTNode of that size, and allocates memory to mRoot for initialization.
    • void Update(float deltaTime):
      • Updates the area of mRoot based on the camera.
      • Adds all colliders to mRoot and performs its update function.

4. CQTNode Class | View Repository

class CQTNode
{
	friend class CQuadTree;
	
public:
	CQTNode();
	~CQTNode();
	
private:
	CCamera* mCamera;
	
	CQTNode* mParent;
	CQTNode* mChilds[4];
	std::vector<CCollider*> mColliders;
	
	SDL_FRect mBoundary;
	
	int mSplitLevel = 0;
	
public:
	void Update(float deltaTime);
	void Render(SDL_Renderer* renderer);
	
public:
	bool HasChild();
	bool ShouldSplit();
	void Split();
	
	bool IsWithinNode(CCollider* collider);
	void AddCollider(CCollider* collider);
	
	void MoveCollidersToChildren();
	
	void Clear();
};

  • Role:
    • Represents individual nodes in the quadtree, handles storing of colliders, node splitting, and reassigning colliders.
    • Collision calculations are not performed directly, but are delegated to CSceneCollision.
  • Key Variables:
    • mColliders:
      • A container that stores colliders belonging to this node.
    • mChilds[4]:
      • An array of child nodes created when the quadtree is subdivided.
    • mBoundary:
      • Defines the spatial area of the node.
  • Key Methods:
    • void Update(float deltaTime):
      • If child nodes exist, recursively calls Update on each child node.
      • If no child nodes exist, checks collisions for all pairs of colliders in the node if collision is enabled between the pair.
    • void AddCollider(CCollider* collider):
      • Checks if the collider from the parent node is within this node’s bounds.
        • If out of bounds, ends the function.
        • If within bounds:
          • If child nodes exist, forwards the collider to the appropriate child node.
          • If no child nodes exist, adds the collider to this node.
            • If collider count exceeds threshold, splits node and moves existing colliders to the child node.

1. CPhysicsManager Class | View Repository

class CPhysicsManager
{
	friend class CScene;
	
private:
	CPhysicsManager();
	~CPhysicsManager();
	
private:
	static CPhysicsManager* mInst;
	
	const float CONST_MinMtvLSq = 0.5f;
	
public:
	void ResolveOverlapIfPushable(CCollider* collider1, CCollider* collider2);
	
private:
	void ResolveOverlap(CCollider* collider1, CCollider* collider2, bool pushObj1, bool pushObj2);
	
	void ResolveAABBOverlap(CBoxCollider* collider1, CBoxCollider* collider2, bool pushObj1, bool pushObj2);
	void ResolveCircleCircleOverlap(CCircleCollider* collider1, CCircleCollider* collider2, bool pushObj1, bool pushObj2);
	void ResolveAABBCircleOverlap(CBoxCollider* collider1, CCircleCollider* collider2, bool pushObj1, bool pushObj2);
	
	void MoveBy(CCollider* collider, const FVector2D& mtv);
	
public:
	static CPhysicsManager* GetInst();
	static void DestroyInst();
};

  • Role:
    • Manages the physical interactions between colliders in the scene and, when they meet physical processing conditions, calculates the minimum translation vector (MTV) based on the CRigidbody type to move the colliders.
  • Key Variable:
    • CONST_MinMtvLSq:
      • The minimum squared length used to ignore the MTV if its value is too small.
  • Key Method:

2. CRigidbody Class | View Repository

class CRigidbody : public CComponent
{
public:
	CRigidbody();
	virtual ~CRigidbody();
	
private:
	ERigidbodyType mType;
	
	float mMass;
	float mGravityScale;
	
	FVector2D mVelocity;
	FVector2D mAcceleration;
	FVector2D mAccumulatedForce;
	
private:
	virtual void Update(float deltaTime) final;
	virtual void Release() final;
	
public:
	void AddForce(const FVector2D& force);
	void AddImpulse(const FVector2D& impulse);
	
	const FVector2D& GetVelocity() const { return mVelocity; }
	ERigidbodyType GetType() const { return mType; }
	float GetMass() const { return mMass; }
	
	void SetVelocity(const FVector2D& velocity)
	{
		mVelocity = velocity;
	}
	void SetType(ERigidbodyType type)
	{
		mType = type;
	}
	void SetMass(float mass)
	{ 
		mMass = mass;
	}
	
private:
	void ApplyGravity();
	void ApplyForces();
	void ApplyAcceleration(float deltaTime);
	void ApplyDrag(float deltaTime);
	void UpdateObjectPos(float deltaTime);
	void ClearForces();
};

  • Role:
    • Provides physical properties to colliders and controls physical responses according to CRigidbody type.
    • Moves the object by applying the displacement calculated by CPhysicsManager.
  • Key Variables:
    • mType:
      • Indicates the type of CRigidbody (DYNAMIC/STATIC/KINEMATIC).
    • mMass, mGravityScale, mVelocity, mAcceleration, mAccumulatedForce:
      • Indicates the motion state and accumulated forces, including mass and gravity, and is used for collisions and physics.
  • Key Method:
    • void Update(float deltaTime):
      • If CRigidbody is DYNAMIC type, it sequentially updates gravity, accumulated force, acceleration, velocity, and position based on mass.

Conclusion

This collision and physics system is based on spatial partitioning algorithms and collision channels to reduce unnecessary collision checks and handle collision detection and physical responses reliably. This allows for efficient performance optimization, flexible collision control design, and makes interactions between various objects easier to implement.