Repository navigation
Box2DPlatformer Entita e Gameplay
Questa pagina parte dal ponte tra body Box2D e oggetti del core per seguire le regole concrete del platform. Le classi del gioco scelgono shape, forze, filtri e reazioni: il solver rimane Box2D.
Player deriva da DynamicObject e crea una capsule shape all'interno del proprio rettangolo orientato. Imposta densità, attrito, restituzione, eventi di contatto e filtro Player contro Enemy, Static e Kinematic. Blocca la rotazione intorno a Z con i motionLocks, così i contatti non lo fanno ribaltare. La shape fisica e l'immagine non hanno necessariamente gli stessi margini.
A ogni passo fisico, PlatformerGameScene::updatePhysicsControls() traduce le frecce in move(), che applica una forza orizzontale. Il salto invoca jump(), che applica un impulso verso Y positivo soltanto quando DynamicObject::onGround() vede almeno un contatto valido. D avvia un dash di mezzo secondo: finché _dashing è vero, Player::update() applica una forza aggiuntiva nella direzione ricordata. F crea un proiettile Fire nella posizione del player, diretto verso l'ultima direzione orizzontale non nulla.
Z cambia _running e _xVelMax tra 5 e 10, oltre a influire sulla scelta dell'animazione. Nel codice attuale il blocco di clipping della velocità in DynamicObject::update() è commentato: il nuovo valore di _xVelMax non impone da solo un limite fisico alla corsa. È un esempio utile di differenza tra stato di gameplay e effetto realmente applicato al corpo.
Lo sprite passa tra idle, walk, jump e dash in base allo stato e ai contatti; durante la camminata il suo FPS segue la velocità orizzontale. Il flip orizzontale segue l'ultima direzione di movimento. Lo sprite non decide il movimento: lo rappresenta.
Nel livello JSON, Terrain è una multiline: LevelLoader::loadJson() ne legge i punti tramite LevelData e costruisce un Terrain per ogni coppia successiva che forma un segmento valido. Ogni Terrain è uno StaticObject rettangolare sottile, ruotato secondo la linea; il costruttore marca le pendenze quando l'angolo è diverso da zero. normal() restituisce una normale geometrica della superficie. L'helper Terrain::TerrainSequence() rimane disponibile per costruzioni da codice, ma il livello incluso usa la polilinea.
La grafica fg_ground è creata nel loader C++ e registrata con addBackgroundImage(): nell'editor resta visibile senza coprire i collider con una grande regione selezionabile. Il JSON contiene soltanto il profilo fisico del terreno.
Quando onGround() è vero, Player::update() esegue un raycast verso il basso con b2World_CastRayClosest(). Se la shape colpita appartiene a un Terrain inclinato, calcola una forza tangenziale per compensare la componente della gravità lungo la pendenza. Questo trattamento serve alla sensazione del movimento sulle rampe; non sostituisce il contatto fisico Box2D. Il raycast aiuta inoltre a scegliere un terreno quando il player tocca segmenti adiacenti.
| Entità | Body e shape | Comportamento nel livello |
|---|---|---|
Gear |
Body cinematico con una shape circolare e dodici shape poligonali per i denti. | Due ingranaggi sono costruiti nel livello; ruotano con velocità angolare impostata. |
Box |
Body dinamico con shape rettangolare. | Il clic sinistro ne crea una al puntatore; parte con un impulso verso l'alto e una componente X casuale. |
Slime |
Enemy dinamico con shape poligonale. |
Il clic destro ne crea uno; usa animazione e categoria di collisione Enemy. |
Fire |
Body dinamico con shape rettangolare arrotondata. | Nasce premendo F; non subisce gravità, ha velocità iniziale, colpisce la categoria Enemy e viene eliminato dopo tre secondi. |
I valori -1 e 1 dei campi layer dei due Gear nel JSON sono layer di rendering, non versi di rotazione: Gear imposta per entrambi la stessa velocità angolare -0.5. Il costruttore di Gear richiede autonomamente lo sprite gear alla factory. Gli sprite e i layer decidono cosa appare davanti o dietro, le shape decidono i contatti.
Enemy::collision() cerca un Fire: quando lo trova, chiama hurt() ed elimina il proiettile dalla scena. hurt() disabilita il corpo, riproduce un suono, attiva _dying e programma l'eliminazione del nemico dopo un secondo; durante l'attesa Enemy::update() ne riduce le dimensioni di riferimento. Fire programma comunque la propria eliminazione dopo tre secondi per evitare proiettili persistenti fuori scena. Sono regole del gioco, non funzionalità automatiche di Box2D.
Un dettaglio da leggere con attenzione: Enemy::collision() nel codice attuale non controlla begin prima di reagire e non richiama DynamicObject::collision(). Non va quindi assunto che un nemico mantenga l'insieme dei contatti col terreno come il player, né che la reazione al proiettile sia esplicitamente limitata al solo evento di ingresso. Player non implementa un proprio handler di danno: l'interazione nemico/giocatore non è completata in questo esempio.
Trigger è un'altra possibilità di gameplay: osserva un RigidObject ed esegue il task std::function<void()> ricevuto dal chiamante all'ingresso nella propria sensor shape. La classe è pronta, ma non fa parte del livello level0 costruito dal loader.
- Salta su terreno piano e inclinato, poi osserva il raycast e i contatti di
onGround(). - Crea una scatola con il clic sinistro e uno slime con il destro; mostra i collider per vedere differenze fra sprite e shape.
- Spara con
Fverso uno slime e segui l'evento Box2D,Enemy::collision(), la disabilitazione del corpo e l'eliminazione programmata. - Confronta
GearconTerrain: entrambi possono entrare nei contatti del player, ma il primo è cinematico e composto da più shape.
-
Player.cppeDynamicObject.cpp -
Terrain.cppeGear.cpp -
Box.cpp,Slime.cpp,Fire.cppeEnemy.cpp Trigger.cpp
Torna alla panoramica di Box2DPlatformer o confronta queste entità con quelle di CustomPlatformer.
- 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