Stessa logica di gioco su due librerie grafiche separate


11

Quale filosofia / struttura del codice di astrazione / progettazione del programma consentirebbe di utilizzare un gioco con grafica 2D e 3D (separatamente) SENZA dover ricodificare la logica di gioco?

Stiamo parlando dello stesso codice, cambiando un minimo di cose (ad esempio, scambiando nomi di file per risorse 2D con nomi di file per risorse 3D) e forse inserendo alcune specializzazioni di una classe base per generici / modelli.

Per dirlo in un contesto reale in cui ha senso: immagina un gioco multiplayer LAN in cui c'è un client 3D di prim'ordine e affamato di prestazioni per i giocatori con alcune piattaforme di gioco davvero buone e un client 2D più umile per il vecchio scatole polverose che qualcuno ha trovato nella loro soffitta. Ma è sempre lo stesso gioco: vengono registrati gli stessi eventi (qualcuno ha preso una moneta), viene utilizzato lo stesso protocollo di rete, i mondi sono proporzionali, ecc.

Per dirla in un contesto MVC: i controller sono esattamente gli stessi (premendo il tasto "Su" si imposta l'accelerazione dei giocatori a 3,5 unità / secondo), le viste sono totalmente diverse (2D contro 3D) e il modello è lo stesso fatta eccezione per qualsiasi cosa direttamente correlata alla grafica (un controllo delle collisioni per l'ambiente viene eseguito ogni 5 secondi e utilizza lo stesso algoritmo. Si noti che ciò significherebbe che esiste una coordinata Z per tutti gli oggetti di gioco nella versione 2D, ma è semplicemente ignorato o visualizzato all'utente in un altro modo, ad esempio da un'ombra che viene visualizzata più a sinistra quando il giocatore è in aria).

Ciò che rende questo argomento così affascinante è che FORZARE lo sviluppatore di avere un'idea molto chiara di come sono strutturati i suoi dati e di come scorre il controllo. Si noti che ciò non implica l'utilizzo di nient'altro che una libreria grafica come SDL, D3DX o OpenGL. Nessun motore di gioco!

Poiché questa è una domanda prevalentemente teorica, lascerò fuori i linguaggi di programmazione, ma se vuoi fare un esempio puoi usare qualsiasi linguaggio che ti piace, C ++ se vuoi andare tutto il maiale, o anche Brainfuck se ti senti fino alla sfida (eventuali risposte concrete saranno apprezzate, così come eventuali risposte astratte!).


Non sono sicuro che sia pratico. Tanta logica di gioco utilizza la matematica vettoriale, dovresti fare qualsiasi cosa in 3D prima di convertire in 2D o qualsiasi altra cosa per il rendering, o dovresti estrarre completamente la tua libreria vettoriale - che sarebbe sicuramente impraticabile?
tenpn,

Cerca il termine "Livello di astrazione" e conoscilo, perché voi due lavorerete insieme per un po '.
Zaratustra,

Risposte:


8

Penso che tutto (?) Di cui avresti bisogno sarebbe uno strato di astrazione che avvolge la tua libreria grafica; avresti bisogno di uno nuovo per ogni libreria che utilizzeresti e ognuno dovrebbe avere esattamente la stessa API esterna.

Pensa alla localizzazione delle stringhe: invece di scrivere nel codice la stringa "Inventory" nel tuo gioco, chiameresti invece la tua libreria di localizzazione (possibilmente personalizzata), che farebbe alcuni processi e restituirebbe una stringa corretta, a seconda del contesto di il gioco.

Allo stesso modo, tutte le chiamate al tuo motore grafico verrebbero effettuate tramite il tuo wrapper.

Nel fare questo, limiti / restringi quali comandi puoi dare al tuo motore grafico. Eccone alcuni essenziali:

  1. Disegna (oggetto grafico) in (posizione)
  2. Modifica proprietà (alfa, rotazione, ecc.) Di (oggetto grafico)
  3. Sposta (oggetto grafico) in (posizione)
  4. Crea mappa di (nome livello / struttura dati)

E alcuni altri, che troverai mentre lavori al tuo progetto.

Se stai usando un linguaggio orientato agli oggetti rigorosamente tipizzato, chiameresti i comandi precedenti l' interfaccia che tutti i tuoi wrapper implementeranno. Preferibilmente, questi saranno gli unici metodi non protetti / pubblici.

