Se dois objetos interagem, o que contém o código de interação?


28

Pense em uma bala e um inimigo, ou no jogador e no chão. Se esses objetos interagem, o que contém o código de interação?


2
Interagir de que maneira? Você quer dizer detecção de colisão? Nesse caso, é mais provável que você implemente uma classe de detecção de colisões e um gerenciador de resolução de colisões.
CaptainRedmuff

Em parte sim, estou interessado na colisão e no que acontece após a colisão. A bala verifica se está perto do inimigo ou o contrário? E o que acontece após a colisão, um objeto de bala pode apenas dizer a um objeto inimigo que foi atingido? Como você pode ver, estou bastante confuso sobre a coisa toda, e isso torna alguns códigos muito difíceis de ler.
ThatOneGuy

Respostas:


23

TL; DR:

Os objetos do seu jogo não se conhecem nem executam verificações em relação a outros objetos. Você cria um padrão de detecção e resolução de colisão que verifica os objetos do jogo e executa as ações apropriadas para simular a física do jogo.

The Good Stuff

De tentativas anteriores de escrever a detecção de colisões e ler este livro , existem dois estágios para a detecção e a resolução de colisões. O primeiro estágio (detecção de colisão) é uma passagem antecipada em que você determina se dois objetos podem ter uma colisão em potencial. Se dois objetos formarem uma colisão em potencial, você os passará para o segundo estágio (resolução de colisão) para executar uma verificação mais refinada nos objetos e tentar resolver a colisão.

Em algum lugar do seu mecanismo / jogo, você manterá uma variedade de todos os objetos em seu mundo. Em cada quadro, você passaria pela matriz e verificaria cada objeto em relação a qualquer outro objeto com uma simples detecção de colisão de caixa / esfera delimitadora.

Pseudo-código:

dectectCollisions(objects)
{
    for(objectA in objects)
    {
        for(objectB in objects)
        {
            if(objectA != objectB) //ignore self
            {
                if(BoundingSpheresIntersect(objectA, objectB))
                {
                    collisionResolver.addObjects(objectA, objectB);
                }
            }
        }
    }
}

Esse tipo de loop é bastante ineficiente, mas deixa espaço para melhorias através do uso de particionamento espacial como uma saída antecipada para objetos que são garantidamente distantes demais para colidir.

Após verificar os dois objetos em busca de uma colisão em potencial (ou seja, os dois objetos estão próximos o suficiente para colidir), os objetos são transmitidos para executar uma rotina de detecção de colisão mais precisa.

Imagine que você tem dois polígonos de formas e tamanhos aleatórios, suficientemente próximos para se interceptarem, mas não devido à sua geometria:

Imagem encontrada via google

Usando esferas delimitadoras, esses dois objetos criariam um falso positivo para uma colisão em potencial. É aqui que você executaria uma passagem mais completa para determinar se os dois objetos realmente se cruzam.

Depois de encontrar uma verdadeira colisão, sua etapa de resolução de colisão executaria a ação apropriada para resolver os objetos aplicando forças ou momentos, dependendo da granularidade e das necessidades da física do jogo.

Com isso em mente, você pode abstrair todo o processo de detecção e resolução de colisões, para que seus objetos não precisem saber nada um do outro, nem o processo necessário para determinar e resolver colisões. As duas classes / gerenciadores que lidam com isso para você precisam conhecer apenas as propriedades básicas de cada objeto para executar uma verificação rápida e suja de colisões e, em seguida, uma verificação mais completa, se necessário.


2
Em particular, o padrão de design do Mediador seria apropriado. O padrão Observer seria uma boa alternativa, com uma intenção muito diferente. Você pode obter um resumo muito bom deles nesta postagem do Stackoverflow .
kurtzbot

12

Uma maneira que o Unreal Engine 3 lida com isso:

A bala recebe uma mensagem de colisão dizendo que atingiu algo, com um argumento dizendo o que atingiu. Em seguida, ele pode chamar objectHit.takeDamage (self). O alvo então recebe a mensagem TakeDamage, com um ponteiro para a coisa que o atingiu, e executa a ação apropriada.

Eu pessoalmente gosto dessa abordagem porque significa que a bala pode executar ações especiais (como fazer algum tipo de efeito de explosão, dependendo do tipo de coisa atingida) e o alvo pode executar ações especiais, dependendo do tipo de bala.

Também é possível que o marcador saiba o que faz com os alvos e possa chamar funções nele, como objectHit.freeze (self). Então o alvo sabe que foi atingido por algo que o congela e que tipo de objeto era esse.

EDIT: Esta resposta é uma imagem geral de como ela pode funcionar, pois você provavelmente não está trabalhando com UE3. :)


10

Thief fez isso muito bem no Dark Engine com Sources e Receptrons. Um objeto pode ter essas duas propriedades, com tipos diferentes. Por exemplo, uma seta Água teria uma Fonte para WaterStim em contato. Uma explosão teria um AoE FireStim.

Quando uma Flecha de Água atinge um objeto, o objeto de destino procura seus Receptrons em busca de algo que esteja procurando um WaterStim com os valores de intensidade apropriados. Em seguida, ele executa qualquer comando associado a ele (nesse caso, transformar uma tocha acesa em uma tocha apagada e emitir uma nuvem de fumaça).

Como o mesmo mecanismo é usado no SystemShock2, é assim que todos os tipos de dano são tratados, balas diferentes têm diferentes Stims definidos e monstros diferentes recebem Receptrons para os diferentes tipos de Stim e causam dano igual a 1 *, 2 *, 1 / 2 a intensidade, dependendo se o tipo de munição é "super eficaz" ou não.

Parecia um sistema muito flexível, pois você podia adicionar fontes e receptores a objetos no editor de níveis (para criar uma porta única que se abre se for atingida pelo fogo, digamos.) Embora você também possa pedir ao receptor para "enviar o script mensagem "se o objeto tiver scripts especiais associados a ele.

O que você não quer fazer é codificar uma matriz de interação nXn de todos os objetos possíveis, colidindo com todos os objetos possíveis! Ao generalizar as interações por meio de mensagens padronizadas, você simplifica o processo.


Do ponto de vista dos scripts, essa abordagem parece a mais flexível e a mais expressiva. Muito legal.
drhayes

-2

Uma solução é manter os contêineres de marcadores e jogadores em classes separadas e, em seguida, ter a função main () que mantém o loop de quadros responsável pela interação.

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.