Nota : este tutorial é destinado a usuários avançados e experientes e não abrange tópicos como adição de componentes, criação de novos scripts GameObject e sintaxe C #. Se você precisar aprimorar suas habilidades no Unity, consulte nossos tutoriais Introdução ao Unity e Introdução ao script de unidade .
Na
primeira parte do tutorial, aprendemos como criar um gancho para gatos com a mecânica de enrolar uma corda em torno de obstáculos. No entanto, queremos mais: a corda pode envolver objetos ao nível, mas não se solta quando você retorna.
Começando a trabalhar
Abra o projeto finalizado da primeira parte do Unity ou faça o download do
rascunho desta parte do tutorial e abra
2DGrapplingHook-Part2-Starter . Como na primeira parte, usaremos o Unity versão 2017.1 ou superior.
Abra a cena do
jogo no editor na pasta do projeto
Scenes .
Inicie a cena do jogo e tente prender o gancho do gato nas pedras acima do personagem e depois gire para fazer a corda envolver um par de bordas de pedra.
Ao retornar, você notará que os pontos da pedra através dos quais a corda costumava girar não se soltam novamente.
Pense no ponto em que a corda deve se desdobrar. Para simplificar a tarefa, é melhor usar o estojo quando a corda envolver as bordas.
Se a lesma, agarrada a uma pedra acima de sua cabeça, girar para a direita, a corda dobrará após o limiar no qual cruza o ponto de ângulo de 180 graus com a nervura à qual a lesma está atualmente presa. Na figura abaixo, é mostrado por um ponto verde destacado.
Quando a lesma balança de volta na outra direção, a corda deve soltar novamente no mesmo ponto (destacada em vermelho na figura acima):
A lógica de desvendar
Para calcular o momento em que você precisa desenrolar a corda nos pontos em que foi enrolada anteriormente, precisamos de conhecimento de geometria. Em particular, usaremos uma comparação de ângulos para determinar quando a corda deve se soltar da borda.
Essa tarefa pode parecer um pouco intimidadora. A matemática pode inspirar horror e desespero, mesmo nos mais corajosos.
Felizmente, o Unity tem ótimas funções auxiliares de matemática que podem facilitar nossa vida.
Abra o script
RopeSystem no IDE e crie um novo método chamado
HandleRopeUnwrap()
.
private void HandleRopeUnwrap() { }
Vá para
Update()
e adicione no final uma chamada ao nosso novo método.
HandleRopeUnwrap();
Enquanto
HandleRopeUnwrap()
não faz nada, mas agora podemos processar a lógica associada a todo o processo de desanexação das bordas.
Como você se lembra da primeira parte do tutorial, armazenamos as posições de quebra de corda em uma coleção chamada
ropePositions
, que é uma coleção
List<Vector2>
. Sempre que uma corda envolve uma borda, mantemos a posição desse ponto de empacotamento nesta coleção.
Para tornar o processo mais eficiente, não executaremos nenhuma lógica em
HandleRopeUnwrap()
se o número de posições armazenadas na coleção for igual ou menor que 1.
Em outras palavras, quando a lesma estiver conectada ao ponto inicial e sua corda ainda não estiver enrolada nas bordas, o número
ropePositions
de
ropePositions
será 1 e não seguiremos a lógica de processamento sem torção.
Adicione esta
return
simples na parte superior de
HandleRopeUnwrap()
para salvar valiosos ciclos da CPU, porque esse método é chamado de
Update()
muitas vezes por segundo.
if (ropePositions.Count <= 1) { return; }
Adicionando novas variáveis
Sob esse novo teste, adicionaremos algumas dimensões e referências aos diferentes ângulos necessários para implementar a base da lógica sem torção. Adicione o seguinte código ao
HandleRopeUnwrap()
:
Existem muitas variáveis aqui, então vou explicar cada uma delas, além de adicionar uma ilustração conveniente que ajudará a entender seu objetivo.
anchorIndex
é o índice na coleção ropePositions
em duas posições do final da coleção. Podemos considerá-lo como um ponto em duas posições na corda a partir da posição da lesma. Na figura abaixo, este é o primeiro ponto de fixação do gancho à superfície. Ao preencher a coleção ropePositions
novos pontos de empacotamento, esse ponto sempre permanecerá o ponto de empacotamento a uma distância de duas posições da lesma.hingeIndex
é o índice da coleção que armazena o ponto da dobradiça atual; em outras palavras, a posição na qual a corda está enrolando no ponto mais próximo do final da corda da lesma. Está sempre a uma distância de uma posição da lesma, e é por isso que usamos ropePositions.Count - 1
.anchorPosition
calculado referenciando o lugar anchorIndex
na coleção ropePositions
e é o valor simples Vector2 dessa posição.hingePosition
calculado referenciando o local de hingeIndex
na coleção ropePositions
e é o valor simples Vector2 dessa posição.hingeDir
é um vetor direcionado de anchorPosition
para hingePosition
. É usado na variável a seguir para obter o ângulo.hingeAngle
- a útil função auxiliar Vector2.Angle()
é usada aqui para calcular o ângulo entre anchorPosition
e o ponto de dobradiça.playerDir
é um vetor direcionado de anchorPosition
para a posição atual da lesma (playerPosition)- Em seguida, usando o ângulo entre o ponto de ancoragem e o jogador (lesma), o
playerAngle
calculado.

