Esta é uma questão de design ... Tenho certeza de que isso poderia ser mais generalizado, mas estou tendo dificuldades com isso. Estou pensando em design para interações com objetos de jogos - aqui está o meu exemplo (jogo de plataformas em 2D).
Digamos que o jogador esteja tentando progredir em um nível. Existem muitas luzes que podem ser apontadas em direções diferentes. Aqui está um exemplo de como esses objetos de luz podem interagir ...
- Uma luz projeta uma plataforma que permite ao jogador atravessar uma lacuna
- Uma luz diminui os coeficientes de atrito de qualquer coisa que toque, outra aumenta
- Uma luz anula os efeitos de todas as luzes, o que faria a plataforma desaparecer enquanto essa luz estiver acesa e anula os modificadores de atrito
- Etc ...
Qual é a melhor maneira de abordar esse problema ao usar uma arquitetura de componentes? Os componentes para cada objeto principal parecem óbvios, bem como uma maneira limpa de definir seus efeitos no ambiente. Uma classe para "resolver" a interação (parece que isso pode se tornar uma bagunça rapidamente)? Algum uso do padrão decorador para criar objetos combinados para aqueles que estão interagindo em um determinado momento? Uma estrutura de dados que se presta a isso?
Além disso, conectando o áudio a essas interações? Parece que conectar o áudio ao sistema seria como conectar qualquer outra propriedade, como visibilidade ou movimento / colisão do player.
Obviamente, à medida que mais componentes são adicionados, seria bom se houvesse um sistema robusto que pudesse lidar com novos com poucas modificações, mas não estou familiarizado com o modo de projetar isso.
Outras informações: O mecanismo que estou usando é um mecanismo XNA chamado IceCream .
fonte
Respostas:
Em um sistema orientado a objetos, a única resposta real para a pergunta sobre qual é a melhor maneira de fazer o X é que você deve fazê-lo da maneira mais direta possível para colocar algo em funcionamento e alterá-lo quando um expressão mais fácil se torna aparente. Se preocupar em escolher o padrão certo antes de escrever qualquer código é uma boa maneira de encontrar a resposta errada desde o início; deixe que todos os pensamentos sobre padrões e componentes se dissolvam e siga estas etapas, começando de onde você está hoje (assumindo que você implementou um componente leve):
Neste ponto, você (provavelmente) terá uma tonelada de código duplicado. Extraia o código comum em funções ou outra classe (talvez uma classe base) ou o que parecer apropriado. Só porque você começou com um "componente leve", no entanto, não significa que o LightComponent seja uma base apropriada; pode ser que o código que compõe o componente leve não seja realmente um "componente" em si e talvez seja melhor representado por um conjunto de funções ou mesmo por uma classe separada que seja agregada aos seus novos componentes (como variável de membro )
fonte
Em termos gerais, quando um objeto do tipo A interage com um objeto do tipo B, você deseja obter algum efeito C. Isso é chamado de "despacho duplo" e é muito difícil de executar com elegância em linguagens do tipo C.
A maneira eficaz, mas difícil de manter, é apenas um monte de instruções switch e if, dependendo dos tipos de seus objetos. Você se sentirá sujo ao escrevê-lo, mas ele fará o trabalho.
O padrão Visitor é uma solução mais robusta que oculta a troca de tipo desagradável, mas pode ser difícil de configurar.
Normalmente, qualquer tipo de troca de tipo no seu código é um cheiro, mas aqui você está tentando generalizar o polimorfismo, que normalmente alterna funções com base em um único tipo, para alternar funções com base em dois tipos. O polimorfismo é uma base do POO, portanto não é um cheiro.
fonte
Deixe-me ver. Isso é apenas algo que eu cozinhei na minha cabeça enquanto escrevia, desculpe se estou perdendo alguma coisa.
Coloque todos os nós de luz a uma distância razoável do seu cara.
Para cada luz, você renderiza um polígono que representa sua área de efeito em um objeto buffer de moldura. Portanto, um cone de luz criaria um cone de um tipo de pixel no seu FBO. Renderize cada tipo de nó em prioridade apropriada. Você pode codificar informações em cada pixel, como o canal verde pode ser fricção, o vermelho é a gravidade, o azul e o alfa são outra coisa.
Técnicas inteligentes de mistura de cores podem criar efeitos interessantes. Cada nível pode ter suas próprias regras de mesclagem. Você também pode adicionar sombreamento de fragmentos para efeitos dinâmicos psicodélicos, como gravidade pulsante etc.
Por fim, basta verificar em quais pixels seu mandado está tocando e faça um novo cálculo do bitmap sempre que estiver próximo das bordas da área pré-calculada.
Scetch áspero feito em 2 minutos, ilustrando minha ideia:
Editar: Na prática, isso significa que a única coisa que você precisa é de um componente de luz que emita uma determinada cor. As regras relacionadas a que cor faz o que pode estar em algum outro lugar. Você pode codificar muitos dados nos 32 bits que possui pixel PR. Como alternativa, você pode ter vários FBOs contendo atributos diferentes que não se afetam. Você pode ter um FBO de gravidade / fricção e um FBO de colisão de 1 bit. Se você escolher isso, é claro que teria que sinalizar em qual FBO sua luz deve renderizar.
fonte
O padrão do observador é uma das melhores soluções. A mensagem será enviada apenas para os objetos (componentes) realmente interessados nela. Portanto, o destinatário deve se inscrever neste tipo de mensagem / evento.
Existem muitas implementações de sinal / slot. Por exemplo, em C ++, há uma biblioteca de sigslot
Para mais informações, leia sobre os sinais e slots Qt .
fonte