Transcrições
1. Introdução: Os jogos de combate e videogames podem parecer assustadores e difíceis de
implementar Este curso
fornecerá todas as ferramentas e
conhecimentos necessários para criar um sistema de combate escalável e dinâmico em Gado. Vamos dividir o sistema de
combate em mecânicas
individuais
e combiná-las para criar um sistema de combate de
ação robusto que pode ser personalizado
para atender às suas necessidades Você aprenderá a combinar animações de
combate e movimento Sincronize caixas de sucesso
com animações de ataque, implemente molduras oculares
em animações de esquiva e
bloqueie inimigos bloqueie Dispare projéteis com uma arma
arranjada e controle os inimigos
com scripts de IA Se precisar de ajuda, nosso servidor de
discórdia está cheio de outros estudantes e desenvolvedores de
jogos que podem responder a quaisquer
perguntas que você possa ter Clique no link do site
em meu perfil para participar. Vou usar um projeto inicial
feito em Deus, versão 4.3 que está disponível no meu GitHub usando ativos gratuitos
do dot IO Mas você pode acompanhar seu próprio projeto usando ativos
diferentes. Para tirar o máximo proveito
desse curso, você precisará de uma cena
em seu projeto com um personagem que o jogador possa controlar e pelo menos um inimigo. Você também pode querer ter um sistema de
inventário e equipamento capaz de equipar personagens com uma arma e um escudo Para obter mais informações
sobre esses tópicos, consulte meu curso anterior. O combate não precisa
ser uma batalha difícil. Vamos sacar nossas armas e
enfrentar o combate juntos.
2. Configuração: Olá, amigos. Antes de
começarmos, você deve ter um projeto com um personagem de jogador que possa se mover em um ambiente e alguns inimigos
para ele lutar. Você também pode querer
ter um menu de inventário capaz de equipar itens, incluindo pelo menos
uma arma mala, uma arma arranjada e
um escudo Ao longo deste curso,
adicionaremos controles, mecânicas e animações ao nosso projeto
para fixar um alvo,
atacar, esquivar, bloquear e disparar projéteis atacar, esquivar, bloquear
3. Lock On: Em nossa primeira aula, permitiremos que
o jogador bloqueie um inimigo. Vamos começar adicionando um mapeamento de entrada para
ativar o bloqueio Abrindo as configurações do projeto, alternando para a guia do mapa de entrada. Podemos adicionar um
evento de entrada chamado Toggle Lock. Ao rolar para baixo para encontrar
o novo evento de entrada, vincularei a tecla Q no teclado e o botão
direito do meu controle a esse No script de
manipulação de entradas do jogador, precisaremos de referências
ao personagem, braço de
mola e à câmera, tudo configurado usando addon ready. Durante a função de entrada, após verificar a pausa, abra ou feche
o menu de inventário e se o
controle do jogador foi desativado Eu dividi o resto
da entrada em câmera e controles de
personagens para uma melhor organização. Atualmente, o único controle
da câmera é girar o braço de mola segura a câmera
usando o mouse Vamos também verificar se o botão de
bloqueio foi pressionado. Essa será uma entrada
sensível ao contexto com várias funções
possíveis diferentes. Precisaremos saber se o jogador está atualmente preso
a um alvo. Então, vamos declarar uma
variável para manter o
alvo atualmente bloqueado como um nó três D, para que qualquer objeto de três D em nosso mundo de jogo possa
ser bloqueado Podemos primeiro dividir as funções
do botão de bloqueio de alternância em
duas categorias possíveis, se o valor do alvo
for nulo ou não, que podemos encurtar
para Vamos começar no bloco s, onde o jogador não está
preso a nada no momento. Aqui, precisaremos
atribuir o valor do alvo como o alvo
visível mais e podemos delegar a
responsabilidade de
descobrir qual é o alvo
visível mais próximo da câmera No caso de
não haver um alvo visível mais próximo, o alvo ainda será nulo Em muitos jogos de ação e aventura, ao pressionar o botão de bloqueio do
togo, não há
nada
para bloquear. A câmera então reinicia para ficar
atrás do personagem do jogador, que será uma função
do braço de mola Se o jogador
já estiver preso em um alvo e pressionar
o botão de bloqueio do togo, também há vários casos
a serem considerados Se houver vários alvos
visíveis, o jogador se fixará
no próximo alvo
visível mais próximo,
além daquele em que está bloqueado no
momento Podemos reutilizar
a mesma função da câmera para encontrar
o alvo mais próximo Mas desta vez também forneça o alvo atual
como argumento, e escreveremos o algoritmo
para ignorar esse alvo. No caso abaixo, ainda
podemos passar o alvo atual, pois
seu valor é nulo, então
não teremos nada a ignorar Se não houver vários alvos
visíveis, essa função também retornará null e o bloqueio
será desativado Independentemente de
haver ou não vários alvos, se o jogador
também estiver pressionando, maioria dos jogos desativará o
bloqueio nesse Podemos determinar se a
direção de entrada fornecida é semelhante à direção descendente usando um
produto escalar dos dois vetores e verificando se
é maior que 0,75 Isso cobrirá todas as
direções próximas à descida, mas não alcançando as
diagonais Queremos ter a
capacidade de ativar o bloqueio de fora
do script, então seria uma boa ideia
torná-lo uma função pública Vamos chamá-lo de toggle
lock e fornecer um parâmetro opcional para forçar o bloqueio com um valor
padrão false O valor do alvo
será definido como nulo se estiver sendo forçado a sair. Caso contrário, ele pode ser configurado para o alvo visível mais próximo,
conforme determinado pela câmera, ignorando o
alvo atual, se houver um Todos os três
casos acima agora podem chamar o Toggle lock
, bastando especificar que o bloqueio
está sendo forçado a ser desativado no caso de
a
direção de entrada para baixo também ser fornecida, e outros scripts também podem forçar o player a bloquear
ou desligar por Mudando para o script
spring arm. Vamos supor que o jogador pressione o botão de bloqueio, mas nenhum alvo Queremos que o
braço de mola posicione a câmera atrás do personagem. Portanto, precisaremos de uma referência
ao caractere ao
qual o
braço da mola está conectado, que no meu caso
sempre
será o nó principal
do braço da mola. Se você estiver usando uma estrutura de nós
diferente, talvez
queira
exportar essa variável e definir seu valor
no painel do inspetor Para girar a câmera atrás personagem
gradualmente ao longo
do tempo, usaremos uma
variável de interpolação do tipo interpolação Seria uma boa
ideia exportar uma variável
durante a interpolação Vou usar um quarto
de segundo. Também podemos querer um valor para a rotação x preferida para redefinir
a rotação dois dos
braços de mola. Vou usar 0,5 radianos negativos, posicionando a câmera
um pouco acima do personagem, olhando para frente e
ligeiramente para baixo em um ângulo Vamos também declarar
uma variável para manter
a rotação alvo das interpolações
como um vetor três e inicializá-la como um vetor três
com a rotação x redefinida como seu valor x, mas zero para as rotações y
e Dando
uma definição à função, também
podemos aceitar um
parâmetro opcional para a duração
da interpolação usando isso como seu valor padrão para
que possa ser sobrescrito Para girar a câmera
atrás do personagem, podemos chamar uma nova função
privada interpolar a rotação dos
braços da mola Especificando que queremos que
a rotação y seja a rotação das plataformas de caracteres mais
uma meia rotação representada como Pi Em seguida, vamos escrever
a função privada que interpola a rotação dos braços da
mola, aceitando uma
rotação y alvo como flutuação, bem
como uma duração
para a interpolação com um valor padrão da Começaremos definindo
a propriedade y
da rotação do alvo como
a rotação
y do alvo aceita
como parâmetro. Mas para garantir que
a rotação sempre siga o caminho mais curto
ao redor do caractere, devemos dividir seu
valor para
estar sempre entre o ponto de
rotação atual y menos meia rotação e o ponto de rotação atual
y mais meia Se uma interpolação já
existe e está em execução
, devemos eliminá-la
antes de criar uma nova Podemos então intercalar a rotação dos braços da
mola
com a rotação do alvo
ao longo da duração Em seguida, vamos deixar a câmera
detectar alvos visíveis. Minha câmera ainda não tem nenhum comportamento
programado, então vamos adicionar um novo script e colocá-lo na pasta de
scripts dos jogadores Precisaremos de uma função
pública para obter o alvo visível mais próximo, aceitando um
parâmetro opcional
do alvo atual com
um valor padrão de null, para que possamos potencialmente ignorá-lo Isso retornará um nó três D, e o caso padrão
será retornar null se não conseguirmos
encontrar um alvo visível Para determinar qual dos
alvos visíveis está mais próximo, precisaremos manter uma lista de todos os alvos visíveis. Vamos declarar outra
variável para conter todos os alvos visíveis como
uma matriz de nós três Ds. Inicializado para ficar vazio. Uma maneira fácil de saber
quais alvos estão visíveis é conectar um nó
D de área três à câmera. Vamos chamá-lo de alcance alvo. Essa área
monitorará qualquer coisa na camada de
colisão 11, que eu escolhi para
representar inimigos Certifique-se de que seus inimigos tenham
sua camada de colisão definida na mesma camada que está sendo mascarada pelo bloqueio na Também precisarei
redefinir as áreas transformadas para posicioná-las
na origem da câmera. O nó D da área três
precisa de uma forma de colisão, e podemos preencher o recurso de forma
com um polígono convexo Usando um polígono convexo, podemos definir a
forma como uma pirâmide, que copia exatamente o campo de visão da
câmera, mas com Como o
campo de visão da câmera terá a forma de
uma pirâmide de quatro lados, podemos defini-lo com
cinco pontos sendo
o primeiro ponto
igual à posição da câmera Os outros quatro serão
posicionados ao longo do eixo Z, a distância máxima
do nosso alcance de bloqueio Vou usar uma
distância máxima de 15 metros. Mudando para a visão ortogonal superior e ocultando o
ambiente por um momento, ajustarei rapidamente as posições de cada ponto na pirâmide para corresponder
aproximadamente ao campo de visão da
câmera, 11,4 metros à
esquerda e à direita Da mesma forma, na visão
ortogonal esquerda, ajustando os valores y dos pontos
da pirâmide, 6,4 Até termos uma forma de pirâmide, compatível com o
campo de visão da câmera, que alcança 15 metros. Em seguida, voltarei
à visão em perspectiva e voltarei a falar sobre a visibilidade
do ambiente. Sempre que um corpo entra nessa área, conectando o
sinal inserido pelo corpo ao script da câmera, podemos anexar o corpo à nossa
matriz de alvos Da mesma forma, sempre que um
corpo sai dessa área, o corpo pode ser apagado
da matriz Qualquer
corpo de colisão de três D na camada 11, que exista dentro dessa área agora
será considerado
um alvo visível No meu script spring arm, precisarei de qualquer tag para usar
a função get parent. Executando o jogo e mudando
para a árvore da cena remota, podemos selecionar a câmera e visualizar suas propriedades
no inspetor, incluindo a matriz
de alvos visíveis Conforme a câmera se
move pela cena, a matriz de alvos visíveis é
atualizada automaticamente para adicionar e remover cada inimigo à medida que eles entram ou saem
do campo de visão. Pressionar o botão de bloqueio ainda
não
atingirá nada, mas podemos ver como
ele reposiciona a câmera atrás do personagem Antes de permitir
o bloqueio em um alvo, talvez também
queiramos verificar
se a linha de
visão do jogador em relação ao alvo está
obstruída pelo terreno Vamos também adicionar um nó de três D de
projeção de raios à câmera
e nomeá-lo como linha de visão. Em seguida, pegue uma referência a
ela no script da câmera. Para encontrar o
alvo visível mais próximo com nossa câmera, se a matriz estiver vazia, seu tamanho for zero, então não há alvos
visíveis a serem considerados e
devemos simplesmente retornar. Se houver
alvos visíveis a serem considerados, precisaremos comparar
as distâncias de cada um com a câmera para descobrir
qual é o mais próximo. Para fazer isso, precisaremos de
uma variável para manter a distância
do alvo atual até a câmera flutuando A distância mais próxima à tona
e o índice do alvo
visível mais próximo como Definiremos a distância
mais próxima como
infinita usando a palavra-chave I NF e o
índice mais próximo como menos
um para significar que não é um Se depois de iterar por toda
a matriz de alvos
visíveis, o índice mais próximo
ainda for negativo, nenhum alvo visível
foi considerado válido e devemos retornar null Caso contrário, podemos retornar o alvo visível
no índice mais próximo. Se o alvo visível no índice
I for o alvo atual, podemos ignorá-lo com
a declaração continuada Para qualquer outro alvo visível, precisaremos calcular sua
distância da câmera. Podemos usar a distância ao quadrado pois é matematicamente
mais eficiente Se a distância atual for menor que a
distância mais próxima
, precisaremos
verificar se a linha de visão desse
alvo está obstruída Primeiro, precisaremos redefinir qualquer rotação que a linha
de visão tenha atualmente. Em seguida, defina
a posição alvo do raio lançado para a posição
global
do alvo menos
a posição global da câmera e
force-a a atualizar Mas a posição dos personagens geralmente
está no chão, que é facilmente obstruído
por pequenos pedaços de terreno e nem sempre é um bom
indicador da linha de visão Vamos também somar 1 metro de altura. Se a linha de visão
está colidindo com algo e esse algo
é o alvo visível, então a linha de visão
não está obstruída por nada, que torna esse alvo
o alvo visível mais próximo que
encontramos Podemos definir a distância mais próxima da distância
atual
e o índice mais próximo I antes de prosseguir com
o resto da matriz Agora, isso retornará o alvo visível nulo ou o
alvo visível mais próximo da câmera A linha de visão também
colidirá com a camada 11, procurando inimigos, mas também a
camada um que seja
obstruída pelo terreno Também seria bom
informar ao jogador o
que está bloqueado com
o indicador de alvo. Vamos adicionar um nó Sprite de três
D como filho do manipulador de entrada
do player e
renomeá-lo Para a textura, usarei o ponteiro em branco da barra de
rolagem. Mas altere suas
configurações de entrada para ativar o Alpha pré-multiplicado para que
pareça um E reduza para um
quarto de seu tamanho. Em seguida, expandindo a seção da bandeira, configurarei a
bandeira do outdoor para habilitar, que ela esteja sempre voltada
para a câmera E a bandeira de teste sem profundidade sempre
desenhará o sprite sobre todo resto, independentemente de sua posição no espaço de três D em
relação à câmera O indicador de alvo
pode ficar invisível por padrão, pois o jogador começa sem um
alvo para indicar. Obtendo uma referência ao indicador de destino
usando
o complemento pronto Em seguida, precisaremos
posicioná-lo sobre o alvo bloqueado. Então, depois de determinar em
que o jogador está preso, se
há um alvo. Uma maneira fácil de fazer com que o
indicador de alvo siga o alvo é
repará-lo nesse alvo. Podemos então movê-lo alguns
metros para cima para posicioná-lo sobre a cabeça do alvo e definir sua propriedade
visível como verdadeira. Se não houver um
alvo para indicar, podemos reparar o indicador de
volta para esse nó e definir sua propriedade de visibilidade de
volta para quedas para ocultá-la. Vamos experimentar. Quando pressionamos o botão
de bloqueio, o inimigo mais próximo é atingido e o indicador posicionado
sobre a cabeça do alvo Pressionando o botão de
bloqueio novamente, mudança é para o
próximo inimigo mais próximo Manter pressionado e pressionado o botão de bloqueio
força o bloqueio Se houver apenas
um alvo visível qual já estamos presos, bloqueio também está desativado. Agora temos o jogador bloqueando
inimigos em nosso jogo. Na próxima lição, mudaremos o comportamento da câmera e do personagem
enquanto estiverem bloqueados. Te vejo na próxima aula.
4. Strafe: Olá, amigos.
Na lição anterior, adicionamos um
botão de bloqueio
sensível ao contexto ao nosso jogo Nesta lição,
mudaremos a forma como os
nós do jogador se comportam enquanto se
fixam em um alvo Começando no script do player, quando um alvo estiver
bloqueado, vamos emitir um sinal para
que qualquer outro script possa ouvir e reagir ao
valor da mudança de alvo, especificando o que foi
direcionado como parâmetro Usando um setter,
podemos emitir o sinal sempre que o valor do alvo
for alterado por qualquer Agora, todos os três
personagens, o braço de mola e a câmera podem se conectar
ao sinal, usando-o para definir suas
próprias variáveis privadas para o alvo. Não importa qual seja o
valor do alvo no script de
manipulação de entrada do player, todos os outros nós
também terão as mesmas informações, inclusive se estiverem definidas como nulas Escrever uma função simples
para cada um que define uma variável de destino local todos
possam
acessá-la facilmente. Depois que nosso personagem estiver
preso em um alvo, esperaríamos que ele ficasse voltado
para o alvo em vez de na direção
em
que está se movendo. No meu roteiro,
a rotação do personagem está sendo feita
no processo físico, que faz com que o
personagem fique
voltado para a direção
da entrada do movimento Vamos declarar uma nova variável
na parte superior do script, quer ver a
direção como três E substitua a direção
de entrada direção desejada
na chamada de função. Então, antes dessa chamada de função, podemos verificar se o personagem
está preso a um alvo. Se eles estiverem presos
a um alvo, a direção que
eles desejarão enfrentar será em direção ao alvo, que podemos determinar facilmente
subtraindo suas posições
globais Se eles não estiverem bloqueados,
eles desejarão ficar voltados para a direção da
entrada de movimento, da mesma forma que estavam antes. Agora, o personagem enfrenta
o alvo bloqueado,
mas suas
animações em movimento locais não parecem muito boas, pois elas se
misturam apenas com base na
rapidez com que o personagem está se movendo
e não na Na máquina de estado da
árvore de animação do personagem, eles estão no estado de salto ocioso porque não há
piso na cena O estado de movimento loco é
um espaço de mistura unidimensional, combina as
animações de andar e correr em marcha lenta com base na velocidade de movimento do
personagem Vamos remover esse estado e substituí-lo por
outra máquina de estado. Reconectando as transições
aos outros estados, começando com uma
transição do início
para a locomoção para
torná-lo Eu
habilitei a transição
para o jump start com um
peso cruzado de 0,3 segundos. E salte da terra para a troca de
locomoção no final com um
destino cruzado de 0,67 segundos Vou omitir temporariamente a transição
da locomoção para a
marcha lenta enquanto trabalho na máquina de estado de locomoção, para que o personagem permaneça no estado de locomoção e eu
possa ver
os resultados em locomoção e eu
possa ver
os na máquina de estado de locomoção, para que o personagem permaneça no estado de locomoção e eu
possa ver
os resultados em tempo real. Pressionar o botão play
forçará o personagem
a entrar no estado de locomoção e ele jogará porque está
vazio Dentro do estado de locomoção, precisaremos ter
dois conjuntos diferentes de animações de locomoção para
quando o personagem estiver
preso a um alvo
e quando
não estiver, e poder fazer a transição entre eles não estiver, e poder O padrão será o
mesmo de antes, um espaço loiro unidimensional Digamos que não está bloqueado. Então, também podemos adicionar um espaço loiro
bidimensional. Vamos nomear este bloqueado. Adicionar uma transição
de inicial para não bloqueada torna
essa a padrão. Podemos então fazer a transição
entre não bloqueado para bloqueado se o valor
do alvo não for nulo, o que podemos encurtar para apenas alvo e fazer
um pequeno crossfade E volte
para o alvo não bloqueado, se não estiver bloqueado, com
o mesmo crossfade Dentro do espaço de mistura não bloqueado
. Podemos recriá-lo
exatamente como era antes, com um valor mínimo
de zero misturando animações de marcha lenta, caminhada e corrida com base na velocidade de movimento do personagem Feito isso, use as migalhas de pão para
subir um nível até
a máquina de estado de locomoção
e pressione o botão play na
máquina estado bloqueada para forçar o personagem a
entrar Dentro do espaço de mesclagem bloqueado
, combinaremos
as animações com base na direção em que o personagem está se movendo em relação à direção para
frente, que é em direção ao alvo Vou configurar o ajuste da grade em incrementos de um para
facilitar as coisas Se posicionarmos nossa visão para
ficar atrás do personagem e imaginarmos que ele está preso em um alvo à sua frente
, o eixo y
representa a rapidez o personagem está se aproximando
ou se afastando do alvo. O eixo x representa a
rapidez com que o personagem está se movendo
para a esquerda ou para a direita
, contornando o alvo Vamos começar colocando a animação
ociosa no meio. Para o eixo x,
vamos querer colocar uma animação de metralhamento esquerdo no
lado esquerdo e uma animação lado esquerdo e uma metralhamento direito
no lado direito Para o eixo y, podemos colocar uma animação em execução na posição avançada,
o que gerará
triângulos no espaço de mesclagem mostrando como as
diferentes animações serão mescladas E adicionando uma animação andando
para trás na posição y negativa, também
adicionaremos mais triângulos Se mudarmos a posição de mesclagem, podemos ver a aparência do
personagem enquanto damos a entrada de movimento
em qualquer direção. Dependendo dos
ativos que você está usando, você também pode ter animações de
movimento diagonal para adicionar a esse espaço de mesclagem Às vezes, essa prévia
não
simula com precisão como o personagem
se comportará enquanto o
jogo estiver rodando E você deve sempre
testá-lo jogando o jogo para ter certeza de que
fica bem no jogo. Mas antes de fazermos
isso, vamos retornar ao nível raiz
da máquina de
estado e adicionar a transição da
locomoção para o salto ocioso sob a condição de
que o personagem não
esteja no chão Eu costumava usar um tempo de cross fade de 0,3 segundos para essa transição Também precisamos atualizar a parte
do nosso script, que define a
posição de mesclagem do espaço de mesclagem, o que no script do meu personagem está acontecendo na física terrestre. Selecionando a árvore de animação, podemos copiar o
caminho da propriedade da posição de
mesclagem não bloqueada e atualizada
na função set. Mas isso só precisa ser definido se o personagem não estiver
preso a um alvo. Se eles estiverem bloqueados
em um alvo, precisaremos definir
a posição
de mesclagem do espaço de
mistura bloqueado. A posição de mesclagem bloqueada é um vetor
dois com um x e um y, que precisaremos calcular. Então, vamos declarar uma variável para mantê-la chamada locked on blend Para evitar repetir os mesmos
cálculos várias vezes, também
declararei
outra variável para armazenar a velocidade
relativa do personagem,
que será sua velocidade x z
dividida pela velocidade dividida pela Depois de calcular esse valor, a posição
de mesclagem do espaço de
mesclagem não bloqueado pode ser definida
para o comprimento desse vetor Se o personagem estiver
preso a um alvo, podemos encontrar o valor x da posição de
mistura usando o produto escalar do vetor de base global
x da plataforma com sua velocidade relativa O produto escalar de dois
vetores resulta em um número que representa o quão
semelhantes ou diferentes eles são Então, estamos verificando se
a velocidade
relativa do personagem é semelhante a velocidade
relativa do personagem é a um vetor apontando
diretamente para a direita Dependendo de como seu
personagem está configurado, qual direção é
considerada para frente, talvez seja necessário
multiplicar esse valor por menos um para revertê-lo A posição de mesclagem y também pode ser determinada usando
o mesmo método, mas usando o vetor z
direto do caractere. Em seguida, enquanto estiver
bloqueada em um alvo, a câmera deve olhar para o alvo, não para o personagem do
jogador. Na função de
processo da câmera, ignorando o Delta, se
houver um alvo, podemos dizer
à câmera que olhe para o alvo e adicionar 1 metro para
não olhar para os pés Ao definir o
valor do alvo, se o alvo for definido como nulo, podemos redefinir a rotação da
câmera podemos redefinir a rotação da
câmera
para voltar ao
mesmo que seu nó pai, o braço de mola, definindo
sua rotação para
o vetor 30 Também podemos
acionar a função de bloqueio se o alvo atual sair do
nosso limite de alcance visível O éter é bloqueado ou mudança
automática
para um alvo mais próximo Então, vamos adicionar um sinal para quando o alvo atual
sair do alcance e emiti-lo se o corpo que saiu da área for
o Podemos então conectar esse sinal ao script de
manipulação de entrada do player. Chamando a função de
bloqueio de alternância. Dependendo se você
deseja que o comportamento mude para o
alvo mais próximo ou simplesmente se bloqueie, talvez
queira vincular
um argumento verdadeiro para a força do parâmetro No script Spring Arm, enquanto estiver preso a um alvo, queremos que o braço de mola
sempre aponte para longe do alvo para manter o alvo e o personagem do
jogador à
vista da câmera. Vamos adicionar uma nova variável para manter essa direção
como um vetor três. Então, quando o valor
do alvo está sendo definido, se não for nulo, podemos definir o valor da direção do alvo como a
diferença em nossa posição global menos a posição global do
alvo Isso resultará em
um vetor apontando do alvo de volta para
o personagem do jogador. Podemos então reutilizar a função
de rotação de interpolação, mas ela espera um parâmetro flutuante
representando uma Podemos obter a rotação y, que apontará
nessa direção usando a função trigonométrica
A t dois, fornecendo os valores x e z da
nossa Depois que o alvo for definido, o braço de mola girará
a câmera para ficar
na direção oposta
ao alvo atrás do jogador. Mas queremos que fique lá. Na função de processo, se o valor do alvo tiver
sido definido e entre parênteses,
se a interpolação não
existir ou não estiver em execução, o que
significa que a interpolação terminou
e o braço da mola
está em posição, podemos realizar os mesmos cálculos
,
mas apenas definir
o
valor da rotação
y diretamente em vez de fazer outra significa que a interpolação terminou
e o braço da mola
está em posição, podemos realizar os mesmos cálculos
, mas apenas definir
o valor da rotação
y diretamente em vez de y diretamente em vez Isso manterá o braço de mola apontando para longe do alvo, enquanto estiver preso ao alvo, mantendo o alvo
e o
personagem do jogador à vista da câmera. Por fim, no script de manipulação
de entrada do jogador, queremos evitar que
o jogador
gire o braço da mola
enquanto está preso em um alvo Isso está acontecendo em dois lugares
diferentes no meu script, um para controles de PC
usando o mouse e outro para
suporte de controle com o controle direito. Então, vou apenas incluir ambos em uma
instrução if para não permitir
essas entradas enquanto estão bloqueados em um alvo. Vamos experimentá-lo. Quando bloqueamos um inimigo, a câmera foca
no alvo,
enquanto o braço da mola gira para
posicionar a câmera
na direção oposta Movendo o personagem,
eles giram para enfrentar o inimigo e animar
movimentos fluidos em todas as direções O braço de mola mantém a posição da câmera de
estar atrás do personagem, apontando para longe do alvo, enquanto a câmera continua olhando
para o alvo. Os controles normais da
câmera do jogador foram desativados
enquanto estavam bloqueados. Se o alvo bloqueado
estiver fora do alcance, ele mudará
automaticamente para o alvo mais próximo ou será
bloqueado se não houver
um em quem se fixar. Se forçarmos o bloqueio,
a câmera se
concentra novamente no personagem do jogador, o controle
normal do braço de
mola é retomado
e as animações de locomoção do personagem animações Agora temos nossos nós de
jogadores adaptando seus comportamentos para ficarem
presos em um alvo Na próxima lição, faremos com que o personagem do jogador
realize ataques. Te vejo na próxima aula.
5. Ataque: Olá, amigos.
Na lição anterior, mudamos o comportamento dos nós
do jogador enquanto
estavam presos a um alvo. Nesta lição, adicionaremos animações de
ataque para que os personagens possam
atacar uns aos outros Vamos começar abrindo as configurações
do projeto, a guia do mapa de entrada e adicionando um novo
evento de entrada para atacar Vou usar o botão esquerdo do mouse
e o botão direito do ombro
no meu controle. Em seguida, no script do manipulador de
entrada do jogador, podemos verificar se o botão de
ataque foi pressionado ao verificar as entradas de controle do
personagem Se o botão de ataque
foi pressionado nesse quadro, devemos mandar o
personagem atacar. Mas e se o
personagem estiver ocupado? Eles podem estar pulando ou
realizando alguma outra ação e talvez não queiramos que eles consigam atacar neste
momento Exigir que o jogador
espere até que o ataque seja possível antes de
pressionar o botão seria bastante frustrante A maioria dos jogos modernos
considera que o pressionamento do botão é válido por um curto período
após o pressionamento do botão, que é conhecido como buffer
de entrada Vamos adicionar uma hora ou um nó
ao manipulador de entrada do player. Nomeie seu buffer de entrada e defina sua
propriedade one shot como true, para que ele faça a contagem
regressiva apenas uma vez por vez Obtendo uma referência a esse cronômetro de buffer de entrada
usando addon ready, podemos iniciar o cronômetro
depois de mandar o personagem atacar e aguardar o esse cronômetro de buffer de entrada
usando addon ready,
podemos iniciar o cronômetro
depois de mandar o
personagem atacar e aguardar o sinal de tempo limite. Depois que o cronômetro tiver
contado até zero, diremos
ao personagem que
cancele a instrução dada para atacar Então, a qualquer momento enquanto o
cronômetro estiver em contagem regressiva, o personagem tentará
atacar quando estiver pronto O tempo de espera padrão para
o cronômetro é de 1 segundo, o que é um
tempo razoável para o buffer de entrada de ataque Outra entrada que talvez queiramos armazenar
em buffer é a entrada de salto. Seguindo o
mesmo padrão da entrada de ataque, podemos iniciar o cronômetro, aguardar o sinal de tempo limite cancelar
a entrada de salto No script do personagem, vamos começar criando uma
nova região de código para combate. Em seguida, mova a
função alvo do jogador para essa região. Precisaremos de uma função pública
para mandar o personagem atacar e outra para
pedir que ele cancele
a instrução. A função de salto também precisará de uma combinação e cancelamento da função de
salto dois. O objetivo principal
dessas funções é definir variáveis que serão verificadas
pela árvore de animação para que ela saiba para quais
estados viajar. Na parte superior do script, adicionaremos mais
variáveis para indicar intenções
do personagem sobre o
que ele quer fazer a seguir, entradas
armazenadas em buffer como booleanos, se ele quer
pular ou atacar Em seguida, a função de ataque
definirá a
variável want to attack como verdadeira e cancelar o ataque a retornará
como falsa. Como a entrada está
sendo armazenada em buffer, não
precisamos
mais exigir que o personagem possa
se mover ou ficar no chão, e podemos delegar
essa responsabilidade à máquina de estado
das árvores de animação E também não precisamos fazer com que a reprodução da máquina de
estado da árvore de animação viaje
para o
estado inicial Faremos com que essa transição seja
automática se as
condições forem atendidas. Mas não queremos que essas duas variáveis sejam verdadeiras
ao mesmo tempo. O personagem vai
querer pular ou atacar, não os dois. Portanto, sempre que uma
entrada em buffer for definida como verdadeira, todas as outras serão definidas como
falsa,
substituindo a falsa,
substituindo Na
cena do personagem, selecionando a árvore de animação e alternando para o painel da árvore de
animação, podemos ver a máquina de estado. Vamos mudar a
transição da locomoção para o
salto e começar a ser automática, com a
condição de que o personagem esteja no chão, possa
se mover e queira Agora, o personagem pulará
automaticamente assim que puder, dentro de 1 segundo após
pressionar o botão de pular. Isso é particularmente útil para encadear saltos
um após o outro, já que o jogador
poderá pressionar o botão de pular antes
de cair no chão Mas, olhando para a máquina de estado de
salto, vamos considerar como incorporar
as animações de ataque Poderíamos fazer a transição
da locomoção para o ataque e vice-versa Mas as animações
ficariam ruins se
quiséssemos que o personagem pudesse se
mover enquanto ataca Eu não permitiria que o personagem
atacasse enquanto pulava. Em vez disso, seria melhor
separar as animações que envolvem mover o personagem das de
execução de ações Se sua
máquina de estado ainda não tiver sido salva como um
recurso do projeto, clique no menu suspenso ao lado da raiz
da árvore e selecione Salvar como. Eu já salvei a minha
na
pasta de cenas de personagens e a chamei de animações de
personagens Mas vou renomeá-lo
para movimentos de personagens. Com a máquina de estado salva, vamos removê-la da árvore de animação do
personagem
e, em vez disso, substituí-la por
uma árvore de combinação de nós de animação. O painel da árvore de animação
agora exibe um gráfico, que conterá nossa árvore de mesclagem, permitindo combinar qualquer
quantidade de animações Clique com o botão direito do mouse no
espaço vazio e selecione carregar. Em seguida, navegue pelos recursos
do projeto para encontrar a máquina de estados de
movimento do seu personagem. A máquina de estado que usávamos anteriormente agora é um nó
no gráfico da árvore do Blend, e o resultado da máquina de
estado
será gerado pelo pino
no lado direito. Se conectarmos a saída
da máquina de estado à
saída da árvore de mesclagem
, a animação
funcionará exatamente como antes. Mas o objetivo
da árvore de mesclagem é combinar várias
animações Vamos desconectar o pino. Em seguida, clique com o botão direito do mouse e
adicione uma mistura de dois nós. O nó de combinação de dois
começará com a animação
conectada ao pino
de entrada e se misturará em uma porcentagem da animação conectada ao pino de entrada de
combinação. O resultado dessa mistura será saída do pino
no lado direito, que podemos conectar à saída
das árvores de mistura. A animação que queremos
misturar com os
movimentos do personagem
serão as ações do personagem,
ou seja, seus ataques. Podemos adicionar outra máquina de
estado
à árvore de mesclagem e
chamá-la de ação. Em seguida, conecte sua saída
ao pino de entrada de
mistura de dois nós. Em seguida, abriremos a máquina de estado de
ação e iniciaremos o personagem
na animação ociosa Transição do início para o
inativo para torná-lo o estado de ação
padrão Em seguida, precisaremos ver
nosso personagem e iniciar
as máquinas de estado de movimento e ação
clicando
no botão play em seus
respectivos estados iniciais. Em seguida, retorne à raiz
da árvore de mistura. Nosso personagem ainda
parece estar na animação jump idle porque
a porcentagem da
animação de ação que
está sendo misturada
a ela
é atualmente zero Se arrastarmos a
alça até uma, podemos ver a animação mudar
gradualmente de
pular inativo para inativo Em seguida, clique no botão
Editar filtros e ative a opção Ativar filtragem Vamos
tirar a janela do caminho para que possamos ver nosso personagem enquanto
filtramos ossos individuais, decidindo em quais ossos
nossas animações de ação devem ser aplicadas
e quais não Ative todos os ossos que compõem a parte superior do corpo do
personagem Agora, a parte inferior do corpo do personagem, incluindo sua posição, está sendo afetada pelo estado
do movimento. Pule inativo, enquanto
a parte superior do corpo está sendo controlada pelo estado
de ação ocioso Isso nos permite combinar essas animações de três
maneiras diferentes Se o personagem estiver se movendo, mas
não executando nenhuma ação
, a
quantidade de mistura será zero, usando somente a saída
da máquina de estado do movimento. Se o personagem estiver executando
uma ação, mas não
estiver se movendo, a
quantidade de mistura será uma e os filtros serão desativados, usando somente a saída
da máquina de estado da ação. Se o personagem estiver se movendo
e executando uma ação
, os filtros
serão ativados. Usando a saída da máquina de estado de
movimento para a parte inferior do corpo do personagem e a saída da máquina de
estado de ação para
a parte superior do corpo. Vamos chamar essa mistura de dois
nós inferior e superior, já que ela mistura as animações da
parte superior do corpo com as animações inferior do corpo Mas se a
quantidade de mistura for zero ou uma, as animações em uma
das máquinas de estado não serão
executadas para economizar tempo de processamento, que pode resultar em
alguns problemas se
confiarmos nelas para definir
propriedades ou chamar métodos Pode ser útil ter sempre as duas máquinas de estado
funcionando o tempo todo, mesmo que o personagem não esteja
executando nenhuma ação
ou não esteja se movendo. Para garantir que ambas as
máquinas de estado estejam sempre ativas, podemos definir a quantidade de
mistura para 1%
e, ao realizar uma ação, aumentá-la para 99%. Podemos supor que ele deve começar com uma quantidade de mistura de 1% já que o personagem não
realizará nenhuma ação
quando carregado pela primeira vez. De volta ao roteiro do personagem, como a árvore de animação se tornará
muito mais complexa, seria uma boa ideia abstrair seus comportamentos
em seu próprio roteiro. Podemos remover a variável
de reprodução da máquina de estado do script
do personagem e adicionar um novo script
à árvore de animação Vou salvá-lo na pasta de scripts de
personagens. No novo script da
árvore de animação, nosso principal objetivo é criar as três
combinações de animação que acabamos de mencionar Na função de processo, precisaremos definir o parâmetro de quantidade de
mistura como fizemos com
os espaços de mistura. Copiar o caminho da propriedade e
especificar uma quantidade de mistura. Vamos transformar a
quantidade de mistura em uma variável
flutuante privada com um valor
padrão de 1% e passar isso como argumento Em seguida, precisaremos alterar
o valor da quantidade de mistura com base no fato de o
personagem estar ou não realizando uma ação. Vamos armazenar a
reprodução das máquinas de estado de
ação em uma variável Desta vez, usando
a palavra-chave self, já que esse script está
anexado à árvore e usando o caminho da propriedade para a reprodução da máquina de estado de
ação Em seguida, na função de processo, podemos verificar em qual nó a reprodução do estado da ação
está atualmente E se estiver no estado ocioso, isso significa que
o personagem
não está realizando nenhuma ação e podemos definir a quantidade de
mistura em 1% Caso contrário, eles estão executando uma ação e
podemos configurá-la para 99%. Mas essa será uma mudança
instantânea que pode parecer um pouco Então, em vez de definir a
variável diretamente para 1% ou 99%, vamos movê-la em direção a
esse número um pouco ao longo do tempo. Usando a função move em direção, podemos começar do que a
variável é atualmente, movendo-a em direção ao que
queremos que seja por Delta. Isso fará com que a
transição demore 1 segundo, o que é um pouco longo. Então, vamos multiplicar Delta por uma nova variável para
manter a velocidade de mistura, que darei um valor
padrão de quatro A transição levará
um quarto de segundo. Para ativar ou desativar os filtros, precisaremos acessar diretamente o nó de
combinação de dois. Então, declarar uma
variável para mantê-la, que é do tipo
animation node blend two Podemos acessá-lo a partir da raiz
da árvore de animação, usando a função get node. Essa função aceita
um nome de string, que podemos especificar como
o mesmo nome que demos ao nó no
gráfico da árvore de mistura, inferior mais superior. Tenha cuidado para que a
grafia seja exatamente a mesma. Não podemos ativar ou
desativar os filtros durante o processamento da
árvore de animação. Então, vamos criar uma função pública para permitir que o
script do personagem faça isso por nós, dizendo à árvore de animação se o
personagem está se movendo ou não. Se o personagem estiver se movendo, os filtros devem
estar habilitados para combinar as ações da parte superior do corpo com os movimentos
da parte inferior do corpo. Se o personagem estiver parado, os filtros podem ser desativados para usar apenas as animações de
ação Enquanto estamos aqui, vamos também adicionar mais
duas funções para
definir as quantidades de mistura dos espaços de mistura de locomoção
para mantê-los abstraídos do script
do personagem Defina a mistura bloqueada, aceitando um
parâmetro vetorial dois para a quantidade da mistura, definindo o parâmetro
da
quantidade de mistura do espaço de mistura bloqueado. E defina como não bloqueado na mistura, aceitando um parâmetro flutuante
para a quantidade da mistura, definindo o parâmetro
da
quantidade de mistura do espaço de mistura não bloqueado De volta ao script de caracteres, podemos ver que
os caminhos das propriedades para os valores de mistura não
são mais válidos, pois não se referem à máquina de estado
do movimento. Abstraindo essas
funções, manteremos todas as alterações na árvore de
animação contidas em seu próprio script No processo normal da física, também
precisaremos dizer à árvore de animação
se
o personagem
está ou não se movendo no momento. No entanto, agora estamos assumindo
que cada personagem deve ter esse script anexado
à sua árvore de animação e que eles estão usando
a mesma árvore de animação Então, vamos salvar nossa
nova árvore de animação como um recurso do projeto. Vou colocá-lo na pasta de cenas do
personagem, junto com a máquina de estado do
movimento do personagem. Em seguida, atualize cada um dos
outros personagens para usar a nova árvore de animação e
anexe o script a ela, para que todos
funcionem da mesma maneira. Estou usando apenas o Bárbaro e os esqueletos neste projeto, mas o mago noturno e o ladino também
devem ser atualizados
se você os estiver usando No entanto, isso cria
um novo problema. Se todos os caracteres compartilharem o
mesmo recurso de árvore de mistura
, a alteração da propriedade enable
filters para um caractere a
alterará para todos os caracteres. Podemos contornar isso dando cada personagem sua própria cópia
exclusiva da árvore de mistura. Para evitar ter que replicar todas as mudanças na árvore de
mistura de cada personagem todas as vezes, usarei um atalho simples No script da árvore de animação, durante a função ready, definirei a
propriedade
raiz da árvore uma duplicata
da árvore de mistura Passar true como argumento também
duplicará quaisquer subrecursos que esse
recurso esteja Como a árvore de mistura, essa árvore de
animação está sendo usada, pois sua raiz não é mais a mesma que foi
originalmente atribuída. Precisaremos
atribuir os valores da reprodução
do estado de ação e da combinação de dois nós
após essa duplicação Agora, toda vez
que um
personagem for carregado, ele fará sua
própria cópia exclusiva da árvore de mistura e
poderá alterar seu comportamento de
filtragem sem afetar
outros personagens Vamos voltar à máquina de estado de
ação dos personagens. Nosso personagem ainda não tem
nenhum item equipado, então vamos
transformá-lo em ídolo desarmado Por enquanto, vamos estabelecer que
a condição para essa transição seja se eles estão mirando em um inimigo
ou se
querem atacar usando um cruzamento
curto, e eles podem
voltar se não estiverem
mirando em um inimigo e
não quiserem Depois, para manter as coisas organizadas. Adicione também outra máquina de estado
chamada ataques desarmados e faça
a transição para a máquina de estado se o personagem
quiser atacar Eles podem então voltar para o ídolo
desarmado no final da animação
de ataque Editando a máquina de
estado desarmada. Vamos começar com o soco de ataque
masculino desarmado A. Isso fará
a transição para o final ou para soco de ataque masculino
desarmado B no final da animação, com base no
fato de o personagem
querer ou não Podemos repetir esse padrão
fazendo a transição para um chute de ataque masculino final ou desarmado
no final da animação, com base no fato de o personagem
querer ou
não atacar E podemos criar uma combinação
infinita de ciclismo voltando
ao primeiro golpe, desde que o jogador continue
pressionando
o Quando eles pararem de pressionar
o botão de ataque, a máquina de estado fará a
transição para o fim, que
voltará ao modo inativo desarmado Talvez também queiramos restringir a forma como o jogador se move
enquanto ataca Por exemplo, não
faria nenhum sentido o personagem se movesse
durante a animação do chute, já que seus pés deveriam estar ocupados. Vou ampliar a exibição da faixa de
animação para ajustar melhor a duração
dessas animações. Vamos adicionar uma função pública ao script
do personagem
para restringir o movimento, aceitando um parâmetro booleano para determinar se o
personagem pode ou não se mover Em seguida, definiremos o valor
da variável
de movimento como o oposto. Na animação de
chute do personagem. Podemos adicionar uma faixa de método de chamada chamando um método no nó raiz do
personagem. Chamando a função de restrição de
movimento no início da animação, passando true como argumento, restringindo o
movimento do personagem ao chutar E outra tecla no final
da animação pode restaurar a habilidade de movimento do personagem alterando o
argumento para falso. Mas para que isso funcione,
precisamos retornar à árvore de mesclagem e
adicionar funções aos filtros de combinação de dois nós para que, se o personagem estiver se movendo
e executando uma ação, as funções de ações
sejam chamadas. Vamos experimentar.
Nossas animações parecem estar funcionando
como antes Assim que mandamos o
personagem atacar,
ele passa para o estado ocioso desarmado antes de realizar um Se continuarmos clicando, eles
continuarão atacando repetidamente, percorrendo as diferentes animações de ataque
desarmado É até possível se mover
ou pular enquanto ataca, e o personagem
usará as animações apropriadas para a parte superior e inferior do corpo, mas não poderá
se mover ou pular enquanto Se nos fixarmos em um alvo, o personagem passa
para o estado ocioso desarmado
e o bloqueio
volta para o ídolo normal Agora temos nosso personagem
realizando ataques desarmados. Na próxima lição, adicionaremos animações de ataque com
armas. Te vejo na próxima aula.
6. Arma: Olá, amigos.
Na lição anterior, combinamos ações da parte superior do corpo
com movimentos da parte inferior do corpo, permitindo que nosso personagem
realize ataques desarmados Nesta lição, também adicionaremos uma variedade de
animações de ataque com armas Vamos começar na árvore de
animação dos personagens, onde
já temos ataques desarmados, ociosos
e desarmados Seguindo esse
padrão, adicionaremos a animação inativa em duas mãos Neste pacote de ativos,
não há animações inativas com uma mão ou duas
rodas Mas podemos simplesmente
adicionar duas novas cópias da animação ociosa
e renomeá-las A partir de cada uma dessas animações
inativas, podemos nos conectar a máquinas de
estado de ataque que funcionam exatamente
como os ataques desarmados Conectando-se
de cada uma das animações inativas aos ataques, se o
personagem quiser atacar, e retornando no
final da Só precisamos de uma maneira de dizer
ao personagem qual conjunto de animações usar com
base na arma equipada Neste projeto, temos
um script chamado enums, contendo todas as nossas enumerações, ao qual
adicionaremos Começando com desarmado
como padrão, depois listando cada um
dos diferentes tipos de armas que precisam de animações diferentes, mala de
uma mão, mala de duas mãos e roda
dupla É importante saber que
a enumeração é
apenas uma lista numerada, então cada um desses valores
são na verdade números, começando com
desarmado sendo zero,
uma mão é uma, duas mãos é duas
e roda dupla é três e No
script do personagem, adicionaremos outra variável chamada animação de
ataque com um tipo de nossa
nova enumeração Podemos exportar essa variável
para fins de teste. Vamos mudar a animação de ataque do
personagem para algo diferente de desarmado Vou usar combate corpo a corpo com duas mãos. De volta à máquina de
estado de ação, podemos definir a
condição de transição de inativo para inativo
desarmado para ser se animação de ataque do personagem for zero,
o
que está desarmado em
nossa enumeração, e também pelo menos uma das outras condições
colocando-as entre A condição de devolução também será oposta. Ou a
animação do ataque não é zero ou as outras duas
condições são atendidas. Adicionando transições a cada um
dos diferentes estados de inatividade, podemos definir suas condições para serem as mesmas de inatividade desarmada, usando
apenas um valor diferente
para Também darei a cada um deles o
mesmo tempo de cross fade. Em seguida, voltando ao modo inativo sob condições logicamente
opostas Dentro de cada uma das máquinas de estado de
ataque, podemos usar as
animações de ataque da mesma forma que fizemos com
os ataques desarmados Existem quatro ataques diferentes com
uma mão, criando um ciclo de animações
diferentes , desde que o personagem
queira continuar atacando Repetir o mesmo processo
para ataques com duas mãos, que têm apenas três ataques
diferentes E a máquina de
estado de duas rodas também tem apenas três ataques Podemos
testar isso no jogo,
já que a animação de ataque dos personagens está configurada para duas mãos, eles usam as animações de
ataque com duas mãos Podemos dizer a eles que usem animações de ataque com uma
mão
ou animações de duas rodas
. Agora, só precisamos mudar a variável
ao equipar
itens para o personagem Nos recursos personalizados, precisaremos de uma classe mais
específica para descrever uma arma
herdada do equipamento Dando a ela o nome de classe arma, podemos adicionar uma variável extra
exportada para armazenar o tipo
de arma e podemos usar a mesma
enumeração do Então, qualquer um dos
recursos do item do projeto que são armas pode ser
reclassificado como arma, dando a eles um valor
para o tipo de arma, o personagem saiba quais animações usar
ao equipá-las Para fins de demonstração,
atualizarei o x para ser uma arma de
uma mão. Lembre-se de preencher novamente
todos os campos que não foram
transferidos ao
alterar o script do recurso O grau como arma de
duas mãos
e o punhal como arma de
duas rodas No int ou qualquer script que você esteja
usando para equipar itens, precisaremos de uma exceção para se o item que está sendo
equipado for E se for
uma arma de duas mãos
ou uma arma de dupla empunhadura
, precisaremos
remover qualquer coisa o personagem tenha equipado
em seu espaço externo Verifique primeiro se o arquivo, a matriz de equipamentos de
progresso tem algo equipado
no slot improvisado Em seguida, usarei isso para
indexar os botões
do item no inventário do jogador e remover o E
de equipado do botão. Em seguida, defina também o valor das matrizes do
equipamento para menos um ou vazio Em seguida, direi ao
personagem que qualquer equipamento em seu
soquete manual No roteiro do personagem, o personagem precisará saber o que está segurando
nas mãos. Vamos adicionar variáveis do tipo nó três D para segurar o equipamento principal e
não manual. Nosso personagem usando uma
arma também pode ter lógica
extra adicionada para determinar
se o item for uma arma O item principal da mão do personagem pode então ser atribuído
a essa arma, e as animações de ataque dos personagens podem
ser configuradas
para coincidir com
as da arma que está sendo equipada Se o item for uma arma do tipo
roda dupla, também
adicionarei outra cópia
duplicada da arma no soquete manual do
personagem E atribua-a à variável
improvisada. Ao retirar um
equipamento,
se esse equipamento estiver sendo
removido da mão principal do
personagem,
podemos definir a variável da mão
principal como
nula e também verificar se ela
está usando se esse equipamento estiver sendo removido da mão principal do
personagem,
podemos definir a variável da mão principal duas armas no momento Se estiver empunhando duas vezes, direi ao personagem que também faça o item
de improviso E então eu vou definir a
animação do ataque para desarmado. Da mesma forma, se o soquete que está sendo
desligado estiver desligado, devemos definir a variável
improvisada Não precisamos mais exportar
a animação do ataque, pois agora ela será definida
pela arma equipada. Agora, o personagem começa a
usar ataques desarmados. Mas quando equipado com
uma arma de uma mão passa a usar ataques com
uma mão. Podemos equipá-los com um escudo, depois mudar para uma arma de
duas mãos, e o escudo será removido
automaticamente O personagem agora usa animações de ataque com duas
mãos. Mudando para os punhais de duas
rodas,
o personagem tem um
punhal nas duas mãos
e usa as animações de ataque de duas e usa Ao equipar os punhais, personagem volta
a
usar ataques desarmados A última coisa que nossos ataques
precisam são caixas de quadril. Áreas de colisão para detectar se o ataque realmente atinge um
inimigo e causa dano Abrindo as cenas das armas, podemos adicionar caixas de acerto
a cada uma delas. Usando um nó D de área três, que não será monitorado
ou monitorado por padrão, nem terá nenhuma camada de colisão ou máscara de
colisão até que
sejam instruídos a fazê-lo Como esses
modelos de personagens têm membros
curtos e armas pequenas, seus ataques não
chegam muito longe Então, vou ser muito
generoso com suas caixas de quadril, tornando-as maiores do que
as armas reais. Criando um novo script para as armas,
herdando do item Vou substituir o
script anexado
ao nó raiz da arma
e abri-lo para edição. Podemos dizer à
arma que pegue ou faça referência à
caixa de acerto usando o complemento pronto. Em seguida, adicione funções para definir a
máscara de colisão das caixas de acerto para um novo número inteiro E outra que
ativará ou desativará a caixa de acerto definindo
sua propriedade de monitoramento O personagem que segura
essa arma
agora pode especificar em qual camada de
colisão seus inimigos estão e
ativar a caixa de acerto ao
balançar a O modelo do personagem também
precisará uma caixa de quadril para ataques desarmados Assim como as
armas, elas não precisam ser monitoradas,
monitoráveis, nem ter uma camada de colisão ou máscara de colisão e
terão uma forma de
colisão de grandes dimensões Mas não precisamos
posicioná-lo agora e podemos delegar essa responsabilidade
às animações No
script do personagem, podemos obter uma referência à caixa do
quadril desarmada usando addon ready Lembre-se de adicionar um quadril
a cada caractere ou usar a
função get node ou null para evitar erros Também vamos exportar uma camada física de
três D para conter a camada de colisão dos inimigos
desse personagem Isso adicionará uma grade de números no
inspetor, assim como as camadas de colisão nas propriedades
das três notas D. Dessa forma, podemos especificar
que esse personagem
tentará atingir coisas na camada de colisão
inimiga de Hurt, que eu disse ser
a camada 18 Enquanto isso, inimigos usando
o mesmo script podem definir sua camada de colisão inimiga como a
camada colisão HRT do jogador Durante a função de preparação, podemos definir a máscara de colisão da caixa
do quadril desarmada como a camada de colisão
do inimigo Da mesma forma, sempre que uma
arma é equipada, podemos configurar sua máscara de colisão para ser a camada de
colisão do inimigo, ele
saiba quais camadas
mascarar , independentemente de
quem a esteja Em seguida, precisaremos de
algumas funções no script
do personagem
para ativar e
desativar as caixas do quadril das armas durante as animações de
ataque, aceitando um parâmetro booleano para especificar se a caixa do quadril está sendo ativada ou desativada e um número inteiro E eu vou dar a ela um valor padrão de um para significar a mão principal. Usando uma declaração de partida, podemos criar três casos
separados, ativando a caixa do quadril
para ataques desarmados, ataques mão
principal
ou ataques improvisados Se estiver desarmado, podemos definir a propriedade de monitoramento da caixa do quadril
desarmada Se for mão principal ou improvisada
, podemos dizer à arma ative ou desative
sua caixa de acerto As animações de nossos personagens
podem então ter faixas adicionadas a elas para ativar e
desativar as caixas de sucesso Vou demonstrar apenas com
um ataque de cada tipo, começando com um golpe de ataque
masculino com uma mão. Ao adicionar uma
faixa de método de chamada a essa animação, geralmente
esperaríamos que a caixa de acerto fosse ativada logo após
começar a girar Adicionando uma chave neste momento, podemos mudar o
argumento booleano para verdadeiro para ativar a caixa de acerto da arma principal do
personagem Em seguida, desativado no final
do swing, alterando
o argumento para false Isso evitará que inimigos
entrem
na arma quando ela não estiver se movendo
e não sejam feridos por ela, e só causará dano quando o personagem estiver realmente
balançando a arma com força O processo é o mesmo ao empunhar uma arma nas mãos Adicionar uma faixa e, em seguida, função
de enquadramento de
teclas ativa
a caixa de acerto no início
do giro da arma e desativá-la no final
do Ao empunhar duas vezes,
precisaremos especificar qual caixa do quadril
está sendo ativada, se é a
mão principal ou a mão livre,
alterando também o parâmetro
inteiro para dois, se a caixa do quadril que
está sendo ativada ou
desativada pertencer
à arma improvisada E quando desarmados, precisaremos não apenas
ativar a caixa do quadril, mas também posicioná-la
no local correto Usando uma trilha de propriedades para enquadrar a propriedade de
posição das caixas de quadril. Em seguida, alteraremos o
argumento inteiro nas chamadas de função para zero para indicar que
queremos usar a caixa do quadril desarmada É uma boa ideia
verificar se a caixa do quadril está
posicionada em pelo menos uma estrutura
antes de ativá-la É útil usar
vistas ortogonais para posicionar a caixa
do quadril exatamente no punho
do personagem em
pelo menos dois ângulos Em seguida, clique no ícone da
chave para enquadrar essa posição
na animação. Não poderemos testar
essas caixas de quadril até a próxima aula, quando adicionarmos caixas
feridas para elas atingirem. A caixa do quadril não só será
ativada com a animação, mas também seguirá
o punho do personagem Lembre-se de que você
precisará concluir esse processo para cada animação de
ataque. Agora temos nosso
personagem atacando com animações
diferentes
para cada tipo de arma Na próxima lição, permitiremos que os personagens se
machuquem e sofram danos. Te vejo na próxima aula.
7. Hit: Olá, amigos.
Na lição anterior, adicionamos caixas de acerto às nossas
armas e animações de ataque Nesta lição,
adicionaremos caixas de Hurt aos nossos personagens para que eles
possam ser atingidos por ataques. A caixa Hurt de um personagem é apenas
mais um nodo D da área três. Vamos adicionar aos modelos
de personagens. Eles não serão monitorados, mas serão monitoráveis
pelas caixas de sucesso Eles existirão na
camada da caixa de
ferimento do jogador ou
na camada da caixa
cardíaca do inimigo de forma adequada Mas não precisa mascarar nada pois eles não estão
monitorando de qualquer maneira. Para a forma de
colisão das caixas Hert, outra cápsula é muito comum, mas geralmente é menor que a forma de
colisão corporal do personagem e totalmente contida no modelo
do Não seria justo
que o jogador fosse
atingido por algo que
parece não fazer contato. Lembre-se de que
as armas estão usando caixas de quadril grandes,
então as caixas cardíacas serem menores
também seria razoável, mas vou fazer com que as minhas caibam na cabeça e no corpo do
personagem Em seguida, copiarei e colarei a mesma caixa de coração nas cenas do meu personagem
inimigo,
mudando sua camada de colisão para a
camada HRT inimiga Então, em nossas cenas de armas, usarei o machado como exemplo Precisaremos conectar
o sinal de área
inserida da caixa de acerto ao script da arma. Se a caixa de acerto dessa arma entrar na caixa de ferimento de
um personagem
, precisaremos dessa arma para causar
dano a
esse Por enquanto, vamos adicionar uma variável pública para o dano causado por
essas armas. Quando a colisão acontecer, precisaremos de uma referência ao personagem
ao qual a caixa
Hurt pertence No meu projeto, esse
sempre será o
nó principal da caixa Hurt. Podemos então dizer ao
personagem que sofra dano, passando o
dano da arma como uma discussão. Também pode ser bom saber de onde vem o
dano. Assim, podemos usar a
diferença entre suas
posições globais normalizadas Para manter todas as
informações de nossas armas em um só lugar, seu dano deve ser adicionado
ao arquivo de recursos como
uma variável exportada, e eu darei a ele o
valor padrão de dois danos Cada arquivo de
recurso de arma diferente pode então especificar quanto dano
essa arma causará Lembre-se de conectar também o sinal da área inserida para cada cena de
arma. Da mesma forma, a caixa de quadril
desarmada do nosso personagem também precisa uma conexão de sinal para instruir o personagem a causar
dano desarmado Pegar o pai da Hurt Box
e pedir que eles sofram um dano e forneçam
a direção normalizada Então, no script do personagem, quando criamos a instância da
arma, podemos definir seu dano o mesmo número
do recurso. I. Enquanto estamos aqui, vamos também escrever a função de receber dano
na região de combate. Aceitando a
quantidade de dano a ser sofrida, bem
como
a direção de onde o dano está vindo, dando a ele um
valor padrão de vetor 30. Para sofrer danos, nossos personagens precisarão de saúde. Vou adicionar uma categoria de exportação
para as variáveis de combate. Em seguida, declare um
para a saúde
máxima dos caracteres como um número inteiro, que definirei E sua saúde atual
também como um número inteiro, que podemos definir como sua saúde
máxima
usando addon ready Também vamos declarar alguns parâmetros
booleanos para determinar se o personagem está morto
ou não e se o dano sofrido
foi causado por trás, e também obter uma referência à caixa rt
do personagem
usando addon ready Ao sofrer dano, a saúde atual do
personagem será reduzida pela
quantidade de dano recebido, mas não queremos permitir que
ela fique abaixo de zero. Portanto, podemos usar a
função max para configurá-la para esse cálculo ou
zero, o que for maior O
booleano de trás pode então ser definido como verdadeiro se o produto
escalar da direção
do dano com o vetor de
base direta das plataformas de caracteres for um número
negativo Se a saúde
atual do personagem após sofrer dano for zero,
ele morrerá. Caso contrário, eles serão atingidos. Embora a animação de morte
seja automática, a animação de sucesso pode ser gerenciada pelo script das árvores de
animação, e informaremos
se o dano recebido estava abaixo ou
acima de um determinado limite Dessa forma, podemos alterar a animação do golpe com base na
quantidade de dano recebido. Também podemos monitorar a saúde
de um personagem
ou quando ele morre. Seria uma boa ideia
transmitir esses dois
eventos como sinais. Declarando um sinal para sempre que a
saúde do personagem mudar, podemos usar uma porcentagem
da saúde restante como argumento e outro sinal para quando o personagem morre Em seguida, emita o sinal de
mudança de saúde se eles
sofrerem danos e o sinal de morte
se o personagem morrer Para calcular a porcentagem
de saúde restante, basta dividir a
saúde atual pela saúde MX Mas como esses dois
valores são inteiros, o resultado
também será um número inteiro,
portanto, resultará apenas em zero ou Precisaremos fazer com que
pelo menos um deles flutue primeiro antes de
realizar a divisão, para que o resultado
também surja Se não quisermos mais que personagens
mortos sejam afetados por colisões, também
podemos definir sua camada de
colisão como zero,
sua máscara de colisão como uma, para que eles
sejam
afetados apenas pelo terreno e definir sua propriedade monitorável H
rtbach Também é possível
que um personagem
seja atingido ou morto enquanto
executa uma ação. Portanto, também devemos acompanhar quais ações
interrompidas podem causar problemas e corrigi-las em
uma função privada Por exemplo,
provavelmente deveríamos desligar todas as caixas do quadril se seus
ataques fossem interrompidos, o que também podemos fazer em
uma função separada, verificando se existem referências a cada uma antes de
desativá-las Na árvore de
animação dos personagens, queremos que o personagem que está
morrendo ou sendo atingido interrompa e
substitua
todas as outras Como essa árvore de combinação
já está salva como um recurso, podemos removê-la
da árvore de animação e substituí-la por
uma máquina de estado. No nível mais básico da máquina
de estado, começaremos com as animações de morte de nossos
personagens, já que elas terão a maior prioridade
absoluta sobre todas as outras animações Em seguida, adicione outra máquina de estado
para as animações de sucesso. Faremos a transição do golpe para a morte A se o
personagem estiver morto. Com um pequeno crossfade. Ou, alternativamente,
à morte B, se eles também
forem atingidos por trás dando prioridade a essa prioridade
, definindo-a como zero. Talvez não seja necessário nosso personagem
volte da morte, mas não faz mal adicionar
a transição com a condição de
que ele não esteja morto. Dentro da máquina de estado de acertos, faremos algo semelhante com as animações de sucesso e adicionaremos nossa árvore de mesclagem como animação
padrão aqui Ativando as transições para
as animações de sucesso e retornando à árvore de mesclagem no final de suas Com um crossfade
dentro e fora das animações de
sucesso, com a máquina de
estado da árvore de animação atualizada, vamos salvá-la como
um recurso do projeto Vou chamá-la de animações de
personagens. E pela última
vez, cada personagem pode ser atualizado para usar
a nova máquina de estado. No script Animation trees, precisaremos de uma referência
à reprodução do estado de ocorrência Além disso, como atualizamos
o formato da árvore, precisaremos atualizar todos esses caminhos
de propriedades. Agora acessaremos
o nó
de mesclagem obtendo o nó atingido, depois o nó da árvore de mistura
e, finalmente, o nó inferior
e superior da mistura de dois nós. Dando uma definição à
função get hit, podemos receber o parâmetro
booleano como se o personagem
está sendo atingido levemente ou não Em seguida, diga
ao estado de impacto que deve viajar para atingir A se for atingido levemente ou atingir B se for atingido com mais força. Vamos experimentá-lo. Se
socarmos o esqueleto, eles reagem ao serem atingidos levemente, equipando um machado e Eles são atingidos com mais força. Um
terceiro golpe e eles morrem, caindo para trás desde que
foram atingidos pela frente Podemos equipar o grande machado, que eu configurei para
causar um dano de cinco e matar outro
esqueleto por trás, e ele cair
para frente ao morrer Também seria
bom poder
rastrear a saúde do personagem do jogador na interface do usuário. Vamos adicionar um nó de controle
e chamá-lo de medidor de saúde. Vou colocar isso por trás de
todo o resto na interface do usuário. Isso precisará de um texto
direto para desenhar a borda, uma cor ereta como preenchimento e outro texto direto
se quisermos um ícone Vou usar uma moldura deslizante fina
como imagem da borda. É muito grande, então vou reduzi-lo para um
quarto de seu tamanho. E eu vou usar o ícone, um pequeno coração cheio para o ícone. Redimensione-o e posicione-o onde fique bem
em relação à borda Em seguida, definirei
a cor ect para combinar com
a cor do coração e definirei sua posição e
dimensões para preencher o medidor Vou redefinir sua propriedade de tamanho, ancorá-la no canto
inferior esquerdo Clicando e arrastando na propriedade
tamanho x do preenchimento, podemos ver como o medidor pode ser
facilmente configurado para qualquer porcentagem Anexando um script
ao medidor de saúde, podemos simplesmente chamá-lo de medidor para
reutilizá-lo em qualquer outro
medidor Obteremos uma referência
à cor de preenchimento ret
usando add on ready e também declararemos uma
variável para manter o tamanho ponto x do preenchimento quando
o medidor
estiver completamente preenchido, que é a configuração da propriedade
size dot x quando carregada pela primeira vez Em seguida, escreva uma
função pública chamada set value, aceitando um parâmetro de porcentagem
flutuante Tudo o que precisamos fazer é definir
a propriedade size x
da cor t como
a porcentagem multiplicada
pelo tamanho máximo Conectando o
sinal de mudança de saúde do
personagem do jogador à função de valor
definido dos medidores, ele agora
rastreará automaticamente a saúde do jogador Para testar o medidor de saúde. Vou apenas dizer ao
personagem que sofra
dois pontos de dano toda vez que o
jogador pressiona o botão de execução Agora podemos ver o medidor de
saúde do personagem se esgotar e o personagem morrer
quando está vazio Em seguida, reiniciarei a linha de
absorção de danos para voltar a funcionar. Agora temos nosso
personagem sendo atingido e sofrendo
danos causados por ataques. E na próxima lição, permitiremos que os personagens evitem
ser atingidos por esquiva Te vejo na próxima aula.
8. Dodge: Olá, amigos.
Na lição anterior, permitimos que nossos personagens
fossem atingidos por ataques,
sofressem danos e morressem. Nesta lição, vamos
ajudá-los a evitar danos ao se esquivar. Vamos começar nas configurações do
projeto, na guia Mapa de entrada, adicionando um
evento de entrada para se esquivar Vou usar a barra de espaço ou o
botão direito do meu controle. No script do jogador, podemos usar os mesmos métodos de pular e atacar para amortecer
a entrada de esquiva No script do personagem,
precisaremos de uma variável para determinar se o personagem
quer ou não se esquivar Mas uma esquiva não é
apenas uma entrada simples. Também requer uma direção
como vetor três. Na região de combate, precisaremos de uma função de esquiva
e uma função de cancelamento de esquiva,
configurando a variável booleana E com qualquer entrada armazenada em buffer, todas as outras entradas em buffer
serão Como já estamos armazenando a direção de entrada no script
do personagem, podemos verificar se esse é o vetor
30 no momento em que o
personagem foi instruído a se esquivar Se não der nenhuma contribuição, quero que o personagem
se esquive para trás Vou usar o vetor
dianteiro das bases das plataformas de caracteres, multiplicando-o por menos
um para revertê-lo Se estivermos dando uma entrada
direcional, quero que o personagem se
esquive nessa direção, mas sempre com força total Vou normalizar a direção para
remover a magnitude
da equação Na máquina de estado da
árvore de animação dos personagens, navegando
pelas
animações de morte e sucesso até a árvore de mistura
e, finalmente, a máquina de estado do
movimento Podemos adicionar as animações de esquiva em um espaço de
mesclagem bidimensional Transição de locomoção para esquiva se o personagem
quiser se esquivar
e de volta à locomoção Ambos com um cross fade. Como isso se conecta
à locomoção, a esquiva só será realizada enquanto o personagem
estiver no chão Você também pode querer
ter esquivas aéreas
conectadas ao estado de inatividade do
salto Dentro do espaço de mesclagem do Dodge, alterarei o ajuste da
grade para fatores de um Em seguida, adicione as animações
Dodge forward, Dodge backward, Dodge left e dodge right
que serão
misturadas para que o personagem
possa se esquivar em qualquer direção. O script da árvore de animação
precisará ser capaz de definir
a quantidade de
mistura desse espaço de mesclagem como um vetor dois, da mesma forma que definimos
a quantidade
de mistura das animações bloqueadas no
strafing De volta ao script do personagem, ao mandar o
personagem se esquivar, podemos fazer com que a animação
defina essa quantidade de mistura Mas a direção da esquiva é um vetor três no espaço global, enquanto a
quantidade de mistura da esquiva é um vetor dois no espaço local das plataformas de
caracteres Podemos calcular a quantidade de
mistura comparando a direção de esquiva com os vetores de espaços da plataforma
usando um Vou precisar
reverter a quantidade de mistura x multiplicando-a por menos Se experimentarmos isso,
a animação de esquiva reproduzida três vezes e o personagem não está realmente se movendo A animação se repete
porque o
desejo de se esquivar é válido por
um segundo inteiro, mas a animação dura
apenas 0,4 segundos. Portanto, ela se repetirá quantas vezes puder
até que a variável want to dodge volte a ser falsa antes que o 1 segundo termine Precisaremos definir
a variável como
falsa depois que a esquiva for
executada com sucesso e também aplicar alguma velocidade para
mover o personagem Adicionando outra função, assim como aplicar a velocidade de salto, aplicaremos a velocidade de esquiva e chamaremos essa função a
partir da animação Se essa função for chamada, o caractere foi evitado
com sucesso e podemos definir a
variável como falsa para evitar que mais esquivas
ocorram a partir de uma única entrada Em seguida, definiremos a velocidade do
personagem como a direção de esquiva
multiplicada pela força de esquiva Isso criará um
impulso repentino de velocidade, movendo o personagem rapidamente na direção em que
ele está se esquivando Criando outra variável
exportada para a força de esquiva do personagem Vou ajustá-lo para oito. Também pode querer que nosso dodge
tenha molduras para os olhos,
abreviação de molduras de invencibilidade Esse é um período de tempo em que o personagem não pode
ser ferido por ataques Assim como temos uma
função chamada por nossas animações de ataque para
ativar ou desativar a caixa do quadril, também
teremos uma
função chamada pelas animações de esquiva para ativar e desativar
a caixa Hurt Devemos usar set deferred para definir a
propriedade monitorável da caixa Hurt para
o
valor de active caso isso esteja acontecendo
durante um Como é possível que
queiramos chamar essa
função como resultado de
uma colisão, não possamos ativar ou desativar os colisores enquanto
eles estão sendo processados Nas animações dos personagens, precisaremos adicionar faixas
de chamada de
função a cada uma das animações de
esquiva de nossos personagens Primeiro vou desligar a caixa Hurt do
personagem. Então, quando o
personagem parecer que está começando a se mover
na animação, aplicarei a velocidade de esquiva Quando eles tiverem algum tempo para a velocidade do Dodge tire o personagem do caminho
do ataque, eu ligarei a caixa HRT novamente mudando o
argumento Em seguida, repita o
mesmo conjunto de
chamadas de função para cada uma das animações de
esquiva Embora isso não deva acontecer com esse código como está atualmente, pode ser possível
que o personagem interrompido enquanto
se esquiva, significa que a caixa de alimentação talvez
nunca seja Dependendo de como
o jogo funciona, talvez
você queira
incluir a ativação da caixa do personagem
nas ações de interrupção. Agora que a
velocidade de esquiva está sendo aplicada, eu realmente não gosto de como
a animação de esquiva realmente move a posição raiz da
plataforma do personagem, resultando em alguns movimentos
abruptos, tanto na entrada quanto Então, abrindo as animações, removerei os quadros-chave raiz das animações de esquiva Manter o equipamento do personagem
enraizado onde o personagem deveria estar, conforme determinado pela física
do corpo do personagem E então vou repetir isso para as outras
animações de esquiva também Executando o jogo, podemos
ver a árvore da cena remota, encontrar a caixa de arte do personagem e prestar atenção à propriedade
monitorável esquiva define a
propriedade monitorável como falsa,
depois a redefine como verdadeira, e o personagem anima a esquiva de forma mais suave com
a velocidade, graças à remoção dos quadros-chave raiz Com a esquiva agora animada
e funcionando corretamente, vamos agora considerar
se queremos permitir que o personagem ataque e se
esquive ao mesmo tempo Além disso, o
personagem deve poder atacar ou se esquivar
se for atingido Se não quisermos
permitir esse comportamento, precisaremos rastrear
quando o personagem está atacando, se esquivando
ou sendo Vamos adicionar mais algumas variáveis
booleanas ao nosso script de personagem:
está atacando, esquivando e
sendo Tudo isso precisará ser exportado
para
ficar acessível ao nó do player de
animação Usando faixas de propriedades, as animações de
ocorrência podem definir a variável de ocorrência verdadeira no início
da animação E voltando ao falso no final. Então, na árvore de animação, ao fazer a transição da
locomoção para a esquiva, podemos verificar se o personagem quer se esquivar e nada é
atingido e nada está ao fazer a transição da
locomoção para a esquiva,
podemos verificar se o personagem quer se
esquivar e nada é
atingido e nada está atacando. Antes de passar
para qualquer estado de ataque, podemos verificar não apenas se o
personagem quer atacar,
mas também se ele não foi
atingido e não está se Podemos então repetir o
processo de configuração
das variáveis booleanas nas
animações de esquiva Cada um define
a variável
de esquiva verdadeira no início
e falsa no final Novamente, com cada animação de
ataque, defina a
variável de ataque como verdadeira
no início das
animações de ataque e quedas no final Caso ataques ou
esquivas sejam interrompidos, também
devemos definir essas
variáveis como falsas Também existe a possibilidade de
o personagem morrer
interrompendo a animação de sucesso Então, definiremos a
variável is hit como false aqui. Para que a
variável de ataque seja definida pela máquina de estado de
ação, também
precisaremos
habilitar o filtro para
ela e também a posição da caixa de
acerto Para testar se a
esquiva está realmente funcionando, precisaremos que os inimigos comecem
a atacar Se você ainda não configurou as animações de ataque do
inimigo, uma maneira fácil de fazer isso é copiar o reprodutor de animação do personagem e colá-lo
na cena inimiga Em seguida, podemos dizer
à árvore de animação que use o novo reprodutor de animação. E desde que o inimigo tenha a mesma estrutura
óssea do personagem, todas
as animações funcionarão da mesma forma Caso contrário, você precisará
configurar o inimigo para ter pelo
menos um ataque capaz
de ativar uma caixa de quadril,
mascarando a caixa t do personagem Para fazer o ataque do inimigo, basta anexar um nó em branco
a ele na cena do nível. Com um script simples,
mandando eles atacarem. Vou criar uma nova pasta para scripts
inimigos e
chamá-la de ataque. Depois de pegar uma referência
ao personagem como
pai desse nó, direi ao personagem que
ataque na função pronta Como a variável
nunca voltará a ser falsa, isso é tudo o que é
necessário para que os inimigos
realizem ataques sem parar Vamos tentar rodar o jogo com formas de
colisão visíveis ativadas E veja a árvore da
cena remota, onde
podemos ver os valores de
todas as nossas novas variáveis. O personagem aguardará o término de
um ataque antes de realizar uma esquiva
e vice-versa. Se deixarmos o esqueleto
atingir o personagem, ele sofrerá danos e não conseguirá atacar ou
se esquivar até que a animação de
golpe termine E podemos evitar o ataque do
esqueleto
com nossa nova ação de esquiva Agora temos nosso personagem se
esquivando para evitar ataques e restringindo
quando o personagem pode realizar Na próxima lição, permitiremos que os personagens bloqueiem os
ataques recebidos com um escudo Te vejo na próxima aula.
9. Bloqueio: Olá, amigos.
Na lição anterior, ajudamos nossos personagens a evitar danos ao
se
esquivar de ataques Nesta lição, permitiremos que eles bloqueiem ataques
com um escudo. Vamos começar nas configurações do
projeto, na guia Mapa de entrada, e adicionar um
evento de entrada para bloqueio. Vou usar o botão direito do mouse
e o botão esquerdo do ombro
no meu controle. No script do jogador,
o botão de bloqueio não precisa ser armazenado em buffer, pois se comporta mais
como o botão de execução,
alterando o comportamento do
personagem
enquanto o botão Enviar um sinal para o personagem
bloquear ou não, com base no fato de o botão ser
pressionado ou solto. O script de caracteres pode então armazenar esse valor em uma variável. Quer bloquear. Mas, diferentemente
das outras variáveis, não
há necessidade real de armazenar em
buffer a entrada de bloqueio Em seguida, adicione uma função
na seção de combate que
defina essa variável. Na máquina de estado da
árvore de animação dos personagens
navegando até a máquina de estado de
ação Podemos adicionar a
animação do bloco e fazer a transição a ela se o personagem quiser bloquear com um pequeno crossfade Em seguida, faça a transição de volta para se
eles não quiserem bloquear. Obtendo uma visão do personagem e misturando-se
ao estado de ação, essa animação faz com o personagem
levante o escudo Quando a animação estiver concluída, podemos fazer a transição para
a animação de bloqueio, que deve ser configurada em loop
para manter o escudo levantado, desde o jogador mantenha pressionado
o botão de bloqueio. Isso também voltará ao modo inativo se o personagem
não quiser mais
bloquear com um pequeno crossfade Talvez também queiramos fazer a
transição para
a animação em bloco de alguns
de nossos outros estados ociosos,
como os estados desarmado e ocioso com
uma mão Para reduzir o número de
transições, primeiro
combinarei os estados ocioso
e inativo com uma mão combinando logicamente as condições de
transição
para alcançar o estado de ataque com uma Se a animação de ataque for uma, eles querem atacar e
não são atingidos nem se esquivam Em seguida, volte ao modo inativo no
final da animação do ataque. Excluindo o estado ocioso de uma
mão, reorganizarei
os outros estados para ficarem um pouco mais Agora, um
ídolo ocioso ou desarmado pode fazer a transição para o bloqueio, se o personagem quiser bloquear, e
voltar diretamente para o desarmado, se a
animação de ataque do personagem for zero, ele tiver um
alvo ou quiser atacar, mas não Com prioridade zero. Agora, tanto o ocioso quanto o ocioso
desarmado podem fazer a
transição para bloqueio se o
personagem quiser bloquear Os estados de bloqueio e bloqueio
podem pular a inatividade e retornar diretamente à inatividade desarmada
com prioridade zero Dessa forma, o personagem
não precisa passar por dois estados de inatividade diferentes
entre bloquear e atacar Se experimentarmos, nosso personagem pode fazer a transição para
a animação em bloco ao pressionar o botão de
bloqueio e voltar ao modo inativo quando o
botão de bloqueio for solto Mas faria mais sentido
restringir o personagem
a usar essa animação somente se ele tiver um escudo equipado. Para fazer isso,
precisaremos de outro script
de recursos. Herdando do equipamento, dando a ele o
nome de classe de escudo Se você quiser que seus escudos tenham variáveis
diferentes,
podemos defini-las aqui. Vamos adicionar uma variável para a
quantidade de dano reduzida pelo bloqueio com esse escudo
com o valor padrão de um. Acessando o recurso personalizado de
escudos redondos bárbaros. Podemos transformá-lo em um escudo e alterar a
quantidade de redução de dano, se quisermos. Lembre-se de repreencher
todas as propriedades que foram redefinidas como resultado dessa alteração
de classe e atualizar todos os escudos para
usar o novo Na cena do escudo, precisaremos ser capazes de
armazenar as variáveis do recurso
do item no escudo assim como fizemos
com a arma. Adicionando um novo script, ele terá apenas uma variável inteira
de redução de danos e uma função fictícia de ativação
do quadril, que ignorará o
argumento booleano e Ficará claro por que isso
é necessário em um minuto. Em seguida, podemos substituir o script anexado ao nosso
escudo pelo novo. No script do personagem, vamos adicionar outra variável à categoria de equipamento
para determinar se o personagem tem ou não
um escudo equipado. Ao vestir um
equipamento, se o item for um escudo, definiremos que seja
o equipamento improvisado,
repassaremos o valor de
redução de dano do recurso
do item
para o escudo e configuraremos o escudo
equipado como verdadeiro Como a variável improvisada
agora está segurando um escudo
em vez de uma arma, interromper as ações do
personagem desativará todas as caixas de quadril E como o
improviso não é nulo, estamos pedindo que ele
desative a caixa do quadril Mas dissemos ao escudo
que ignorasse esse pedido. Então, ao tirar um
equipamento,
se o soquete for de improviso,
podemos supor
que o personagem não
está mais segurando um escudo não
está mais Então, ao mandar o
personagem bloquear, podemos adicionar a condição de que o personagem também
tenha um escudo equipado. O script de inventário também
precisará mais
algumas condições ao
equipar um escudo para evitar que o personagem equipe um
escudo quando sua mão improvisada já estiver ocupada com uma arma de duas mãos
ou fora de mão Esse processo
variará dependendo como seus sistemas de inventário e
equipamento funcionam. Se o
item selecionado for um escudo e o personagem tiver algo equipado na mão principal e o personagem
estiver usando as animações de duas mãos ou de
duas rodas, desequiparei o soquete
principal e
direi ao personagem que remova o equipamento com a mão principal direi ao personagem que remova o equipamento com a equipamento Se experimentarmos.
O botão de bloqueio agora
é ignorado se o personagem não tiver um equipamento de escudo. Podemos equipar uma arma de duas
mãos depois equipar o escudo. A arma de duas mãos é
desequipada automaticamente
e, em seguida, o escudo é equipado E agora o personagem pode
bloquear com o escudo. A seguir, vamos considerar como a entrada de bloqueio funciona
com nossas outras ações. Se o jogador estiver bloqueando e decidir
atacar ou se esquivar
, eu gostaria que
essas ações tivessem
prioridade na interrupção do Mas se definirmos a variável de desejo
de bloquear como falsa
, o jogador
terá que soltar o botão de bloqueio e pressioná-lo
novamente para continuar bloqueando. Em vez disso, podemos declarar
outra variável booleana. Vamos chamar isso de bloqueio de interrupção. Se o personagem quiser
atacar ou se esquivar, essa variável
pode ser definida como verdadeira E quando o ataque
ou a esquiva terminar, podemos voltar
para falso para permitir que o personagem continue
bloqueando automaticamente Vou simplificar a função add
dodge velocity para apenas chamar cancel Em seguida, na árvore de animação, podemos adicionar as condições
para sair do bloco
ou bloquear para incluir se o
bloco está sendo interrompido E não permita que as
transições voltem ao bloco até que o bloqueio não seja
mais interrompido Agora, o personagem
deixará de bloquear enquanto estiver atacando
e
retornará automaticamente ao bloqueio enquanto o botão de bloqueio
ainda estiver pressionado E o mesmo também
funciona para se esquivar. A última coisa que precisamos
fazer é realmente reduzir o dano dos
ataques recebidos durante o bloqueio Para isso, precisaremos saber se o personagem está bloqueando. Como o bloqueio não se limita a uma única animação e
aos loops de animação, não
há como simplesmente
dizer animador que
defina uma
variável booleana como verdadeira Vamos adicionar a animação de
sucesso em bloco. Permitindo que
a transição para essa animação bloqueada e retornada
no final da animação. O que contratamos para saber
se o personagem está bloqueando é em qual estado essa máquina de estado
está atualmente. Se estiver no estado de
bloqueio ou bloqueio
, o
escudo do personagem está levantado. A animação do bloco também
é bastante longa. Inclui não apenas
levantar o escudo, mas também um ciclo de animação de
bloqueio. Não acho que o personagem deva
ser considerado
bloqueado até que o
escudo esteja totalmente levantado, mas também não quero esperar que
a animação do bloco termine. Então, no reprodutor de
animação do personagem, vou reduzir a duração da animação do
bloco para fazê-la parar depois que o escudo for levantado
em um terço de segundo. No script de árvores de animação, vamos adicionar uma
função pública para verificar se o personagem está bloqueando,
retornando um booleano Primeiro, armazenar o
nome do nó atual
dos estados de ação em uma variável de string. Podemos retornar se estiver
bloqueando ou bloqueando. E também precisaremos de
outra função para reproduzir a animação de impacto do bloco, fazendo que o estado da ação
viaje até o estado do bloqueio atingido. Em seguida, no script do personagem, na parte superior da função de
receber dano. Podemos verificar se a animação do
personagem está bloqueada no momento e se a direção vem
o dano
é a frente do personagem. Usando um produto escalar da direção
do dano com o vetor de base
frontal do personagem rigs Se o valor for um número
positivo, o dano está vindo de algum lugar na frente deles. Porém, isso cobriria um ângulo
amplo, uma meia esfera inteira na
frente do personagem. Usando algo próximo
a um quarto ou meio, podemos limitá-lo à forma de um cone. Nessas
condições, o ataque deve ser bloqueado com sucesso, reduzindo a quantidade de dano pela redução do dano
do escudo. Usando a função max para
limitá-la a um mínimo de zero. Podemos então dizer
à árvore de animação que reproduza a animação de golpe de bloco
e, se a quantidade de dano for completamente reduzida para zero, eu retornarei, pois o personagem não está
sofrendo nenhum dano. Vamos experimentá-lo.
Equipando o escudo e bloqueando o ataque do
esqueleto O dano é reduzido a zero
e a animação do golpe no bloco é reproduzida. Sofrendo danos
pela lateral ou pelas costas, o personagem ainda
sofre danos. Agora temos nosso
personagem capaz bloquear ataques com um
escudo na frente. Na próxima lição,
daremos a eles uma arma de longo alcance que
pode disparar projéteis Te vejo na próxima aula.
10. Fotografe: Olá, amigos.
Na lição anterior, permitimos que nosso personagem
bloqueasse ataques com um escudo. Nesta lição, daremos a eles uma arma
arranjada capaz
de disparar projéteis Este pacote de ativos não contém
um parafuso para a besta, então vou começar criando
um na cena da besta Começando com um corpo
rígido de três
nós D , renomeando-o como parafuso Vou posicioná-lo
onde a base do parafuso ficará
dentro
da besta, com seu vetor de base z azul apontando para frente, onde
ele será disparado Em seguida, adicionarei uma instância de malha de
três nós D como filho, preenchendo-a com
a malha cilíndrica Reduzindo o raio e a altura, girando-os para apontar para frente e posicionando-os para
frente ao longo do eixo z. Vou apenas dar
um material básico e definir o albedo
para uma cor marrom Em seguida, adicione um
nó básico de três D como outro filho, para que ele seja colocado
na mesma posição e
rotação e renomeie seu soquete de
amplificador Em seguida, repare o soquete na besta, mantendo essa Recolocando o parafuso
no soquete do amplificador, forma que sua posição e rotação em relação ao seu
pai agora sejam O raio agora pode ser
transformado em sua própria cena, que vou colocar em uma nova
pasta para projéteis e depois excluí-la da cena
da besta Agora, a besta pode
ser carregada simplesmente adicionando um parafuso como
filha desse O parafuso precisará de
uma forma de colisão. Vou usar uma cápsula com as mesmas dimensões e
posição do cilindro. Expandindo a seção do solucionador, precisarei ter o monitor de
contatos ativado e o máximo de contatos definido como
algo maior que zero Se quisermos que o parafuso
colida com o terreno, ele precisará mascarar a primeira camada de
colisão E eu quero que meus parafusos
se movam lentamente para que eu possa
ver o que eles estão fazendo Mas não quero que eles
caiam devido à gravidade. Então, vou definir sua escala de
gravidade para zero. Anexando um script ao parafuso, podemos chamá-lo de projétil, ele
possa ser usado para outros
tipos de projéteis em nosso jogo e salvá-lo na pasta de scripts
do item Assim que um parafuso
for instanciado, ele será carregado
na E talvez queiramos
passar informações do personagem ou da arma para a munição neste momento Vamos criar uma
função pública para fazer isso. Mas, por enquanto, vamos definir sua propriedade
de congelamento como verdadeira, já que o corpo rígido
não precisa fazer nada até que
a arma seja disparada Para disparar o projétil, aplicaremos uma força de impulso enviada pela arma
como um vetor três Nesse momento, o corpo
rígido pode começar a
aplicar a física para mover o
parafuso pela cena do jogo, definindo sua
propriedade de congelamento Não queremos mais que o
projétil siga
as propriedades de transformação de
seu progenitor, a besta Ele deve ser adaptado ao cenário do jogo, onde ele
pode se mover e agir livremente Caso não esteja
apontando diretamente
para a direção em que está sendo disparado, podemos dizer ao parafuso que olhe para um ponto
no espaço que seja sua própria posição global menos a direção da força
de impulso Em seguida, aplique a força de impulso no parafuso para que ele se mova
nessa direção Conectando o
sinal inserido pelo corpo do
corpo rígido ao script, essa função será chamada
se o parafuso entrar em contato com qualquer coisa na primeira
camada de colisão, o terreno Se isso acontecer, o parafuso pode ficar exatamente onde
entrou em contato, redefinindo sua
propriedade de congelamento como verdadeira, mas adiada, pois isso
acontece durante uma colisão É muito importante que,
sempre que você implementar um recurso em um jogo que instancia um grande
número de nós, você também implemente alguma
forma de limpá-los Caso contrário, você pode acabar
com quantidades muito grandes que
fazem com que as taxas de quadros caiam e,
eventualmente, travem o jogo. Uma prática comum
com projéteis é dar a eles
uma vida útil máxima Vamos adicionar um nó de tempo aos nossos projéteis e configurá-lo
para contar uma vez Vou configurá-lo para 10 segundos. Em seguida, pegue uma referência
à hora ou ao nó
usando addon ready. Iniciaremos o cronômetro
ao disparar o projétil. Se não
atingir nada, ainda
queremos limpá-lo, para que não voe para longe
para sempre Conectando o sinal de tempo limite
ao script do projétil. Isso fará com que o projétil seja libertado da cena do jogo De volta à cena da besta, precisaremos de um novo roteiro
para essa arma Podemos chamá-la de arma de longo alcance e colocá-la na pasta de scripts do
item Substitua o script
anexado a essa arma por uma arma de longo alcance e forneça uma referência ao arquivo de
recursos personalizado da besta Podemos exportar a munição
como uma cena lotada, uma peça pré-fabricada que podemos usar como modelo para
instanciar quantas precisarmos Em seguida, atribua o parafuso como munição para a
besta no inspetor Precisaremos de uma referência
ao soquete de munição usado estiver pronto e de uma referência à munição que está atualmente carregada na Também pode ser bom
ter um bônus de dano que a arma adicionará
aos tiros disparados
como um número inteiro A quantidade de
força de impulso que a arma aplica à munição quando
é disparada enquanto Usarei um número baixo,
como dez, para que
possamos ver os parafusos se movendo facilmente
pelo ar e a máscara de colisão de nossos
inimigos para que as informações possam ser passadas do personagem, da arma para
a munição Ao equipar a arma, personagens estão
configurando a caixa do quadril, máscara de
colisão das armas, para que possamos facilmente reutilizar a mesma função para
definir a variável da E assim como fizemos
com o escudo, podemos adicionar uma função para
ativar a caixa do quadril, ignorando esse parâmetro,
e simplesmente retornar Já que a arma
não tem caixa de quadril própria. A arma
precisará ser capaz de
disparar o projétil
com uma função pública, e deixaremos o
personagem especificar
a direção em que
deseja que o projétil vá como parâmetro Tudo o que a arma
precisa fazer é passar essa chamada
de função para o amo, multiplicando a direção
pela força da arma Em seguida, defina a referência de
amo carregada nula, já que a arma não
está mais carregada, e uma função de recarga, que instanciará
um novo parafuso, atribuindo-o Em seguida, adicione-o como se fosse filho
do soquete do amplificador, dando-lhe a posição e a
rotação
corretas necessárias para se encaixar
bem na besta Podemos então
transmitir qualquer informação a munição precise
saber antes de ser disparada, como os danos da arma
e a máscara de colisão Então, vamos adicioná-los como parâmetros à função
onload no script do projétil Nosso script de personagem
precisará de uma variável para saber se a arma que eles estão
segurando está carregada no momento. E duas novas funções,
recarregar e disparar. Recarregar, apenas definirá
a variável como verdadeira
e, em seguida, dirá
à arma principal que recarregue Por enquanto, atirar apenas
definirá a variável como falsa e, em
seguida, dirá
à arma principal que atire em uma direção, passando o vetor base do equipamento do personagem
para frente Se a arma não estiver equipada, pois está sendo completamente
removida da árvore da cena, a munição também será
removida junto com Então, vou redefinir a variável da arma
carregada de volta para
falsa neste momento. nossa enumeração de tipos de armas, precisaremos de mais duas entradas para o alcance de ataques com uma mão, que será o número quatro, e ataques de alcance com
duas mãos No recurso
personalizado de bestas, mudarei o script
de equipamento para arma Vou mudar o
tipo de arma para o alcance de uma mão, diminuir o dano e
repovoar seu ícone E, da mesma forma, mude a besta pesada
para o alcance de duas mãos Na árvore de
animação dos personagens, precisaremos de mais ações
para ataques à distância. Essa máquina de estado já está ficando muito grande e bagunçada, então vou incluir os ataques de alcance outra máquina de estado Fazendo a transição para
essa máquina de estado, se os personagens atacarem animação for de
quatro ou cinco, e eles quiserem atacar, serem atingidos
nem Em seguida, volte ao modo inativo
no final da animação. E vou misturar as duas transições
com um pouco de cross fade. Dentro do alcance para
atacar a máquina de estado, podemos adicionar animações para
fotografar e recarregar Tanto para ataques de alcance com uma mão quanto com
duas mãos. Só precisamos jogar a
correta uma vez e depois voltar para a máquina de estado de
ação. Então, todos eles farão
a transição no final. As transições para uma mão
exigirão que a
animação de ataque seja definida para quatro E duas mãos ajustadas para f. A
reprodução das animações de tiro
ou de recarga será baseada no
valor da arma carregada Agora que as animações podem ser reproduzidas pela árvore de animação, precisamos que as animações chamem funções no script do
personagem Durante a animação de filmagem, adicionaremos um método chamado track and scrub ao quadro antes que o personagem recue
do projétil que está sendo
disparado Em seguida, adicione um quadro-chave para
chamar a função de captura. Da mesma forma, durante a animação de
recarga, tentaremos
selecionar um quadro quando o personagem terminar de
recarregar a arma E adicione um quadro-chave à trilha
do método de chamada para
realmente recarregar a arma Se quisermos que essas
animações
impeçam o personagem de
realizar outras ações, precisaremos definir
uma variável booleana como fizemos com os ataques Vou apenas reutilizar a variável está
atacando. E repita também para as animações de longo alcance para duas
mãos .
Vamos experimentá-lo. Podemos equipar a besta
para o personagem
e, pressionando o botão de
ataque uma vez, faremos com que ele carregue a
besta com Pressionando o
botão de ataque pela segunda vez, eles disparam a besta para frente, e o raio dispara até atingir algo
no ambiente, onde para e
se destrói após Agora precisamos dos parafusos para causar
dano aos inimigos. De volta à cena do parafuso,
precisaremos adicionar uma
caixa de acerto ao parafuso A caixa de impacto precisa de
uma forma de colisão. Vou usar a esfera. Vou posicioná-lo
na outra extremidade
do parafuso e dar-lhe
um raio menor Assim como nossas outras caixas de quadril, ela ainda não precisa ser monitorada ou ter uma máscara de colisão Pegando uma referência à caixa do
quadril usando at on ready, vamos também exportar uma variável
para os danos nos parafusos Vou usar o valor padrão de um. Quando o parafuso é carregado
na besta pelo personagem, seria uma boa oportunidade para passar informações, como quaisquer bônus de dano
e a máscara de colisão O bônus de dano da arma pode ser adicionado ao dano
dos parafusos, e a camada de
colisão da caixa do quadril pode
ser definida como a camada de colisão
inimiga do personagem Quando o projétil é disparado, podemos dizer à caixa do quadril que comece a monitorar as caixas de rebanho inimigas Conectando o sinal
inserido na área da caixa do quadril ao script do
projétil Podemos dizer à caixa Hurt
que esse projétil atingiu para fazer com que seu
personagem principal sofresse dano Da direção das caixas
Hurt, a posição global
menos a posição global do Bolt foi normalizada O parafuso pode então ser
removido da cena. E se o parafuso atingir o terreno, ele não deve mais ser
monitorado para causar dano, então vamos configurá-lo como
falso No roteiro do personagem,
eu gostaria de ter certeza absoluta de que, quando o personagem está
preso em um alvo, o projétil é disparado
diretamente contra esse alvo Portanto, a função de tiro
se
dividirá em dois comportamentos diferentes com base no dois comportamentos diferentes com base no fato de o personagem
estar ou não preso a um alvo, chamando uma função separada
para atirar em um alvo, passando o alvo
como argumento. Mas a arma só
deve disparar contra o alvo do bloqueio se o
personagem estiver de frente para ele. Assim, podemos verificar se
o produto escalar
do vetor de base
direta das plataformas de caracteres e a diferença normalizada em suas posições globais
é um número positivo Quanto mais próximo do
positivo, quanto mais parecidos eles são,
mais o personagem fica
voltado para eles. Eu direi que algo maior que 0,75 está perto o suficiente para atirar
no alvo do bloqueio. No script de armas de longo alcance, definindo atirar no
alvo, aceitando um alvo
como parâmetro Agora podemos calcular a
direção como a diferença das posições da gaiola normalizada
e multiplicada pela força Como isso usará a posição tubal da
arma, não a posição
gubal do personagem, a direção
será mais precisa E vou adicionar 1 metro até a posição
do alvo para
não mirar em seus pés. Vamos experimentá-lo.
Equipando uma arma de longo alcance e bloqueando um alvo, primeiro
vou me
virar para o lado,
e o projétil
ainda dispara para frente, já que o personagem
não está de frente para o Movendo-se para encarar o alvo
e disparando um segundo raio, desta vez ele atira diretamente no alvo e causa dano Agora temos projéteis sendo
disparados de armas de longo alcance, atingindo inimigos ou Na próxima lição, permitiremos que os inimigos detectem
jogadores e reajam. Te vejo na próxima aula.
11. Inimigo: Olá, amigos.
Na lição anterior, adicionamos ataques de alcance
que disparam projéteis Nesta lição,
permitiremos que os inimigos detectem, perseguam e ataquem o personagem do
jogador. Na cena do cemitério, adicionamos um
nó simples que diz ao inimigo que ataque constantemente Vamos remover isso
e começar a criar uma versão mais complexa para
atacar apenas quando o personagem do jogador
estiver ao alcance de ser atingido. Na cena do esqueleto dos lacaios, adicionaremos um nó filho do tipo nó três D, pois ele precisará acessar três posições e rotações D. Vou chamar isso de agressão. Em seguida, adicione um nó D de área três, que representará o alcance de ataque do
inimigo. Vou dar a ele uma
forma de colisão e usar uma esfera. Ajustando o tamanho da
esfera para ser um pouco maior, darei a ela um
raio de 1 metro e, em
seguida, posicionarei a 1 metro acima do solo
e 1 metro A área de alcance de ataque
monitorará colisões que mascaram a caixa de rebanho
do jogador Vamos anexar um script a esse nó e colocá-lo na pasta de scripts
do inimigo. Como o objetivo desse
script é controlar um personagem exatamente como o nó
manipulador de entrada do jogador, precisaremos de uma referência
ao personagem está sendo controlado por esse nó Com a forma como estou estruturando
minha árvore de cena, esse nó sempre será filho direto
do nó do personagem, então eu posso acessar o personagem
chamando get parent. Conectando os sinais da
área inserida e da área de saída
ao script,
renomearei os parâmetros
e fornecerei renomearei os parâmetros os tipos para Quando
Hurt box do personagem
do jogador entra no campo de ataque, queremos dizer ao
inimigo que ataque. E quando a caixa Hert
sai do campo de ataque, podemos dizer ao
inimigo que não Podemos salvar essa ramificação como sua própria cena e salvá-la
na pasta de cenas inimigas. Em seguida, exclua-o
dessa cena inimiga. E De volta à cena do cemitério, podemos conectar nosso
nó de agressão
inimigo a qualquer um ou a todos os
nossos inimigos para que eles ataquem
automaticamente o personagem
do jogador se
entrarem no campo de ataque personagem
do jogador se
entrarem no campo Vamos experimentá-lo. Os inimigos ainda não
estão atacando, mas atacaremos se entrarmos seu alcance de ataque e
pararemos quando sairmos dele Em seguida, permitiremos que
os inimigos vejam o personagem
do jogador a uma distância maior. Abrindo a cena do nodo de
agressão, podemos adicionar outro nodo D da área três para representar a visão de
um inimigo Adicionando uma
forma de colisão a essa cena, usarei outra esfera
com um raio muito maior Vou usar 5 metros e posicioná-lo para ficar à frente
do inimigo e um
pouco acima do chão. Essa área pode monitorar a camada
de
colisão do personagem do jogador Vou usar a camada nove. Em seguida, adicione um raio de três nós
D para ser sua linha de visão e também
mova-o para fora do chão. Isso procurará a mesma camada
do campo de visão, mas também estará obstruído
pelo Como usei a camada nove, que é o
corpo do personagem e não a caixa t, conectarei os sinais de entrada
e saída do corpo ao script de agressão Quando um corpo entra
no campo de visão, eu o armazeno em uma variável, vamos chamá-lo de alvo do
tipo corpo do personagem três D. Mas também
precisaremos confirmar se eles também
têm uma linha de
visão clara antes de se tornarem agressivos. Então, precisaremos de uma
referência ao elenco. E podemos armazenar se o inimigo
viu
ou não o jogador em
uma variável booleana também vamos pegar uma referência
ao Agora também vamos pegar uma referência
ao campo de
divisão do inimigo. A. Usando a função de processo, podemos começar verificando se o valor do alvo
foi definido. Se for nulo, o inimigo não poderá ver
o personagem do jogador Deveríamos simplesmente
voltar. Se o inimigo ainda não
viu o jogador
, podemos verificar sua linha
de visão em relação ao alvo. Definir a posição alvo
do raycast como
a diferença em suas posições
globais, adicionando um metro acima
do solo Depois de forçar o raycast a
atualizar se está colidindo com algo e
se algo com o qual está colidindo
é o alvo
, a linha de visão
não é Podemos definir a variável has seen
player como verdadeira. Se o valor dessa
variável for verdadeiro, comportamento do inimigo mudará e faremos com que ele persiga
o personagem do jogador. Quando o personagem do jogador sai do campo de visão do inimigo, se o corpo é o alvo e o inimigo
ainda não viu o jogador
, não precisamos mais
verificar sua linha de visão, para que possamos definir o alvo como nulo Esse nó de agressão é
filho do nó do personagem, que não está girando Portanto, o campo de visão e alcance de
ataque não girarão
com o equipamento do personagem Podemos usar a referência de
caracteres para pegar a rotação do anel, acessar a propriedade y e atribuí-la à rotação y
desse nó. Então, ele seguirá
a mesma rotação. Talvez também queiramos uma maneira de dizer a esse inimigo que pare de perseguir
o personagem do jogador Nesse caso, podemos
definir o alvo como nulo, ver o alvo como falso
e dizer a esse personagem que se
mova sem direção Um bom momento para chamar essa função seria quando o inimigo morresse. Então, substituindo a função
pronta. Podemos conectar o sinal
morto desse personagem à função
de parada. Quando o inimigo vê
o personagem do jogador pela primeira vez, também
podemos conectar o sinal de morte do
alvo
à função de
parada para impedir que o inimigo tente matar o personagem do
jogador depois de ele já ter morrido. Também usarei essa mesma função para desligar a visão desse inimigo, definindo sua
propriedade de monitoramento como falsa. Para que o inimigo
se mova em direção ao jogador, primeiro
precisamos fazer algumas
mudanças em nossa cena de nível. Vamos adicionar
três nós D da região de navegação ao nível. Em seguida, recrie quaisquer nós
que serão usados para gerar nosso mapa de navegação
como filhos desse nó, incluindo o solo
e os obstáculos. Feito isso, selecione o nó da região de
navegação e preencha a
malha de navegação com uma nova malha de navegação Em seguida, clique no botão da malha de
navegação Bake. A malha de navegação cobrirá
o terreno com triângulos que formam uma área onde os personagens poderão andar Expandindo o recurso de
malha de navegação, podemos ver suas propriedades. A única seção
preocupante no momento é a seção de agentes. Agentes são nossos
personagens que
usarão essa malha de navegação
para percorrer a cena. Dando uma olhada rápida nas cápsulas de colisão de nossos
personagens, atribuí a elas uma
altura de 2,6 metros e um raio de 0,75 Vou copiar esses valores para a altura e o raio dos agentes recurso de
medida de navegação e,
em
seguida, refazer a malha de navegação A malha agora deixa mais espaço
entre paredes e obstáculos. Para usar a região de
navegação, todos os
nossos personagens precisarão outro nó anexado a eles, um agente de navegação com três nós D. Certifique-se de anexar
um a cada personagem. Obtendo uma referência a esse
nó usando addon ready. Em seguida, podemos escrever uma função
no script de caracteres, que pode ser usada para dizer a
qualquer personagem que navegue
até qualquer local na malha de
navegação por qualquer motivo. Isso também é muito útil para muitas coisas fora do combate. Aceitando uma posição alvo
como um vetor três, definiremos a posição alvo do
agente de navegação a mesma localização. O agente de navegação usará automaticamente
a malha de navegação, atribuída à mesma camada de
navegação para
produzir um caminho para chegar o mais próximo possível do
local de destino. Fazendo com que os agentes obtenham a
próxima posição do caminho, retornaremos o primeiro ponto intermediário ao longo desse caminho como
um vetor três. Podemos então subtrair
a posição global
atual do personagem para obter um vetor apontando
de onde
estamos para a primeira
posição ao longo do caminho Se multiplicarmos isso por 101 para remover o componente
vertical, normalizaremos esse vetor Agora é funcionalmente equivalente a um
vetor de entrada produzido pelo nosso
script de manipulação de entrada do player quando o player inclina o analógico ou
usa
as Então, podemos atribuir isso à variável
de direção de entrada. E o processo físico
cuidará do resto, mandando o
personagem percorrer esse caminho, que o levará até
o alvo. Seria uma boa ideia transferir tudo o que acontece com um personagem
quando ele morre
para uma
função pública, caso algo além de sofrer
danos possa fazer com que ele morra. Quando um personagem morre, devemos dizer a ele
que pare de se mover. E quando eles são instruídos
a se mover ou realizar qualquer ação, devemos ignorar essas solicitações se o personagem estiver
morto ao retornar. De volta ao roteiro de agressão, só
precisamos
dizer ao inimigo que navegue em direção ao alvo
depois de vê-lo Antes de experimentar,
vamos escolher um inimigo. Vou usar o guerreiro esqueleto e selecionar seu
agente de navegação Three D node. Na seção D Bug, clique em habilitar Toggle para
poder ver o caminho
renderizado aproximarmos do primeiro esqueleto, assim que entramos em
seu campo de visão, a linha de visão imediatamente confirma que eles podem nos ver, e o agente de navegação encontra um caminho para o inimigo
caminhar Então nos ataque.
Derrotar esse inimigo, desta vez, vamos atrair
a atenção do ladino Como eles estão atrás
da lápide, a linha de visão
não foi confirmada e o inimigo permanece escondido E se nos aproximarmos do guerreiro, podemos correr ao redor
da cova aberta, vendo como o agente de
navegação atualizará automaticamente
o caminho em tempo real, para percorrer o caminho mais curto possível para
alcançar o jogador Talvez também queiramos que nossos inimigos sejam
capazes de empunhar armas De volta à cena do cemitério, vamos conectar outro
nó básico a um de nossos inimigos e chamá-lo Anexando um script a esse nó, eu o colocarei na pasta de scripts do
inimigo Tudo o que precisamos fazer é pegar uma
referência ao nó principal, o personagem, e exportar uma arma para
equipar esse personagem Em seguida, na função pronta, diga ao personagem
para usar a arma. Vou dizer ao meu guerreiro esqueleto
que equipe um grande machado. Em seguida, copie e cole
esse nó em outro inimigo e troque a
arma por outra coisa. Vou dar algumas facas ao bandido. Cada uma das
cenas de nossos inimigos precisará ter
nós de fixação óssea adicionados a elas. Seguindo a
fenda da mão esquerda e a fenda da mão direita. Podemos então preencher o conjunto de
soquetes do equipamento do personagem com esses nós para serem usados
ao equipar armas Por fim, seria
bom não precisar recarregar o jogo quando morrermos Então, vamos conectar o sinal
morto do personagem do
jogador ao script do gerenciador do
jogo. Depois de ficar preto,
vou pedir à árvore de cenas que recarregue
a cena atual,
redefinindo tudo de volta ao que estava quando a cena
foi carregada pela primeira Vamos experimentá-lo.
O guerreiro esqueleto está equipado com
o grande a e está usando as animações de
ataque com duas mãos Quando morremos, toda a
cena é recarregada. E, desta vez, enfrentando
o ladino, eles estão equipados
com facas e usam animações de duas rodas Agora temos um
sistema de combate complexo em nosso jogo com uma variedade de
mecânicas que podem ser ajustadas para atender
às necessidades do seu jogo