Ora crea un nuovo wrapper per ciascuna delle tue librerie grafiche e implementa l'API . Quando ti viene dato un comando per disegnare __ in __ , devi usare il codice per creare lo sprite o il modello e disegnarlo nel tuo ambiente. Ciò potrebbe richiedere alcuni stratagemmi, come la memorizzazione di ogni sprite in un hash per essere nuovamente accessibile in un altro momento da un determinato simbolo.

Per quanto riguarda la costruzione di mappe, il modo più efficiente sarebbe quello di pre-costruire ogni mappa per ciascun motore grafico prima di fare e cercare. In alternativa, è possibile memorizzare la mappa nella propria struttura di dati personalizzata e quindi utilizzare il wrapper per creare una mappa da quella struttura di dati.

Spero che questo ti aiuti a iniziare =]


2

Costruire l'architettura del tuo gioco con un paradigma abbastanza vicino a MVC per consentire l'astrazione completa del codice di visualizzazione sarebbe probabilmente abbastanza difficile per qualsiasi grande progetto. Tuttavia, sembra che il principale ostacolo alla creazione di un gioco che supporti sia un client 2D che 3D sarebbe la progettazione di un gioco in cui entrambi i client sono ugualmente capaci.

Sarebbe necessario iniziare la progettazione del tuo gioco con la piena intenzione di creare e supportare i due client, e probabilmente sarebbe più sicuro limitare tutte le funzionalità di gioco a ciò che ha senso per il client 2D.

Ad esempio, se non si progettava un set di funzionalità limitato, è possibile creare livelli in cui informazioni o oggetti importanti erano visibili solo da angolazioni specifiche. Anche se ciò andrebbe bene per i client 3D che hanno una libertà di visione a 360 gradi a meno che il tuo client 2D non supportasse esplicitamente un angolo di visione che avesse visibilità su ciascuno di quegli oggetti importanti, comprometteresti gli utenti del client.

Sarebbe meglio stabilire un numero specifico di angoli di visualizzazione per il client 2D (8 o 16 o simili) e sviluppare tutto il contenuto per adattarsi a tali vincoli. Sfortunatamente se hai livelli e oggetti progettati per essere visualizzabili solo da una specifica serie di angolazioni, può sembrare abbastanza strano all'interno di un client 3D.

A mio avviso, sarebbe una scelta sbagliata tentare una progettazione del gioco che consenta ai client 2D e 3D di avere le stesse capacità. Penso che sarebbe un uso migliore delle risorse per progettare opzioni di gioco asimmetriche e consentire a ciascun cliente di giocare ai suoi punti di forza. Ad esempio, se il client 2D si concentrava principalmente su una prospettiva a livello strategico sul mondo di gioco, con il client 3D utilizzato per il gameplay a livello tattico.


0

Penso che tu abbia praticamente risposto alla tua domanda:

Per dirlo in un contesto MVC: i controller sono esattamente gli stessi (premendo il tasto "Su" si imposta l'accellerazione dei giocatori a 3,5 unità / secondo), le viste sono totalmente diverse (2D contro 3D) e il modello è lo stesso fatta eccezione per qualsiasi cosa direttamente correlata alla grafica.

Quindi, fornendo un'adeguata astrazione tra input, logica di gioco, ecc. E grafica, avrai risolto il problema.

Questo è fondamentalmente il punto del modello MVC, soprattutto per quanto riguarda le applicazioni desktop e Web: possono esserci più client che accedono e manipolano gli stessi dati (ad esempio un'interfaccia web, un client mobile e un client desktop per la posta elettronica).


0

Mantienilo semplice se lo vuoi semplice: - Scrivi la logica di gioco per spostare gli oggetti. Non archiviare su di essi alcun dato correlato al rendering. - Scrivi renderer a cui viene data la possibilità di guardare lo stato dei dati di gioco e disegnarli.

Per questo puoi usare tecniche di programmazione più o meno complicate. L'unica cosa di cui hai bisogno è un modo per ottenere dati "extra" che devi renderizzare per ogni oggetto di gioco. Il modo più semplice è avere zero dati extra richiesti! Se l'oggetto di gioco è un "Mago", disegna un Mago.

Se hai bisogno di metodi più complicati, considera il polimorfismo, il modello di ricordo, le tabelle di hash, i puntatori void *, ecc. Non progettare eccessivamente (la maggior parte di questi metodi sono ingegnerizzati).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.