O título é um pouco confuso, mas não pensei em como explicar minha pergunta em uma frase curta. Então aqui está:
Sempre que estou escrevendo motores de jogos, seja com base em física / base etc, sempre chego ao ponto em que não tenho certeza de como devo gerenciar as coisas. As entidades no mundo devem lidar por conta própria ou deve haver algum sistema global para gerenciá-las?
Aqui está um exemplo fácil: Movendo coisas. Cada objeto deve ver o mundo ao seu redor (verifique se há colisões) e se mover com base nisso.
[note, este é um jogo baseado em blocos em que objetos se movem por bloco, então não estou usando a física para passar de bloco a bloco]
public class Actor : GameObject
{
private void MoveTo(Vector2 location)
{
if (world.getTile(location) != solid && world.objAtTile(location) == null)
{
Tweener.addTween(this, location);
}
}
}
Ou o movimento de cada objeto deve ser manipulado no mundo, onde o mundo verifica tudo?
public class Actor : GameObject
{
private void MoveTo(Vector2 location)
{
world.moveTo(location);
}
}
public class World
{
public void moveObject(GameObject obj, Vector2 location)
{
//called from object
if (getTile(location) != solid && objAtTile(location) == null)
{
Tweener.addTween(obj, location);
}
}
}
Realmente não importa muito para este exemplo, suponho, mas posso me ver tendo problemas mais tarde. Desde já, obrigado.
fonte
Actor
saber sobreworld
tudo?Respostas:
Vejo que seus exemplos estão em Java, mas suas tags não especificam nenhum idioma. No C ++, a resposta é nenhuma - você não deve estar usando uma função de membro para isso!
fonte
Não existe uma resposta simples.
Como na maioria das coisas na programação, é uma troca. Dar mais poder a objetos individuais os torna maiores - e, portanto, mais lentos - mas facilita a compreensão e a extensão do mecanismo. Ter uma megaclasse capaz de lidar com tudo juntos pode ser mais rápido, mas ao custo de ter uma megaclasse; isto é, geralmente é considerado uma má forma criar classes supermassivas.
Li alguns artigos sobre design orientado a componentes e dados, em que você tem uma única classe que representa todos os objetos de um determinado tipo, armazena os dados em listas e transmite apenas índices para obter propriedades de um objeto individual. Embora eu possa ver isso como um tipo viável de arquitetura, acho que isso se complica com o ponto inteiro da orientação a objetos, que também recebeu sua parte justa de críticas.
Eu, pessoalmente, recomendo dar mais poder aos objetos. Faz mais sentido em uma linguagem orientada a objetos e (imagino) mais fácil de entender e manter ao longo do tempo.
fonte
Estou atualizando minha resposta porque muitas coisas não estavam claras antes dos comentários. Por favor, fique comigo enquanto explico meus pensamentos.
Em geral, dois aspectos principais a serem considerados em qualquer projeto são a coesão e o acoplamento . Todos sabemos que precisamos de alta coesão e baixo acoplamento para poder criar um design mais reutilizável e extensível.
Portanto, se o mundo precisa gerenciar tudo, isso significa que ele possui baixa coesão e acoplamento rígido (porque precisa saber e fazer tudo). No entanto, esse também é o caso quando uma entidade do jogo precisa fazer tudo. Atualize sua localização, renderize sua textura, etc. etc.
O que você realmente está interessado é criar sistemas que se concentrem em um aspecto da entidade. Por exemplo, uma entidade do jogo poderia ter uma Textura, mas um Renderer seria responsável por renderizar essa textura na tela. O Renderer não se importa com as outras propriedades da entidade.
Indo um pouco mais longe, uma entidade do jogo é simplesmente um saco de propriedades. Essas propriedades são manipuladas por sistemas focados em propriedades específicas. E é aí que os Sistemas de Entidades Baseados em Componentes (CBES) entram, onde propriedades = componentes.
Especificamente, CBES com sistemas (ou subsistemas). Esse design tende a ter alguns sistemas focados em componentes específicos de uma entidade, sem se preocupar com os outros componentes que a entidade possui. Além disso, os sistemas são acoplados apenas às informações necessárias para processar esses componentes.
Vamos dar o seu exemplo. Como a entrada de onde mover a entidade é baseada no controlador do player, você provavelmente teria um PlayerControllerSystem. Esse sistema controlaria, além de muitas outras coisas, o PositionComponent da entidade. Nesse caso, o PlayerControllerSystem precisaria saber sobre o Level e o PositionComponent. Se, posteriormente, você decidir adicionar a detecção de colisão, criaria um CollisionSystem que usaria novamente a posição das entidades, mas desta vez para calcular as caixas delimitadoras (ou você pode ter um BoundingBoxComponent, sua chamada). O fato é que você pode ativar ou desativar facilmente o comportamento (mesmo em movimento) simplesmente adicionando / removendo componentes. Portanto, mais comportamento significa que mais sistemas estão manipulando os componentes de uma entidade, mas todos eles estão em uma classe bem definida com baixo acoplamento. Quer scripts? Adicione um ScriptComponent. BAM! Você acabou de adicionar recursos de script com 2 classes. Física? Som? O mesmo novamente.
Portanto, a razão pela qual estou defendendo o CBES com os subsistemas é que ele é perfeitamente OO e um sistema fácil de manter / extensível em geral. Adicionar um comportamento a uma entidade é tão simples quanto decidir quais dados esse comportamento precisa e quais entidades precisam.
Para obter mais informações sobre os sistemas de entidades baseados em componentes com subsistemas, há uma excelente série de postagens de blog de T = Machine na Entity Systems, que são o futuro do desenvolvimento do MMOG . O autor chegou a criar um wiki para coletar várias implementações denominadas Entity Systems Project
Um post geral (e bem conhecido) sobre os sistemas de entidades baseados em componentes em geral é o Evolve sua hierarquia que criou o sistema para o Tony Hawk Pro.
Finalmente, se você estiver procurando por uma biblioteca com código de exemplo, não vá além da biblioteca Artemis . Artemis é principalmente em Java, mas aqui está uma porta em C # (que atualmente estou usando no meu projeto XNA).
fonte
Eu costumo ir com um design no qual os objetos se manipulam (afinal, para isso servem os métodos), mas o World base tem listas de todos os objetos e usa essas listas para coordená-los. Então, algo como:
fonte
Mantenha-o seco, tímido e diga ao outro cara.
É melhor pedir ao mundo que mova seu ator do que perguntar ao mundo se você pode ir para onde você quer ir. Dessa forma, você pode alterar o algoritmo de busca de caminhos facilmente na classe mundial e tal. Claro, você poderia deixar isso para uma classe básica para o ator, mas essa é a direção que eu tomaria e a razão disso.
fonte
EDIT: Reescrito devido ao feedback afirmando que eu não tinha desenhado a linha suficientemente clara para esta resposta à pergunta original.
Gostaria de esclarecer um pouco mais a questão, se possível. A lógica que atua sobre um objeto deve ser interna ou externa a esse objeto. A última parte do post menciona especificamente sobre a longevidade do design como base para a pergunta, para evitar problemas mais tarde.
Minha resposta simples de alto nível é manter toda a lógica que atua sobre um objeto dentro desse objeto.
Você não precisa que o mundo mova um objeto, tudo o que você precisa é o objeto a ser movido e o vetor que representa o local a ser movido para ele. O mundo pode entrar em jogo quando um destino está sendo escolhido ou quando uma reação ao meio ambiente é necessária devido a uma colisão, mas essas estão fora do exemplo dado para trabalhar.
Para abordar a parte subjacente da questão e alcançar a longevidade do design, eu sugeriria uma arquitetura orientada a componentes. As arquiteturas de componentes dividem um objeto em conjuntos discretos de dados e funcionalidade (supondo que você vá com a minha resposta acima, que afirma manter a lógica com os dados). Se sua estrutura se parece com CEntity-> CHuman-> CSoldier-> CPlayerCharacter, você invariavelmente entrará em problemas em que precisa alterar alguma lógica e dependendo de onde ela fica nessa árvore (quantos outros tipos de seres humanos existem, por exemplo?) pode ter efeitos de varredura em vários tipos de objetos.
Em vez disso, um sistema de componentes teria um conjunto de interfaces que define o que o objeto CEntity é composto como ICompRenderable, ICompMoveable, ICompHealth, ICompInventory e assim por diante. Onde você teria CCompMoveableHuman e possivelmente um CCompMoveableSoldier e CCompMoveablePlayer para manter seus padrões de movimento individuais separados. Digamos que o soldado seja alterado para rodar em formações. Essa alteração afetará apenas entidades criadas usando esse componente.
Então, para resumir, sugiro que você contenha a lógica com os dados aos quais a lógica se aplica. Também recomendo dividir objetos em componentes discretos para reduzir o 'Onde devo colocar isso?' perguntas e proporcionar estabilidade no futuro com facilidade de manutenção e sua extensão.
Espero que isto ajude.
fonte
Eu recomendo que você tente ler sobre arquiteturas baseadas em componentes. Existem algumas postagens no blog, apresentações e artigos sobre eles que podem fazer um trabalho melhor do que eu jamais poderia.
AltDevBlogADay tem algumas postagens sobre o assunto, sendo uma delas muito boa essa série sobre entidades de jogos: http://altdevblogaday.com/2011/07/10/the-game-entity-–-part-ia-retrospect/ várias partes que se concentram no problema que você está tentando resolver.
fonte