Como os videogames são orientados a objetos? [fechadas]

18

Eu sempre me perguntei até que ponto a orientação a objetos é usada pelos videogames, especialmente os grandes projetos em 3D. Eu acho que seria legal que tanto trolle werewolfherdou seus atributos de enemye substituiu alguns deles. Mas talvez as aulas sejam muito pesadas para serem práticas, eu não sei ...

vemv
fonte
2
Como quantificar (ou mesmo qualificar objetivamente) a orientação a objetos? Deseja uma resposta em Meyers ou Dahl-Nygaards?
Obviamente, eles são tão pesados ​​que uma linguagem fortemente baseada em OO é o padrão da indústria.
The Duck comunista
4
Se você quer dizer C ++, foi escolhido porque é uma boa linguagem para explorar a programação genérica com segurança de tipo de maneira consciente da velocidade; os poucos recursos de POO são obviamente um infeliz desenho incorreto mantido apenas para compatibilidade com versões anteriores. ;)

Respostas:

20

Para dar o seu exemplo, explicarei meus pensamentos sobre Entites nos videogames. Não discutirei as vantagens e desvantagens gerais de objetos e classes, nem todo o seu papel nos videogames.

As entidades em pequenos videogames são definidas principalmente por classes separadas; em grandes jogos, geralmente são definidas em arquivos. Existem duas abordagens gerais a seguir:

Extensão : no seu exemplo Trolle Werewolfserá estendido Enemy, o que se estende Entity. Entitycuida das coisas básicas como movimento, saúde etc., enquanto Enemydeclararia as subclasses como inimigos e faria outras coisas (o Minecraft segue essa abordagem).

Baseado em componentes : a segunda abordagem (e a minha favorita) é uma Entityclasse, que possui componentes. Um componente pode ser Moveableou Enemy. Estes componentes cuidar de uma coisa como movimento ou física. Esse método quebra longas cadeias de extensão e minimiza o risco de ocorrer um conflito. Por exemplo: Como você pode criar inimigos não móveis, se eles herdarem de um personagem móvel? .

Em grandes videogames como World of Warcraft ou Starcraft 2, as Entidades não são classes, mas conjuntos de dados, que especificam toda a Entidade. O script também é importante, porque você define o que a Entidade não define em uma Classe, mas em um Script (se for exclusivo, não como mover).

Atualmente, estou programando um RTS e adoto a abordagem baseada em componentes com arquivos de descritor e script para Entites, Skills, Items e tudo mais dinâmico no jogo.

Marco
fonte
2
Parece interessante. No entanto, não vou mentir, não sei o que componenté nesse contexto. Um link seria muito apreciado.
vemv
Um componente é uma entidade que é responsável por uma única funcionalidade. A entidade baseada em componente possuirá um componente (se for o caso) que não herdará dele. A propriedade implica que uma entidade pode desativar um de seus componentes, alterando seu comportamento. No paradigma clássico de extensão, o comportamento é "pertencente a" uma superclasse. Uma entidade pode ser um componente e um componente pode ser modelado como uma classe ou como uma estrutura, se você preferir.
FxIII
Componente (às vezes chamado de sistemas de entidades) - você pode pesquisar neste blog por idéias t-machine.org Existem variantes, mas a idéia básica é que um componente é um objeto de propósito especial e seu ator une vários componentes, como a construção de um modelo de Legos.
Patrick Hughes
2
Comecei um blog sobre desenvolvimento de jogos e escrevi minha primeira entrada sobre isso. Nada de novo, mas com um pouco de código: jagamedev.wordpress.com/2011/06/26/...
Marco
23

Eu acho que seria legal que tanto trolls quanto lobisomens herdassem seus atributos do inimigo e substituíssem alguns deles.

