Oggetto di matrici o matrice di oggetti?


13

Sto realizzando un gioco di simulazione gestionale, qualcosa sulla falsariga di Roller Coaster Tycoon. Voglio sapere qual è il modo migliore per strutturare i miei oggetti del mondo in modo da massimizzare le prestazioni.

Diciamo che nel mio gioco ho 5.000 persone che potrei:

Crea un oggetto e memorizzalo in un array in questo modo;

class person() {
    this.x = 0;
    this.y = 0;
    this.thirst = 15;
    this.hunger = 15;
    // etc.. add methods:
    public findPath(int destX, int destY) {
    // and so on
    }

    people = new person[5000];

for (int = 0; i < 5000; i++) {
    people[i] = new person;
    }

O dovrei creare un oggetto di persone che contenga molti array di byte che rappresentano gli attributi di persone in questo modo:

class people() {
    this.hunger = new byte[5000]
    this.thirst = new byte[5000]

    getThirst(int i) {
        return this.thirst[i]
        }

 // and so on....

O sono totalmente fuori dal comune?


Domanda piuttosto interessante, soprattutto da quando nel 2013, oltre una dozzina di anni dopo l'uscita di RCT, l'idea di avere 5000 NPC indipendenti e visibili in un mondo sembrerebbe del tutto impossibile (nonostante i progressi della tecnologia)
Katana314

Risposte:


15

La terminologia comune è "struttura di matrici" (SOA) e "matrice di strutture" (AOS) che provengono da C ed è spesso vista in termini di lavoro SIMD.

Tipicamente, l'approccio AOS è più veloce, se usato in modo appropriato, ma SOA tende ad essere più facile da lavorare (e quindi ottimizza per la qualità più importante - i tempi di sviluppo).

La SOA, specialmente in Java, significa che i tuoi dati possono rimanere ben confezionati in memoria. È possibile scorrere le proprietà e aspettarsi che la cache della CPU e simili rimangano felici. Con AOS, specialmente in Java, ogni oggetto finisce allocato "da qualche parte" nella memoria. L'iterazione su oggetti potrebbe potenzialmente danneggiare la cache della CPU piuttosto pesantemente.

Alla fine, prenderei qualunque approccio tu trovi più facile da usare. Il tuo tempo di sviluppo è molto più prezioso rispetto al fatto che il tuo gioco supporti PC di 10 anni o solo PC di 9 anni (è molto improbabile che tu stia facendo qualcosa di cui ha bisogno l'hardware più recente).


1
Nel tuo terzo paragrafo intendi fare riferimento ad AOS due volte? I commenti sembrano contraddittori ...
ali_goes_oosh

Spiacente, risolto.
Sean Middleditch l'

4

Non c'è motivo per cui non si possano avere entrambi, usando il modello Facciata per tradurre da un'interfaccia all'altra rappresentazione sottostante. Ad esempio, usando i termini SOA / AOS di Sean:

Facciata SOA

class PeopleFacade {
    Person persons[5000];
    getThirst(int i) { return persons[i].thirst; }
}

Facciata AOS

class People { int thirsts[5000]; } people;
class PersonFacade {
    int i;
    getThirst() { return people.thirsts[i]; }
}

In questo modo puoi scegliere liberamente tra un modulo con cui ti senti a tuo agio nell'utilizzare , come interfaccia per sviluppatori, rispetto a ciò che è meglio come implementazione per qualsiasi motivo, inclusi motivi di efficienza / cache.

Un altro vantaggio della facciata è che conduce in modo molto naturale al modello Flyweight , in cui si utilizza un'interfaccia per rappresentare molte più persone di quelle effettivamente presenti nella memoria. Ad esempio, forse hai clienti robot che non hanno mai sete; quindi puoi inserire quel caso speciale nel tuo PersonFacadee gli utenti di quella interfaccia non devono mai sapere dei robot:

class People { int nonRobotThirsts[1000]; } people;
class PersonFacade {
    int i;
    bool isRobot;
    getThirst() {
        if (isRobot)
            return 0;
        else
            return people.nonRobotThirsts[i];
    }
}

... o usando un approccio più OO, avresti una Robotclasse separata che si comporta esattamente come Personun'eccezione getThirst().


-1

Crea oggetti e conservali in un array! Creare array per fame e sete può risparmiare un po 'di spazio e correre più veloce in alcune semplici situazioni, ma non è OOP. Java e OOP faranno molto per te se darai loro una possibilità. Per un gioco davvero semplice, il tuo secondo esempio potrebbe funzionare bene, ma anche in questo caso dovresti praticare le tue abilità OO. Il tuo primo approccio funzionerà bene per te, non importa quanto grande, complesso e peloso diventi il ​​tuo programma.

Pensa a tutte le volte che sarà utile recuperare un Personoggetto da una query. Chi ha inviato questo messaggio? per esempio. Molti metodi che scriverai vorranno sapere con chi hanno a che fare. E avrai molti metodi che si adatteranno perfettamente a una Personclasse corretta . Se Personè statico o singleton, dove metti metodi che agiscono sulle singole persone?

Se dovessi mai fare il multithreading - e con 5000 utenti potresti essere spinto al suo interno - troverai l'istanza Parent per ogni utente molto più pratica.

(E quella schiera di persone: per ora seguitela, ma a un certo punto vorrete altri dispositivi di archiviazione. Una mappa di qualche tipo in modo da poter trovare le persone per nome. E forse diversi elenchi con chiavi diverse, e probabilmente mazzi di elenchi abbastanza brevi da essere matrici o elenchi collegati.)

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.