Todas essas variáveis são calculadas usando posições armazenadas como valores de Vector2 na coleção
ropePositions
e comparando essas posições com outras posições ou a posição atual do jogador (lesma).
As duas variáveis importantes usadas para comparação são
hingeAngle
e
hingeAngle
.
O valor armazenado em
hingeAngle
deve permanecer estático, pois é sempre um ângulo constante entre o ponto nas duas "dobras da corda" da lesma e a atual "dobra da corda" mais próxima da lesma que não se move até que a corda seja destorcida ou depois de ser dobrada um novo ponto de curvatura será adicionado.
Quando a lesma está
playerAngle
muda. Comparando esse ângulo com
hingeAngle
e também verificando se a lesma está à esquerda ou à direita deste canto, podemos determinar se o ponto de dobra atual mais próximo à lesma deve ser destacado.
Na primeira parte deste tutorial, salvamos as posições de dobra em um dicionário chamado
wrapPointsLookup
. Cada vez que salvamos o ponto de dobra, o adicionamos ao dicionário com a posição como chave e com 0 como valor. No entanto, esse valor de 0 era misterioso, certo?
Usaremos esse valor para armazenar a posição da lesma em relação ao seu ângulo com o ponto de articulação (o ponto de dobra atual mais próximo da lesma).
Se você atribuir um valor
-1 , o ângulo da lesma (
playerAngle
) será menor que o ângulo da dobradiça (dobradiçaAngle) e, com o valor
1, o ângulo da
playerAngle
maior que a
hingeAngle
.
Devido ao fato de salvarmos os valores no dicionário, toda vez que comparamos
hingeAngle
com
hingeAngle
, podemos entender se a lesma acabou de ultrapassar o limite após o qual a corda deve ser desengatada.
Pode ser explicado de maneira diferente: se o ângulo da lesma acabou de ser verificado e é menor que o ângulo da dobradiça, mas a última vez que foi salva no dicionário de pontos de dobra, foi marcada com um valor indicando que estava do outro lado desse canto, então o ponto deve ser removido imediatamente !
Desacoplar corda
Dê uma olhada na captura de tela abaixo com notas. Nossa lesma se agarrou à rocha, balançou para cima, enrolando uma corda em volta da borda da rocha em seu caminho.
Você pode notar que, na posição de giro mais alta, onde a lesma é opaca, seu ponto de dobra mais próximo atual (marcado com um ponto branco) será armazenado no dicionário
wrapPointsLookup
com o valor
1 .
No caminho para baixo, quando o
playerAngle
se torna menor que o
hingeAngle
(duas linhas verdes tracejadas), como mostra a seta azul, é realizada uma verificação e, se o último valor (atual) do ponto de curvatura for
1 , o ponto de curvatura deverá ser removido.
Agora vamos implementar essa lógica no código. Mas antes de começarmos, vamos criar um espaço em branco do método que usaremos para relaxar. Devido a isso, após criar a lógica, ela não levará a um erro.
Adicione um novo método
UnwrapRopePosition(anchorIndex, hingeIndex)
inserindo as seguintes linhas:
private void UnwrapRopePosition(int anchorIndex, int hingeIndex) { }
Feito isso, volte para
HandleRopeUnwrap()
. Nas variáveis recém-adicionadas, adicione a seguinte lógica, que tratará de dois casos:
playerAngle
menos que
hingeAngle
e
hingeAngle
mais que
hingeAngle
:
if (playerAngle < hingeAngle) {
Este código deve corresponder à explicação da lógica descrita acima para o primeiro caso (quando
hingeAngle
<
hingeAngle
), mas também lida com o segundo caso (quando
hingeAngle
>
hingeAngle
).
- Se o ponto de dobra atual mais próximo da lesma tiver um valor de 1 no ponto em que
hingeAngle
< hingeAngle
, removeremos esse ponto e realizaremos um retorno para que o restante do método não seja executado. - Caso contrário, se o ponto de dobra não tiver sido marcado pela última vez com um valor de 1 , mas
playerAngle
menor que hingeAngle
, -1 será atribuído. - Se o ponto de dobra atual mais próximo da lesma for -1 no ponto em que
hingeAngle
> hingeAngle
, remova o ponto e retorne. - Caso contrário, atribuímos as entradas no dicionário de pontos de dobra na posição da dobradiça para 1 .
Esse código garante que o dicionário
wrapPointsLookup
sempre atualizado, garantindo que o valor do ponto de dobra atual (mais próximo da lesma) corresponda ao ângulo da lesma atual em relação ao ponto de dobra.
Não se esqueça de que o valor é -1 quando o ângulo da barra é menor que o ângulo da dobradiça (em relação ao ponto de referência) e 1 quando o ângulo da barra é maior que o ângulo da dobradiça.
Agora,
UnwrapRopePosition()
no script
RopeSystem com um código que se envolverá diretamente no desacoplamento, movendo a posição de referência e atribuindo um novo valor de distância ao valor da distância da corda DistanceJoint2D. Adicione as seguintes linhas ao disco do método criado anteriormente:
- O índice do ponto de ancoragem atual (a segunda posição da corda da lesma) torna-se a nova posição da dobradiça, e a posição antiga da dobradiça é removida (a que estava anteriormente mais próxima da lesma e que agora estamos "desenrolando"). A variável
newAnchorPosition
recebe o valor anchorIndex
na lista de posições da corda. Ele será usado para posicionar a posição atualizada do ponto de ancoragem. - A junta de cabo RigidBody2D (à qual o cabo DistanceJoint2D está conectado) muda sua posição para a nova posição do ponto de ancoragem. Isso garante um movimento contínuo suave da lesma na corda quando ela está conectada ao DistanceJoint2D, e essa conexão deve permitir que ela continue a balançar em relação à nova posição, que se tornou a referência - em outras palavras, em relação ao próximo ponto da corda a partir de sua posição.
- Em seguida, é necessário atualizar o valor da distância distanceJoint2D para levar em consideração uma mudança acentuada na distância da lesma ao novo ponto de referência. Se isso ainda não tiver sido feito, uma verificação rápida do sinalizador
distanceSet
é executada e a distância recebe o valor da distância calculada entre a lesma e a nova posição do ponto de ancoragem.
Salve o script e retorne ao editor. Comece o jogo novamente e observe como a corda se desprende das bordas quando a lesma passa os valores limite de cada ponto de curvatura!
Embora a lógica esteja pronta, adicionaremos algum código auxiliar ao
HandleRopeUnwrap()
antes de comparar o
hingeAngle
com o
hingeAngle
(
if (playerAngle < hingeAngle)
).
if (!wrapPointsLookup.ContainsKey(hingePosition)) { Debug.LogError("We were not tracking hingePosition (" + hingePosition + ") in the look up dictionary."); return; }
Na verdade, isso não deve acontecer, porque redefinimos e desconectamos o gancho do gato quando ele envolve uma costela duas vezes, mas se isso ainda acontecer, podemos sair facilmente desse método com uma
return
simples e uma mensagem de erro no console.
Além disso, graças a isso, lidaremos mais convenientemente com esses casos limitantes; além disso, recebemos nossa própria mensagem de erro caso algo desnecessário ocorra.
Para onde ir a seguir?
Aqui está um
link para o projeto finalizado desta segunda e última parte do tutorial.
Parabéns por concluir esta série de tutoriais! Quando se trata de comparar ângulos e posições, tudo se tornou bastante complicado, mas nós sobrevivemos a isso e agora temos um maravilhoso sistema de gancho e corda que pode acabar com objetos no jogo.
Você sabia que nossa equipe de desenvolvimento do Unity escreveu um livro? Caso contrário, confira o
Unity Games By Tutorials . Este jogo ensinará como criar quatro jogos prontos do zero:
- Atirador com dois bastões
- Atirador em primeira pessoa
- Jogo de defesa de torre (com suporte a VR!)
- Jogo de plataformas 2D
Depois de ler este livro, você aprenderá a criar seus próprios jogos para Windows, macOS, iOS e outras plataformas!
Este livro é destinado a iniciantes e aqueles que desejam atualizar suas habilidades em Unity para um nível profissional. Para dominar o livro, você precisa ter experiência em programação (em qualquer idioma).