Repository navigation
Core Estendere il Core
Il core offre il ciclo e le strutture comuni; ogni progetto decide quali scene creare, quali oggetti istanziare e come implementare regole e collisioni. Questa pagina collega le classi del core in un percorso di lavoro concreto.
Una sottoclasse di Game configura titolo, dimensioni, rapporto d'aspetto e rendering nel costruttore e inizializza i servizi dopo che la finestra è pronta. La SpriteFactory riceve il renderer tramite init(renderer). Il main registra il gioco con Game::setInstance() e chiama init() e run(). In init() si costruiscono soltanto scene, HUD e menu: il reset richiama questo metodo senza ricreare i servizi. Il distruttore concreto libera prima le scene e poi i servizi; la classe base libera la finestra. Per il caso di errore durante la costruzione, vedi Servizi e risorse.
Prima di creare una GameScene, deve esistere il Game: il costruttore della scena crea una View che legge Game::instance()->aspectRatio(). Anche le texture hanno bisogno del renderer, disponibile dopo la costruzione di Game.
Deriva da GameScene e ricevi nel costruttore dimensioni della mappa, pixelUnitSize, intervallo _dt e colore di sfondo, definiti nel loader C++. Configura la vista iniziale nella scena concreta. Usa updateControls() per i comandi continui (in Box2DPlatformer le forze sono applicate da updatePhysicsControls() a ogni passo fisico), event() per quelli discreti e, soltanto se serve, updateWorld() o updateCamera() per modificare il comportamento standard. Se ridefinisci event() o update(), valuta la chiamata alla versione base: altrimenti perdi inoltro ai viewport, scheduler, overlay o simulazione.
I LevelLoader degli esempi costruiscono la scena di gioco e gli oggetti, quindi restituiscono una Scene* da inserire nello stack. load() legge il file tramite LevelData e crea la scena; loadJson(world, level) interpreta categorie e proprietà. Questa separazione è comune ai quattro prototipi. I loader sono classi di utilità con metodi statici, senza singleton; appartengono ai progetti, mentre LevelData è nel core. Imposta setPlayer() se vuoi usare la camera che segue il giocatore: updateCamera() accede al rettangolo di _player quando quel comportamento è attivo.
Scegli la classe base in funzione del ruolo:
| Ruolo | Punto di partenza |
|---|---|
| Logica invisibile, trigger, dato spaziale | Object |
| Entità disegnata o semplice elemento UI | RenderableObject |
| Corpo fisico o collider specifico del gioco | Sottoclasse del progetto, costruita sopra Object/RenderableObject
|
Il costruttore di Object chiama scene->newObject(this): non aggiungere una seconda volta lo stesso puntatore. La scena incorpora le nuove istanze al successivo refreshObjects(). Per rimuoverle usa kill(), non delete diretto. Se sovrascrivi update(), chiama Object::update(dt) o RenderableObject::update(dt) secondo la tua classe base per conservare timer, scheduler, rotazione e animazione.
Se conservi un puntatore a un altro oggetto della stessa scena, ridefinisci forgetObject(Object* objectToRemove) per azzerarlo quando quell'oggetto sta per essere distrutto. Per esempio, in una sottoclasse di CollidableObject con un campo _target:
void forgetObject(Object* objectToRemove) override
{
CollidableObject::forgetObject(objectToRemove);
if (_target == objectToRemove)
_target = nullptr;
}Richiama la versione della tua classe base per conservare la pulizia già prevista; per una collezione, rimuovi il puntatore anziché assegnare nullptr. Chi usa _target, anche in una callback differita, deve gestire il caso nullo. La scena invia questa notifica anche agli oggetti congelati: la pulizia non deve dipendere da update(). Il significato del parametro è spiegato nel ciclo di vita degli oggetti.
Movimento e cambio del rettangolo devono passare da setPos() o setRect(), che notificano Scene::objectMoved(). setSize() della classe base non lo fa: con un quadtree attivo la dimensione indicizzata potrebbe diventare obsoleta.
Il RenderableObject può disegnare un rettangolo colorato oppure usare uno Sprite. Una factory del progetto può caricare una texture una volta e creare sprite diversi per le varie regioni della spritesheet. Sprite non possiede il file immagine e RenderableObject non elimina automaticamente lo sprite nel proprio distruttore: definisci esplicitamente chi gestisce la durata delle risorse del tuo progetto. setSprite() offre un parametro deallocateSprite per l'eventuale sprite sostituito.
Se il rettangolo logico è il collider e l'immagine deve estendersi oltre, usa fit = false e configura correttamente pixelUnitSize. Per UI e testo consulta Sprite, animazioni e testo.
Una classe specifica richiede alla factory lo sprite nel proprio costruttore: per esempio Lift sceglie platform e Gear sceglie gear. Il loader passa posizione e parametri di gioco. I collider StaticObject generici sono trasparenti e senza sprite. La grafica di sfondo viene creata nel loader C++ con RenderableObject; il suo costruttore può ricevere una sprite dal codice. Il JSON non sceglie sprite, colori o layer. Il layer ha un default nel costruttore e può essere adattato dalla classe o dal loader.
-
Input ed eventi: usa
event()per pressioni singole eupdateControls()per stato continuo. - Quadtree: attivalo prima di creare gli oggetti e verifica che la radice comprenda le posizioni raggiungibili.
-
Servizi e asset: carica file rispetto a
SDL_GetBasePath(), non alla directory corrente del processo. -
UI e overlay: scegli fra scena UI nello stack e layer di parallax collegato alla
GameScene.
Definisci la classe dell'entità e aggiungi il suo nome in categories. Nel loadJson() del progetto, associa quella categoria al costruttore e leggi le proprietà necessarie, fornendo default dove opportuno. Ogni regione usa l'indice della categoria e una geometria; aggiungi name soltanto se serve identificarla individualmente. L'editor conserva gli attributi aggiuntivi durante il salvataggio. Consulta LevelData e livelli JSON per formato ed esempi.
I comportamenti semplici possono restare C++: il trigger di CustomPlatformer riceve una lambda dal loader, senza introdurre nel JSON un sistema di azioni, ID e riferimenti.
| Esigenza | Modulo da modificare o estendere |
|---|---|
| Nuova regola di movimento | Oggetto del progetto e GameScene::updateControls()
|
| Nuovo menu |
UIScene o sua sottoclasse, poi Game::pushScene()
|
| Nuova animazione |
AnimatedSprite creato dalla factory del progetto |
| Nuova collisione precisa | Metodo geometrico del collider del progetto; il core offre le query candidate |
| Effetto su tutto il frame |
CPUShaderWindow o GPUShaderWindow
|
| Formato comune di livello |
LevelData del core per lettura, validazione e geometrie; editor per la modifica visuale |
| Categoria o proprietà di gameplay nel JSON |
LevelLoader::loadJson() del progetto e costruttore dell'entità |
-
ActionRPG/main.cppeRPGGame.cppper avvio e stack delle scene. -
CustomPlatformer/LevelLoader.cppper costruzione della scena e degli oggetti. -
core/GameScene.cppecore/Object.cppper i punti di estensione.
Per gli strumenti opzionali, prosegui con Editor dei livelli e Post-processing e shader.
- 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