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ê
| Ator | O que faz nesta página |
|---|---|
room-owner | declara 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:
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
])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[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.
| Declara | O que é |
|---|---|
shape | uma 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 fica | em 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 é verificada | stepwise 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 participa | em quais volumes o corpo é contado |
relação com o modelo artístico | nenhuma é 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:
| Resposta | O que significa |
|---|---|
stop | o movimento para na última posição admissível |
slide | o movimento continua ao longo do obstáculo pela componente que for admissível |
bounce | a direção é refletida e a velocidade é multiplicada por um coeficiente declarado |
damp | o movimento continua com a velocidade multiplicada por uma fração declarada |
pass | o obstáculo não afeta o movimento, mas o contato continua observável |
cease to exist | a 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.
| Sempre | O que é |
|---|---|
todo par | tem uma resposta: um par sem resposta é um defeito de declaração, recusado no deploy, e não descoberto em combate |
a tabela de respostas | o 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 plataformas | a 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 fato | os 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 contato | antes 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ódulo | nã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 evento | por 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.