Objeto de matrizes ou matriz de objetos?


13

Estou fazendo um jogo sim de gerenciamento, algo parecido com o Roller Coaster Tycoon. Quero saber qual é a melhor maneira de estruturar meus objetos mundiais para maximizar o desempenho.

Digamos que tenho 5.000 pessoas no meu jogo que eu poderia:

Crie um objeto e armazene-o em uma matriz como essa;

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

Ou devo criar um objeto de pessoas que contenha muitas matrizes de bytes que representem atributos de pessoas como:

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

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

 // and so on....

Ou estou totalmente errado?


Pergunta muito interessante, especialmente desde que, em 2013, mais de uma dúzia de anos após RCT saiu, a idéia de ter 5000 visíveis, NPCs independentes em um mundo que parece completamente impossível (apesar dos avanços na tecnologia)
Katana314

Respostas:


15

A terminologia comum é "estrutura de matrizes" (SOA) e "matriz de estruturas" (AOS) que vêm de C e são mais frequentemente vistas em termos de trabalho SIMD.

Normalmente, a abordagem do AOS é mais rápida, se usada adequadamente, mas a SOA tende a ser mais fácil de trabalhar (e, portanto, otimiza a qualidade mais importante - o tempo de desenvolvimento).

SOA, especialmente em Java, significa que seus dados podem permanecer compactados na memória. Você pode iterar sobre as propriedades e esperar que o cache da CPU permaneça satisfeito. Com o AOS, especialmente em Java, todo objeto acaba alocado "em algum lugar" da memória. A iteração sobre objetos pode potencialmente sobrecarregar bastante o cache da CPU.

No final, eu adotaria a abordagem que você achar mais fácil de usar. Seu tempo de desenvolvimento é muito mais valioso do que se o seu jogo suporta PCs com 10 anos ou apenas com 9 anos (é improvável que você esteja fazendo algo que precise do hardware mais recente).


1
No seu terceiro parágrafo, você pretende se referir ao AOS duas vezes? Os comentários parecem contraditórios ...
ali_goes_oosh

Desculpe, consertou.
Sean Middleditch

4

Não há razão para que você não possa ter os dois, usando o padrão Facade para converter de uma interface para outra representação subjacente. Por exemplo, usando os termos SOA / AOS de Sean:

Fachada SOA

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

Fachada AOS

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

Dessa forma, você pode escolher livremente entre um formulário com o qual se sinta confortável usando , como interface do desenvolvedor, o que for melhor como implementação, por qualquer motivo, incluindo eficiência / cache.

Outra vantagem da fachada é que ela leva muito naturalmente ao padrão Flyweight , onde você usa uma interface para representar muito mais pessoas do que realmente está na memória. Por exemplo, talvez você tenha clientes robóticos que nunca têm sede; você pode colocar esse caso especial no seu PersonFacadee os usuários dessa interface nunca precisam saber sobre robôs:

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

... ou usando uma abordagem mais OO, você teria uma Robotclasse separada que age exatamente como uma Personexceção getThirst().


-1

Crie objetos e armazene-os em uma matriz! Criar matrizes para fome e sede pode economizar um pouco de espaço e correr mais rápido em algumas situações simples, mas não é POO. Java e OOP farão muito por você se você lhes der uma chance. Para um jogo realmente simples, seu segundo exemplo pode funcionar bem, mas mesmo assim você deve praticar suas habilidades de OO. Sua primeira abordagem funcionará bem para você, não importa o tamanho, a complexidade e a complexidade do seu programa.

Pense em todos os momentos em que será útil recuperar um Personobjeto de uma consulta. Quem enviou esta mensagem? por exemplo. Muitos métodos que você escreve querem saber com quem estão lidando. E você terá muitos métodos que se encaixam perfeitamente em uma Personclasse adequada . Se Personé estático ou um singleton, onde você coloca métodos que atuam em pessoas individuais?

Se você executar multithreading - e com 5.000 usuários poderá ser pressionado -, a instância Parent de cada usuário será muito mais prática.

(E esse conjunto de pessoas: fique com ele por enquanto, mas em algum momento você precisará de outros dispositivos de armazenamento. Um mapa de algum tipo para encontrar pessoas pelo nome. E talvez várias listas com chaves diferentes e provavelmente grupos de lista cada uma delas curta o suficiente para ser matrizes ou listas vinculadas.)

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.