Pular para o conteúdo principal
O jogo ao vivo

Esta página ainda não foi traduzida: mostrando a versão em inglês.

Collision

Vincule um transform ao mapa de obstáculos e declare o que acontece no contato. O módulo Collision roda dentro da simulação da plataforma. Você declara corpos, camadas e respostas e assina os eventos de contato.

Quando usar

  • Entidades em movimento precisam resolver contatos no servidor (deslizar, parar, quicar) sem uma rotina de desvio escrita à mão.
  • O gameplay reage ao toque: itens coletáveis são recolhidos na sobreposição, e volumes de trigger disparam a máquina de estados de uma entidade.
  • O módulo Locomotion e os projéteis precisam de resolução por varredura (swept) contra o conjunto de obstáculos do mapa.
  • A prévia de posicionamento ou a mira precisam perguntar “isso cabe aqui?” e consultar a sobreposição de volumes.
  • Dispensável quando nada se encontra fisicamente. Para gameplay de requisição e resposta sobre registros, basta o Data & Subscriptions.

Quem faz o quê

AtorO que faz nesta página
room-ownerdeclara corpos, camadas e respostas; consulta sobreposições e contatos

A quais salas isso se aplica

Este módulo roda onde a plataforma avança a simulação: nas salas (room) declaradas com Host = "Backend". Se o seu próprio servidor de jogo é dono da simulação (PlayServ como metaservidor), movimento, colisões e predição ficam do lado da engine, e esta página descreve a alternativa hospedada pela plataforma, não uma exigência.

Resumo

A forma, a camada e o que acontece no contato ficam no próprio corpo — nada declara pares de camadas à distância:

Um Body em cápsula no tanque, na camada vehicles: desliza nas paredes, atravessa itens coletáveis e decide as caixas contato a contato
[Entity("tank")]
public class Tank
{
    [Sync] public Vector3 Position;

    [Body(Shape.Capsule, Radius = 0.6f, Layer = "vehicles")]
    [CollidesWith("walls", Response.Slide)]
    [CollidesWith("pickups", Response.Pass)]        // reported, motion passes through
    public Body Body;
}
@Entity('tank')
export class Tank {
  @Sync() position!: Vector3;

  @Body({ shape: 'capsule', radius: 0.6, layer: 'vehicles' })
  @CollidesWith('walls', Response.Slide)
  @CollidesWith('pickups', Response.Pass)        // reported, motion passes through
  body: Body;
}
@entity("tank")
class Tank:
    position: Vector3 = sync()

    body = collision.body(shape="capsule", radius=0.6, layer="vehicles",
                           collides_with=[
                               ("walls", Response.SLIDE),
                               ("pickups", Response.PASS),   # reported, motion passes through
                           ])
Em breve — Go

Ainda não está decidido como declarar com atributos em Go (O-1). Os exemplos chegam quando a forma de escrita for escolhida.

// the declaration rides inside the engine's own reflection macros, in the specifier position —
// UHT reads it from the header text, and the member is a reflected property at the same time
UCLASS(PSEntity = "tank")
class UTank : public UObject
{
    GENERATED_BODY()

    UPROPERTY(PSSync)
    FVector3f Position;

    // walls slide, pickups report the contact and let motion pass through —
    // multi-entry values are one quoted list (a specifier value is a single token)
    UPROPERTY(PSBody = (Shape = "Capsule", Radius = "0.6", Layer = "vehicles"),
              PSCollidesWith = "walls:Slide, pickups:Pass")
    FPSBody Body;
};
// declarations compile into the same pushed model — playserv push from the UE project or CI
Unity C# is the same C# API here — os mesmos atributos compilam no Unity, na versão base 2021.3 — sem sintaxe de C# 12 aqui
[Entity("tank")]
public class Tank
{
    [Sync] public Vector3 Position;

    [Body(Shape.Capsule, Radius = 0.6f, Layer = "vehicles")]
    [CollidesWith("walls", Response.Slide)]
    [CollidesWith("pickups", Response.Pass)]        // reported, motion passes through
    public Body Body;
}

Um contato é um evento, e os módulos o assinam. Não existe hook no contato: quando ele passa a existir, o passo da simulação já o resolveu e não sobra nada para rejeitar. Se um estúdio precisa de regras diferentes, ele sobrescreve as verificações de admissibilidade e de trajetória com uma implementação própria — veja Extensibility — e a resposta continua declarada.

O modelo

O que um corpo declara.