Infelizmente, essa abordagem do polimorfismo, popular nos anos 90, mostrou-se uma má ideia na prática. Imagine que você adicione 'wolf' à lista de inimigos - bem, ele compartilha alguns atributos com o lobisomem, então você deseja consolidá-los em uma classe base compartilhada, por exemplo. 'WolfLike'. Agora você adiciona 'Humano' à lista de inimigos, mas os lobisomens às vezes são humanos, então eles também compartilham atributos, como andar com duas pernas, poder conversar, etc. Você cria uma base comum 'Humanóide' para humanos e lobisomens , e você precisa parar de lobisomens derivados de WolfLike? Ou você multiplica a herança de ambos - nesse caso, qual atributo tem precedência quando algo no Humanoid colide com algo no WolfLike?

O problema é que tentar e modelar o mundo real como uma árvore de classes é ineficaz. Faça três coisas e provavelmente você pode encontrar quatro maneiras diferentes de fatorar o comportamento deles em compartilhado e não compartilhado. É por isso que muitos optaram por um modelo modular ou baseado em componente, onde um objeto é composto por vários objetos menores que compõem o todo, e os objetos menores podem ser trocados ou alterados para criar o comportamento desejado. Aqui você pode ter apenas 1 classe Inimigo e contém subobjetos ou componentes de como anda (por exemplo: Bipedal vs. Quadrupedal), seus métodos de ataque (por exemplo: mordida, garra, arma, punho), sua pele (verde para trolls, peludo para lobisomens e lobos), etc.

Isso ainda é completamente orientado a objetos, mas a noção do que é um objeto útil é diferente do que costumava ser ensinado nos livros didáticos. Em vez de ter uma grande árvore de herança de várias classes abstratas e várias classes concretas nas pontas da árvore, você normalmente tem apenas 1 classe concreta representando um conceito abstrato (por exemplo, 'inimigo'), mas que contém mais classes concretas representando conceitos mais abstratos (por exemplo, ataques, tipo de pele). Às vezes, essas segundas classes podem ser melhor implementadas por meio de um nível de herança (por exemplo, uma classe de ataque básica e várias classes derivadas para ataques específicos), mas a árvore de herança profunda desapareceu.

Mas talvez as aulas sejam muito pesadas para serem práticas, eu não sei ...

Na maioria dos idiomas modernos, as aulas não são 'pesadas'. Eles são apenas outra maneira de escrever código e geralmente envolvem a abordagem processual que você teria escrito de qualquer maneira, exceto com uma sintaxe mais fácil. Mas, por todos os meios, não escreva uma classe onde uma função funcionará. As classes não são intrinsecamente melhores, apenas onde elas tornam o código mais fácil de gerenciar ou entender.

Kylotan
fonte
3
Amo esta resposta :)
Czarek Tomczak
8

Não sei ao certo o que você quer dizer com "muito pesado", mas C ++ / OOP é a língua franca do desenvolvimento de jogos pelas mesmas boas razões que são usadas em outros lugares.

Falar em soprar caches é um problema de design, não um recurso de idioma. O C ++ não pode ser tão ruim, pois é usado em jogos nos últimos 15 a 20 anos. O Java não pode ser tão ruim, pois é usado nos ambientes de tempo de execução muito apertado dos smartphones.

Agora, a verdadeira questão: por muitos anos, as hierarquias de classe se tornaram profundas e começaram a sofrer problemas relacionados a isso. Em tempos mais recentes, as hierarquias de classes se achataram e a composição e outros projetos orientados a dados estão sendo mais do que a herança orientada a lógica.

É tudo OOP e ainda é usado como linha de base ao projetar um novo software, apenas um foco diferente no que as classes incorporam.

Patrick Hughes
fonte
2

As classes não envolvem nenhuma sobrecarga de tempo de execução. O polimorfismo em tempo de execução é apenas chamar através de um ponteiro de função. Essas despesas gerais são extremamente mínimas em comparação com outros custos, como chamadas Draw, sincronização de simultaneidade, E / S de disco, comutadores de modo kernel, localidade insuficiente de memória, uso excessivo de alocação dinâmica de memória, má escolha de algoritmos, uso de linguagens de script e a lista continua. Há uma razão pela qual a orientação a objetos substituiu essencialmente o que veio antes e é porque é muito melhor.

