Estou tentando criar um efeito semelhante ao de Mario Galaxy ou Geometry Wars 3, onde o jogador caminha pelo "planeta" a gravidade parece se ajustar e eles não caem da borda do objeto, como faria se a gravidade foi fixado em uma única direção.
(fonte: gameskinny.com )
Consegui implementar algo parecido com o que estou procurando usando uma abordagem em que o objeto que deveria ter a gravidade atraia outros corpos rígidos, mas usando o mecanismo de física incorporado para o Unity, aplicando movimento com AddForce e coisas do gênero, Eu simplesmente não conseguia fazer o movimento parecer certo. Não consegui fazer com que o jogador se movesse rápido o suficiente sem começar a voar para fora da superfície do objeto e não consegui encontrar um bom equilíbrio de força aplicada e gravidade para acomodar isso. Minha implementação atual é uma adaptação do que foi encontrado aqui
Eu sinto que a solução provavelmente ainda usaria a física para aterrar o jogador no objeto se ele deixasse a superfície, mas uma vez que o jogador tenha sido aterrado, haveria uma maneira de encaixar o jogador na superfície e desligar a física e controlar o jogador por outros meios, mas não tenho muita certeza.
Que tipo de abordagem devo adotar para encaixar o player na superfície dos objetos? Observe que a solução deve funcionar no espaço 3D (em oposição ao 2D) e deve poder ser implementada usando a versão gratuita do Unity.
Respostas:
Consegui realizar o que eu precisava, principalmente com a ajuda deste post do blog para a peça de quebra-cabeça da superfície e tive minhas próprias idéias para o movimento do jogador e a câmera.
Como encaixar o player na superfície de um objeto
A configuração básica consiste em uma esfera grande (o mundo) e uma esfera menor (o jogador), ambas com coletores de esferas ligados a eles.
A maior parte do trabalho que está sendo realizado foi nos dois métodos a seguir:
o
Vector3 movementDirection
parâmetro é exatamente o que parece, a direção que vamos mover nosso player nesse quadro, e calcular esse vetor, embora tenha sido relativamente simples neste exemplo, foi um pouco complicado para eu descobrir no começo. Mais adiante, mas lembre-se de que é um vetor normalizado na direção em que o jogador está movendo esse quadro.Avançando, a primeira coisa que fazemos é verificar se um raio, originário da posição hipotética futura direcionada aos vetores inativos dos jogadores (-transform.up), atinge o mundo usando o WorldLayerMask, que é uma propriedade pública do script LayerMask. Se você quiser colisões mais complexas ou várias camadas, precisará criar sua própria máscara de camada. Se o raycast atingir com sucesso algo, o hitInfo é usado para recuperar o normal e o ponto de impacto para calcular a nova posição e rotação do player, que deve estar no objeto. Pode ser necessário compensar a posição do jogador, dependendo do tamanho e da origem do objeto do jogador em questão.
Finalmente, isso realmente só foi testado e provavelmente só funciona bem em objetos simples, como esferas. Como a postagem do blog em que baseei minha solução, sugere, você provavelmente desejará executar vários raycasts e calculá-los como média para sua posição e rotação para obter uma transição muito mais agradável ao se deslocar em terrenos mais complexos. Também pode haver outras armadilhas em que não pensei neste momento.
Câmera e Movimento
Uma vez que o jogador estava grudado na superfície do objeto, a próxima tarefa a ser abordada era o movimento. Inicialmente, eu comecei com um movimento em relação ao jogador, mas comecei a encontrar problemas nos polos da esfera, onde as direções mudavam repentinamente, fazendo com que meu jogador mudasse rapidamente de direção várias vezes, sem me deixar passar pelos polos. O que acabei fazendo foi fazer meus jogadores se moverem em relação à câmera.
O que funcionou bem para minhas necessidades foi ter uma câmera que seguisse estritamente o jogador com base apenas na posição do jogador. Como resultado, mesmo que a câmera estivesse tecnicamente girando, pressionar para cima sempre movia o player em direção à parte superior da tela, para baixo em direção à parte inferior e assim por diante com a esquerda e a direita.
Para fazer isso, o seguinte foi executado na câmera em que o objeto alvo era o jogador:
Finalmente, para mover o player, alavancamos a transformação da câmera principal para que, com nossos controles para cima, para cima, para baixo, para baixo, etc. E é aqui que chamamos UpdatePlayerTransform, que obterá nossa posição ajustada ao objeto mundial.
Para implementar uma câmera mais interessante, mas com os controles semelhantes aos que temos aqui, você pode implementar facilmente uma câmera que não é renderizada ou apenas outro objeto fictício para basear o movimento e, em seguida, usar a câmera mais interessante para renderizar o que você quer que o jogo pareça. Isso permitirá boas transições de câmera à medida que você percorre os objetos sem interromper os controles.
fonte
Eu acho que essa ideia vai funcionar:
Mantenha uma cópia do lado da CPU da malha do planeta. Ter vértices de malha também significa que você tem vetores normais para cada ponto do planeta. Em seguida, desative completamente a gravidade para todas as entidades, aplicando uma força exatamente na direção oposta a um vetor normal.
Agora, com base em qual ponto esse vetor normal do planeta deve ser calculado?
A resposta mais fácil (que eu tenho certeza que funcionará bem) é aproximar-se da mesma forma que o método de Newton : quando os objetos aparecem, você conhece todas as suas posições iniciais no planeta. Use essa posição inicial para determinar o
up
vetor de cada objeto . Obviamente, a gravidade estará na direção oposta (na direçãodown
). No próximo quadro, antes de aplicar a gravidade, projete um raio da nova posição do objeto em direção ao seudown
vetor antigo . Use a interseção desse raio com o planeta como a nova referência para determinar oup
vetor. O raro caso do raio não atingir nada significa que algo deu muito errado e você deve mover seu objeto de volta para onde estava no quadro anterior.Observe também que, usando esse método, quanto mais a origem do jogador for do planeta, pior será a aproximação. Por isso, é melhor usar em algum lugar ao redor dos pés de cada jogador como sua origem. Estou supondo, mas acho que usar os pés como origem também resultará em um manuseio e navegação mais fáceis do jogador.
Uma última observação: para obter melhores resultados, você pode até fazer o seguinte: acompanhar o movimento do jogador em cada quadro (por exemplo, usando
current_position - last_position
). Em seguida, prenda-o demovement_vector
forma que o comprimento em direção ao objetoup
seja zero. Vamos chamar esse novo vetorreference_movement
. Mova o anteriorreference_point
porreference_movement
e use esse novo ponto como origem do traçado de raios. Depois (e se) o raio atingir o planeta, váreference_point
para esse ponto de impacto. Por fim, calcule o novoup
vetor, a partir deste novoreference_point
.Algum código pseudo para resumir:
fonte
Esta postagem pode ser útil. A essência é que você não usa os controladores de caracteres, mas cria o seu próprio usando o mecanismo de física. Em seguida, use as normais detectadas abaixo do player para orientá-las para a superfície da malha.
Aqui está uma boa visão geral da técnica. Existem muitos outros recursos com termos de pesquisa na web como "passeio pela unidade em objetos 3d mario galaxy".
Há também um projeto de demonstração da unidade 3.x que tinha um mecanismo de caminhada, com um soldado e um cachorro e em uma das cenas. Ele demonstrou andar em objetos 3D no estilo Galaxy . É chamado de sistema de locomoção por runevision.
fonte
Rotação
Confira a resposta desta pergunta em answers.unity3d.com (realmente solicitada por mim). Citar:
Aqui está o código que ele me sugeriu:
Chame isso de atualização, e você deve fazê-la funcionar. (observe que o código está no UnityScript ).
O mesmo código em C # :
Gravidade
Para a gravidade, você pode usar minha "técnica de física do planeta", que descrevi na minha pergunta, mas não é realmente otimizada. Foi apenas algo que me ocorreu.
Eu sugiro que você crie seu próprio sistema para a gravidade.
Aqui está um tutorial do YouTube de Sebastian Lague . Essa é uma solução muito eficiente.
EDIT: Na unidade, vá para Editar > Configurações do projeto > Física e defina todos os valores para Gravity como 0 (ou remova o Rigidbody de todos os objetos), para evitar que a gravidade interna (que apenas puxa o jogador para baixo) entre em conflito com a solução personalizada. (Desligue isso)
fonte