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
/Block-References/01_Game-Projcets/Self-Made-Game-Framework/Source/Collision--and--Physics-System-Initialization-Flowchart_Eng.png)
This diagram briefly illustrates the initialization process of the collision and physics system.
2. Update Flowchart | Full View
/Block-References/01_Game-Projcets/Self-Made-Game-Framework/Source/Collision--and--Physics-System-Update-Flowchart_Eng.png)
This diagram briefly illustrates the update process of the collision and physics system.
Collision Related Class Descriptions
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(); };
- Role:
- Stores and manages all collision profiles.
- Provides collision calculation algorithms to determine collisions among various colliders.
- Key Variable:
mProfileMap:- Manages collision profiles for all colliders and stores the interaction settings between them.
- Key Methods:
- bool AABBCollision(CBoxCollider* collider1, CBoxCollider* collider2):
- Determines AABB overlap between two box colliders and records the intersection point in
mHitPointfor both if they overlap.
- Determines AABB overlap between two box colliders and records the intersection point in
- bool CircleCircleCollision(CCircleCollider* collider1, CCircleCollider* collider2):
- Determines if two circle colliders overlap based on the sum of their radius compared to the distance between their centers, and records the intersection point in
mHitPointfor both if they overlap.
- Determines if two circle colliders overlap based on the sum of their radius compared to the distance between their centers, and records the intersection point in
- bool AABBCircleCollision(CBoxCollider* collider1, CCircleCollider* collider2):
- Determines collision between a box and a circle based on the distance from the circle’s center to the nearest point on the box’s edge, and records that closest point in
mHitPointif they overlap.
- Determines collision between a box and a circle based on the distance from the circle’s center to the nearest point on the box’s edge, and records that closest point in
- bool AABBCollision(CBoxCollider* collider1, CBoxCollider* collider2):
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
CQuadTreeto manage registered collider pairs and track their states (ENTER/STAY/EXIT). - Delivers collision events to each collider and performs physical collision handling via
CPhysicsManagerif needed.
- Scene-level collision management system, using
- Key Variables:
mQuadTree:- Pointer to
CQuadTree, which manages the scene’s colliders through spatial partitioning.
- Pointer to
mPairs:- Manages all collider pairs (
FColliderPair) and their collision states (EPair::Status).
- Manages all collider pairs (
- 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
CPhysicsManagerif needed.
- resolves physical interactions via
- On collision exit, performs
OnCollisionExit(CCollider* other).
- On collision enter, performs
- Determines whether two colliders intersect and updates their states.
- void CleanPairs():
- If any collider pairs are inactive, triggers exit events and removes the pair from
mPairs.
- If any collider pairs are inactive, triggers exit events and removes the pair from
- void HandleCollision(CCollider* collider1, CCollider* collider2):
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.
- The root node of the quadtree (
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 forCQTNodeof that size, and allocates memory tomRootfor initialization.
- Parameterized constructor, which calculates the total number of nodes based on
- void Update(float deltaTime):
- Updates the area of
mRootbased on the camera. - Adds all colliders to
mRootand performs its update function.
- Updates the area of
- CQuadTree(CCamera* camera):
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
Updateon 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.
- If child nodes exist, recursively calls
- 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.
- Checks if the collider from the parent node is within this node’s bounds.
- void Update(float deltaTime):
Physics Related Class Descriptions
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
CRigidbodytype to move the colliders.
- 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
- Key Variable:
CONST_MinMtvLSq:- The minimum squared length used to ignore the MTV if its value is too small.
- Key Method:
- void ResolveOverlapIfPushable(CCollider* collider1, CCollider* collider2):
- Called when physical interaction is needed; pushes colliders if one has
CRigidbodyof DYNAMIC type with BLOCK interaction.
- Called when physical interaction is needed; pushes colliders if one has
- void ResolveOverlapIfPushable(CCollider* collider1, CCollider* collider2):
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
CRigidbodytype. - Moves the object by applying the displacement calculated by
CPhysicsManager.
- Provides physical properties to colliders and controls physical responses according to
- Key Variables:
mType:- Indicates the type of
CRigidbody(DYNAMIC/STATIC/KINEMATIC).
- Indicates the type of
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
CRigidbodyis DYNAMIC type, it sequentially updates gravity, accumulated force, acceleration, velocity, and position based on mass.
- If
- void Update(float deltaTime):
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.