Objekt von Arrays oder Array von Objekten?

13

Ich mache ein Management-Sim-Spiel, ähnlich wie Roller Coaster Tycoon. Ich möchte wissen, wie ich meine Weltobjekte am besten strukturieren kann, um die Leistung zu maximieren.

Angenommen, ich habe 5.000 Leute in meinem Spiel, die ich könnte:

Machen Sie ein Objekt und speichern Sie sie in einem Array wie folgt;

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;
    }

Oder sollte ich ein Objekt von Personen erstellen, das viele Byte-Arrays enthält, die Attribute von Personen wie folgt darstellen:

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

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

 // and so on....

Oder bin ich total daneben?

ali_goes_oosh
quelle
Ziemlich interessante Frage, besonders seit 2013, über ein Dutzend Jahre nach Erscheinen von RCT, die Idee, 5000 sichtbare, unabhängige NPCs in einer Welt zu haben, völlig unmöglich erscheint (trotz technologischer Fortschritte)
Katana314

Antworten:

15

Die gebräuchliche Terminologie ist "Struktur von Arrays" (SOA) und "Array von Strukturen" (AOS), die von C stammen und am häufigsten in Bezug auf die SIMD-Arbeit verwendet werden.

Normalerweise ist der AOS-Ansatz bei angemessener Verwendung schneller, aber SOA ist in der Regel einfacher zu bearbeiten (und optimiert daher für die wichtigere Qualität - Entwicklungszeit).

SOA, insbesondere in Java, bedeutet, dass Ihre Daten dicht im Speicher bleiben können. Sie können die Eigenschaften durchlaufen und erwarten, dass der CPU-Cache und so weiter zufrieden sind. Mit AOS, insbesondere in Java, wird jedes Objekt "irgendwo" im Speicher zugeordnet. Das Durchlaufen von Objekten kann möglicherweise den CPU-Cache ziemlich stark beschädigen.

Letztendlich würde ich den Ansatz wählen, der für Sie am einfachsten ist. Ihre Entwicklungszeit ist weitaus wertvoller, als wenn Ihr Spiel 10 Jahre alte PCs oder nur 9 Jahre alte PCs unterstützt (es ist sehr unwahrscheinlich, dass Sie etwas tun, das die neueste Hardware benötigt).

Sean Middleditch
quelle
1
Wollen Sie in Ihrem dritten Absatz zweimal auf AOS verweisen? Die Kommentare scheinen widersprüchlich ...
ali_goes_oosh
Entschuldigung, das Problem wurde behoben.
Sean Middleditch
4

Es gibt keinen Grund, warum Sie nicht beides haben können. Verwenden Sie das Facade-Muster , um von einer Oberfläche in die andere zugrunde liegende Darstellung zu übersetzen. Zum Beispiel mit Seans SOA / AOS-Begriffen:

SOA Fassade

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

AOS Fassade

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

Auf diese Weise können Sie frei zwischen einem Formular wählen, das Sie gerne als Entwicklerschnittstelle verwenden, und dem, was aus irgendeinem Grund als Implementierung am besten geeignet ist, einschließlich Effizienz- / Cache-Gründen.

Ein weiterer Vorteil der Fassade besteht darin, dass sie auf ganz natürliche Weise zum Flyweight-Muster führt , bei dem Sie über eine Benutzeroberfläche viel mehr Personen darstellen, als sich tatsächlich im Speicher befinden. Zum Beispiel haben Sie vielleicht Roboter-Gönner, die niemals durstig sind. Dann können Sie diesen speziellen Fall in Ihr PersonFacadeSystem einfügen , und Benutzer dieser Schnittstelle müssen nie etwas über Roboter wissen:

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

... oder mit einem OO-Ansatz hätten Sie eine separate RobotKlasse, die genau wie eine PersonAusnahme wirkt getThirst().

congusbongus
quelle
-1

Erstelle Objekte und speichere sie in einem Array! Das Erstellen von Arrays für Hunger und Durst spart möglicherweise ein bisschen Platz und läuft in einigen einfachen Situationen schneller, aber es ist kein OOP. Java und OOP werden viel für Sie tun, wenn Sie ihnen eine Chance geben. Für ein wirklich einfaches Spiel könnte Ihr zweites Beispiel gut funktionieren, aber selbst dann sollten Sie Ihre OO-Fähigkeiten trainieren. Ihr erster Ansatz wird für Sie gut funktionieren, egal wie groß, komplex und haarig Ihr Programm wird.

Denken Sie an alle Zeiten, in denen es praktisch ist, ein PersonObjekt aus einer Abfrage zurückzugewinnen. Wer hat diese Nachricht gesendet? zum Beispiel. Viele Methoden, die Sie schreiben, wollen wissen, mit wem sie es zu tun haben. Und Sie werden eine Menge Methoden haben, die gut in eine richtige PersonKlasse passen . Wenn Personstatisch oder ein Singleton, wo platzieren Sie Methoden, die auf einzelne Personen einwirken?

Sollten Sie jemals Multithreading durchführen - und mit 5000 Benutzern könnten Sie dazu gedrängt werden -, finden Sie die Parent-Instanz für jeden Benutzer viel praktischer.

(Und diese Gruppe von Leuten: bleiben Sie fürs Erste dabei, aber irgendwann werden Sie andere Speichergeräte benötigen. Eine Karte, auf der Sie nach Namen suchen können. Und vielleicht mehrere Listen mit verschiedenen Schlüsseln und wahrscheinlich auch ein paar Listen, die jeweils kurz genug sind, um Arrays oder verknüpfte Listen zu sein.)

RalphChapin
quelle