Come si dovrebbe modulare l'implementazione degli oggetti correlati?

4

Ho cercato di rendere il titolo della domanda il più applicabile possibile, ma non sono sicuro di averlo scritto così bene. È stato causato da un problema molto specifico che ho, e per il resto di questa domanda cercherò di descriverlo.

Sto tentando di scrivere un piccolo motore di gioco con grafica, fisica e collisioni *. Sto cercando di implementare ciascuna di queste cose separatamente; è perfettamente concepibile che io abbia un oggetto grafico, fisicamente in movimento, che non può collidere (effetti di fuoco?) o un oggetto di collisione che non è reso o governato dalla fisica (barriera invisibile). Tuttavia, un gran numero di oggetti avrà bisogno di tutti e tre.

Sono abbastanza sicuro di poter isolare i tre pezzi quasi completamente nelle loro classi, con l'unica eccezione che tutti devono fare riferimento alla stessa posizione e all'orientamento angolare del loro oggetto.

Inizialmente, pensavo di mettere ogni cosa nella sua classe e solo costruire ogni oggetto di gioco reale con ereditarietà multipla, ma alla luce del fatto che tutti hanno bisogno di condividere i dati non ero così sicuro che quello funzionerebbe.

L'opzione successiva consisteva nel far inizializzare ogni oggetto con i puntatori ai dati di posizione e orientamento appropriati, ma mi sentivo strano trattare quelli come membri speciali. . . Vorrei che ogni classe agisse il più ignorante possibile degli altri, e non farei mai i suggerimenti se stessimo progettando ogni classe in modo indipendente.

Potrei anche permettere a ogni classe di vivere con i propri dati di posizione e fare in modo che la classe di combinazione (tramite amicizia o getter / setter) li costringa tutti a coincidere, ma anche questo non sembrava giusto.

Ho provato a cercare su Google informazioni su ciò che è in genere fatto, ma la maggior parte di tutto ciò che ho trovato si è concentrata su una parte specifica del sistema e non ho detto molto sull'integrazione di tutto. Sono semplicemente troppo filosofico, o c'è un modo migliore per farlo?

Se è importante, sto usando C ++.

Grazie.

* So che implementarlo da solo non ha senso, ma è solo per divertimento.

    
posta Jordan 23.06.2015 - 21:28
fonte

2 risposte

3

Servizi, non Superclassi

Queste cose non sono oggetti correlati, sono aspetti comportamentali degli oggetti del gioco che possono andare e venire mentre lo stato degli oggetti del gioco cambia; pensaci come servizi, non come superclassi. Non sono adatti nemmeno agli elementi puramente compositivi, poiché il comportamento nel gioco dipenderà molto dallo stato degli oggetti del gioco nel tempo.

Esempio

Un oggetto "fantasma" può essere visibile e in movimento, ma può passare attraverso oggetti solidi ma potrebbe non essere in grado di passare attraverso una barriera magica e può anche infliggere danni quando si scontra con il tessuto vivente. Può essere danneggiato solo da armi magiche.

Spiacenti

La programmazione dei giochi è difficile, a questo livello per lo più dovuto alla complessità della modellazione. Attacca per avere le tue idee (se solo ti diverti) e / o studia i motori di gioco esistenti per vedere cosa hanno fatto gli altri (es. Codice sorgente di Unreal Engine )

    
risposta data 23.06.2015 - 21:51
fonte
0

Stai naturalmente lavorando verso i sistemi di componenti di entità.

L'ultimo passo che è più difficile da fare se applichi da anni una mentalità OOP, è trasformare quei componenti condivisi in dati grezzi , ma è solo allora che puoi davvero venire ad apprezzare la vera flessibilità della ECS. In realtà ho resistito ostinatamente a farlo fino a una seconda iterazione in cui ho appena creato componenti in dati non elaborati.

Il modo di contrastare la sensazione che tutto ciò sembri sbagliato e una totale violazione di incapsulamento e occultamento delle informazioni è ricordare che in genere solo uno o due sistemi accedono a un dato componente e spesso a un solo sistema che effettivamente si trasforma ( muta) quei dati. Di conseguenza, in realtà non è molto più difficile, se esiste, mantenere invarianti intracomponenti. Inoltre, tende a semplificare il mantenimento di invarianti più ampi e intercomponenti con sistemi grossolani che elaborano tutto.

Le entità sono solo contenitori di componenti (con un'istanza di tipo componente massima per entità). I componenti sono solo dati grezzi. I sistemi processano entità / componenti e sono gli unici fornitori di funzionalità tra questi tre. I sistemi sono generalmente disaccoppiati l'uno dall'altro e in genere non chiamano funzioni l'uno nell'altro. La maggior parte dei sistemi assomiglia anche al modello di loop di:

for each entity with these specific components:
    do something with the components

Ad esempio, il sistema di rendering sopra potrebbe essere come questo:

for each entity with pos/velocity and sprite components:
    render sprite component at pos

Mentre il sistema di movimento potrebbe apparire come questo:

for each entity with pos/velocity components:
    pos += velocity * time_elapsed
    
risposta data 18.12.2017 - 01:07
fonte

Leggi altre domande sui tag