Repository navigation
ActionRPG Movimento e Collisioni
ActionRPG non usa Box2D. Il core fornisce scene, oggetti e timestep; le classi di questo progetto definiscono movimento top-down, collider OBB, collision detection SAT e collision response. La gerarchia è simile a quella di CustomPlatformer, ma qui non ci sono gravità, salto o Swept AABB.
Object -> RenderableObject -> MovableObject -> CollidableObject
|-> DynamicObject -> Link, Enemy, NPC, Sword
|-> StaticObject
`-> Trigger -> Portal
| Classe | Cosa aggiunge |
|---|---|
MovableObject |
RotatedRectF di riferimento, direzioni, velocità, forze di movimento e frenata. |
CollidableObject |
Collider OBB locale, query dei candidati, SAT, notifiche e interfaccia di collision response. |
DynamicObject |
Risposta ai contatti: separazione completa dagli statici e parziale dagli altri dinamici. |
StaticObject |
Ostacolo immobile; non esegue autonomamente detection e response nel proprio update(). |
Trigger |
Collider attraversabile che osserva un oggetto e attiva una callback. |
Link, Soldier, NPC e Sword aggiungono regole specifiche; la scena non contiene uno switch sul loro tipo a ogni frame.
MovableObject::update(dt) salva la velocità precedente, applica forza lungo X e Y secondo le direzioni, frena gli assi senza input, limita la velocità per componente e chiama setPos(pos() + vel * dt). Non applica gravità. Le frecce possono fornire contemporaneamente una direzione X e una Y; DynamicObject::move() aggiorna anche _facingDir, usata dagli sprite e dall'attacco.
MovableObject conserva un RotatedRectF (_rrect) e pubblica il suo bounding rectangle come rect() del RenderableObject. Il suo setPos() sposta _rrect e chiama RenderableObject::setRect(): quest'ultima notifica la scena, così il quadtree può aggiornare la posizione dell'oggetto. Cambiare soltanto un campo locale senza passare da setRect() lascerebbe l'indice spaziale obsoleto.
CollidableObject crea per default un _collider rettangolare orientato nelle coordinate locali dell'oggetto. sceneCollider() lo sposta nel sistema della scena usando il centro di _rrect. Link e Soldier restringono il collider rispetto allo sprite; la spada cambia anche angolo e dimensioni durante l'animazione. rect() serve alle query spaziali e al culling, mentre sceneCollider() descrive la forma usata per il test preciso.
La broad phase di detectCollisions() chiede a Scene::objects(sceneCollider().boundingRect()) i candidati. In RPGGameScene questa chiamata usa il quadtree perché _useQuadtree = true. La narrow phase filtra i CollidableObject, esclude sé stesso e gli oggetti non collidibili, poi chiama checkCollisionSAT() sui vertici dei due OBB. In caso di overlap, SAT restituisce un asse per la correzione e la profondità di compenetrazione. La collision detection è discreta: verifica le posizioni dopo il movimento, senza un tempo d'impatto continuo.
setPos() -> aggiorna quadtree
objects(boundingRect) -> candidati (broad phase)
checkCollisionSAT(vertici) -> collisione precisa (narrow phase)
collision() sui due oggetti -> regole di gameplay
resolveCollisions() -> correzione delle posizioni
Prima che la scena distrugga un oggetto, CollidableObject::forgetObject() elimina i riferimenti a esso dai contatti memorizzati, anche se l'oggetto che li conserva è congelato: vedi il ciclo di vita degli oggetti.
Per ogni overlap rilevato, detectCollisions() chiama collision(other, true, axis) su entrambi gli oggetti con assi opposti. Conserva i contatti precedenti e invia collision(other, false, {}) quando un contatto scompare. begin = true viene passato a ogni update in cui persiste l'overlap, non soltanto al primo frame: una callback che deve scattare una sola volta richiede una guardia. Trigger::collision() verifica l'oggetto osservato e begin; Portal aggiunge uno stato per evitare il rimbalzo immediato tra due portali.
DynamicObject::resolveCollisions() sposta il dinamico dell'intera profondità contro uno StaticObject, oppure di un decimo della profondità contro un altro DynamicObject. Gli statici e i trigger non eseguono un proprio solver. Il flag _compenetrable è presente nelle classi, ma questa implementazione di resolveCollisions() non lo consulta: non attribuirgli effetti fisici che il codice non applica.
CollidableObject::intersectsRect() usa prima il bounding rectangle e poi SAT; intersectsLine() usa il collider orientato. Per questo anche query della scena e raycast di interazione possono tenere conto della geometria reale, oltre al rect() usato come prima selezione.
La visualizzazione dei collider sovrappone l'OBB allo sprite. È particolarmente utile per distinguere Link, Soldier e Sword dalle loro immagini. Confronta questo percorso con la CCD di CustomPlatformer: qui il quadtree accelera la selezione dei candidati, ma non trasforma SAT in detection continua.
MovableObject.cppCollidableObject.cpp-
DynamicObject.cpp,StaticObject.heTrigger.cpp -
RPGGameScene.cppeutils/collisionUtils.h
Prosegui con Pathfinding e NPC.
- Panoramica
- Diagramma delle classi
- Architettura e game loop
- Sequenza di un frame
- Input ed eventi
- Scene e oggetti
- Rendering e coordinate
- Sprite e testo
- UI e overlay
- Quadtree
- Servizi e asset
- Estendere il core
- Editor dei livelli
- LevelData e livelli JSON
- Shader