Sembra che tu stia cercando di conoscere gli alberi!
E sto seriamente, se al momento stai eseguendo il loop su una matrice di tutti i tuoi cubi, allora dovresti davvero esaminare varie strutture di dati spaziali. In questo caso, il modo migliore per reinventare il tuo mondo cubo è come un albero.
Prima di addentrarci nei motivi del perché, pensiamo al nostro problema. Stiamo cercando una soluzione in cui, per il minor costo possibile, possiamo recuperare un elenco di cubi vicini con cui il giocatore potrebbe scontrarsi. Questo elenco dovrebbe essere il più piccolo, ma preciso possibile.
Ora per determinare questa zona, dobbiamo mappare lo spazio delle coordinate del nostro giocatore allo spazio delle coordinate della mappa del cubo; vale a dire, dobbiamo mappare la posizione in virgola mobile del lettore su un indice discreto della matrice multidimensionale di cubi (potrebbe essere la notazione di esempio world[31][31][31]
, ovvero il centro esatto per una matrice multidimensionale 64 * 64 * 64).
Potremmo semplicemente calcolare i blocchi circostanti utilizzando questa stessa indicizzazione discreta, magari campionando solo i cubi vicini, ma ciò richiede comunque un ricalcolo costante e non consente alcun oggetto che non sia discreto nel posizionamento (cioè potrebbe non essere mappato al cubo carta geografica).
La situazione ideale è un insieme di secchi che contengono i nostri gruppi di cubi per sezioni particolari della nostra mappa dei cubi, divisi equamente in modo che, invece di ricalcolare l'area circostante, ci muoviamo semplicemente dentro e fuori da queste zone . Per qualsiasi calcolo non banale, conservare i nostri dati in questo modo potrebbe eliminare l'iterazione di tutti i cubi e solo questi singoli set che si trovano nelle vicinanze.
La domanda è: come lo implementiamo?
Per il mondo 64 * 64 * 64, immagina che sia suddiviso in 8 * 8 * 8 zone . Ciò significa che nel tuo mondo avrai 8 zone per asse (X, Y, Z). Ognuna di queste zone conterrà 8 cubi, facilmente recuperabili da questo nuovo indice semplificato.
Se avessi bisogno di eseguire un'operazione su una serie di cubi vicini, invece di iterare ogni cubo nel tuo mondo, potresti semplicemente iterare su queste zone , abbattendo il numero massimo di iterazioni dall'originale 64 * 64 * 64 (262144) a solo 520 (8 * 8 * 8 + 8).
Ora diminuire da questo mondo di zone, e posizionare le zone in grandi super-zone ; in cui ogni superzona contiene 2 * 2 * 2 zone regolari . Mentre il vostro mondo attualmente contiene 512 (8 * 8 * 8) zone , siamo in grado di rompere i * 8 * 8 8 zone in 64 (4 * 4 * 4) super-zone dividendo 8 zone da 2 zone per super-zona . Applicando la stessa logica dall'alto, ciò interromperebbe le iterazioni massime da 512 a 8 per trovare la super-zona ; e quindi un massimo di 64 per trovare la zona di avanzamento(totale massimo 72)! Puoi vedere come questo ti sta già salvando molte iterazioni (262144: 72).
Sono sicuro che ora puoi vedere quanto sono utili gli alberi. Ogni zona è un ramo sull'albero, con ogni superzona come ramo precedente. Stai semplicemente attraversando l'albero per trovare ciò di cui hai bisogno; utilizzando set di dati più piccoli per ridurre al minimo i costi complessivi.
Lo schema seguente dovrebbe aiutarti a visualizzare il concetto. (immagine tratta da Wikipedia: Octrees ):
Disclaimer:
In una configurazione ideale come sopra, in cui il tuo mondo voxel è già strutturato in un array multidimensionale di dimensioni fisse, potresti semplicemente interrogare la posizione del giocatore, quindi indicizzare i blocchi circostanti con un costo O (1)! (Vedi la spiegazione di Olhovskys) Ma questo diventa più difficile quando inizi a considerare che il tuo mondo ha raramente dimensioni fisse in un gioco voxel; e potrebbe essere necessario che la struttura dei dati sia in grado di caricare intere superzone dall'HDD alla memoria. A differenza di un array multidimensionale a dimensione fissa, gli alberi lo consentono prontamente senza troppo tempo impiegato in algoritmi combinatori.