2012-01-04 13 views
8

Di solito, entità e componenti o altre parti del codice di gioco in progettazione basata sui dati avranno nomi controllati se si desidera scoprire quale oggetto si sta trattando con esattamente.Quali sono alcuni buoni metodi per sostituire i nomi di stringa con hash di interi

void Player::Interact(Entity *myEntity) 
{ 
    if(myEntity->isNearEnough(this) && myEntity->GetFamilyName() == "guard") 
    { 
     static_cast<Guard*>(myEntity)->Say("No mention of arrows and knees here"); 
    } 
} 

Se si ignora la possibilità che questo potrebbe essere l'ottimizzazione prematura, è abbastanza chiaro che la ricerca entità sarebbe molto più veloce se il loro "nome" è stato un valore a 32 bit semplice invece di uno stringa effettiva.

L'hashing di calcolo dei nomi di stringa è una possibile opzione. Non l'ho ancora provato, ma con una gamma di 32 bit e una buona funzione di hashing il rischio di collisione dovrebbe essere minimo.

La domanda è questa: ovviamente abbiamo bisogno di un modo per convertire in-code (o in un qualche tipo di file esterno) nomi di stringhe a quei numeri interi, poiché la persona che lavora su questi oggetti nominati vorrà comunque fare riferimento al oggetto come "guardia" invece di "0x2315f21a".

Supponendo che stiamo usando C++ e vogliamo sostituire tutte le stringhe che appaiono nel codice, questo può anche essere ottenuto con funzionalità incorporate in linguaggio o dobbiamo costruire uno strumento esterno che controlli manualmente tutti i file e gli scambi i valori?

+1

+ LOL per il messaggio della guardia: D – Petruza

+0

Direi che vorresti davvero 'dynamic_cast ' qui. RTTI può avere un brutto nome nello sviluppo del gioco, ma questo è destinato ad essere molto più lento di quello, per non dire più difficile da mantenere. – MSalters

risposta

10

Jason Gregory scritto questo his book:

A Naughty Dog, abbiamo utilizzato una variante l'algoritmo CRC-32 per cancellare le nostre stringhe e non abbiamo incontrato una singola collisione in oltre due anni di sviluppo su Uncharted: Drake's Fortune.

Quindi potresti volerlo esaminare.

E a proposito del passo di costruzione che hai citato, ne ha anche parlato. In sostanza incapsulano le stringhe che hanno bisogno di essere hash in qualcosa di simile:

_ID("string literal") 

e utilizzare un tool esterno in fase di compilazione di hash tutte le occorrenze. In questo modo si evitano i costi di runtime.

+1

In C++ 11, dovresti essere in grado di utilizzare una funzione 'constexpr' per eseguire l'hashing in fase di compilazione, eliminando la necessità di uno strumento esterno. –

+0

@ MikeSeymour Questo è davvero bello, non ne avevo idea. Non ho ancora visto molto in C++ 11. Deluso da VS [mancanza di supporto] (http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx) .. –

+0

Questo è davvero fantastico Mike, totalmente dimenticato di constexpr. Aggiungilo come risposta e lo accetterò. – TravisG

1

Questo è quello per cui sono le enumerazioni. Non avrei il coraggio di decidere quale risorsa è meglio per il tema, ma ci sono un sacco da scegliere: https://www.google.com/search?q=c%2B%2B+enum

+1

Il problema con l'enumerazione è che sono "corretti" e non si adattano bene a un sistema di script estensibile oa una progettazione basata sui dati. –

+0

Puoi farlo alla vecchia maniera con le macro, in questo modo hai il controllo completo del processo. – aaaaaaaaaaaa

+1

Potresti approfondire un po 'questo pensiero? Forse non stiamo pensando a scenari simili. Ad esempio, supponiamo di creare un'entità denominata "level1_garden_door" nel tuo editor di livelli. Quindi vorresti fare riferimento a quell'entità in un file di script per aggiungere un po 'di interattività. Per facilità d'uso, dovresti comunque essere in grado di fare riferimento alla tua entità per nome. Ma la ricerca delle stringhe è lenta, quindi l'hashing di questi ID negli interi durante la compilazione fornisce una via di mezzo decente tra usabilità e velocità. Un enum ha bisogno di conoscere tutti i valori che può rappresentare, ma qui quei valori sono usati-definiti. Qual è la soluzione? –

0

Direi di andare con l'enumerazione!

Ma se avete già un sacco di codice già utilizzando le stringhe, beh, o semplicemente mantenere in questo modo (semplice e di solito abbastanza veloce su un PC in ogni caso) o hash utilizzando un qualche tipo di CRC o MD5 in un numero intero.

0

Questo è fondamentalmente risolto aggiungendo un riferimento indiretto in cima a una mappa di hash.

dire che si desidera convertire le stringhe di numeri interi:

  • scrivere una classe avvolge sia un array e un HashMap. Io chiamo questi dizionari di classi.
  • L'array contiene le stringhe.
  • chiave del hash_map è la stringa (puntatori condivisi o matrici stabili dove puntatori prime sono lavoro sicuro e)
  • valore della mappa hash è l'indice nella matrice stringa si trova, che è anche il manico opaca essa ritorna al codice chiamante.
  • Quando si aggiunge una nuova stringa al sistema, viene cercata già presente nella hashmap, restituisce l'handle se presente.
  • Se l'handle non è presente, aggiungere la stringa all'array, l'indice è l'handle.
  • Impostare la stringa e l'handle nella mappa e restituire l'handle.

Note/Avvertenze:

  • Questa strategia rende sempre la corda dalla pista manico in tempo costante (si tratta semplicemente di una deferenza array).
  • gli identificatori di handle sono i primi arrivati, ma la serializzazione delle stringhe anziché i valori non avrà importanza.
  • I sovraccarichi dell'operatore [] per la chiave e il valore sono abbastanza semplici (registrazione di nuove stringhe o ritorno della stringa), ma il wrapping dell'handle con una classe definita dall'utente (il wrapping di un intero) aggiunge un sacco di molto necessario digita sicurezza ed evita l'ambiguità se vuoi che la chiave e i valori siano gli stessi tipi (sovraccarico [] non compilare ed ecc.)
  • Devi memorizzare le stringhe nella RAM, che può essere un problema.
Problemi correlati