DeclaraO que é
shapeuma primitiva de um conjunto fechado — esfera, cápsula, caixa — com dimensões declaradas. Malha arbitrária não está disponível: é a mesma restrição, pelo mesmo motivo, do modelo de mundo do servidor no mapa
onde ficaem um aspecto, junto com o transform: essa é a unidade de política, e o corpo tem o mesmo destino do seu transform
como a trajetória é verificadastepwise verifica a posição final do passo — é rápido. swept verifica o segmento entre as posições — custa mais e elimina o efeito túnel (tunnelling) dentro de um passo. O modo é declarado; a implementação nunca o escolhe pela velocidade
áreas de que participaem quais volumes o corpo é contado
relação com o modelo artísticonenhuma é exigida: o corpo é uma simplificação e pode divergir do modelo artístico dentro de limites declarados

Um corpo stepwise rápido atravessa obstáculos finos

stepwise só verifica onde o passo termina, então um corpo rápido pode atravessar um obstáculo fino. swept verifica o segmento entre as posições e elimina o efeito túnel dentro de um passo. Se um projétil pode ou não atravessar uma parede é uma propriedade do seu jogo, e quem declara isso é você.

A resposta é declarada por par — o tipo de passabilidade do obstáculo × o tipo de corpo — e vem de um conjunto fechado:

RespostaO que significa
stopo movimento para na última posição admissível
slideo movimento continua ao longo do obstáculo pela componente que for admissível
bouncea direção é refletida e a velocidade é multiplicada por um coeficiente declarado
dampo movimento continua com a velocidade multiplicada por uma fração declarada
passo obstáculo não afeta o movimento, mas o contato continua observável
cease to exista entidade deixa de existir — um projétil contra uma parede

Os coeficientes são valores declarados, não calculados a partir de massas e materiais — este contrato não tem nem uma coisa nem outra.

O que vale para toda verificação.

SempreO que é
todo partem uma resposta: um par sem resposta é um defeito de declaração, recusado no deploy, e não descoberto em combate
a tabela de respostaso cliente consegue lê-la: é a mesma tabela que a autoridade usa no cálculo, então cliente e servidor com a mesma declaração respondem do mesmo jeito ao mesmo contato
reproduzível dentro de uma autoridade, não entre plataformasa mesma entrada na mesma ordem dá o mesmo resultado dentro de um processo e de um build. Resultados idênticos bit a bit em plataformas e builds diferentes não são garantidos
simultaneidadeé declarada: quando dois corpos em movimento colidem dentro do mesmo passo, a ordem de resolução é declarada e determinística. A ordem de percurso do armazenamento, a ordem de chegada da entrada e o acaso não podem servir de base para ela
um contato, um fatoos dois lados observam o contato entre dois corpos como um único fato, com um único identificador, e não como dois eventos independentes
os pontos de extensão ficam no passo, não no contatoantes do passo, o transform pode ser alterado; depois dele, só resta observar. A sobrescrita das verificações de admissibilidade e de trajetória também precisa estar disponível no cliente
o módulonão move nada por conta própria: responde se uma posição é admissível e qual é a resposta; aplicá-la cabe à movimentação
um contato é um eventopor isso os módulos assinam o evento em vez de se acoplarem: a máquina de estados de uma armadilha liga uma transição à entrada em um volume de trigger, os drops são coletados na sobreposição e os projéteis resolvem acertos pela varredura deste módulo

Erros

  • “Inadmissível” é uma resposta, não um erro, e diz qual dos três motivos se aplica: fora dos limites, ocupado por um obstáculo estático ou ocupado pelo corpo de outra entidade. O cliente reage a cada um de um jeito: dar meia-volta, contornar ou esperar.
  • Falhas de declaração aparecem no deploy, nunca no primeiro contato: um corpo com forma fora do conjunto fechado, um corpo em um aspecto sem transform e um par sem resposta declarada são todos recusados no deploy.
  • Entidade ou local inexistente responde not found, e não adianta repetir.
  • Taxa de verificações excedida responde na categoria de rate limit, com o prazo antes do qual não adianta tentar de novo.

Limites

Os números chegam com o capítulo de limites da plataforma; o que acontece em cada teto já está definido.

  • Corpos em uma sala: declarar mais um é recusado como conflito; corpos existentes nunca são removidos para abrir espaço.
  • Contatos por passo: o excedente nunca é descartado em silêncio. Ou o passo é recusado, ou a ordem de corte é declarada.
  • Tamanho do corpo em relação ao passo da grade do mapa: recusado no deploy, porque um corpo menor que o passo do campo de altura cai através do terreno.
  • Áreas em que um corpo pode estar ao mesmo tempo: o excesso é recusado no deploy.
  • Taxa de verificações por ator: rate limit com prazo.
  • Corpos em uma resposta a “quem está nesta área?”: truncados por uma ordem declarada, e o indicador de truncamento é obrigatório.