DeadMG
fonte
O envio entre vários tipos polimórficos é feito de uma maneira que fornece pouca localidade de memória. Mesmo nas implementações mais leves, como o C ++ vtables ou o cache do Objective-C IMP, se você realmente usar o polimorfismo para lidar com objetos de tipos variados, irá explodir seus caches. Obviamente, se você não usar o polimorfismo, a vtable permanecerá em seu cache ou a mensagem em cache do IMP levará ao local correto, mas por que se preocupar? E em Java ou C #, o custo é mais alto e, em JavaScript ou Python, o custo é mais alto ainda.
11
@ Joe Wreschnig: Se você estiver usando esses idiomas mais lentos, o custo do OO será trivial em comparação com outros custos, como interpretação / JIT. Mais importante, você pode criar teoricamente o que deseja sobre a falta de localidade da memória, mas o fato é que a previsão de ramificação, a execução fora de ordem e os recursos similares na CPU praticamente negam totalmente o custo. Senão, por que tanto software de alto desempenho é escrito usando orientação a objeto?
DeadMG
1

Uma coisa a ter em mente é que os conceitos de código orientado a objetos costumam ser mais valiosos do que sua implementação em linguagens. Em particular, ter que fazer milhares de chamadas de atualização virtual para entidades em um loop principal pode causar uma bagunça no cache em C ++ em plataformas como 360 ou PS3 - para que a implementação evite palavras-chave "virtuais" ou mesmo "de classe". de velocidade.

Muitas vezes, embora ainda siga os conceitos OO de herança e encapsulamento - apenas implementando-os de maneira diferente da maneira como a linguagem se faz (por exemplo, modelos curiosamente recursivos, composição em vez de herança (o método baseado em componentes descrito por Marco)). Se a herança sempre pode ser resolvida no tempo de compilação, os problemas de desempenho desaparecem, mas o código pode se tornar um pouco complicado com modelos, implementações personalizadas de RTTI (novamente as incorporadas geralmente são impraticamente lentas) ou lógica de tempo de compilação. macros etc.

No Objective-C para iOS / Mac, existem problemas semelhantes, mas piores, com o esquema de mensagens (mesmo com o armazenamento em cache sofisticado) ...

jheriko
fonte
0

O método que tentarei usar mistura herança de classe e componentes. (Primeiro, eu não faço do Enemy uma classe - faço disso um componente.) Não gosto da idéia de usar uma classe de entidade genérica para tudo e, em seguida, adicionar os componentes necessários para aprimorar a entidade. Em vez disso, prefiro que uma classe adicione automaticamente componentes (e valores padrão) ao construtor. Em seguida, as subclasses adicionam seus componentes adicionais em seu construtor, para que a subclasse tenha seus componentes e seus componentes de classe pai. Por exemplo, uma classe de armas adicionaria componentes básicos comuns a todas as armas e, em seguida, a subclasse Espada adicionaria componentes adicionais específicos para espadas. Ainda estou debatendo sobre o uso de ativos de texto / xml para definir valores para entidades (ou espadas específicas, por exemplo), ou fazer tudo isso em código, ou qual é a combinação certa. Isso ainda permite que o jogo use as informações de tipo e o polimorfismo da linguagem de código, e torna o ObjectFactories muito mais simples.

Chris
fonte
3
Ei, Chris. Embora seja ótimo compartilhar sua experiência e seus planos, não está respondendo diretamente à pergunta. Acho que a pergunta é mais sobre como essas coisas geralmente são feitas, quando você responde como planeja fazê-lo . São perguntas semelhantes, mas não são realmente as mesmas.
MichaelHouse