Transcrições
1. Trailer 0-0: Bem-vindo ao meu curso
sobre como criar ametroivnia no motor de jogo
Gadot Meu nome é Thomas Ionizlo
e eu serei seu instrutor. Sou bacharel
em ciência da computação e ensino desenvolvimento de
jogos em várias plataformas
há mais de cinco anos. Incluí um conjunto
completo de recursos, incluindo sprites, efeitos
sonoros
e músicas, que você
pode usar para
acompanhar ou usar seus
próprios recursos, se preferir Este curso ajudará você a se familiarizar com o motor
GDOGame É um fluxo de trabalho muito eficiente para criar jogos e sua linguagem de script
nativa, o script GD. Você aprenderá como criar
e editar cenas usando vários
nós de Gado e alterar seu comportamento
com scripts. Ao escrever esses scripts, você aprenderá a aplicar princípios de
programação orientada a
objetos para manter seu código conciso, escalável e reutilizável Mais importante ainda,
você aprenderá como
estruturar um projeto complexo
dessa magnitude
dividindo-o em seus componentes
individuais. Começaremos criando e animando um personagem de
plataforma em dois D. Em seguida, construa um ambiente
para o personagem explorar e mover
a câmera do jogo. Em seguida, permitiremos que o personagem faça
a transição entre salas
diferentes e
desenhe o mundo em um mapa para ajudar o jogador a
explorar seu mundo. Depois de salvar e carregar
o progresso do jogador, desenharemos um heads-up display. Em seguida, adicione nossas habilidades
desbloqueáveis, incluindo um salto duplo, um salto na parede, uma corrida
e um disparo de um projétil e um disparo Por fim, adicionaremos
alguns inimigos para combate, uma luta contra chefes e
acompanharemos o
progresso do jogador no jogo. Se você é
novato no desenvolvimento de jogos, no motor de jogo Gadot ou apenas no Metroid venias, este curso ensinará
tudo o que você precisa
saber para criar um
jogo completo do zero Se precisar de ajuda, nosso servidor de
discórdia está cheio de outros estudantes e desenvolvedores de jogos
iniciantes que podem responder a qualquer uma
de suas Clique no link em
meu perfil para participar. Você pode visualizar as duas primeiras seções do curso gratuitamente, e eu também tenho outro curso
que aborda os fundamentos da programação GD Script
totalmente gratuito Quando estiver pronto,
podemos começar a aprender como construir
uma metróvnia em cado
2. Download 0-1: Olá amigos. Para
seguir este curso, você precisará do motor Godot Abra qualquer navegador da web
e acesse godot.org e baixe
a versão mais recente, que na gravação
deste vídeo é O uso do motor é gratuito, mas você pode optar por
doar para apoiar o
desenvolvimento, se quiser Depois que o download for concluído, você precisará extrair os
arquivos da pasta compactada armazená-los em um
local seguro no seu computador Para executar o editor,
tudo o que você precisa fazer é executar o arquivo maior que
não termina no console. Não há instaladores ou
lançadores com que se preocupar. Na primeira vez que você abrir Godot, sua lista de projetos estará vazia e ela perguntará se
você deseja explorar alguns dos exemplos de projetos
disponíveis Vamos ignorar isso
e criar nosso primeiro projeto, que abre uma nova janela. Aqui podemos decidir onde
salvar o projeto. O local padrão está
na pasta de documentos, mas é uma boa ideia criar uma subpasta separada para
armazenar seus projetos Godot Em seguida, podemos dar um nome ao
nosso projeto. Não se preocupe
muito com isso agora. Você sempre pode alterá-lo mais tarde. Uma nova subpasta
também será criada com o mesmo nome para conter todos
os arquivos relacionados
a este projeto Três renderizadores diferentes
podem ser selecionados, cada um otimizado para finalidades
diferentes. Eu recomendo iniciar todos os seus projetos usando
o renderizador
de compatibilidade
para começar, pois é melhor para compilações web e só
troque seu renderizador posteriormente se você precisar de melhor suporte para efeitos visuais de melhor qualidade O controle de versão com o Gi
Hub é
suportado automaticamente e eu recomendo
aprender a usá-lo. Ao criar este
projeto, ele será aberto automaticamente
para que possamos editá-lo. No entanto, vou fechar o
editor e reabri-lo. Nosso projeto agora está incluído
na lista de projetos e podemos abri-lo
clicando duas vezes nele ou selecionando-o na lista e clicando no botão Editar. Agora temos acesso ao Godot e podemos começar a
editar nosso primeiro projeto No próximo vídeo,
exploraremos o layout da janela
do editor. Te vejo no próximo vídeo.
3. Editor 0-2: Olá, amigos. Antes de
começarmos a editar nosso projeto, precisaremos nos
familiarizar com o layout da janela do
Godot Editor A maior parte da
janela é preenchida com uma visão em três D
da cena atual. Este projeto será em dois D, não três D. Podemos
alternar a visualização entre três D e dois D usando os botões
na parte superior da janela. Em dois D, temos o eixo
X desenhado em vermelho, o eixo Y desenhado em verde e um retângulo azul
que mostra a janela de visualização, ou o que realmente será desenhado na tela ao
executar o jogo Observe que a janela de visualização
está abaixo do eixo X com Y igual a zero representando
a parte superior da tela O eixo Y está invertido, então os valores positivos para Y se
moverão para baixo no eixo
Y, não para cima No canto superior esquerdo, temos uma guia para a estrutura da
cena atual, que atualmente está vazia e está solicitando que criemos um nó
raiz para essa cena. Como nosso jogo será em dois D, vamos fazer uma cena em dois D. A guia de cena agora mostra o nó raiz de
nossas cenas, um nó dois D.
Exploraremos mais sobre cenas
e nós no próximo vídeo. Esse dock também contém
a guia Importar, que nos permitirá alterar
as configurações de importação dos arquivos
importados que usaremos em nosso projeto, como
gráficos e áudio. Esses arquivos serão armazenados e organizados no sistema de arquivos do
projeto, que podemos ver
no canto inferior esquerdo. Atualmente, nosso projeto
tem apenas um arquivo, que é o ícone do Gadot Na guia do sistema de arquivos, podemos manter nossos
arquivos de projeto organizados criando pastas e
pesquisando-as usando o filtro. Voltando à guia da cena, se tivermos uma nota selecionada
, suas propriedades serão apresentadas na
guia Inspetor à direita Podemos expandir as categorias
dessas propriedades e
editar seus valores aqui. Esse dock também
contém a guia Node, que fornece uma lista de
sinais que esse nó pode emitir, bem
como de quais grupos
ele faz parte A guia de histórico contém uma
lista de todas as alterações que
fizemos na cena atual
ou em todo o projeto. Você pode ver todas
as alterações que fizemos,
além disso, eu também editei
o Editor Fontie No momento, o encaixe inferior está fechado, mas podemos clicar no botão
de saída para expandi-lo A saída também
nos mostrará as alterações que fazemos no projeto e também exibirá a saída de
texto do nosso jogo, o que é muito útil
para depuração Podemos
enviar mensagens manualmente aqui, mas o editor também emitirá avisos e erros aqui. O depurador tem uma variedade
de ferramentas úteis para nos
ajudar a descobrir o que está atrasando ou
travando Também existem guias
específicas para áudio,
animação, shaders e mais guias serão adicionadas aqui
conforme necessário Podemos fechar essa doca clicando na guia
atualmente selecionada. Ao clicar nos três pontos,
essas docas podem ser reorganizadas
para atender às suas necessidades, da maneira que você
achar que funcionará melhor
para acomodar seu fluxo de trabalho para acomodar As guias individuais também podem
ser arrastadas entre os documentos. Ao encontrar um layout
que funcione bem para você, você pode salvá-lo
no menu do editor. Você também pode alterar uma variedade de configurações do editor para personalizá-lo de acordo com suas necessidades Quando finalmente tivermos
um jogo para rodar, podemos fazer isso usando os botões
no canto superior direito. Jogando o jogo desde o início ou apenas
executando a cena atual, pausando ou parando o jogo No próximo vídeo,
aprenderemos como criar uma cena. Te vejo no próximo vídeo.
4. 0 a 3 cenas: Olá, amigos. Agora que estamos familiarizados com o
layout do editor, vamos começar a editar
nossa primeira cena. Começaremos
clicando em duas cenas D, transformando o nó raiz
da nossa cena em um nó dois D. Um nó dois D na verdade não
representa nada em nosso jogo. É apenas uma transformação
bidimensional. Uma transformação é uma combinação de posição, rotação e escala. Godot também inclui um
componente de inclinação em duas transformações D. Se realmente quisermos
desenhar alguma coisa, precisaremos adicionar outro
nó à nossa cena. Clicando com
o botão direito do mouse no nó raiz e selecionando Adicionar filho ou clicando
no botão Mais, podemos adicionar um
nó filho à nossa cena. Há muitos tipos
diferentes de nós, todos com propósitos
diferentes. A forma mais comum
de desenhar algo em dois jogos D é
usando um sprite Então, adicionaremos um nó Sprite
two D à nossa cena. Os tipos de nós herdam
de outros tipos de nós. Portanto, um sprite, dois nós D, também é um nó, dois D e um item de tela, um nó básico, e tem de um nó básico, e tem
todas as mesmas propriedades
herdadas desses tipos, além de algumas mais próprias O nó Sprite two D é adicionado como filho
do nó raiz, indicado pelo recuo As cenas são organizadas
em uma hierarquia, começando com um
único nó raiz depois se ramificando em qualquer
número de nós secundários Esses nós secundários também podem ter seus próprios nós secundários
formando a árvore de cenas. Podemos derrubar
galhos da árvore ou da árvore inteira clicando
na seta ao lado deles e novamente para expandi-los. O nó do sprite
ainda não está desenhando nada porque não
foi dito o que desenhar Selecionando-o, para que possamos ver suas propriedades
no inspetor, onde ele realmente tem propriedades
herdadas do node, do item
Canvas e do node D. seção Sprite two D, ele também tem uma propriedade de textura, que atualmente está Podemos carregar um arquivo de
textura ou arrastar o ícone GAD da guia
do sistema de arquivos para o campo de textura
para preenchê-lo E agora o nó Sprite
two D está desenhando a textura do ícone GADO como
um sprite em nosso jogo Vamos duplicar esse nó
Sprite two D na árvore
da cena clicando com o botão direito do mouse e selecionando duplicar ou selecionando o nó e
pressionando Control ou Command D. O duplicado tem todas as mesmas propriedades
do nó original e é renomeado anexando um
número crescente Os irmãos na árvore da cena não podem
ter o mesmo nome Podemos mover qualquer um
dos nossos sprites na visualização
da cena simplesmente arrastando-os Isso atualizará automaticamente suas duas
propriedades de posição D transformadas no inspetor Também podemos girar o sprite, escalá-lo e
incliná-lo, se quisermos Em seguida, vamos arrastar esse nó
Sprite Tu Di
para o outro, atribuindo-o a ser um nó filho
do outro nó Sprite Tu Di, indicado por outro
nível Agora, se selecionarmos o nó pai do Sprite tu Di e editarmos
suas propriedades de transformação, essas alterações serão
herdadas pelo As propriedades de
transformação da própria criança são definidas em relação
às do pai. Essa estrutura hierárquica
de cenas e a herança de propriedades nos permitem construir cenas
complexas com Podemos adicionar qualquer número de nós
diferentes à
cena de diferentes tipos, como um
reprodutor de fluxo de áudio, dois nós D e uma partícula de GPU, dois nós D. Agora, essas duas cenas D podem
desenhar algo, emitir sons e partículas, e todos esses componentes
herdarão sua
posição
de transformação do nó raiz Para facilitar as coisas, a transformação de um
nó raiz deve sempre ter todos os valores padrão e ter somente nós secundários com
suas transformações editadas Podemos renomear os nós, o que é particularmente útil para o nó raiz de uma cena
descrever o que é Vamos chamá-lo de
algo como robô. Em seguida, podemos salvar essa cena como um arquivo de cena em nosso projeto, e ela será automaticamente nomeada da mesma forma que o nó raiz. Em seguida, crie uma nova cena em
dois D e imagine que isso represente uma
sala contendo o robô. Nossa cena de robô pode ser adicionada à cena
como um único nó. Podemos até ter vários
robôs, se quisermos. A partir do contexto
dessa cena maior, agora
podemos editar as propriedades
de
transformação de um robô para movê-lo,
girá-lo, escalá-lo, incliná-lo, etc Vamos renomear essa cena para
Room e salvá-la. Se voltarmos à cena do robô e editarmos os nós
secundários do robô, essas alterações serão aplicadas a todas as instâncias do
robô em outras cenas. A cena da sala
não precisa se preocupar com a forma como o
robô é construído, apenas onde ele está
dentro da sala. Construir cenas a partir de componentes
individuais nos
permite manter os detalhes de objetos
individuais contidos e
escondidos de escopos maiores Também nos permite
produzir facilmente várias cópias
da mesma coisa, mas com apenas uma fonte para esse objeto que
precisa ser editada. Construir um jogo inteiro
consistirá em construir muitas cenas menores que representem objetos,
personagens e locais individuais do
jogo e, em
seguida, combinar várias dessas cenas
para criar uma cena maior enquanto
o jogo está em execução. No próximo vídeo,
exploraremos como o mecanismo fornece tipos de
nós integrados úteis para
simular a física Te vejo no próximo vídeo.
5. 0-4 Física: Olá, amigos. Agora que entendemos como as
cenas são construídas, veremos como
os mecanismos de jogo fornecem funcionalidades
integradas para facilitar
o desenvolvimento de jogos. Podemos nos livrar dos robôs e excluir essa cena
do projeto. Vamos começar adicionando um corpo
rígido à nossa cena. No contexto da física, um corpo é qualquer objeto que possa colidir com outros
objetos e tenha massa Um corpo rígido representa
um objeto sólido. Ele será afetado por forças
externas, como a gravidade, colidirá com outros objetos
sólidos, mas não se deformará nem quebrará Ele manterá sua forma. Esse corpo rígido precisa de uma forma, que é outro
nó que deve ser adicionado como filho direto
do corpo rígido. Esse nó de forma não
sabe qual é sua forma até fornecermos a ele um
recurso de forma no inspetor No menu suspenso, podemos selecionar algumas opções diferentes. Vou fazer uma forma de retângulo. Agora, esse corpo rígido tem uma forma, mas nada está
realmente sendo desenhado Então, adicionaremos um nó
Sprite two D a ele e faremos com que ele desenhe a textura do ícone
Godot O sprite e a
forma da colisão não coincidem. Portanto, selecionando o nó da forma de
colisão, podemos ajustá-lo para melhor se adequar
ao sprite clicando e arrastando os pontos vermelhos ou editando suas propriedades Mantendo pressionada a tecla Alt com o
nó do corpo rígido selecionado, vamos
posicioná-lo em
algum lugar na parte superior central
da tela Em seguida, pressione o botão Executar cena
atual ou pressione F seis como atalho O motor do jogo
aplica forças automaticamente
ao corpo rígido para simular a física do mundo
real, como A escala de massa e gravidade
pode ser ajustada rapidamente no inspetor para
ajustar o comportamento do corpo rígido. Podemos até mesmo fornecer a ele
um material físico para adicionar atrito ou ressalto, ajustar o centro de massa e muitas outras opções Por enquanto, vamos fazer com que essa
caixa simples colida com o chão. Objetos muito resistentes que não
queremos mover
geralmente são construídos a partir de um corpo estático
em vez de um corpo rígido. Um corpo estático ainda pode
colidir com outros corpos, mas não se moverá como resultado
dessa colisão e não será afetado por forças como Um corpo estático também precisa de
uma forma de colisão. No menu suspenso,
selecionarei o limite mundial. Ao contrário de outras formas, uma fronteira mundial
se estende até o infinito Em dois D, isso é
representado como uma linha. A seta nas duas vistas em D aponta para longe do limite. Por padrão, ele
criará um piso. Mover a posição
do nó do corpo estático
até a parte inferior
da janela de visualização impedirá o corpo rígido
ultrapasse esse limite mundial Vamos duplicar o corpo
rígido e ver como ele se comporta ao colidir Podemos clicar em um nó
e alterar seu tipo. Então, vamos transformar esse
corpo rígido em um corpo estático. Em seguida, posicione-o e
gire-o para que o corpo rígido
colida com ele Lembre-se de renomear os nós depois alterar o tipo deles para
saber de que tipo eles são Mas você também pode ver pelo
ícone ao lado do nome deles. Se fôssemos programar
tudo isso manualmente, seria muito trabalhoso
desenhar esses sprites, calcular como eles são
afetados pelas forças, descobrir quando eles
colidem uns com os outros e determinar como isso
afeta seu comportamento Junto com a física, os motores de jogo nos
ajudam automatizando muitas das funcionalidades
comuns na maioria dos jogos para acelerar
e simplificar drasticamente No próximo vídeo,
aprenderemos como
anexar scripts aos nós
para editar seu comportamento. Te vejo no próximo vídeo.
6. de 0 a 5 Scripts: Olá, amigos. Embora
o motor de jogo
ofereça muitas funcionalidades
integradas, também
podemos adicionar nossas próprias
anexando scripts aos nós Selecionando qualquer nó
na árvore da cena, usarei o corpo estático
que é uma caixa flutuante. Podemos
clicar com o botão direito do mouse e selecionar script
anexado ou pressionar
o botão do script anexado. Isso abre uma nova janela. O script herdará
automaticamente do tipo
de nó ao qual
está sendo anexado, e podemos iniciar nosso script a
partir de um modelo, se quisermos Também especificaremos um
nome para o script, que deve refletir
sua finalidade. Vou nomear meu script spin, bem
como a pasta em
que ele está salvo. Clicar no botão Criar mudará automaticamente a
visualização para visualização de script, para que possamos começar a
editar o script. O modelo nos inicia com duas funções,
pronto e processo. Qualquer texto após o símbolo
Octothorp é um comentário. Ele não é usado pelo
mecanismo e existe apenas para nosso benefício, para nos ajudar a entender
melhor o script. Conforme descrevem esses comentários, a função ready será chamada
automaticamente quando esse nó entrar na árvore da
cena pela primeira vez, que é um
pouco enganador Mas, por enquanto, isso significará
quando o jogo começar. O processo, por outro lado, será chamado a cada quadro
enquanto o jogo estiver em execução, o
que, com as configurações padrão do
projeto será de 60 vezes por segundo. Uma declaração de função começa
com a palavra-chave funk, seguida pelo nome
da função Esses nomes de funções
começam com um sublinhado, que é a maneira pela qual Gudo marca as funções como privadas, o que significa que elas
só devem ser usadas dentro do contexto
desse script O nome da função é
seguido por parênteses, que conterão parâmetros para a função,
se houver A função de processo
tem um parâmetro, Delta, que é o número de segundos que passaram
desde o quadro anterior. Portanto,
geralmente será um 60º, mas às vezes aumentará se processamento de um quadro demorar
mais do que o esperado Os parâmetros são seguidos por um hífen maior que uma seta e, em
seguida, pelo tipo
de retorno da função, que em ambos os casos é nulo, o que significa que
não retornam nenhum valor Declarar os
tipos de devolução é opcional e eles podem ser
removidos se você preferir O conteúdo de uma função é recuado em uma guia,
sem necessidade de chaves Ambas as funções
contêm apenas a palavra-chave pass, que basicamente
significa não fazer nada. Mas podemos substituir essa instrução por
algo diferente. Para ver como isso
funciona, vamos mudar o corpo da
função pronta para fazer alguma coisa. A função de impressão
exibirá o
que quisermos no painel de saída
quando o jogo for executado. Podemos chamar funções
especificando seu nome seguido
por parênteses Então, dentro dos parênteses, podemos fornecer argumentos que
correspondam aos parâmetros declarados da função Dentro das aspas,
podemos escrever o que quisermos, como pronto para girar Tudo o que colocamos entre aspas é
conhecido como string, abreviação de sequência de caracteres Na função de processo, vamos fazer a mesma
coisa, mas desta vez, imprima o valor de Delta. Vamos também fazer o que esse
script deveria fazer e modificar o valor
dessa rotação de nós, aumentando-a em Delta usando
o operador mais igual. O operador mais igual a igual
pegará o valor de Delta e o adicionará ao valor
da rotação Em seguida, atribua também o
resultado à rotação. Executando a cena, podemos ver
que a caixa está girando. Parando o jogo, podemos ver na saída que
a
mensagem pronta foi impressa primeiro, apenas uma vez, seguida
por vários números, maioria dos quais é um 60º Como isso funciona? Tanto pronto quanto processado são
funções do nó, o que significa que cada nó em nossa árvore de cena já
tem essas funções, mas elas não estão fazendo nada. Nosso script está substituindo
as definições
dessas funções para
um nó específico qual esse script está anexado Podemos ver em nosso script quando
uma função está substituindo uma definição de função
quando tem uma seta azul
na frente dela Quando rodamos o jogo,
o motor reconstrói a
árvore de cenas dessa cena,
começando pela raiz, adicionando um nó por vez,
de cima para baixo A função pronta
para cada nó será chamada depois de adicionada
à árvore
de cena, mas também depois que todos os seus filhos tiverem sido adicionados e suas funções
prontas
forem chamadas primeiro. Isso significa que os pais podem
contar com a
adição de seus filhos à árvore de cenas antes de
serem considerados prontos. Depois que toda a árvore da
cena estiver pronta, os
quadros do processo serão iniciados. O processo será chamado
em cada nó na árvore
da cena, de cima para
baixo, em ordem sequencial Ao contrário de Ready, os pais não permitem que seus filhos
processem primeiro. Agora que temos uma compreensão básica
de como Godot funciona, no próximo vídeo, começaremos a configurar o projeto
para criar nosso jogo Nos vemos no próximo vídeo.
7. Jogo de 0 a 6: Olá, amigos. Antes de
começarmos nosso projeto de jogo, precisaremos preparar
algumas coisas. Primeiro, podemos
excluir tudo ou iniciar um novo projeto para que
possamos começar do zero. Vou remover tudo,
exceto a colisão no chão. Em seguida, renomeie essa cena e
seu nó raiz para jogo. A cena do jogo será uma cena centralizada em que toda a
jogabilidade principal acontecerá O nó raiz do jogo terá
duas ramificações secundárias principais, um nó do ambiente mundial e um nó de camada de tela. Eles representam uma distinção
clara entre o que existe
no mundo do jogo, como o nível em que o jogador
está jogando atualmente, todos os
itens do personagem, etc., e o que existe fora
desse mundo apenas para
o benefício do jogador, informações exibidas em um
heads-up display ou interface de usuário O nodo ambiental mundial
terá vários filhos. Um ou mais nós para os níveis
atuais que estão carregados, por enquanto vamos apenas representar
isso como um corpo estático tutti Um nó tutti corporal do personagem
é mais frequentemente usado para o personagem do jogador e um nó tutti da câmera que
geralmente segue o Vou redefinir a posição
da colisão
no chão de volta
à origem da cena Com um nó de câmera na cena, o retângulo azul não
representa mais qual parte do
mundo está desenhada na tela; em
vez disso, a
porta de visualização da câmera é mostrada em Magenta, atualmente centralizada
na origem Portanto, o chão estará no
centro da visão desta câmera. A camada de tela terá filhos para coisas
como exibir as informações do jogador na
tela, menus etc Todos eles serão representados
com nós de controle. O Canvas e
os nós de controle ainda usarão o retângulo azul
como janela de visualização para organizar
suas posições
na forma como isso funciona enquanto o jogador está jogando é que a câmera vê o
mundo e desenha o que vê, todas as crianças do Nodo Ambiental
mundial. Depois que a câmera renderizar uma
imagem retangular do mundo em Toti,
a camada Canvas desenhará seus
filhos por cima dela,
criando a
tela de jogo típica que estamos
acostumados Esses dois ramos também compartilham
outra distinção clara. O mundo
precisará ser pausado, mas a camada de tela não Portanto, selecionar o nó do jogo
no inspetor abaixo do nó, expandindo o processo, mudará seu
modo de processo para sempre O
nó do ambiente mundial será definido pausável e a camada Canvas permanecerá como herança
padrão Ele herdará o
modo de processo de seu pai, que é o nó do jogo, então também será sempre Como o modo de
processo padrão é herdar, todos os filhos do
ambiente mundial herdarão sendo
pausíveis, enquanto os filhos da camada Canvas
herdarão sempre
o Na primeira vez que pressionarmos o botão Executar projeto
em qualquer novo projeto, seremos solicitados a
definir a cena principal Podemos selecionar a cena atual ou selecionar outra
do projeto. Com a cena do jogo
atualmente aberta, podemos defini-la como
a cena principal por enquanto e alterá-la posteriormente,
quando tivermos uma cena do título. Isso pode ser alterado
nas
configurações do projeto , nas configurações de execução. Também é uma boa ideia definir as configurações de exibição
antes de começar. Então selecione a janela. Aqui podemos definir
a largura
e a altura da janela de visualização medidas em pixels Acho que 12 80 por 720 é um
bom tamanho para a maioria dos jogos e é compatível
com a maioria das plataformas Em Stretch, alterar o modo de
alongamento de desativado para itens
Canvas garantirá que dois nós D se estendam ou diminuam para caber
na janela do jogo Como vou usar arte em pixels, mudarei o modo de escala
de fracionário para inteiro Portanto, os pixels terão apenas o
dobro ou a metade do tamanho, evitando pixels de tamanho misto. Em renderizar
texturas, também
alterarei o
filtro de textura padrão de linear para Isso desenhará meus
ativos de pixel art exatamente como estão, evitando que
fiquem embaçados Depois de fechar as configurações do
projeto, talvez seja necessário acionar uma atualização apenas
ampliando ou girando a janela de visualização para forçar
o retângulo
ou a câmera da janela de visualização azul
a ou Agora estamos prontos para começar a
dividir o projeto em seus componentes individuais e abordá-los um de cada vez. Na próxima seção, criaremos um personagem básico de
plataforma Tutti que o jogador pode controlar Nos vemos no próximo vídeo.
8. PersonagemCorpo 1-1: Olá, amigos. Nesta seção, vamos criar um personagem de plataforma em dois
D que o jogador possa controlar Se sua cena de jogo
ainda não tem um corpo de personagem com dois Dnode,
você deve adicionar um agora O corpo do personagem dois D não é um corpo no
sentido de uma pessoa, mas um corpo físico, como o corpo
rígido ou o corpo estático Ao contrário dos corpos rígidos, o corpo de um
personagem não tem
automaticamente a
gravidade aplicada a ele, mas reagirá às colisões, ao contrário de um corpo estático Portanto, o nódulo corporal do personagem também precisa de
uma forma de colisão quando filho dela, com um recurso de forma para dizer qual
é a forma A maioria dos jogos usa uma cápsula
para representar um personagem, mas retângulos e
círculos também são usados Por enquanto, vou usar
um retângulo com dimensões de 128 por 128 Sempre podemos alterar ou
redimensionar para a forma de colisão depois de termos um desenho
do personagem para
baseá-lo posteriormente Além da forma de
colisão, também
precisaremos de um
nó de sprite para desenhar o personagem É importante não usar um nó de Sprite animado pois esse não é o propósito
pretendido Os nós de Sprite animados servem apenas para desenhar sprites
animados simples Assim que você precisar
sincronizar outros nós com suas
animações, como sons,
partículas ou
funções, você precisará mais flexibilidade do que o
nó Animated Sprite Por enquanto, vou usar apenas o ícone de Godot como textura do
personagem, que tem 128 por
128 pixels quadrados que combinam com a forma
da colisão Vamos renomear o nó
Toti do corpo do personagem para o nome
do Embora possamos não
ter a intenção de ter várias cópias
desse personagem, ainda
é uma boa ideia compor sua estrutura
em uma cena separada,
isolada da cena do jogo Podemos fazer isso clicando com o botão
direito do mouse no nó e selecionando salvar
ramificação como cena. Vamos criar uma nova
subpasta para cenas, outra dentro dela
para personagens salvá-la como o
nome desse personagem Na cena do jogo,
esse personagem agora é representado como
apenas um único nó com um ícone de claquete, nos
dizendo que é Todos os seus
nodos secundários estão ocultos, agora contidos
na cena do personagem. Podemos abrir a cena do personagem clicando no ícone da
claquete. Na cena do personagem, é uma boa prática considerar que a origem do
personagem está no
ponto central entre
os pés, como se o eixo
X fosse ponto central entre o chão. Isso garante que todos os
personagens tenham seu ponto de origem em comum
, independentemente do tamanho. Então, vamos mover os nós Sprite e em forma de
colisão
para cima ao longo do eixo Y. Além da
forma de colisão e dos nós do Sprite, nosso personagem precisará de
um reprodutor de animação para reproduzir as animações do Sprite Também é uma
árvore de animação para controlar qual animação está sendo reproduzida a qualquer
momento. Um
reprodutor de streaming de áudio com dois nós D também nos
permitirá reproduzir efeitos
sonoros. Também podemos querer um emissor de
partículas de GPU para
criar efeitos de partículas para criar efeitos de partículas para coisas como Cada um desses nós
será abordado em seu próprio vídeo para
explicá-los com mais detalhes. Por enquanto, é importante
entender como uma cena
pode representar qualquer coisa no jogo, com sua própria cena tendo muitos nós secundários
que são usados para construí-la. O nó raiz dessa cena
geralmente terá um script
anexado a ele. Dependendo de como você prefere
organizar seus arquivos, talvez
você queira
manter esse script na mesma pasta
da cena
à qual ele está anexado ou em uma pasta separada
especificamente para scripts. Você deve
nomear seus scripts de acordo a finalidade pretendida, com um nome o mais
vago possível Esse script não será específico
para meu personagem infantil, mas deve ser escrito de
forma que possa aplicado a qualquer personagem, pelo
menos por enquanto O objetivo do
script será não apenas controlar o nó
corporal do personagem em si, mas também conduzir as
operações de todos os
nós secundários para operar em harmonia conforme necessário, para criar
nosso personagem. Esse script anexado
ao nó raiz da cena do nosso
personagem também pode ser acessado na cena
do jogo e servirá a dois propósitos
adicionais. Ele ofuscará o processamento dos componentes individuais da cena
do personagem,
além de fornecer uma interface limpa
e concisa para interação com outros scripts e objetos na Isso será explorado com mais detalhes
no restante desta seção Agora que temos uma estrutura básica de
personagens pronta, precisaremos receber informações do jogador para controlá-los. Te vejo no próximo vídeo.
9. Mapa de entrada 1-2: Olá, amigos. Neste vídeo, vamos
receber informações
do jogador e
enviá-las para o personagem. Como criei o script para nó Tu Di do corpo do
meu personagem a partir de um modelo, ele já tem algum
código que
receberá entradas e moverá o
personagem para a esquerda ou direita. Se rodarmos a cena do jogo, pressionar as teclas de
seta esquerda e direita moverá o personagem, mas isso não parece muito bom e não está muito bem implementado. O comentário fornecido até nos
diz que devemos pelo
menos substituir as ações esquerda e direita da interface por nossas próprias ações de
jogabilidade personalizadas. Para fazer isso, abriremos as configurações
do projeto e, em
seguida, mudaremos para a guia Mapa
de entrada. No campo que
diz adicionar nova ação, digitaremos o nome
da nossa ação, começando com mover para a esquerda. Isso não deve conter espaços e geralmente é escrito
em minúsculas,
todas em minúsculas separadas por
sublinhados todas em minúsculas separadas por Pressione a tecla Enter ou clique
no botão Adicionar para adicionar
a ação de entrada e, em
seguida, faça
outra para mover para a direita. E também precisaremos de
um para o Jump mais tarde. À direita de cada uma
dessas ações, clique no botão de adição para adicionar um evento a
essa ação de entrada. Esse será o botão que será
pressionado para acioná-lo. O campo de escuta detectará
automaticamente os eventos de entrada ou você poderá pesquisar
os eventos de entrada disponíveis. Para mover para a esquerda, vou usar
a tecla de seta esquerda, mover para a direita com
a tecla de seta direita, e pular será a tecla z. Podemos adicionar vários
eventos diferentes a cada ação, o que significa que podemos adicionar suporte ao
controlador facilmente adicionando
eventos extras ao controlador. Vou usar o teclado direcional esquerda e para a direita para
mover o personagem, bem
como o manípulo esquerdo para a
esquerda e para a direita, e também o
botão inferior para pular Quando terminar, feche
as configurações do projeto. Neste vídeo, vamos alterar
apenas essa linha em que
estamos recuperando a entrada
e, o mais importante,
movê-la para um script separado É uma boa prática que todos os seus scripts tenham
apenas um único propósito. Esse script só será
usado para controlar um personagem, não para receber informações
do jogador. Adicionando um novo nó
à árvore de cena, este pode ser apenas um nó
normal, pois não fará nada
além de executar nosso script. Vamos chamá-lo de Player. Em seguida, anexe um novo script a ele. Há várias
maneiras de receber informações. O mais comum é
substituir a função de entrada. substituições de função devem corresponder exatamente à
função que está sendo Portanto, o nome deve ter exatamente
a mesma grafia, os mesmos tipos de parâmetros
e o mesmo tipo de retorno A função de entrada
tem um parâmetro, um evento de entrada, que
podemos nomear como quisermos. Mas eu prefiro usar
seus nomes padrão, e isso não retorna nada. A função de entrada
será chamada durante qualquer quadro quando ocorrer qualquer evento de
ação de entrada, seja
pressionando um botão, inclinando um controle analógico
ou movendo o mouse Dentro dessa função de entrada, podemos acessar o evento de entrada pelo nome e acessar seu
conteúdo com um ponto. Queremos chamar uma função do evento de entrada chamada
A ação
é pressionada. Ao chamar uma função, o nome da função deve ser
seguido por parênteses Dentro dos parênteses,
fornecemos argumentos para a função que
correspondem aos seus Nesse caso, uma string, o nome da
ação de entrada que estamos verificando. Então, escreveremos o salto
entre aspas, tomando cuidado para combinar a letra e
a
grafia exatas da ação de entrada que criamos nas configurações do
projeto Essa função retorna um booleano, verdadeiro se o botão foi pressionado ou
falso se não foi Ao colocar essa função
após a palavra-chave if, seguida por dois pontos, podemos criar um novo
nível de indentação para Qualquer coisa que colocarmos aqui
dentro só será executada se o resultado da declaração
I for verdadeiro,
portanto, somente se o
botão for pressionado. Por enquanto, vamos apenas
imprimir a palavra pular. executar o jogo,
se pressionarmos qualquer um
dos eventos de entrada que especificamos
como a ação de entrada de salto, veremos que o salto está
impresso no painel de saída. Não precisamos da
função ready, então vamos removê-la. Para coisas como movimento, especialmente ao usar
controladores com manípulos analógicos
, pode ser útil verificar essa entrada dentro da função do
processo Assim como o
script do personagem estava fazendo, precisaremos usar
o singleton de entrada Essa classe singleton tem uma
função chamada get axis. A função do eixo G
requer dois parâmetros, uma ação negativa e
uma ação positiva. A esquerda é sempre considerada negativa e
a direita positiva, correspondendo ao eixo X
em nossos dois mundos D. Então, escreveremos os nomes
de nossas ações de entrada que criamos nas
configurações do projeto entre aspas, moveremos para a esquerda e para a direita Essa função retornará um número decimal entre
menos um e positivo, representando
até que ponto o controle esquerdo está inclinado em qualquer direção, ou simplesmente negativo ou positivo se estiver usando
teclas ou botões Como o valor zero, o que significa que nenhuma entrada está sendo
fornecida, ainda é uma entrada válida, sempre
desejaremos enviar essas informações ao
jogador a cada quadro. Portanto, não há necessidade de
uma declaração if aqui. Vamos apenas imprimir o valor está sendo retornado aqui
para que possamos vê-lo. Durante o jogo, o número zero está sendo
impresso repetidamente. Pressionar as teclas de seta esquerda ou
direita, as teclas do teclado de direção no
meu controle ou inclinar o manípulo analógico esquerdo altera o valor entre menos
um e positivo Se você quiser obter
mais informações sobre qualquer uma dessas
classes ou funções, acesse a
documentação
segurando a
tecla control ou comando e clicando nelas. Abrindo o
script de caracteres anterior, temos uma variável
chamada direção sendo declarada dentro
da função de processo. Vamos comentar isso e
mover essa variável para o escopo global
do nosso script,
declarando-a na parte superior
do script. Voltando ao
script do player, onde recebemos a entrada de
movimento para passar essas informações de
um script para outro, precisaremos de uma referência
ao outro script. No script do jogador, criaremos uma
variável que contém uma referência ao corpo de um
personagem para dende Ao adicionar uma tag
de exportação na frente da declaração da
variável, a variável poderá ser
acessada pelo inspetor e podemos atribuir seu
valor como nosso caractere Então, em vez de imprimir o valor do eixo de entrada dot get, nós o enviaremos para
o personagem
atribuindo-o à variável de
direção do personagem Quando rodamos o jogo, o nó do
jogador verificará cada quadro o estado de
nossas entradas de movimento para a esquerda e
para a direita Em seguida, atribua isso à variável de direção do
personagem. A função de
processamento de scripts de caracteres verificará a variável de
direção, cada quadro, e a
usará para mover o
personagem para a esquerda e para a direita. Agora temos nosso jogador dando sugestões para mover nosso personagem. Te vejo no próximo vídeo.
10. 1–3 Movimento: Olá, amigos. Neste vídeo, vamos
melhorar o
movimento do personagem aplicando a física. No script de caracteres, podemos ver que o modelo
padrão é verificar se o valor
da direção é zero. Zero é tratado como falso e
qualquer outro valor é verdadeiro. Portanto, se for dado qualquer valor de
direção que não seja zero, a
velocidade X do personagem está sendo definida como direção
multiplicada pela Ou se a direção for zero, então ele está movendo o valor
da velocidade X do personagem
em direção a zero pela velocidade O resultado disso é que a velocidade do personagem
é zero ou velocidade, exceto no caso de
inclinar o manípulo analógico Isso não é muito realista
e não parece muito bom. Esses valores de velocidade e
velocidade de salto também
são definidos como constantes
que, diferentemente das variáveis,
nunca podem ser alteradas Isso é problemático, e
devemos mudar isso se
quisermos que os personagens se movam em velocidades diferentes em nosso jogo Nós vamos lidar com o salto mais tarde. Outra coisa a ser observada é que esses valores são
medidos em pixels, então eles variam de acordo com
o tamanho do seu personagem. Por enquanto, vamos substituir
nossa constante
de velocidade uma
variável de velocidade de movimento do tipo float Vou definir o meu para 256
pixels por segundo. É uma boa ideia separar variáveis e funções
entre o que deveria ser público e privado,
precedendo os nomes privados
com um sublinhado Qualquer coisa privada
deve
ser acessada apenas de dentro
desse script em si, ao contrário da variável de direção, que está sendo
acessada e alterada a
partir do script do player,
portanto, é pública. No processo de física, substituiremos a
constante de velocidade pela nossa variável de velocidade de
movimento. E agora tudo funciona
exatamente como antes, exceto que a velocidade
é um pouco mais lenta Se adicionarmos uma tag
de exportação na frente dessa declaração de
variável, poderemos alterar o
valor dela no inspetor Essa é uma ótima
maneira de testar e ajustar o valor para
que pareça perfeito Como podemos rodar nosso jogo, ver se está bom, depois
alterá-lo e testar novamente. Outro benefício é que, se tivermos vários caracteres
usando esse mesmo script, cada um poderá ter seu próprio
valor para essa variável. Mas os personagens geralmente não deixam de
ficar parados se movem instantaneamente em sua
velocidade máxima Em vez disso, eles têm
uma certa aceleração
aplicada ao longo do tempo antes de
atingirem sua velocidade máxima. Isso pode ser feito
declarando outra variável
chamada aceleração, também flutuante e
medida em pixels
por segundo medida em pixels Se isso facilitar, você pode considerar que seu valor um múltiplo da sua velocidade. Se minha aceleração
for o dobro da minha velocidade, atingirei a
velocidade máxima em meio segundo. Ou se for metade da minha velocidade
, levará 2 segundos
para atingir a velocidade máxima. Para aplicar a aceleração
no processo físico, tudo o que precisamos fazer é mover o valor da nossa velocidade X
atual
em direção à velocidade multiplicada pela direção em uma taxa
de Mas isso acontecerá de uma só vez
em um único quadro. Para ajustar a velocidade ao longo do tempo, temos que fazer o que o
modelo está fazendo aqui onde aplica a gravidade
e multiplica por Como Delta é a
quantidade de segundos que passaram desde
o quadro anterior, geralmente um 60º de segundo, isso fará com que a taxa
de aceleração seja
aplicada ao longo do tempo, e não de uma só
vez A função move em direção pega o que está no
primeiro parâmetro, o
move em direção ao valor
do segundo parâmetro pela segundo parâmetro pela quantidade do
terceiro parâmetro e retorna o resultado. Ele não modifica o valor
do primeiro parâmetro, então temos que
atribuí-lo para sobrescrever o valor anterior
da nossa velocidade X. A função de movimento e deslizamento é definida na classe D do corpo
dois do personagem e
executará todos os
cálculos difíceis para nós, considerando a velocidade do
personagem, forças
externas como gravidade, forças
externas como gravidade, colisões com outros corpos
físicos, e então decidirá onde o
personagem deve estar em cada quadro Executando o jogo agora, temos uma aceleração
gradual
sendo aplicada antes de atingirmos
nossa velocidade máxima, e também podemos
ajustar o valor de nossa aceleração
no inspetor para que ela se sinta
da maneira que queremos Podemos remover esses comentários. A mesma lógica pode ser aplicada à desaceleração simplesmente
adicionando outra variável Esse valor geralmente é muito
maior que a aceleração. O código no processo de física já
está usando o move direction. Só precisamos substituir a velocidade pelos tempos de desaceleração Delta. No entanto, há outro momento
em que podemos querer aplicar a desaceleração, exceto quando o jogador não está
dando nenhuma contribuição, ou seja
, quando ele quer dar meia
volta e ir para o Podemos expandir nossa declaração de I
para considerar esse caso. Depois de verificar se a
direção não é zero, se nossa velocidade X é zero, o personagem está parado, então ainda
queremos acelerar Além disso, se o
seno da direção for o mesmo que o
seno da velocidade X, o jogador está tentando continuar se movendo na
mesma direção em que já
está se movendo e
queremos continuar acelerando
até a A função seno transformará
qualquer número em menos um, zero ou positivo, tornando mais simples comparar se
esses dois valores são positivos ou
negativos Podemos combinar condições
com ou. Portanto, se qualquer um desses
valores for verdadeiro, toda a
afirmação é verdadeira. Se ambos forem falsos, então queremos dar meia-volta, que significa aplicar
desaceleração vez de aceleração, resultando em uma
reviravolta muito mais rápida do que
aplicaria aceleração
se o valor
da desaceleração então queremos dar meia-volta, o
que significa aplicar
desaceleração em
vez de aceleração,
resultando em uma
reviravolta muito mais rápida do que
aplicaria aceleração
se o valor
da desaceleração fosse maior. Testando isso, mover
nosso personagem para a esquerda e para a direita deve parecer
muito mais realista agora, e podemos ajustar facilmente
os valores de nossa velocidade, aceleração e desaceleração
no Te vejo no próximo vídeo.
11. Salto 1–4: Olá, amigos. Neste vídeo, vamos melhorar a forma como
o salto é implementado. Antes de começarmos
a pular, vou mover a câmera para
cima ao longo do eixo Y para que o chão fique na parte inferior da tela, não no meio O script modelo
para nosso personagem já tem um
botão de pular usando a interface do usuário, exceto que é a barra de espaço, definindo a velocidade Y do personagem para a
velocidade de salto Mas já adicionamos nosso próprio botão de pular
em um vídeo anterior. Ao contrário da gravidade ou da aceleração, que são
multiplicadas por Delta e aplicadas
ao personagem em vários quadros, essa velocidade de salto é aplicada imediatamente
ao personagem de
uma só vez Executando o jogo, podemos
pressionar a barra de espaço para pular, mas há vários problemas. O salto tem sempre
a mesma altura e temos o
script do personagem verificando a entrada. Vamos primeiro remover isso
do processo físico
do personagem e, em vez disso,
colocá-lo em uma função pública. Vamos chamar isso de salto. Então, no script do jogador, ao pressionar o botão de pular, em vez de imprimir pular, podemos dizer
ao personagem que pule. Acessando o
conteúdo do personagem com um ponto seguido pelo
nome da função, e a função não
tem parâmetros, então não há nada
entre parênteses Mas agora estamos
permitindo que o personagem pule sempre que o
botão for pressionado, mesmo que não esteja
no chão Precisamos verificar se
o personagem está
no chão primeiro antes de
permitir que ele pule. Esta função está no chão é definida na classe D
do corpo do personagem. Agora, o personagem só pode
pular se estiver no chão, mas o salto é sempre
da mesma altura. Na maioria dos jogos, o
personagem pula mais alto segurando o botão
do que se ele fosse pressionado. Às vezes, podemos
medir por quanto tempo o botão de salto é pressionado
antes de soltá-lo e, em
seguida, passar essas
informações por meio da chamada da função de salto para
ajustar a força do salto Mas, especialmente em dois jogos de plataforma
D, geralmente
esperamos que os saltos
aconteçam imediatamente quando
pressionamos o botão, que significa que mal podemos esperar o botão seja
pressionado ou solto Então, em vez disso, é mais comum presumir que
o salto terá a altura total do salto
e, em seguida,
interrompê-lo se o jogador
soltar o botão mais cedo. Da mesma forma que reagimos ao pressionamento de
um botão
no script do player, também
podemos reagir ao lançamento dele Usando a palavra-chave if, isso só será verificado se as condições
anteriores
forem falsas, removendo a redundância
de verificar se o botão foi pressionado
e solto ao mesmo tempo Se o botão de salto for solto, podemos chamar uma função
diferente para cancelar o salto,
encurtando-o. De volta ao script do personagem, precisamos declarar a função de salto
cancelada, sem
exigir parâmetros
e sem retornar nenhum valor Uma maneira simples de fazer
isso seria
definir a velocidade
Y do personagem para zero, mas isso pode parecer pouco natural parar
completamente no ar. Então, em vez disso, dividirei
a velocidade Y por dois. Mas só queremos que
isso aconteça se a velocidade
do personagem for
atualmente menor que zero, significa que ele está
subindo e somente se sua velocidade for menor que
zero porque ele Se houvesse algum outro
motivo pelo qual o personagem estava subindo, mas ele não pulou, não
gostaríamos que ele
cancelasse um salto e
reduzisse sua velocidade Podemos controlar isso
declarando uma nova variável. Vamos chamá-lo de Is jumping
do tipo Boolean, que naturalmente assumirá o
padrão false Se definirmos essa variável como
verdadeira quando o personagem pula
, podemos verificar
se o personagem está pulando antes de permitir que
ele cancele o Caso eles
não cancelem o salto, precisamos definir a
variável is jumping de volta para
false automaticamente Então, no processo físico, verificando se o personagem
está pulando e se sua velocidade y é
maior ou igual a zero, significa que o personagem está caindo ou pelo menos
não está subindo
, podemos configurar o salto de
volta para falso porque é tarde
demais para o personagem
soltar o botão
para cancelar esse Isso funciona muito bem, mas
agora talvez queiramos
ajustar a altura em que o
personagem pode pular. O script do modelo declara a velocidade do
salto como uma constante. Assim como fizemos com
a velocidade de movimento, podemos mudar isso
para uma variável. Mas saber quanta
velocidade é necessária para atingir uma altura específica
não é muito intuitivo
e, do ponto de vista do design, geralmente
é melhor
controlar exatamente a altura em que
um personagem pode pular Então, vamos declarar
outra variável chamada altura do salto
como um número inteiro Isso será medido em pixels. Vou definir o meu para 256, que é o dobro da
altura do personagem. Usando a etiqueta on ready, podemos usar um pouco de
matemática para calcular a força de salto necessária para
atingir essa altura exata. A tag on ready
executará essa linha
do script quando o nó estiver pronto antes da função ready. Eu não sou físico,
então eu não seria capaz de explicar por que essa
equação funciona, mas funciona Basta pegar a raiz quadrada da gravidade multiplicada pela força do
salto vezes dois Em seguida, multiplique tudo
isso por menos um, pois o negativo
ao longo do eixo y está para cima Para fazer isso, precisamos saber
a força da gravidade aplicada
ao caractere como um número decimal flutuando Portanto, ao declarar outra variável
usando a tag on ready, esta deve estar acima
da variável de força de salto, então ela será definida primeiro Podemos obter a força da gravidade nas configurações do
projeto. Só precisamos especificar o caminho para a configuração
que queremos em uma string. Finalmente, quando o
personagem pular, definiremos sua velocidade Y para
essa força de salto calculada Agora, o jogador pode
controlar a altura em que deseja pular. E podemos editar facilmente altura máxima de salto de
um personagem a partir do inspetor Te vejo no próximo vídeo.
12. 1-5 Caindo: Olá, amigos. Neste vídeo, ajustaremos a forma como o personagem se sente e controla no ar. Nosso personagem pode
pular mais alto agora, mas parece muito flutuante, e o personagem pode
controlar seus movimentos no ar com
a mesma facilidade com
que no solo Você pode querer isso para o seu jogo, mas geralmente o jogador tem menos controle sobre o
personagem enquanto está no ar. No script de caracteres, podemos remover essas constantes
antigas pois elas não estão mais
sendo usadas em nenhum lugar Como nosso roteiro está
fazendo várias coisas, movendo o personagem para a esquerda
e para a direita e pulando, seria uma boa ideia
mantê-lo organizado Vou manter minhas
variáveis de
velocidade de movimento,
aceleração, desaceleração e direção
agrupadas e fazer o
mesmo com as variáveis relacionadas Podemos até mesmo criar categorias
para nossas variáveis usando a tag da categoria de exportação e especificar o nome
da categoria como uma string. Vamos ter uma
categoria separada para variáveis relacionadas à locomoção
e outra para Isso adiciona cabeçalhos
ao inspetor, para que nossas variáveis exportadas sejam organizadas nessas categorias Nossa categoria de salto
tem apenas uma variável, mas adicionaremos
mais algumas, começando com um multiplicador de gravidade Isso será um float e eu darei a ele o valor
padrão de um Em seguida, multiplique nossa
gravidade pelo
multiplicador de gravidade depois de
recuperá-la das configurações do projeto Como esse número é
usado para calcular a força de salto necessária para
atingir a altura de salto desejada, a
altura do salto do personagem não mudará e a força
será aumentada automaticamente para compensar Abrindo as configurações do projeto, examinando Physics two D, gravidade
padrão é definida como 980
pixels por segundo ao quadrado Podemos modificar a força
da gravidade aqui para todo
o projeto e
afetará todos os nossos corpos
físicos. Talvez queiramos que algumas coisas
pareçam mais pesadas ou
mais leves do que outras, e uma maneira fácil de fazer
isso é multiplicar sua própria gravidade individual
por um número diferente Aumentar o multiplicador de
gravidade do nosso personagem fará com que ele pule mais rápido e faça com que
o personagem se sinta Diminuir o multiplicador de gravidade fará com que se sintam
mais leves Em seguida, podemos reduzir
a quantidade de controle o jogador tem sobre o personagem
usando mais multiplicadores, comumente chamados de
controle aéreo e freios controle aéreo é usado quando o jogador está dando entrada de
movimento
no ar e freios pneumáticos quando não está dando
entrada no Vou definir ambos como 0,5, o que significa que a
aceleração
e desaceleração do personagem serão No processo de física, podemos organizar melhor
tudo o que está acontecendo dividindo-o
em diferentes funções, uma que é chamada somente quando o personagem está no chão
e outra quando não está Vamos transmitir o valor
de Delta para ambas as funções. Definindo uma função de física
terrestre separada, agora
podemos nos
concentrar em aplicar apenas a física apropriada para quando o personagem
estiver no chão. Em seguida, crie outra função
para física do ar e use essa função para
controlar o personagem forma diferente de
quando ele está no solo. Aqui é onde aplicaremos
a força da gravidade. Em seguida, copie também os
controles para que o personagem se mova e não se mova
da física do solo. Virar é menos
importante no ar pois não há solo
que forneça atrito, então não faria sentido
dar meia volta Tudo o que precisamos fazer é multiplicar a
aceleração natural do personagem pelo do controle aéreo e
sua desaceleração pelo multiplicador sua desaceleração Outro método é considerar o controle aéreo
e os freios pneumáticos como valores
alternativos que
substituem a aceleração e a
desaceleração , em vez de
usá-los Você também pode considerar
adicionar uma velocidade terminal, dependendo da quantidade de quedas o personagem causará por
longas distâncias e
se o jogador precisa ter um melhor
controle em tais situações Uma velocidade terminal é
a velocidade máxima que um objeto será capaz de viajar
pelo ar, uma
vez que a força da resistência do
ar
acabará se igualando à força da gravidade e
se anulando Como ainda não temos um ambiente adequado
para testar isso, tudo o que podemos fazer é definir a altura de salto do personagem
para algo muito alto, talvez até mesmo diminuir o zoom da câmera
para que possamos ver mais alto. Mas podemos ver que
o personagem se move muito rápido ao
percorrer longas distâncias, e é muito difícil para o jogador controlar
com precisão. Então, vamos exportar outra variável para nossa velocidade terminal Na atmosfera da Terra,
um humano que salta de paraquedas
atingirá a velocidade terminal em
cerca de 54 Se 100 pixels são 1 metro, então são 5.400
pixels por segundo Para aplicar esse limite na função física
do ar, podemos simplesmente usar a função
Min para retornar a velocidade Y
atual do personagem
ou a velocidade terminal, o
que for menor Em seguida, atribua o valor retornado à velocidade Y do personagem Agora podemos limitar facilmente a
rapidez com que o personagem pode
cair no inspetor, dando ao jogador mais controle quando está percorrendo
longas distâncias Vou definir o meu para 4.096 por enquanto. Te vejo no próximo vídeo.
13. 1-6: Olá, amigos. Neste vídeo, adicionaremos um botão de corrida
que o jogador pode manter pressionado para alterar
sua velocidade de movimento. Primeiro, vou redefinir
o zoom da câmera e posicioná-la
onde estava antes. A velocidade de
movimento do personagem ao jogar com o teclado
é sempre a mesma, mas podemos ajustar
a velocidade de movimento inclinando apenas parcialmente o
manípulo analógico Em alguns jogos, isso é suficiente para permitir que o jogador ande
ou corra. Mas em outros, há
um botão de corrida designado para o jogador
segurar para se mover mais rápido. Abrindo as configurações do projeto, podemos adicionar um botão Executar
ao nosso mapa de entrada. Vou usar a tecla shift ou o
botão direito do meu controle. No script do player,
usaremos as mesmas funções que usamos com o salto para
verificar se o botão de execução está sendo
pressionado ou solto. Quando o botão de corrida é pressionado, podemos mandar o
personagem correr
e, quando solto,
mandar ele andar. Enquanto estamos aqui, podemos
lidar com esse aviso de que a função de processo não está realmente usando o
valor de Delta. Para substituir
uma função existente, os parâmetros devem
corresponder exatamente,
portanto, não podemos remover completamente o
Delta Em vez disso, o mecanismo Godot
preferiria que marcassemos esse parâmetro como não usado precedendo seu nome
com Como alternativa, podemos abrir
o painel de avisos e clicar em Ignorar para fazer com que
o motor ignore
esse aviso Agora, o
script do personagem precisará dessas funções públicas:
correr e andar. Começaremos adicionando mais
duas variáveis exportadas
na categoria de locomoção, uma velocidade de caminhada e uma velocidade Em seguida, a velocidade de movimento pode ter
sua tag alterada de exportar para pronta e seu valor atribuído à velocidade de
caminhada por padrão. dar
uma declaração às funções de caminhar
e correr ,
não aceitando parâmetros e não retornando valores, precisamos apenas definir o valor da velocidade de movimento como velocidade de corrida ou
velocidade de caminhada. Em seguida, o processo físico
cuidará do resto usando o
valor atual da velocidade de movimento. Isso é tudo o que precisamos para mudar a velocidade de movimento do
nosso personagem enquanto pressiona um botão. Poderíamos facilmente reverter isso para que o personagem
corresse por padrão, mas mantenha pressionado um botão para caminhar apenas alterando o valor
padrão da velocidade de movimento para velocidade de corrida e fazendo com que o script do jogador
chame as funções opostas. Como essa lição foi muito curta, também
vou me preparar para o próximo vídeo adicionando um bloco para o personagem pular
usando um nó corporal estático. R :
Nos vemos no próximo vídeo.
14. Coyote de 1 a 7: Olá, amigos. Neste vídeo, vamos ajudar o
jogador adicionando recursos de
acessibilidade
que farão com que nosso personagem se sinta mais
tolerante ao controle Começarei redefinindo a altura
de salto do personagem para um número razoável Na maioria dos dois jogos de plataforma D, o jogo permite que
o jogador pressione o botão de pular por
um curto período após o personagem
sair de uma saliência e também quando ele estiver caindo
e quase pousando Em ambos os casos, a função is on floor
retornará false, mas faria com que o
jogo parecesse melhor para o jogador se ele ainda
pudesse realizar um salto. Para adicionar esses recursos, vamos começar alterando
o tipo de retorno
da função de salto de
nada para booleano Portanto, retornaremos verdadeiro se o salto for bem-sucedido
ou falso se não for. Dessa forma, o script do jogador pode reagir ao
botão de pular ser pressionado muito cedo e tentar pular novamente depois que o personagem
cair no chão Mudando para o script do player, em vez de apenas chamar a função dot jump do
personagem, podemos reagir ao seu valor de retorno colocando-o dentro
de uma instrução if. Se o salto retornar verdadeiro, não
precisamos fazer nada, mas se ele retornar falso, podemos supor que o
jogador queira pular quando for possível,
se isso acontecer relativamente em breve. Portanto, se não pular, se o salto retornar falso
, armazenaremos
essa entrada de salto em buffer por um breve período de tempo A maneira mais fácil
de controlar o tempo é usando um nó temporizador Podemos adicionar isso como
filho do nó do jogador
ou, como o nó do jogador não tem um tipo
específico para o qual o estamos usando,
podemos alterá-lo para ser o próprio cronômetro Examinando suas propriedades
no inspetor, podemos definir a
duração do cronômetro, que será a janela de tempo
durante a qual a entrada será armazenada em buffer e definir sua propriedade one
shot Isso significa que, uma vez iniciado, o cronômetro
contará apenas até 01 vez O comportamento padrão seria fazer uma contagem regressiva até zero repetidamente. Em seguida, vamos declarar
uma nova variável. Vamos chamá-la de
entrada em buffer do tipo callable. Callable é uma classe que contém uma chamada de função completa
com argumentos Portanto, se nosso salto falhar, queremos definir nossa entrada em
buffer salto de pontos de
caracteres
sem parênteses, já que não estamos chamando
a função agora, mas armazenando-a E também inicie o cronômetro. Como alteramos o tipo
desse nó para um cronômetro, teremos que alterar o tipo de nó que esse script estende
na parte superior do
script para poder acessar as funções
da classe timer Então, na função do processo, se esse cronômetro estiver em execução, se não estiver parado, chame a entrada em buffer Se a
entrada armazenada em buffer retornar verdadeira
, ela foi bem-sucedida e
podemos parar Se a entrada armazenada em buffer
retornar falsa
, isso
ainda não pode acontecer nesse quadro, e vamos querer
tentar novamente no próximo quadro até que o cronômetro
acabe ou Para fins de teste, também
vamos usar algumas instruções de impressão para imprimir quando o
salto é armazenado em buffer, quando a entrada em buffer falha
e quando é bem-sucedida e Ao executar o jogo, se
pressionarmos o botão de pular mais cedo, a entrada do salto será armazenada em buffer Ele falha algumas vezes depois é bem-sucedido quando o
personagem cai no chão Se pressionarmos o botão de pular quando o personagem estiver
no ar, a entrada
será armazenada em buffer, mas falhará até que o cronômetro
acabe e Quando estivermos satisfeitos com o desempenho do
nosso buffer de entrada, podemos remover ou
comentar essas instruções de impressão Em seguida, queremos permitir que
o personagem pule se tiver
saído recentemente de uma saliência,
comumente chamada de hora do coiote, referindo-se
ao coiote Wiley referindo-se
ao Na
cena do personagem, podemos adicionar um nó temporizador e
renomeá-lo Como o cronômetro do buffer de entrada, será um cronômetro único e podemos ajustar a
duração do Com a cena do personagem aberta
no script do personagem, podemos obter uma referência
a qualquer nó secundário mantendo
pressionada a tecla de
controle ou comando e, em
seguida, clicando e arrastando
o nó para o script Isso
cria automaticamente uma variável com o mesmo nome e usa a tag on ready
para definir seu valor usando a notação do caminho do nó
começando com o sinal $1 uso dessa notação de caminho de
nó de cifrão exige que esse nó exista com o caminho exato do nó em relação ao nó ao qual
esse script está anexado Caso contrário, isso
causará um erro. No entanto, esse
tempo de coiote é um recurso que geralmente só
se aplica ao personagem do jogador Talvez não queiramos
ter esse nodo em todas as cenas dos personagens. Portanto, podemos usar a
função get node ou
null passando o mesmo
caminho do nó como um argumento de string Essa função retornará uma referência
ao nó seguindo esse caminho do nó ou nula se ela não existir sem
causar erros Na função de salto, nossa verificação para ver se
um salto é possível agora
será se
o personagem está no
chão ou se o personagem tem
um cronômetro de coiote e
o cronômetro de coiote não está
parado Em operações lógicas, e será avaliado antes ou a menos que
você inclua colchetes. Em relação à declaração A, o lado esquerdo será verificado
antes do lado direito. Portanto, se o
cronômetro do coiote não existir, a declaração A
será considerada falsa Portanto, o lado direito
de saber se o cronômetro
do coiote está funcionando ou não não
será verificado Agora tudo o que precisamos fazer é
iniciar o cronômetro do coiote. Para fazer isso, precisamos saber quando o personagem
sai de uma saliência Vou considerar que isso está incluído na categoria de
salto e declararemos
duas novas variáveis Está no chão para armazenar o valor retornado
da função I no chão
para esse quadro. Isso nos permitirá
realizar essa verificação uma vez por quadro e armazenar os resultados que possamos usá-la várias vezes, evitando a necessidade de chamar a
função várias vezes por quadro e estava no chão, que manterá o valor de is on floor em relação
ao quadro anterior. Durante o processo de física, definiremos o valor de was
on floor para is on floor e, em
seguida, is on floor para o valor retornado
da função is on floor. Qualquer outra chamada para a função
is on floor pode usar nossa variável
para ser mais eficiente. Então, se o personagem
estava no chão no
quadro anterior e não está
no chão desse quadro e sua velocidade y é
maior ou igual a zero, significa que ele não pulou, a única conclusão lógica é que esse
personagem
saiu de uma saliência ou o chão
em que estava desapareceu, e esse é o quando o
cronômetro do coiote deve começar. Para fins de teste, vamos adicionar instruções impressas para
sabermos quando o cronômetro do coiote começa e quando um salto de coiote Isso exigirá uma instrução if
redundante, mas a removeremos posteriormente OK. Executando o jogo para testá-lo. Podemos sair de uma saliência e ver que o cronômetro do coiote começa. Se pressionarmos o botão de pular enquanto o
cronômetro do coiote estiver funcionando, o personagem ainda
poderá realizar Agora temos uma
plataforma Toti sólida e um controlador de
personagens Na próxima seção,
desenharemos e animaremos o personagem Nos vemos na
próxima seção.
15. Sprite 2-1: Olá, amigos. Nesta seção, vamos pegar
nosso ícone simples de Gadot e transformá-lo em um personagem
totalmente animado Para isso, precisaremos
de ativos, imagens e arquivos de áudio. Os que estou usando serão incluídos se você
quiser usá-los, mas eu recomendo que estudantes
intermediários usem seus próprios recursos ou
outros ativos gratuitos. Antes de começarmos
a importar ativos, é uma boa ideia criar uma pasta separada para armazená-los. Também podemos criar subpastas
diferentes para diferentes tipos de ativos, como folhas de sprites e efeitos sonoros Clique na pasta em que você deseja que seus ativos importados estejam e, em
seguida, basta clicar e arrastar os ativos para a janela
do Gadot O processo de importação
ocorrerá automaticamente e eles serão classificados
na pasta em foco Se eles não estiverem
na pasta correta, você sempre poderá arrastá-los para a guia do sistema de arquivos para
reorganizá-los também. Mas isso
acionará uma reimportação, então é melhor importá-los
para a
pasta correta para começar, especialmente para arquivos maiores Abra a cena do seu personagem
se ela ainda não estiver aberta. Usar esses recursos para desenhar o personagem pode ser
tão simples quanto substituir o ícone do Gadot pelo arquivo de imagem
importado se seus ativos tiverem apenas
um sprite por Os ativos que estou usando estão
organizados em uma folha de sprites, então há vários
sprites em uma única textura, que não é o que eu quero desenhar Usando o menu suspenso, podemos selecionar outros tipos de texturas, e aquela para
usar uma folha de sprite é chamada de textura de atlas Clicando na
textura do atlas para expandi-la, podemos editá-la
aqui mesmo a partir do inspetor Atribuindo a
planilha de sprites como atlas. Podemos então editar a
região do atlas, que será desenhada
pela textura do atlas Ao selecionar uma região da
planilha gráfica a ser usada,
podemos usar o recurso de
corte automático para selecionar um único sprite ou
encaixe de pixel para clicar e
arrastar Como esses sprites são todos de tamanho e espaçamento
uniformes, usarei essa região de 32 por
36 pixels Ao alterar o sprite, a largura e a altura não
serão alteradas Somente as posições X e Y serão incrementadas em valores
uniformes Isso facilita muito
a animação do personagem. Antes de se comprometer a usar um conjunto de ativos para
animar um personagem, talvez valha a pena
editar sua planilha de sprites para ter esse espaçamento uniforme e
economizar Vou mover o sprite para baixo para que ele
fique no eixo X. Sua posição Y agora é metade da altura
da região do sprite. Agora que temos uma representação
visual precisa do nosso personagem, podemos ajustar melhor a forma
da colisão Podemos reordenar os nós
secundários para desenhar
a forma de colisão sobre o sprite do personagem e
facilitar as coisas Vou usar o formato de uma cápsula
e torná-la grande o suficiente para incluir a cabeça, mas
não as orelhas e o corpo, mas não necessariamente os
braços, a cauda ou a arma. Isso será usado para colidir
com o ambiente,
portanto, qualquer coisa fora
da forma de colisão se
sobreporá às
paredes, teto Certifique-se de que a forma de
colisão e o sprite permaneçam centralizados em torno do eixo Y e se encaixem confortavelmente no eixo X,
como se fosse o Se o tamanho do seu personagem
mudar significativamente, você provavelmente desejará
alterar os valores de suas variáveis para coisas como velocidade de
movimento e altura de salto. Também podemos digitar
equações matemáticas nesses campos, e o mecanismo
determinará o resultado para nós Mas vou reordenar a forma da colisão para ficar atrás do sprite Com o personagem
centralizado ao longo do eixo Y, para que o
personagem fique voltado para a esquerda ou para a direita, tudo o que precisamos fazer é
alterar o valor da variável flip horizontal
no nó Sprite two D. Passando para o script do
personagem, pegaremos uma referência ao nó D
do Sprite two e a armazenaremos em uma variável, mantendo
pressionada a tecla de controle ou comando e
arrastando-a para o Em seguida, declararemos uma
função pública chamada face left, não
aceitando parâmetros
e não retornando nenhum valor Embora a
intenção atual seja
usar essa função apenas de forma privada
nesse script, você provavelmente pode imaginar
que mandar um personagem
encarar uma direção pode ser
útil em um contexto público Para virar para a esquerda, tudo o que
precisamos fazer é definir o valor da propriedade
flip H do sprites como true Também poderíamos escrever outra
função chamada face right, mas a função
estaria apenas configurando o valor dessa
variável de volta para false. Às vezes, é mais fácil escrever nossas funções para
sermos mais flexíveis. Em vez de ter uma função face esquerda e face direita,
podemos dar à função face esquerda um parâmetro
que permite que ela faça as duas coisas. Vou apenas nomeá-lo à esquerda e atribuir um valor padrão verdadeiro. Dar a um parâmetro um
valor padrão o torna opcional. Portanto, essa função
chamada face left pode ser chamada sem
fornecer nenhum argumento, e assumiremos
que ela deseja ficar voltada para a esquerda. Podemos então definir o valor do
flip H para o valor da esquerda. Para fazer com que o personagem fique com a
face direita, tudo o que precisamos fazer é chamar a
face esquerda, mas fornecer false como argumento, em
vez de chamar uma função completamente
diferente. No processo de física, se a
direção de um personagem for negativa, ele quer ficar virado para a esquerda. E se for positivo, eles
não querem ficar para a esquerda, o que é para a direita. Se a direção for zero, eles permanecerão voltados para a mesma direção em que
estavam no quadro anterior. Para ter uma visão melhor
do meu pequeno personagem, ampliarei a câmera em
um fator de quatro e reposicionarei de forma que o chão
fique na parte inferior da tela O. Quando clicamos em play, o personagem está sendo desenhado e seu sprite virado para
a direção correta, mas ele ainda não está
sendo animado Eu gostaria que meu
personagem fosse mais rápido, então vou aumentar seus valores na cena do personagem. Te vejo no próximo vídeo.
16. 2-2 Reprodutor de Animação: Olá, amigos. Neste vídeo, vamos adicionar
animações ao nosso personagem Se seu personagem não tiver um nó de jogador de animação,
você deve adicionar um agora. Com o nó
do player de animação selecionado, a guia de animação deve
se expandir automaticamente. Se não estiver aberto, você pode
abri-lo clicando no botão
Animação. O painel de animação está
vazio no momento , pois ainda
não há animações. Ao clicar no botão
Animação, selecionaremos Novo para criar uma nova animação
e chamá-la de ociosa Com uma animação selecionada, agora
há uma linha do tempo
medida em segundos. Se preferir, você pode alterar os segundos para
quadros por segundo
e, em vez disso, a linha do tempo será
exibida em quadros As molduras estão muito
próximas umas das outras, então vou ampliar para exibir as molduras mais
afastadas umas das outras. Também podemos alterar a taxa de
quadros. Vou definir o meu para 12
quadros por segundo. Também ajuda aplicar o encaixe ao
cursor da linha do tempo com essa opção Agora, quando percorremos a linha do tempo
da animação, ela é automaticamente ajustada
ao quadro Nesse painel,
podemos adicionar faixas
à animação clicando
no botão de adição. A mais comum é
uma trilha de propriedades, que nos permite editar qualquer propriedade de qualquer nó na árvore
da cena ao longo do tempo. O nó que queremos animar
é o nó Ti do sprite, especificamente, sua propriedade de
textura Isso adiciona uma faixa à linha
do tempo da animação
e, nessa faixa, podemos adicionar quadros-chave para editar a propriedade com um novo
valor naquele momento Clicando com o botão direito na faixa, podemos selecionar Inserir tecla para
adicionar um quadro-chave a essa faixa Por padrão, o valor
desse quadro-chave será
seu valor atual, que é a mesma textura que
definimos no vídeo
anterior Isso é bom o suficiente para arquivos de sprite
únicos, já que podemos simplesmente alterar
a textura aqui Mas como estou usando
uma folha de sprites, na verdade não
quero alterar
a textura Eu só quero mudar a região da textura que
está sendo usada. Há algumas maneiras
de fazer isso. Uma delas é clicar na faixa
da propriedade e
editar o nome da propriedade, adicionando dois pontos e a
palavra região após a textura Isso diz à animação
que eu quero
editar a propriedade
de região da textura, não a textura em si. Vou redefinir a animação
para ficar vazia por enquanto. Certifique-se de ter o nó do reprodutor de
animação selecionado na árvore da cena e, em
seguida, selecione o nó
Sprite two D. Expandindo a propriedade de
textura do atlas, podemos ver suas propriedades
em um painel aninhado passar o mouse sobre o nome da propriedade da
região, o pop-up nos mostrará
o nome da Isso é útil para
garantir que você tenha a letra e a grafia exatas ao tentar
acessá-la por meio de código ou
do nome da faixa de animação, como acabamos Mas o segundo método de adicionar faixas de
propriedades a uma animação, que é muito mais fácil, é usar o botão de tecla
à direita da propriedade. Esse botão só estará aqui se o nó do player de animação tiver sido selecionado
anteriormente
na árvore da cena. Uma animação está aberta no momento
e, em seguida, outro nó
na árvore da cena é selecionado. Clicar nesse botão de tecla
adicionará um quadro-chave
à animação atual na posição do cursor da
linha do Na primeira vez que
adicionamos um quadro-chave para uma propriedade que
atualmente não tem uma faixa
na animação, Godot nos perguntará se queremos
criar uma faixa para Além disso, se quisermos adicionar essa faixa à animação de
reinicialização, diremos sim para ambas. Isso adiciona a faixa
à animação, além de adicionar o primeiro
quadro-chave ao mesmo tempo Ao clicar no nome da animação
ociosa para expandir o menu suspenso, ele também criou a animação de
redefinição, que é como
o GoDo armazenará os valores padrão
das propriedades Isso ajuda a evitar problemas com a execução de animações
no editor e a alteração permanente dos valores das propriedades
sem querer Godot redefinirá todas as
propriedades para os valores padrão especificados
nesta animação de redefinição Para facilitar isso,
tente sempre adicionar faixas de
propriedades às animações quando elas estiverem em
seu estado padrão Agora estamos prontos para iniciar o processo de animação
real. Você deve ter uma trilha de
textura para alterar sprites
individuais ou
uma faixa de região de textura para alterar sprites
em uma folha de sprites Seus ativos também podem usar folhas de sprites
diferentes
para animações diferentes Se for esse o caso, você também
precisará de uma trilha para textura do atlas
e para a região da textura Tudo o que precisamos fazer é avançar na
linha do tempo em um quadro,
editar o valor da textura ou da região da
textura e clicar no
botão
da tecla para adicionar
outro quadro-chave Como sei que todos os
meus sprites têm
o mesmo tamanho e estão uniformemente espaçados, posso fazer isso ainda mais facilmente
simplesmente inserindo novos quadros-chave do que
editando manualmente a propriedade X, aumentando-a em 32 por Se testarmos essa animação, o mecanismo assumirá
que queremos interpolar os valores dessas
propriedades entre
os quadros-chave Como a taxa de quadros do jogo geral é de
60 quadros por segundo
, essa animação é de
12 quadros por segundo. O mecanismo cria
quatro quadros adicionais entre cada quadro-chave para
criar uma transição mais suave Obviamente, isso não é o que queremos com uma animação de sprite, então precisaremos mudar
o modo de atualização
dessa faixa de contínuo para discreto Agora, a propriedade só
mudará quando a animação atingir um quadro-chave e
mudará o valor imediatamente A animação é muito longa, então precisaremos definir
o número de quadros da animação para que ela termine
após o último quadro-chave Essa animação
também precisará ser repetida,
então clique no
botão de loop da animação para que o ícone de
loop fique azul. Se você clicar nele mais uma vez, ele será definido como Ping Pong, que é um
tipo diferente de loop Para animações de personagens,
geralmente queremos um loop para frente É uma boa ideia também
definir as faixas de
animação redefinidas discretas, caso
você decida
usá-las para redefinir um personagem
por meio de um script Essa animação ociosa agora
está completa e podemos
continuar fazendo o resto
das animações necessárias para
nossa plataforma e personagem Ao clicar no botão de
animação, podemos adicionar uma nova animação
e começar do zero, ou podemos duplicar essa animação ociosa e
usá-la como modelo Como sei que meus
sprites estão uniformemente espaçados, só
preciso editar as propriedades Y
dos
meus quadros-chave para alternar
de quadros inativos para quadros Podemos copiar e colar chaves
para facilitar as coisas. Uma linha conectando duas chaves significa que os valores não estão
mudando entre elas. Ao fazer a animação
em execução, simplesmente
dobrarei
a taxa de quadros. Podemos clicar e arrastar as teclas para movê-las
ao longo da linha do tempo Também precisarei fazer animações de salto
e queda. Dependendo dos
ativos que você está usando, talvez seja necessário criar animações
diferentes Por exemplo, você pode
precisar de animações de salto inicial,
salto em marcha lenta, queda em marcha lenta
ou aterrissagem Certifique-se de saber
quais animações precisam ser repetidas e quais não Agora, o personagem tem
todas as animações, mas está preso
na animação inativa Então, precisaremos
dizer ao personagem quando mudar para
outras animações. Nos vemos no próximo vídeo.
17. 2 a 3 árvore animada: Olá, amigos. Neste vídeo, controlaremos qual
animação está sendo reproduzida
no player de animação
usando uma árvore de animação. Se a
cena do seu personagem não tiver um nó de árvore de animação,
você deve adicionar um agora. O objetivo da árvore de
animação é controlar o reprodutor de
animação, decidindo qual animação deve ser
reproduzida a qualquer momento Portanto, com o nó da árvore de animação selecionado na árvore de cena
examinando o inspetor, definiremos sua propriedade
de
player de animação nosso nó de player de animação A propriedade tree root é um
recurso que será usado para determinar qual
animação será reproduzida pelo nó do player de
animação. Ao clicar no menu suspenso, temos algumas
opções diferentes para isso, maioria das quais é
mais aplicável ao usar três animações em D
ou bone, que geralmente combinam várias
animações Como esse é um sprite
simples de dois D, usaremos uma máquina de estados Ao clicar em nossa nova máquina de
estado, abriremos o
painel da árvore de animação na parte inferior
da janela do editor com uma
máquina de estado aberta para edição. Nossa máquina de estado atualmente tem um nó inicial e um nó final. Eles não são iguais aos nós
na árvore de cena, mas são nós no
contexto de um gráfico de nós. Podemos clicar no
espaço vazio para adicionar mais nós. Vamos adicionar a
animação ociosa como um nó. Podemos clicar e
arrastar esses nós para
organizá-los da maneira que quisermos. Suas posições dentro
desse espaço são irrelevantes. Alterando nosso modo de edição de selecionar e mover nós
para conectar nós, podemos clicar e arrastar
de um nó para outro, criando uma seta que os
conecta em uma direção. Essa é uma transição
do nó inicial para o nó ocioso Portanto, quando a
máquina de estado for iniciada, ela passará imediatamente
para o nó ocioso, que instrui o reprodutor de animação a reproduzir a animação inativa Voltando
ao modo de edição para selecionar e mover nós, vamos adicionar também as animações de caminhada e
corrida E voltando a
conectar os nós mais uma vez, crie uma transição de marcha lenta
para caminhada e caminhada para corrida Quando essa máquina de estado for iniciada, ela fará a transição
imediata do
nó inicial para o nó de execução. Então, queremos adicionar condições a essas transições para restringir quando essa transição
pode acontecer Selecionando a transição
de inatividade para caminhada, expanda a seção avançada Abaixo da
expressão avançada, há uma área de texto. Aqui, podemos especificar qualquer expressão
lógica
que desejamos controlar quando essa
transição pode ocorrer, desde que o resultado
seja booleano, verdadeiro ou falso Nesse caso, queremos
reproduzir a animação de caminhada se a velocidade X do personagem
for diferente de zero Portanto, isso acomodará
a caminhada tanto para a esquerda quanto para a direita. Essa expressão será
verificada no nó que
especificamos nas propriedades do nó
da árvore de animação,
o nó base da
expressão avançada. Definindo isso como o nó
raiz da cena, o corpo do personagem dois nós D, podemos fazer com que a máquina de
estado da animação reaja automaticamente à velocidade do
personagem para alterar a animação Voltando à máquina de estado, passando da caminhada para a corrida, queremos verificar se
o valor absoluto da velocidade X
do personagem
é maior que a velocidade de caminhada do
personagem Talvez você queira especificar
um limite diferente, como exigir que
o valor absoluto da velocidade X seja igual à velocidade corrida ou maior que
a média da velocidade de caminhada e
corrida, etc Agora, precisamos adicionar uma transição de
volta à marcha lenta da caminhada. Ao criar loops de transição entre dois ou mais nós em
uma máquina de estados como essa, as condições de
todas as transições não
devem ser todas verdadeiras
ao mesmo tempo Isso
impossibilitaria que
a máquina estatal decidisse qual estado deve
estar ativo atualmente, pois ela apenas circulará entre
os estados indefinidamente Como a condição para a
transição da marcha lenta para a caminhada é que a velocidade X seja
qualquer coisa diferente de zero, a transição
da marcha lenta para a marcha lenta
deve ser se a
velocidade X
for igual a Essas duas condições não podem
ser verdadeiras ao mesmo tempo, então a máquina de estados não pode ficar presa entre
esses dois Aplicando a mesma lógica à
transição de corrida para caminhada, as condições para essa
transição devem ser logicamente incompatíveis com a transição de caminhada para Portanto, se o valor absoluto da velocidade X do personagem for menor ou igual à velocidade de caminhada do
personagem, isso nunca será verdade ao
mesmo tempo que maior que Quando executamos o jogo, a máquina de
estados começa
do nó inicial e
segue as transições entre estados
diferentes, cada estado representando
uma ou mais animações Em alguns casos, a máquina de estado pode fazer a transição para o nó final. Nesse caso, ele
deixará de funcionar. Ao animar nosso personagem, nunca
queremos que essa
máquina de estado alcance o nó final, então não há nenhuma transição que
leve a ela Isso funciona para animar
o personagem em marcha lenta, andando e correndo para a
esquerda ou para a direita, mas também precisamos adicionar
animações para Se adicionássemos a animação de
salto aqui, precisaríamos adicionar
transições de todos os nossos estados existentes à
animação de salto, já que o personagem pode pular
de qualquer um desses estados Isso ficará confuso,
confuso e difícil de gerenciar, especialmente se seu personagem
tiver várias animações de
salto diferentes Em vez disso, o que podemos fazer é
criar uma máquina de estado aninhada. Começaremos salvando nossa máquina de estado atual
como um recurso do projeto. Chame isso de locomoção. Em seguida, substitua essa
máquina de estado por uma nova. Em nossa nova máquina de estado em branco, clique com o botão
direito no
espaço vazio e selecione Carregar. Encontre a máquina de
estado da Locomoção e adicione-a à nova
máquina de estado como um único nó e renomeie-a para que você saiba que é a máquina de estado da
Locomoção Em seguida, adicione uma transição
do início para a locomoção. Toda a
máquina de estado do Locomotion agora existe como um único nó que
podemos abrir
clicando no
botão Editar com um ícone de lápis Ainda temos as animações de andar e
correr inativas em
transição como antes, mas agora elas estão aninhadas em
uma máquina de Podemos retornar à
outra máquina de estado clicando nas migalhas de pão Nessa máquina de estado, adicionaremos todas
as animações relacionadas ao salto e
as conectaremos às Essa é a aparência de um loop infinito em uma máquina de estado. Queremos que o personagem mude
de qualquer estado de locomoção para pular se sua velocidade Y
for menor que zero, significa que ele está Se a velocidade Y for
maior ou igual a zero, eles atingiram o
ápice do salto e eu mudarei para
a animação de outono Em seguida, faça a transição
da queda para a locomoção se o
personagem estiver no chão Podemos chamar a função ou usar nossa variável privada
que criamos anteriormente. Talvez queiramos deixar de
pular e começar
a cair direto se o personagem
sair de uma Então, vamos adicionar isso como
outra transição sob a condição de
que o personagem não
esteja mais no chão. Isso cria um conflito em nossa máquina de estado quando o personagem está em estado de
locomoção e pula Sua velocidade é menor que zero e eles não
estão no chão Então, qual transição
a máquina de estado deve usar? Em casos como esse,
podemos dar
prioridade às nossas transições em relação às outras diminuindo
sua propriedade prioritária Se o personagem pular, sua velocidade Y
é menor que zero e ele não está no chão Mas a transição para o
salto tem prioridade. Então essa é a transição
que será usada. Se o personagem
sair de uma saliência, sua velocidade é
maior que zero e ele não está no chão, então não há conflito Nosso
personagem de plataforma em dois D agora está animado, mas podemos fazer com que se sinta
muito melhor
adicionando mais polimento Te vejo no próximo vídeo.
18. 2-4 Efeitos sonoros: Olá, amigos. Neste vídeo, vamos adicionar efeitos sonoros ao nosso personagem animado. Para isso, precisaremos importar
alguns arquivos
de som para o nosso projeto, classificados em uma pasta
apropriada Incluirei alguns efeitos
sonoros que você pode usar para
acompanhar esta lição, mas recomendo que estudantes
intermediários usem recursos próprios ou gratuitos. Primeiro, vou me livrar
do nó corporal estático que é esse retângulo branco, pois não o
estou mais usando Comece adicionando um stream de áudio Player two D node à cena do
seu personagem, se você ainda
não tiver um. Os dois nós D
do reprodutor de fluxo áudio
diferem de um nó
reprodutor de
fluxo de áudio porque o volume do efeito sonoro varia de acordo com sua
proximidade com o ouvinte O ouvinte
padrão é a câmera. Podemos preencher a propriedade de
transmissão do
nosso reprodutor de streaming de áudio com um efeito sonoro e clicar no botão de reprodução
para ouvi-lo Se dermos uma olhada nas animações do nosso
personagem, particularmente a animação de salto, podemos adicionar uma
faixa de reprodução de áudio à animação e
selecionar o reprodutor de
fluxo de áudio para denode como
reprodutor dessa Em seguida, podemos
enquadrar os efeitos sonoros para reproduzir como
parte dessa animação, mas isso vem com
muitas limitações Se o efeito sonoro
for maior que a animação, ele
será interrompido. Se a animação estiver em loop,
ela será repetida
e, com efeitos sonoros,
o jogador ouvirá várias vezes enquanto joga
este jogo É uma boa ideia
adicionar um pouco de variedade e aleatoriedade para que o jogador não se
canse de ouvir Então, vamos remover essa faixa
da animação e tentar
um método diferente. Como sabemos o
momento exato em que o personagem
salta do roteiro, seria mais fácil
reproduzir o som dessa forma Vamos renomear o reprodutor de
fluxo de áudio para DNodet jump e pegar uma referência para armazená-la em uma Quando o personagem pula, tudo o que precisamos fazer
é mandar ele jogar Mantendo o efeito sonoro
fora da animação, ele será
reproduzido na íntegra e apenas Também podemos duplicar esse reprodutor de
streaming de áudio em dois nós D para adicionar mais efeitos sonoros, como um para
um som de aterrissagem Então, no roteiro, podemos reproduzi-lo da
mesma forma que o som do salto, mas ainda não temos uma função
conveniente para quando o personagem
cai no chão. No processo de física, temos uma declaração if verificando se o personagem
saiu de uma saliência Invertendo essa lógica, podemos verificar se o personagem
pousou nesse quadro, se não estava
no último
quadro do andar e se está no
chão nesse Em seguida, chamaremos uma nova função
privada. Vamos chamá-lo de landed. Por enquanto, essa função só precisa reproduzir o efeito sonoro de
aterrissagem. Esses efeitos sonoros serão reproduzidos quando o personagem
pular e pousar, mas
sempre serão os mesmos, o que incomodará
o jogador depois de algum Podemos melhorar isso aleatoriando
ligeiramente a escala de tom do som
toda vez que ele é reproduzido Então, vamos anexar um script ao nosso reprodutor de streaming de áudio two dende e
chamá-lo de algo como randomizador de efeitos
sonoros sem usar um modelo e salvá-lo
na pasta apropriada Esse script precisará de
uma função pública que
lhe diga para reproduzir um efeito sonoro
aleatório, não
aceitando parâmetros
e não retornando nenhum valor O resultado final
disso será chamar
a função de reprodução definida no reprodutor de fluxo
de áudio
para denode Mas antes de reproduzir
o efeito sonoro, queremos editar o valor da propriedade
da escala de tom. Usando a
função incorporada rand F range, podemos gerar uma flutuação
aleatória entre um
valor mínimo e máximo que especificamos Sendo uma a escala de tom
padrão, vou randomizá-la para ficar
entre 0,5 e 1,5, o que deve produzir uma ampla
variedade de sons semelhantes Podemos anexar esse mesmo script ao outro reprodutor de
streaming de áudio Dnode clicando
e arrastando da guia
do sistema de arquivos para
o nó na árvore da cena De volta ao script do personagem, em vez de chamar
o Audio stream Player para a função de
reprodução das classes D, chamaremos nossa função play
random. Isso pode ser
suficiente para reduzir
a monotonia de nossos sons de salto
e aterrissagem, mas passos serão ouvidos constantemente durante Portanto, talvez você queira ter vários efeitos sonoros
diferentes
para algo assim e fazer com
que o
reprodutor de fluxo de áudio escolha um aleatoriamente Vamos duplicar dois nós D de um reprodutor
AudioStream para criar outro
para sons de passos, também com o mesmo script aleatório ainda anexado. No script, exportaremos
uma variável para manter todos os diferentes efeitos
sonoros de passos como uma matriz de fluxos de áudio Isso pode ser preenchido rapidamente por um grupo selecionando todos os sons de
passos
na pasta de ativos
e
arrastando-os para a matriz
exportada Então, ao reproduzir um efeito sonoro
aleatório, verificaremos se o tamanho
dessa matriz não é zero Se a matriz não estiver vazia, isso significa que devemos
definir o valor do stream como um
elemento aleatório dessa matriz. Acessar um membro
da matriz com um número de índice inteiro como um inteiro aleatório entre zero e o tamanho da
matriz menos Isso simplesmente escolherá
um som aleatório de nossa variedade de sons. No caso de nossos outros sons
aleatórios, como eles não estão especificando
nenhum valor para a matriz, seu tamanho é zero e ele não tentará
randomizar o efeito sonoro, apenas ajustará sua Agora só precisamos
que o efeito sonoro acionado pelas animações de caminhada
e corrida Alternando da
visualização do script para duas visualizações D, primeiro selecione o nó da Árvore de
Animação e, em
seguida, o
nó do Reprodutor de Animação para
visualizar temporariamente as animações sem interferência
da Árvore de Animação Com as animações de caminhada ou
corrida abertas, podemos adicionar uma
faixa de método de chamada à animação e chamar um método no reprodutor de
fluxo de áudio de passos para Ao inserir uma chave na
animação dessa faixa, chamaremos o método play
random Um método nesse contexto é
sinônimo de uma função. Podemos vasculhar
a animação para
encontrar os quadros em que os pés do
personagem realmente entram em contato com o chão e
definir os quadros-chave para que estejam exatamente
nesses quadros Em seguida, repita esse processo
com a outra animação. Agora temos vários passos
aleatórios, efeitos
sonoros de saltos e aterrissagens, mas também podemos
querer nuvens Nos vemos no próximo vídeo.
19. 2–5 Sprite animado: Olá, amigos. Neste vídeo, vamos criar partículas de
poeira para nosso personagem de plataforma Para isso, precisaremos
importar mais planilhas de sprites. Começando na cena do personagem, adicionaremos um Sprite animado ao nó e o chamaremos
de Jump dust O Animated Sprite
to dende difere de um Sprite normal para o de node porque não tem uma
única Ele tem um recurso de molduras Sprite. Clicando no menu suspenso, podemos criar um
novo
recurso de quadros Sprite para esse nó de dois D do Animated
Sprite Em seguida, clique no
recurso para abri-lo. Isso abrirá uma nova guia
no painel inferior
chamada Sprite frames Nessa janela, podemos criar uma ou mais animações de
quadros do Sprite que esse nó
poderá reproduzir Essas animações só podem
mudar o Sprite em si. Eles não podem ser
sincronizados com áudio, chamadas de
função ou
outras propriedades da mesma forma que um nó do Animation
Player Dependendo dos
ativos que você está usando, você pode adicionar sprites de arquivos
individuais ou de uma única planilha Sprite Estou usando Sprite Sheets, então vou clicar nos quadros
de anúncios no botão Sprite Sheet Navegue pelo sistema de arquivos para encontrar os ativos desejados. Se estiver usando uma folha de sprite, você será solicitado
a selecionar quais quadros da
planilha de sprite você deseja Ao contrário da textura de um atlas, essas molduras de sprite
devem ser espaçadas uniformemente Selecione o número de quadros em cada linha e coluna
da planilha de sprite e eles serão cortados Em seguida, você pode selecionar cada um
dos quadros que deseja
usar clicando neles. O número no canto
de cada quadro de sprite é a ordem em que ele
será adicionado à animação Se eles não estiverem
na ordem correta, você pode desmarcar e
selecionar novamente os quadros Sprite ou importá-los fora de ordem
e reordená-los Assim como as animações
dos
personagens um quadro a
mais do que o último quadro, é uma boa ideia animações de
sprites como essa tenham um
quadro vazio no final Portanto, o último quadro
permanecerá desenhado na tela por toda
a duração de um quadro antes que a animação seja
considerada concluída. Podemos definir a
taxa de quadros da animação. Vou usar 12 quadros por segundo e se
essa animação deve ou não ser repetida, o que vou desativar. Também existe a opção de
reproduzir automaticamente essa animação. Cada nó Animated Sprite
Toti pode ter apenas uma animação de
reprodução automática, e o nó
reproduzirá essa animação quando o nó for adicionado
à árvore Quando uma nuvem de poeira é criada
pelo jogador pulando, queríamos reproduzir
essa animação Então, vamos fazer com que essa
animação seja reproduzida automaticamente. Podemos visualizar a
aparência da animação clicando
no botão play. Para ver melhor a animação, podemos ocultar
temporariamente o
sprite do personagem e a forma da colisão clicando no ícone
do olho ao lado
deles na árvore da cena Assim como o personagem,
essa animação
precisa ficar limpa no
chão do eixo X. Portanto,
na seção de deslocamento do inspetor, podemos definir seu deslocamento Y como
metade de seu Com os ativos
que estou usando, são 16 pixels acima. Isso mantém as origens dos nós em 00 enquanto ainda desenha
o deslocamento do Sprite Se a cor dos
sprites não estiver
correta ou se você quiser
ajustar sua transparência, você pode fazer isso na seção de itens de
tela das propriedades
dos nós
no inspetor A propriedade modulate é uma cor com um
valor padrão de branco, que tem valores de um vermelho, um verde, um azul
e um Alpha Cada pixel no sprite
terá sua própria cor
multiplicada por essa cor modulada antes de ser desenhado Assim, podemos ajustar seus valores de vermelho, verde, azul ou alfa. Vou dar
meia transparência à minha nuvem de poeira definindo
seu módulo Alpha para 0,5 Podemos reordenar os sprites
clicando e arrastando-os
usando os botões de seta, excluir quadros, adicionar quadros vazios
ou importar mais quadros, se necessário Quando estiver satisfeito com a
aparência da animação, lembre-se de mostrar o sprite do
personagem e a forma de
conluio sprite do
personagem e a forma de
conluio Vou ativar o loop para fins de
demonstração. Quando rodamos o jogo,
a poeira acompanha o personagem
, pois ele é filho dele. Mas o que normalmente queremos para
algo assim é a nuvem de poeira apareça em um local específico
e não se mova Essa nuvem de poeira precisará ser uma irmã do
personagem, não uma criança Clicando com o botão direito do mouse no nó D do
Animated Sprite two, podemos salvá-lo como sua própria cena Coloque-o em uma nova pasta
para nuvens de poeira. Exclua-o da cena do
personagem. Em seguida, abra-o para que possamos
editá-lo isoladamente. Vamos desligar o loop
dessa animação. Ainda queremos que ele seja reproduzido automaticamente quando a nuvem de poeira for criada, mas trataremos
disso no próximo vídeo Por enquanto, temos mais duas nuvens de
poeira para criar. Um para quando o personagem pousa e outro para
quando ele anda ou corre. Assim, podemos duplicar nossa cena existente de poeira saltada
para facilitar as coisas Não fará diferença, mas eu gosto de
garantir que o nome do nó raiz
das minhas cenas
corresponda ao nome do arquivo da cena. Depois, basta trocar os sprites pelos
corretos em cada caso A Certifique-se de que tudo esteja devidamente deslocado
para ficar limpo no
chão do eixo X. Agora temos três nuvens de poeira
diferentes que
queremos usar com
nosso personagem. Só temos que
instanciá-los. vejo no
próximo vídeo.
20. 2-6 Instanciar: Olá, amigos. Neste vídeo, vamos instanciar
as nuvens de poeira em reação aos movimentos
do nosso personagem animado A partir da cena do jogo, queremos que nossas
nuvens de poeira existam
no mundo como irmãs de
nosso personagem, não como crianças Vamos anexar um novo script
ao Node Ambiental mundial. Vou chamá-lo de mundo e
colocá-lo na pasta de scripts. O
objetivo principal desse roteiro, por enquanto,
será gerar novas cenas
como crianças Então, escreveremos uma nova
função pública chamada spawn, que aceita uma cena compactada
como primeiro parâmetro Vou chamá-lo de
algo vago como SN e também de uma posição
em que ele deveria ser gerado, que é um vetor dois Então, essa função retornará o nó que ela cria,
caso desejemos usá-lo. Podemos transformar uma cena compactada em um nó chamando sua função
Instantiate. Precisaremos armazenar esse nó em uma variável para
poder usá-lo. Vou chamá-la de instância. Criar um nó não o
adiciona à árvore da cena. Temos que fazer isso também. Mas para adicionar qualquer nó
à árvore de cena, o nó precisará de um pai. Esse
nó do ambiente mundial será o pai, então vamos chamá-lo de função
add child, fornecendo a instância
como argumento. Isso adicionará o nó
à árvore da cena, mas sua posição será na origem
da cena,
coordenadas 00. Então, queremos definir a posição
do nó recém-instanciado como
a posição de geração No entanto, isso pressupõe que o nó recém-instanciado
tenha uma propriedade de posição, que não é verdade Embora isso ainda não
cause um erro, pode
acontecer no futuro, se usarmos a função spawn para criar diferentes
tipos de nós Portanto, seria uma boa ideia verificar
se essa instância é um item de tela antes de tentar acessar sua propriedade
position. Podemos tornar o parâmetro de
posição de desova opcional dando a ele um valor padrão
de vetor de dois pontos zero Por fim, podemos retornar
o nó da instância. Agora precisamos chamar
essa função como uma reação ao personagem que
executa determinadas ações. A maneira mais fácil de fazer
isso é usando sinais. No
roteiro do personagem, podemos declarar sinais na parte superior
do script para cada uma
das três vezes em que queremos gerar uma nuvem de poeira quando o personagem pisa,
pula ou Os sinais são convencionalmente
nomeados no pretérito, modo a dizer que o evento
em questão aconteceu Assim como as funções, os sinais
podem ter parâmetros. Para gerar
as nuvens de poeira, precisaremos saber a posição do
personagem
e para qual direção
ele está voltado, indicando se o
sprite deve ser Na função de salto, podemos emitir o sinal de salto, passando a posição
atual do personagem
e se o sprite
do personagem está ou não invertido
horizontalmente como argumentos O mesmo pode ser feito quando
o personagem pousa. Seguindo os passos, podemos
declarar uma nova função privada. Vamos nomeá-lo na etapa
e emitir o sinal. Se quiser, você também pode fazer com que
o som do passo seja reproduzido dentro dessa função,
em vez de
incluí-lo nas animações
como uma faixa separada Mas, para fazer isso,
precisarei de uma referência
ao reprodutor de áudio Footstep para indicar na parte superior do Selecionar o nó
Animation Player e a animação de caminhada. Podemos adicionar uma
faixa de método de chamada à animação, chamando um método
no nó raiz da cena. Em seguida, insira quadros-chave para
chamar a função on step durante os quadros, quando
os pés do personagem entrarem em contato com o chão Se acionar os
efeitos sonoros por meio do script, não
precisamos mais
fazer isso a partir
da animação e podemos
excluir essa faixa Então, também precisarei repetir esse processo para
minha animação de execução. Mudando para a cena do jogo, podemos conectar sinais a scripts para reagir a
eles automaticamente. Selecionando o personagem, mudando a
guia do inspetor para a guia do nó, podemos ver nossa lista de sinais Clicando duas vezes em um sinal ou clicando com o botão direito do mouse e
escolhendo Conectar, uma nova janela é aberta. Nessa janela, podemos selecionar o nó ao qual queremos
conectar o sinal. Nesse caso, o nó
ambiental mundial. Em seguida, insira o nome
de uma função a ser chamada como reação ao sinal ou
escolha uma de uma lista Vou inserir manualmente o nome de uma nova função e
chamá-la de spawn Jump dust Clicar em Conectar
fechará a janela e exibirá o script do World Environment
Node com essa função
adicionada automaticamente. Essa função também
tem um ícone verde indicando que está sendo chamada por uma conexão de sinal, e o nó do personagem na árvore
da cena tem um ícone de sinal para nos mostrar que está emitindo um sinal
com uma conexão Essa conexão de sinal
também está listada na guia do nó. Podemos exportar variáveis para armazenar nossas três cenas diferentes de nuvem de
poeira, que são do tipo cena cheia. Em seguida, preencha cada uma
dessas variáveis
com as cenas apropriadas na guia
do sistema de arquivos Por enquanto, vamos apenas chamar
a função spawn passando Jump dust como argumento e também a posição
atual do personagem Godot não gosta
quando nomeamos nossos
parâmetros de função da mesma forma que as propriedades já
existentes de
um nó Mas podemos renomear
esse parâmetro para algo mais específico,
como a posição do personagem Isso instanciará
uma nuvem de poeira saltada automaticamente sempre que
o O nó Animated Sprite
two D reproduzirá automaticamente a
animação Sprite que criamos, mas não queremos que esse nó de nuvem de
poeira continue existindo após
o término da animação Depois que o personagem pulou
várias vezes, a árvore da cena
teria muitos dois nós D do Animated Sprite
que não estão fazendo nada Então,
precisaremos limpá-los. A maneira de remover os nós
da árvore de cena é chamar
sua função livre. Mas não queremos fazer isso
até que a
animação termine, o que é um sinal do nó D do
Animated Sprite two Como sabemos que o tipo de nó de nossas cenas de nuvem de poeira é
um Animated Sprite two D, podemos armazená-los em
uma variável privada desse tipo e chamá-la de poeira Podemos conectar sinais por meio de código, assim
como fizemos por meio do inspetor, e conectar sinal finalizado de animação à sua função livre Lembre-se de que, ao referenciar uma função em vez de
chamá-la, não
usamos parênteses Também podemos virar a
nuvem de poeira horizontalmente se o sprite do personagem foi
invertido quando esse sinal foi omitido Repetindo esse processo para
os outros dois sinais, podemos mudar o tipo de nuvem de
poeira que é gerada Ao executar o jogo, retornaremos à janela
do Editor e clicaremos no
botão remoto na guia da cena. Podemos ver a árvore de cenas
do jogo que está sendo executado
atualmente. Expandindo a árvore para que possamos ver os filhos do
Nodo Ambiental Mundial. Podemos ver que os
dois nós D do
Animated Sprite estão sendo criados
e destruídos à medida que pulamos, pousamos e caminhamos A árvore da cena remota
não atualiza todos os quadros, então algumas nuvens de poeira
podem ser criadas e destruídas sem
serem exibidas na árvore da cena remota. vejo
no próximo vídeo.
21. Bus de áudio 2-7: Olá, amigos. Neste vídeo, adicionaremos um
efeito sonoro separado para a voz do
personagem. Vou precisar importar mais
alguns arquivos de áudio para os esforços do personagem. Os efeitos sonoros de voz diferem de outros efeitos sonoros sempre queremos
tocar um por vez, já que nossas caixas de voz só
podem produzir um
som por vez. Portanto, precisaremos ter apenas um nó TD do reprodutor de streaming de áudio para todas as vocalizações de um
personagem Na cena do personagem, vamos duplicar qualquer um dos nós TD existentes
do reprodutor de
stream de áudio para criar um novo para
a voz do personagem Você também pode
posicionar esse nó em algum lugar ao redor do pescoço
ou da cabeça do personagem , em vez
de em seus pés. Embora isso não faça
muita diferença perceptível
no meu pequeno personagem. O randomizador de efeitos sonoros
não é mais aplicável
a esse nó, então podemos remover o script
clicando no botão de script
separado Vamos substituir isso
por um novo script. Vamos chamar isso de voz.
Nesse script, podemos exportar qualquer número de efeitos sonoros de voz
padrão, comumente chamados de
esforços ou esforços Vamos exportar uma variável para o som de esforço do
Jump
como um fluxo de áudio, que podemos preencher
no inspetor Podemos pré-visualizar como isso
soará clicando
no recurso. Em seguida, adicionaremos uma função que reproduzirá um som de esforço de
salto. No entanto, essa função
não precisará fazer nada se o reprodutor de fluxo de áudio de voz para
denotar estiver ocupado
reproduzindo outros sons Somente se não estiver jogando, configuraremos o stream
para Jump effort e reproduziremos. Isso evitará que novas
solicitações para reproduzir outro som
de esforço interrompa
o anterior Também podemos usar as
mesmas técnicas que usamos com nossos efeitos
sonoros aqui, como randomizar a escala de tom ou ter uma variedade
de fluxos de áudio e escolher um
aleatoriamente a cada E, ao contrário dos efeitos
sonoros regulares, que sempre
se espera que sejam reproduzidos todas as vezes, nem sempre é necessário fazer
esforços. Portanto, também podemos adicionar uma chance aleatória de que o
esforço não funcione, mesmo que seja possível. Usando a função rand F, isso retornará um número
aleatório 0-1 Podemos verificar se isso é
menor que uma chance percentual, digamos, 25%,
expressa como 0,25 Anexando isso à declaração
condicional com um operador and, voz
desse personagem não deve estar ocupada tocando nenhum
outro som e também deve ter uma chance aleatória de 25% antes de poder
tocar esse esforço Tudo o que precisamos fazer para
acionar isso é conectar o sinal de salto do personagem à função de
esforço Jump play de vozes Mas o
sinal de salto do personagem fornece dois argumentos e a função de esforço de
salto de reprodução de vozes não
aceita nenhum parâmetro,
portanto, não são
consideradas compatíveis Se clicarmos apenas no botão de alternância de
métodos compatíveis, todas as funções serão mostradas,
mesmo que não correspondam, e podemos selecionar a função play
Jump effort Para evitar que isso
cause um erro, expandiremos a seção
avançada clicando no botão
Avançado Aqui podemos vincular novos argumentos ou desvincular os Basta desvincular os dois argumentos
existentes do sinal de
salto do personagem
e agora o sinal é compatível
com a chamada da função Ao testá-lo, ouviremos som
do esforço ser
reproduzido aleatoriamente com 25% de chance, e ele nunca se
interromperá B. Outra coisa que podemos fazer
para separar vozes de outros efeitos sonoros
é fornecer a elas um barramento de áudio separado no layout
do barramento de áudio. Clique no
botão Áudio na parte inferior do editor para abrir
o layout
do Audio Bus, que atualmente tem apenas um
único barramento, o Master Bus. Mas se clicarmos em Adicionar barramento, podemos adicionar mais barramentos ao layout
do barramento de áudio, um para efeitos sonoros e outro para vozes. Também é uma boa ideia
ter outro para música. Isso nos permite classificar nosso áudio em diferentes
categorias e controlar
facilmente
toda a categoria uma só vez durante todo
o jogo. Podemos ajustar o volume de
todos os efeitos sonoros, vozes e músicas de forma independente, e o volume principal
afetará todos eles. Também existem muitos efeitos de áudio
diferentes que podem ser adicionados a
cada barramento, se quisermos. Em nossa cena de personagem, temos vários reprodutores de fluxo de
áudio diferentes , dois nós D, e cada um deles precisa ser informado qual barramento de áudio eles pertencem, sendo o padrão o Master Bus. Cada um dos efeitos sonoros pode ser instruído a ser reproduzido no barramento de efeitos
sonoros, enquanto os dois nós D do
reprodutor AudioStream de voz podem ser reproduzidos no barramento de voz Agora podemos ajustar o volume dos nossos efeitos sonoros
independentemente das vozes. M. M. Agora
temos um personagem de plataforma em dois
D muito polido Em seguida, começaremos a criar ambientes para nos movimentarmos. Nos vemos na
próxima seção.
22. Mapa de mosaico 3-1: Olá, amigos. Nesta seção, criaremos um ambiente para nosso personagem se mover
e pular. Para fazer isso, precisarei
importar ativos para meu terreno,
classificados em uma nova pasta
para ativos de sprites de terreno Clicando duas vezes no ativo, podemos visualizá-lo
no inspetor Podemos ver que esse ativo é uma planilha de sprites, assim
como o personagem Exceto que, em vez de quadros de
animação, essa folha de sprites contém sprites
diferentes para desenhar o terreno com base nos blocos
ao Começando na cena do jogo, criaremos o corpo estático do
nível atual para denodar sua própria Vou criar uma nova pasta
para as cenas da sala. E, dependendo do
tamanho do seu jogo, talvez
você também queira
classificar as salas em regiões. Então, vou criar outra
pasta para salas na região
da floresta e salvar essa sala como algo
como sala inicial. Em seguida, abra essa nova cena da sala. Não quero mais que o nó D do corpo estático dois seja o nó raiz, pois essa sala conterá
mais do que apenas um piso. Então, adicionarei um nó regular dois D a essa cena quando era criança. Em seguida,
clicando com o botão direito do mouse nesse nó, podemos selecionar criar raiz da cena para reorganizar a árvore da cena para que esse nó
agora seja o nó raiz Agora, o chão é
filho do nó raiz, e poderíamos adicionar
mais corpos estáticos a esse nó para as paredes, teto, as plataformas e
os obstáculos para construir nosso quarto. Vou renomear o nó raiz para que seja igual ao nome
da cena Ao usar blocos de uma folha de sprite que são
igualmente dimensionados e espaçados, podemos usar outro nó
fornecido por Gadot chamado camada do mapa de blocos,
para desenhá-los Adicionar um
nó de camada de mapa de mosaico à cena abre o painel
do mapa de mosaico na parte inferior do editor, mas ainda não podemos fazer
nada aqui. Primeiro, precisamos dar uma olhada nas propriedades dos nós
da camada do mapa de blocos no inspetor O nó da camada do mapa de mosaico não pode desenhar nada até
ter um conjunto de mosaicos. Ao clicar no menu suspenso, criaremos um novo conjunto de blocos. Em seguida, clique no conjunto de blocos
para expandir suas propriedades. A primeira opção é a forma dos ladrilhos nesse conjunto de ladrilhos. Os ladrilhos que estou usando são quadrados, mas também há
opções para ladrilhos isométricos, quadrados
meio deslocados e
hexagonais Geralmente são usados para perspectivas de
cima para baixo, e este jogo é
um rolador lateral, então vou usar ladrilhos
quadrados Em seguida, precisamos definir
o tamanho dos ladrilhos. Minha folha de sprite importada tem
o tamanho do bloco em seu nome, 32 por 32 pixels Ignoraremos o resto
das configurações por enquanto e mudaremos o painel inferior do editor
de Tilemap para conjunto de blocos Agora podemos adicionar blocos ao conjunto de
blocos que acabamos de criar. Clique no botão
Mais na parte inferior navegue pelo
sistema de arquivos para encontrar seus ativos ou clicando
e arrastando os ativos da guia do sistema de arquivos para
a área Isso nos dará uma
solicitação para que o motor divida
automaticamente a folha de sprites em blocos para nós Se selecionarmos sim e
definirmos o tamanho do bloco corretamente
, os blocos na
folha de sprite serão automaticamente cortados nesse tamanho para nós
e adicionados ao Ao clicar no botão da borracha, podemos clicar nos ladrilhos para
removê-los do conjunto de blocos Clicar e arrastar apagará todos os blocos que arrastarmos Segurando o controle ou o comando e, em
seguida, clicando e arrastando, podemos remover todos os blocos
na área selecionada Desligando a borracha novamente, podemos usar os mesmos controles para adicionar peças ao conjunto de peças Se você quiser criar
blocos superdimensionados, mantenha
pressionada a tecla Shift e, em
seguida, clique e arraste
sobre vários blocos Isso tratará várias
peças como se elas sempre fossem desenhadas como
um grupo maior de peças. Mas essa folha de sprites não
tem blocos grandes, então vou apagar isso
e adicionar cada um
desses blocos ao
conjunto de blocos Agora que nosso
conjunto de mosaicos contém mosaicos, nossa camada de mapa de mosaico pode usar esse conjunto de mosaicos para desenhar os mosaicos. Então, vamos mudar do painel
do conjunto de blocos
para o painel do mapa de blocos. Com a ferramenta de pintura selecionada, podemos selecionar uma
fonte de ladrilho do conjunto de ladrilhos e, em
seguida, um ladrilho da origem
do ladrilho. Na visualização de duas cenas em D, o editor fornece diretrizes
laranja de como os ladrilhos serão
dispostos e agora podemos pintar esse ladrilho onde
quisermos clicando. Se quiser alterar
o deslocamento dos mosaicos,
você pode ajustar a posição de transformação dos nós da
camada do mapa nós da
camada Como no conjunto de ladrilhos, podemos usar o botão de apagar para apagar ladrilhos
em vez A ferramenta seletora pode
ser usada para selecionar um ladrilho na visualização T D em vez
do painel do conjunto de ladrilhos Podemos desenhar ladrilhos
virados horizontalmente,
verticalmente ou ambos
e girá-los no sentido horário ou anti-horário Também podemos agrupar vários
ladrilhos e pintá-los todos de uma vez. Ao alternar entre colocar uma peça aleatória, em vez disso, você escolherá aleatoriamente entre
as peças selecionadas O aumento da dispersão deixará alguns ladrilhos sem pintura
ao serem arrastados Você também pode desenhar linhas. Com vários blocos selecionados, eles serão repetidos
ao longo da linha. E a ferramenta retangular pode preencher uma área inteira da camada do
mapa de ladrilhos muito rapidamente A ferramenta bucket pode
ser usada para preencher uma área vazia fechada da camada do mapa
de mosaico As opções aleatórias e de
dispersão também se aplicam às ferramentas Line Wrecked
e Bucket A ferramenta bucket também tem
uma alternância contígua,
que, quando
desativada, pode ser usada para
afetar todos os mosaicos correspondentes
em toda a camada do mapa de mosaicos camada do Com o
nó da camada do mapa de blocos desenhando nosso terreno, não
precisamos mais
do nó
tutti corporal estático e podemos
excluí-lo da cena De volta à cena do jogo,
podemos ver nossa sala de partida. O nó não foi renomeado. Ainda diz o nível atual. Se rodarmos o jogo,
o personagem não colide com o terreno
e simplesmente cai nele Agora temos uma camada de mapa de mosaicos usando um conjunto de mosaicos para desenhar mosaicos, mas precisamos trabalhar mais
para configurar nosso conjunto de mosaicos. Te vejo no próximo vídeo.
23. 3-2 Terreno: Olá, amigos. Neste vídeo, usaremos mais opções de
conjunto de mosaicos para tornar a pintura de mosaicos em uma camada de
mapa de mosaico mais rápida e fácil Começando na cena da sala, selecione o nó da camada do mapa de mosaicos e, em
seguida, expanda o
conjunto de mosaicos no inspetor Expandindo a seção da
camada física, ela está vazia no momento, então adicionaremos uma nova camada de
física. Não precisamos editar nenhuma das propriedades da camada física. Só precisa existir. Examinaremos as camadas de colisão e o mascaramento de colisão
posteriormente no curso Mas se você quiser,
você também pode adicionar um material físico para
ajustar seu atrito,
rugosidade, elasticidade ou absorção Eu não quero um material de física, então vou limpá-lo
no menu suspenso. Com a camada física
adicionada ao nosso conjunto de blocos, podemos abrir a
guia do conjunto de blocos na parte inferior
do editor para aplicar essa camada
física aos nossos blocos. Mude da configuração do atlas para as propriedades da
pintura
clicando neste botão Aqui podemos pintar muitas propriedades
diferentes
em nossos ladrilhos, mas a que queremos
pintar
agora é a camada física zero. Na pintura, o
ladrilho inteiro deve ser preenchido com quatro nós brancos
em todos os cantos por padrão. Se não estiver, clique nos
três pontos e selecione redefinir para a
forma padrão ou pressione a tecla F. Agora podemos pintar essa forma de
colisão física em nossos ladrilhos Todos esses ladrilhos
foram projetados para ter a
mesma forma quadrada. Mas se você estiver usando ativos
diferentes, talvez seja necessário ajustar
a forma de colisão
para blocos diferentes Podemos clicar e arrastar
esses pontos brancos para ajustar a forma da colisão, excluí-los ou adicionar mais conforme necessário para criar
a forma que quisermos Se precisar de uma
visualização melhor para ser mais preciso, você pode expandir esse editor
para preencher todo o painel. Também há opções de ajuste
de grade disponíveis. Definir o ajuste da grade
para o tamanho do pixel
permitirá que você crie uma colisão
perfeita de pixels, se quiser depois de pintar
formas de colisão nos ladrilhos, rodando o jogo
novamente, teremos o personagem colidindo
com nossos Agora temos uma colisão,
mas desenhar terreno um ladrilho por
vez é muito Podemos usar ferramentas incorporadas
ao editor para facilitar. Expandindo a seção de terreno, podemos adicionar um conjunto de terrenos a esse
conjunto de blocos O conjunto de terrenos também precisa de um
terreno adicionado a ele. Então, vamos criar um
elemento aqui também. Podemos nomear o terreno como
quisermos. Vou dar um nome à minha floresta
e dar-lhe uma cor. Essa cor não será
desenhada no jogo apenas no editor como
forma de configurá-la. Ajuda escolher uma
cor que contraste com as cores usadas na folha de
sprites para que ela se destaque. Vou usar rosa para
contrastar com meus ladrilhos de terreno verdes e
marrons Em seguida, abra o painel do conjunto de blocos na parte inferior do editor. terrenos são uma forma de
desenhar ladrilhos
projetados para se conectarem
uns aos outros, como esta folha de
sprites Mude para as propriedades da pintura e a propriedade que queremos
pintar é a propriedade do terreno Em seguida, podemos selecionar nosso
conjunto de terrenos que acabamos de criar, o
conjunto de terrenos zero e o terreno desse conjunto de terrenos,
o terreno da floresta Para pintar a
propriedade do terreno, primeiro temos que selecionar cada um
dos ladrilhos que fazem parte do terreno para que não
fiquem mais Nesta planilha de sprites,
estão todas elas. Ao passar o mouse sobre um ladrilho que foi adicionado
a esse terreno, o ladrilho é
dividido em nove quadrados quadrado médio
precisa ser preenchido para desenhar esse ladrilho como
parte do nosso terreno Os outros quadrados dizem ao editor que desenhe
esse ladrilho se
houver outro ladrilho de terreno adjacente a este
nessa direção Começando com esse ladrilho, deve
ser desenhado se não houver outros
ladrilhos de terreno adjacentes a ele Portanto, apenas o
quadrado do meio é pintado. O ladrilho na
extrema esquerda deve ser desenhado se houver outro ladrilho de
terreno à direita dele, que ele tenha o quadrado
direito pintado O ladrilho oposto
à direita segue a
mesma lógica à esquerda, e o ladrilho do meio
é desenhado se houver terreno
adjacente
à esquerda e à direita Os ladrilhos verticais são os
mesmos, apenas para cima e para baixo. O bloco grande no canto superior esquerdo combina esses dois, adiciona cantos e também tem o ladrilho sólido no meio
com todos os quadrados pintados Isso será suficiente para desenhar blocos de terreno em forma
convexa Abrindo o painel do mapa de blocos, mude de ladrilhos para terrenos e selecione o terreno
que acabamos Com a ferramenta de pintura selecionada, podemos pintar ladrilhos de terreno
livremente na camada do mapa de ladrilhos, da mesma forma que antes Mas agora, se nossos
ladrilhos de terreno estiverem adjacentes a outros ladrilhos de terreno e
formarem formas retangulares
, eles serão automaticamente atualizados para o
ladrilho correto do Apagar os blocos também
atualizará os blocos ao redor. Isso também funciona com as ferramentas de demolição de
linha e caçamba. Se quisermos criar cantos
côncavos, precisaremos retornar
à pintura do terreno Adicionando cada um dos
ladrilhos restantes ao terreno, preencheremos todos os quadrados que correspondam à existência outro ladrilho de terreno adjacente a este
nessa direção Se você estiver
acompanhando esses recursos e certeza de qual padrão
deve ser desenhado em cada bloco, você pode pausar o
vídeo e copiar o Alguns ativos de blocos
fornecerão um guia ou referência para ajudá-lo com as regras de
adjacência para blocos, ou você pode simplesmente experimentar
e ver o que parece bom Tente desenhar um terreno em uma variedade de
formas diferentes para ver se todas as combinações possíveis são consideradas e
desenhar adequadamente Os ladrilhos na parte inferior
também devem ser desenhados com o
terreno adjacente em todas as direções Cada bloco em um mapa de blocos
geralmente é projetado para
ter um padrão exclusivo. Mas se você tiver vários
ladrilhos com o mesmo padrão, a ferramenta de terreno
escolherá
aleatoriamente um com o mesmo
padrão ao desenhar Podemos ajustar a probabilidade
dessa aleatoriedade
pintando outra propriedade na probabilidade
da lista suspensa Basta inserir uma probabilidade. Vou usar 0,01, que é 1%, e pintar isso nos ladrilhos
na parte inferior Sempre que a ferramenta de terreno desenhar um ladrilho com adjacência
em todas as direções, ela terá 1% de chance
de desenhar cada um desses ladrilhos na parte inferior
ou usar o
ladrilho em branco Ao pintar o terreno a
partir do mapa de blocos, se a distribuição aleatória
desses ladrilhos não
parecer muito boa, você pode facilmente continuar
desenhando sobre ele O editor de terreno
recalculará a distribuição aleatória
a cada vez Agora podemos desenhar facilmente salas para nosso jogo usando um nó de camada de mapa de
blocos, mas a câmera não está se movendo, então não podemos mover nosso
personagem muito longe. Te vejo no próximo vídeo.
24. Câmera 3-3: Olá, amigos. Neste vídeo, faremos com que a câmera siga o personagem para que ele possa se mover ainda mais pelo ambiente. Na cena do jogo,
temos o personagem e a câmera dois
nós D como irmãos Obviamente, se atribuirmos a câmera como filha
do personagem
, ela acompanhará
o jogador. No entanto, essa não é uma maneira
muito boa de fazer isso porque a maioria dos jogos
terá transições, cenas ou outras
áreas do jogo que
se ajustam à visão da câmera,
independentemente do personagem do
jogador Em alguns jogos, o jogador escolher
qual personagem deseja jogar, e esse personagem
deve estar carregado, então não pode ser determinado na cena
do jogo que a câmera deve seguir esse personagem. É melhor deixar a
câmera como irmã e fazer com que a câmera siga o personagem
do jogador por meio de um roteiro. Vamos anexar um script à
nossa câmera para denodar. Poderíamos chamá-la de câmera ou
nomeá-la de acordo com o comportamento, seguir o jogador ou combinar
os dois, seguir a câmera. Poderíamos exportar o personagem do
jogador como uma variável, como fizemos
com o manipulador de entrada, mas vamos
supor que essa câmera será instruída a seguir
mais de um personagem ao longo do jogo e em vez disso, definir uma
função pública chamada follow, que aceita um assunto
como parâmetro Teoricamente, esse assunto
pode ser qualquer coisa, desde que exista nos dois
mundos D e tenha uma posição Então, vamos dar a ela um tipo
de nó dois D em vez
do tipo mais específico de corpo de
personagem dois D. Dessa forma, essa câmera poderia
ser instruída a seguir um corpo rígido ou
qualquer outra coisa que quisermos Essa função não
precisa retornar nenhum valor. Tudo o que ele realmente
precisa fazer é armazenar esse assunto em uma variável
privada. Em seguida, substituindo a função de
processo, se esta câmera tiver um assunto, ela definirá
sua posição para ser a mesma que a posição
global do objeto Como o assunto pode
fazer parte de uma cena maior, não
queremos usar
sua posição local em relação à sua mãe, mas sim sua posição global dentro do escopo de toda
a cena do jogo. Não estamos usando o parâmetro
Delta, então vou continuar
com um sublinhado Agora precisamos de outro script
para chamar essa função a partir de um nó que tenha acesso à câmera
e ao nosso personagem, que será o nó do jogo. Anexando um script
ao nó do jogo, chamaremos isso de gerenciador de jogo
e eu
o colocarei em uma
nova pasta de scripts para scripts de gerenciamento Será responsabilidade do gerente de jogo gerenciar quando
o jogador está jogando
ou em
uma cena cortada ou fazendo a transição
entre as Por enquanto, quando o gerenciador de
jogo estiver pronto para substituir
a função ready, diremos à câmera que siga o jogador e ative
o manipulador de entrada Para fazer isso, precisaremos armazenar cada um desses nós
em variáveis. Como a hierarquia
da cena do jogo é bastante complexa em
comparação com outras cenas, talvez
precisemos reorganizar os nós, alterando sua
filiação Quando isso acontecer,
o caminho do nó em nosso script não
será mais válido, causando erros. Podemos evitar isso
clicando com o botão direito do mouse nos nós em nossa árvore de cenas e selecionando
acesso como nome exclusivo. Isso adiciona um sinal de porcentagem à direita do
nó na árvore da cena. Isso nos permite substituir
o caminho do
nó anotado com cifrão pelo nome exclusivo anotado com
sinal de porcentagem Se o nó já tiver um
nome exclusivo atribuído, ele será
aplicado automaticamente ao segurar controle ou o comando e
arrastá-lo para o script Agora que temos todas
essas referências de nós, quando o gerente do jogo estiver pronto, podemos dizer à câmera que siga o personagem
do jogador e
ative o manipulador de entrada Ainda não escrevemos
uma função de habilitação para o manipulador de entrada, então vamos passar para
esse script e escrevê-lo criação de uma
variável privada está habilitada como um booleano, cujo padrão será false, e uma função pública de habilitação que
podemos definir é ativada como verdadeira Então, antes de manipularmos qualquer
entrada do player, verificaremos se o manipulador de entrada está ativado e, se não estiver, sairemos da função, se
estiver ativado, será falso, impedindo que qualquer código
restante Também precisaremos de uma função de
desativação que redefina a
variável is enabled como falsa. Isso pode parecer excessivo, já que poderíamos simplesmente tornar pública a variável
is enabled. Mas usando essa estrutura
encapsulada, podemos fazer outra lógica
dentro dessas funções Por exemplo, quando o
manipulador de entrada está desativado, diga ao personagem para
parar de se mover definindo a
direção como zero e
também diga para ele andar Ao ativar o manipulador de entrada, uma vez que o movimento está sendo
verificado em andamento, ele já será
detectado automaticamente Mas se o jogador
começar a segurar o botão de execução antes que o manipulador de
entrada fosse ativado, a entrada
terá sido ignorada, mas o jogador ainda
espera que seu personagem corra Podemos verificar o status
do botão de execução ao ativar o manipulador de entrada e pedir
ao personagem que seja executado adequadamente Se usarmos a
função de entrada para movimento, poderíamos verificar o singleton de
entrada ao status do movimento
para a esquerda direita e dizer ao
personagem que se mova aqui Voltando à cena do jogo, já que a posição do personagem também
está na origem, é
isso que a câmera
desenhará quando o jogo começar. Esse não é um enquadramento muito bom do personagem ou da sala Normalmente, o jogador
precisa ver mais do que está acima dele ou do
que está à sua frente. Podemos dar à
câmera um
deslocamento de posição para movê-la para cima ao longo do eixo y e para
a direita ao longo do
eixo X para conseguir isso Vou colocá-lo 64 pixels para cima e para a direita e também
mudar meu zoom para dois. Então, quando a
posição da câmera estiver configurada para coincidir com a
posição do personagem, a cada quadro, ela será compensada por
esse valor depois disso, dando ao jogador uma visão ligeiramente superior à
direita do personagem Agora temos nossa câmera
seguindo o personagem, mas a câmera só
olha para a direita. Nos vemos no próximo vídeo.
25. 3-4 Olhar para frente: Olá, amigos. E
esse vídeo permitirá que a câmera olhe à frente
do personagem
para a esquerda ou para a direita. Começando no script de
caracteres, podemos facilitar as coisas para nós mesmos fornecendo nomes de
classes para alguns de nossos scripts usando a palavra-chave nome da classe
na parte superior do script. Vamos chamar essa classe de algo mais genérico, como personagem. Isso permitirá que Godot complete
automaticamente os
nomes das variáveis e funções ao acessar membros dessa classe
em outros scripts Assim como usamos
sinais para reagir
às ações do personagem e
produzir nuvens de poeira, precisaremos emitir
outro sinal para quando o personagem mudar a
direção para a qual está voltado. Declarando um sinal chamado direção
alterada, precisaremos passar para
qual direção o personagem está agora
voltado como parâmetro Adicionando outra variável
à seção de locomoção, precisaremos saber qual direção o
personagem está
voltado atualmente para saber se ele mudou a direção do rosto Como uma variável booleana é
naturalmente padronizada como falsa,
nomearei a variável voltada para a esquerda, o que, quando falsa, implica
que ela
está voltada para quando falsa, implica
que ela Na função face left, podemos emitir nosso novo sinal e passar o valor da
direção como argumento Ah, no processo de física, ao mandar o personagem
ficar virado para a direção, isso
acontecerá toda vez o jogador der uma
entrada em cada quadro. Não queremos emitir
esse sinal a cada quadro, somente nos quadros quando
eles mudam de direção Então, adicionaremos a condição de
que o personagem esteja voltado para a esquerda e a direção
seja maior que zero, ou o personagem não esteja voltado para esquerda e a direção
seja menor que zero. Agora, essas funções
só serão chamadas durante o quadro, quando o personagem realmente mudar a direção do
rosto, que emitirá o sinal
para que possamos reagir a ele Passando para
o script da câmera, precisaremos de uma função
que corresponda à assinatura do sinal que acabamos de
criar para conectá-la. Vamos chamar isso de
mudança de direção do assunto, já que o personagem
será o sujeito,
aceitando a direção para a qual
o personagem está voltado como um flutuador e não
retornando nenhum valor O que queremos fazer
é que o deslocamento X da câmera corresponda
ao sinal de direção Portanto, precisaremos
armazenar o valor do deslocamento em outra
variável inalterada Vamos chamá-lo de
deslocamento padrão e defini-lo como o valor de deslocamento
usando uma tag pronta Agora podemos
editar com segurança o valor do offset sem esquecer
qual era o valor original H. Quando o objeto
mudar de direção, definiremos o valor
do deslocamento como
o deslocamento padrão multiplicado
pelo sinal Portanto, se a direção for positiva, o deslocamento da câmera também
será positivo
e, da mesma forma, negativo Para conectar esse sinal ao dizer
à câmera que siga um assunto, se o assunto não for nulo e o assunto
for um personagem, a classe que acabamos de nomear, podemos acessar com segurança o sinal de
direção alterado do personagem e conectá-lo à nossa função Um Godot não
reconhecerá novos nomes de classes até que você
salve seus scripts Mas se chamarmos essa função de
acompanhamento
no mesmo assunto
mais de uma vez por qualquer motivo, isso causará um erro, pois o sinal já está conectado. Primeiro, vamos verificar se o assunto que a câmera
está sendo instruída a seguir é o
mesmo que ela
já está seguindo. Nesse caso,
não precisamos fazer nada e podemos simplesmente
devolvê-lo a essa função. Agora sabemos que o assunto é algo diferente
do assunto atual. Vamos verificar se o assunto
atual
não é nulo e se
é um caractere Se ambas forem verdadeiras, também devemos verificar se o sinal de mudança de
direção do personagem foi conectado à função de direção
alterada no assunto. E se isso for verdade,
desconectaremos o sinal, já que a câmera não está mais seguindo o objeto e
não precisa reagir a ele executar o jogo, isso
posicionará a câmera
à frente do personagem, mas isso acontecerá
instantaneamente, que é bastante chocante
para o O que seria
melhor é ajustar o valor do deslocamento
gradualmente ao longo do tempo, que é algo que podemos
fazer facilmente usando uma interpolação, abreviação de intermediária Então, vamos declarar uma nova variável, chamá-la de algo como
look ahead tween A então, quando o personagem
muda de direção, atribuindo o valor dessa
variável para criar uma interpolação Criar interpolação é uma função
da classe node,
portanto, qualquer nó pode usá-la Quando a interpolação for criada, acessaremos sua função de
propriedade de interpolação Isso aceita um objeto
como primeiro argumento, que é esse próprio nó. Podemos especificar isso
com a palavra-chave self. Em seguida, a propriedade que queremos
interpolar como uma string, que é a propriedade de deslocamento, especificamente o componente X, que podemos especificar
com O próximo argumento
é o valor final, que é o deslocamento X padrão multiplicado pelo sinal de direção que calculamos anteriormente E, finalmente, a duração
da interpolação em segundos. Por enquanto, vou
configurá-lo para 1 segundo. Como essa interpolação
levará 1 segundo, mas é muito possível
que o personagem mude de direção várias
vezes durante esse 1 segundo, isso criaria várias
interpolações, todas
tentando editar o valor do
deslocamento ao mesmo tempo Portanto, antes de criar a interpolação, devemos verificar se ela
já existe primeiro e se ela a mata Dessa forma, não mais do que
uma dessas interpolações pode existir por vez e estar
tentando editar o deslocamento X. Executando isso agora, o deslocamento X da
câmera está se interpolando para olhar à frente
do personagem por mais de 1 segundo, mas ainda é um pouco Podemos ajustar como essa interpolação acontece exportando mais
algumas variáveis Primeiro, vamos exportar a
duração dessa interpolação como flutuante e atribuir a ela um valor
padrão de 1 segundo Em seguida, substitua o da nossa
função por essa variável. Em seguida, adicionaremos um tipo de transição e um
tipo de atenuação. Juntas, essas três variáveis nos
permitirão criar
uma grande variedade de diferentes ajustando rapidez com que o valor muda no início e no final
da Como create tween
retorna uma interpolação, podemos acessar sua função
trans definida e passar nosso tipo de transição como
argumento na mesma linha A função set trans
também retorna a interpolação, então podemos continuar
essa linha e chamar a função set Es
imediatamente depois disso também. Passando nossa variável Es
como argumento. Tudo isso
retornará a interpolação com o
conjunto de tipos de transição e atenuação e atribuirá o
resultado à variável cena do jogo, selecionando
o nó da câmera e
examinando suas
propriedades no inspetor,
podemos editar os valores dessas variáveis com
os tipos
de transição e atenuação,
fornecendo listas examinando suas
propriedades no inspetor, podemos editar os valores dessas variáveis com
os tipos
de transição e atenuação suspensas convenientes Também podemos tornar a duração
da interpolação mais curta ou mais longa Vou fazer com que o meu use uma interpolação de entrada quádrupla em
2 segundos. Experimente
as diferentes opções para ter uma ideia de como elas funcionam O tipo de transição determina qual fórmula matemática está sendo usada para alterar
o comportamento, enquanto o tipo de atenuação
decide como isso
afetará a primeira metade ou a
segunda metade da interpolação Agora temos a câmera girando
suavemente para a esquerda ou para a
direita para mostrar o que está à frente
da direção em que o
personagem está voltado, mas às vezes o jogador também
pode querer olhar para
cima e para baixo Te vejo no próximo vídeo.
26. 3-5 Olhe para cima: Olá, amigos. Neste vídeo, permitiremos que o jogador diga
ao personagem que
olhe para cima e para baixo. Primeiro, precisaremos adicionar
mais eventos de entrada ao mapa de entrada
nas configurações do projeto para
olhar para cima e para baixo. Vou usar as teclas de seta para cima e para baixo. Os botões
direcionais para cima e para baixo
e o controle direito
inclinado para cima e para Então, no script do jogador, ao contrário da direção do movimento, que está sendo
usada apenas pelo personagem, a direção do olhar será usada tanto
pelo personagem
quanto pela câmera, o que significa que precisaremos de uma
referência à câmera. Vale a pena armazenar a direção
do olhar
em uma variável, então só precisamos
calculá-la uma vez por quadro Em seguida, na função de processo, obtenha seu valor
do singleton de entrada, da mesma forma que fizemos com
a direção do movimento usando a função get axis, alterando os nomes
das ações de entrada Lembre-se de que, como
subir é negativo, esse será o primeiro argumento. Podemos então enviar
essa direção de olhar tanto
para o personagem
quanto para a câmera. Para a câmera, vou
usar uma chamada de função. Mas para o personagem,
vou disdefinir o valor de uma variável pública Para tornar o nome
da variável de direção da classe de caracteres
um pouco mais claro, pode ser inteligente
renomeá-la para mover a direção Como essa função não
existe no script da câmera, vou comentá-la por enquanto para evitar erros até que eu esteja
pronto para escrevê-la. No script do personagem, podemos abrir a caixa de diálogo de substituição com Controle ou Comando R e substituir a direção
pela direção do movimento que
fique mais claro para que
ela será usada. Em seguida, adicione uma nova variável pública
para a direção do olhar. A variável de direção L não precisa ser usada em
nenhum lugar do script. Ele só será lido
pela Árvore de Animação. cena dos personagens, selecionando o Animation Player, precisarei criar animações LU
e L down Vou duplicar minha animação ociosa
para facilitar as coisas. Em seguida, basta editar os valores Y dos meus quadros-chave para desenhar o personagem olhando para
cima ou para baixo adequadamente. Em seguida, na máquina de estado Animation
Tree editando a máquina de
estado Locomotion, posso adicionar as animações de pesquisa para cima e
para baixo. Fazendo a transição para eles com base no valor da direção do olhar E certificando-se de que sua
velocidade X permaneça zero, caso contrário, eles devem
fazer a transição para andar E de volta à marcha lenta no caso a direção do olhar
ser igual a zero Ou se eles começaram a andar, isso fará com que o
personagem animado olhe para cima ou para baixo enquanto pressionamos as direções para
cima e para baixo, mas a câmera ainda não está se movendo Na cena do jogo, tente alterar
o deslocamento Y da câmera e decida até onde você gostaria que a câmera se movesse quando o
personagem olha para cima ou Vou usar 128 pixels e redefinir para o
padrão de 64 negativos. Voltando ao script do player, descomentarei a função da
câmera agora e, em
seguida, mudarei para o script da câmera para declarar essa Aceitarei uma direção como
flutuante e não retornarei nenhum valor. O corpo dessa função
será quase idêntico ao da função de
direção alterada no assunto. Tudo o que precisamos fazer é substituir todas as instâncias de
uma cabeça por cima para baixo. Em seguida, declare-as
como novas variáveis. Também precisaremos de outra variável
exportada para a distância máxima de visualização que
decidimos anteriormente,
que usaremos em vez
do deslocamento padrão,
e o deslocamento X será o deslocamento Y.
No entanto, quando soltarmos as setas para cima ou para baixo,
queremos que a câmera retorne ao valor
de deslocamento No entanto, quando soltarmos as setas para cima ou para baixo,
queremos que a câmera retorne ao valor
de queremos que a câmera retorne ao padrão, não
zero Portanto, isso exigirá um
pouco mais de lógica. Outra forma de adicionar instruções if
simples aos seus scripts é usar
uma operação ternária, que no GDScript usa as mesmas palavras-chave if de uma instrução if
normal,
começando com o caso padrão, que é o valor que
já calculamos, mas somente se a direção
não for zero, Portanto, se a direção for zero, queremos usar nosso deslocamento Y
padrão. Isso funciona, mas na maioria dos jogos
que têm essa mecânica, o jogador precisa segurar o botão por algum tempo
antes que a câmera se mova Podemos conseguir isso adicionando um nó temporizador ao nó do jogador Vamos dar um nome a ele. Olha, espere. Podemos ajustar o
tempo de espera do inspetor, mas 1 segundo é suficiente e o cronômetro
precisará ser único Conectando o
sinal de tempo limite desse cronômetro ao script do player, é quando o
script do jogador dirá à câmera que comece a olhar na
direção Na parte superior do script, precisaremos pegar uma referência
ao antigo nó temporizador e também precisaremos de
um booleano para saber se o jogador
está procurando ou Na função de processo, depois de obter o valor da direção do
olhar
da entrada Singleton, se o jogador
já estiver olhando, também se a
direção do olhar for zero, reiniciaremos a
câmera chamando sua função de aparência e passando
zero como argumento Então, set parece falso. A razão pela qual eu não usei uma declaração
and é
para que eu possa usar outra se, aqui e agora, presumir
que a aparência é falsa. Em seguida, verifique também se a
direção do olhar não é zero. Nesse cenário, em que o
jogador ainda não está olhando, mas está inserindo a direção do
olhar, se o cronômetro de espera for interrompido,
precisaremos iniciá-lo Adicionar
mais uma se o jogador não estiver olhando e não estiver fornecendo
nenhuma entrada de direção de olhar
, e também se o
cronômetro de espera de olhar não estiver parado, isso significa que precisamos
pará-lo e cancelar a aparência Adicionando instruções impressas
para todas elas, podemos confirmar que
cada uma é chamada somente uma vez quando
apropriado. Também precisaremos definir a variável
is looking verdadeira quando o tempo de
espera expirar e a câmera
começar a interpolar Executando o jogo, tocando nas setas para cima ou para baixo
sem segurar, o cronômetro de espera é iniciado, mas parado, e a
câmera não se move, mas o personagem ainda está
animando olhando Mantendo pressionadas as teclas para
cima ou para baixo, o cronômetro expira após 1 segundo e diz à
câmera que olhe para cima ou para baixo. Soltando as teclas para cima ou para baixo, a câmera volta para
sua posição de deslocamento padrão Vou comentar essas declarações
impressas e ajustar minhas configurações de interpolação
no inspetor para reduzir por mais de
meio segundo Agora, o jogador pode manter pressionadas as direções
para cima e para baixo para olhar para cima e para baixo, mas talvez queiramos restringir a
distância que a câmera pode se mover para evitar a exibição de conteúdo
fora da sala atual. Te vejo no próximo vídeo.
27. 3-6 Limites: Olá, amigos. Neste vídeo, restringiremos a câmera para que fique dentro
dos limites do ambiente. Começando na cena da sala, podemos alterar o
nó raiz para ser um nó D da área dois em vez de
apenas um nó D normal de dois. Isso é semelhante
a um corpo
físico pois tem uma forma de
colisão, mas não tem
massa nem reage às forças Em vez disso, você pode pensar nisso como um detector de movimento ou calor. Ela representa uma região
do espaço e
emitirá um sinal quando
corpos físicos entrarem ou saírem dela Isso será útil posteriormente para detectar quando o
personagem do jogador entra na sala Mas, por enquanto, tudo o que precisamos
saber é qual é a forma. Adicionando uma forma de colisão
para denotar quando criança, podemos fornecer a ela um Usaremos uma forma de retângulo. Em seguida, podemos mover e redimensionar a forma para criar limites
de espaço Ao anexar um script
ao nó raiz da cena,
nós o chamaremos de Room e o
classificaremos na pasta de scripts. Ao anexar um script ao nó raiz da cena,
nós o chamaremos de Room e o
classificaremos na pasta de scripts Precisaremos de uma referência à forma da
colisão para dende. Vou renomeá-lo para shape node. Então, precisamos de funções
que possam ser usadas para recuperar o canto
superior esquerdo
e o canto inferior direito
desse retângulo para que eles retornem duas coordenadas
vetoriais Podemos acessar a propriedade de forma de
colisão two denodes
pelo nome shape Então, também queremos
chamar uma função no recurso de forma, Get wrecked A função G wrecked
retorna um wreck two, que se abrirmos a
documentação dessa classe, podemos ver que ela tem uma
posição e um fim A posição é o canto
superior esquerdo e o final é o canto
inferior direito. Mas eles são relativos
à posição dos nós. Precisaremos dessas
coordenadas no espaço global, então as adicionaremos à posição global
dos nós. A posição global de um nó será relativa à origem
do jogo, não à posição do nó principal. Em seguida, podemos retornar esses valores. Agora, tudo o que precisamos fazer é dizer à câmera que fique
dentro desses limites. cena do gerenciador de jogos, por enquanto, vamos pegar uma referência
à sala inicial e armazená-la em uma variável chamada sala atual. Quando a cena do jogo estiver pronta, podemos pegar o canto superior
esquerdo e o canto inferior direito
da sala atual e passá-los
para a câmera
chamando uma função que
define seus limites. Passando para
o script da câmera, declararemos essa
função aceitando dois vetores duplos recuperados da sala atual
e não retornando Nesta função,
descobriremos quão perto a câmera pode chegar dos cantos superior esquerdo e inferior
direito da sala sem ver
nada além desses pontos. Para fazer isso, precisaremos criar essas variáveis como vetores duplos, e isso ajudará a
ter um booleano para determinar se a câmera
está ou não vinculada no momento Também precisaremos saber
o tamanho da janela de visualização, que podemos recuperar automaticamente com a
função Get Viewport, depois acessar sua propriedade de tamanho e armazená-la em uma variável
usando a tag on ready A função Get Viewport é declarada na classe node
e retorna um vetor dois, correspondente ao tamanho da janela que definimos nas configurações do projeto Esse tamanho da janela de visualização
não é necessariamente o mesmo que a quantidade de pixels que serão
desenhados pela câmera, pois a câmera
pode aumentar ou diminuir o zoom Precisaremos dividir
o tamanho da janela de visualização pelo zoom
da câmera para obter o tamanho real em pixels da
área que a câmera pode ver Mas um vetor não pode ser dividido por outro vetor.
Temos que usar um flutuador Vou usar apenas o X Zoom e presumir que o zoom da câmera sempre
será uniforme. Mas isso ainda não é
bom o suficiente porque a posição da câmera está
no centro de sua visão. A posição mais próxima
que a câmera conseguir posicionar
no canto superior esquerdo ou inferior direito da sala
sem ultrapassar esses pontos será, na verdade
, metade do tamanho. Dividindo esse valor por dois, renomearei a variável
para refletir seu novo Ao definir os limites, a
posição mais à esquerda será o canto superior esquerdo da sala mais metade do tamanho
da visão da câmera. Embora a posição
mais inferior direita seja o canto inferior direito
da sala menos metade do
tamanho da visão da câmera, podemos definir o valor
vinculado como verdadeiro H. Na função de processo, depois de dizer à câmera que
corresponda à posição do objeto, aplicaremos essas restrições de
limite usando a função Clamp F. A função clamp F usa um parâmetro flutuante, como
a posição da câmera, depois um valor mínimo
e um valor máximo, retorna um valor que
permanecerá dentro desses limites Em seguida, substituiremos a posição da
câmera pelo resultado fixado e
repetiremos isso para o Y. Mas como nossa câmera
também tem um deslocamento, sua posição não é uma representação precisa
o suficiente do centro de sua janela de visualização Também estamos editando o valor do offset em momentos imprevisíveis Portanto, não é algo que
possamos considerar nos cálculos
no canto superior esquerdo e no canto inferior
direito, pois o valor
provavelmente mudará com frequência. Portanto, precisaremos
fatorar o deslocamento
nas funções
de fixação
subtraindo-o sempre do canto superior esquerdo e
inferior direito Se você quiser que sua
câmera aumente e
diminua o zoom durante o jogo,
respeitando esses limites, você também precisará
incluí-los nos cálculos dentro da função de
processo Isso funciona, mas
as interpolações da câmera parecem lutar contra
os limites. A interpolação move o
deslocamento da câmera ligeiramente para fora
dos limites O quadro é desenhado e, em seguida,
o próximo loop de processo afasta a
posição da câmera do limite
para compensar o Isso acontece repetidamente
até que a interpolação pare. Isso ocorre porque as interpolações
são executadas após o processo no final do quadro pouco antes de desenhar
tudo na tela Para corrigir isso, podemos
mudar nossas interpolações
de usar a propriedade tween
para o método tween Ao chamar um método,
podemos aplicar os limites
ao mesmo tempo
em estamos alterando
o valor do deslocamento Os argumentos para o método tween, em vez de uma referência
a um objeto, ele precisa de um método chamável Vamos dizer definir o deslocamento Y. Seguido
pelo valor inicial, que é o valor atual
do deslocamento Y da câmera
, os
argumentos restantes são os mesmos Dois é o
valor final no final
da interpolação e a
duração da Podemos fazer a mesma coisa com
o look ahead tween two. Nós apenas temos que escrever essa função de deslocamento X
definida, aceitando um único
parâmetro que corresponda ao tipo de
from e dois argumentos Depois de alterar o
valor do deslocamento X, podemos impor o
limite limite na posição
da câmera
para compensar imediatamente e fazer o
mesmo com o Fazendo isso agora,
as interpolações de offset não
atingirão o pico além dos limites
da sala Agora temos a câmera limitada para mostrar apenas o que está
na sala atual, mas o ambiente
parece muito plano. vejo no
próximo vídeo.
28. 3-7 Parallaxe: Olá, amigos. Neste vídeo, corrigiremos a rolagem
paralaxe do primeiro plano e
do plano de fundo Começando na cena da
segunda sala, copiarei todas as minhas cores de
modulação dos nós Parallax Tut
para seus nós Então, posso remover
os pais dos sprites e excluir nós
do Parallax Tut enquanto ainda mantenho Em seguida, anexarei um novo script
a qualquer um desses sprites, chamarei de Parallax e o
colocarei na Esse mesmo script pode ser anexado a todos os sprites que
eu quero no Parallax Para criar um comportamento personalizado, é bom dedicar
algum tempo para pensar sobre o que você está
tentando alcançar, quais referências de nós e outras informações
serão necessárias. Eu tenho vários sprites
diferentes. Quero me mover em quantidades
diferentes em relação à
posição da câmera e sei que a câmera está atualmente limitada
aos limites desta sala. Vou adicionar temporariamente uma câmera de
dois nós D à cena e ampliá-la em um fator de dois para fingir que essa
é a cena do jogo Se a câmera estiver exatamente
no centro desta sala, eu queria desenhar tudo
exatamente como está. Mas quando a câmera se
afasta do centro, movo todos os sprites
de
paralaxe uma quantidade relativa, com fundo se movendo
menos do que
a câmera e os elementos primeiro plano se movendo
na direção oposta Para fazer isso, cada sprite
precisará saber a posição da
câmera em relação ao centro da sala, bem
como sua própria posição
original No script Parallax, declararei uma variável
exportada para conter o fator
pelo qual o sprite se move em relação à câmera e nomearei sua escala
de rolagem como um vetor dois Isso funcionará de forma semelhante
à variável de escala de rolagem
no nó Parallax two D. Quando esta sala é carregada
na árvore de cena, podemos usar a
tag on ready para obter sua posição e armazená-la em uma variável
como a posição original. Obter uma referência
à câmera atual é fácil graças à função Node
G Viewport Retornando a janela de visualização na
qual
esse nó existe, que também tem a função Get camera to D para obter a câmera Também podemos armazenar isso em
uma variável, usando a tag on ready. Substituindo a função do processo, não
precisamos do Delta e
podemos marcá-lo como não utilizado Vou apenas definir a
posição do sprite sua posição original mais a distância da
câmera do ponto médio da sala multiplicada
pela escala
de Agora, a câmera só precisa de uma função
pública que possa nos
dizer sua posição em relação ao ponto médio da
sala atual Passando para
o script da câmera, escreverei essa função,
deslocada do ponto médio, que será a posição da
câmera mais seu deslocamento menos o ponto médio da sala atual Declarando isso como
uma nova variável, posso calculá-la
como a média
dos cantos superior esquerdo e
inferior direito da sala
ao
aceitá-las da função set
bounds Poderíamos modificar essa função
para aceitar o ponto médio e tamanho do retângulo em vez cantos superior esquerdo e
inferior direito, mas isso não fará
nenhuma diferença na eficiência,
então não vou me preocupar Agora podemos definir a escala de
rolagem para cada um
dos sprites de paralaxe para
dar a cada um deles uma
distância diferente da câmera Ainda usarei apenas paralaxe
horizontal, dando às minhas colinas uma escala
de rolagem de um terço ao longo do eixo X, e às colinas mais
afastadas dois Para o primeiro plano,
eles precisarão se mover na
direção oposta à da câmera, eles terão uma escala de rolagem de
menos um terço e menos dois
terços Isso será suficiente
para criar a ilusão de
profundidade em nossos quartos Executando o jogo, podemos
passar para a segunda sala e ver que o efeito de paralaxe parece idêntico ao
da sala inicial, apesar de ser executado
por um script muito simples Como os sprites em primeiro plano estão se movendo na
direção oposta à da câmera, eles precisarão repetir e posição para
criar um loop infinito, ou podemos simplesmente tornar o
sprite maior do que a Tornar meus arbustos 1,5 vezes maiores que o quarto e a
grama dobrar o comprimento da sala deixará mais em
ambos
os lados
para que as bordas nunca
alcancem a visão da câmera R seria
possível usar o nó
Parallax two D para desenhar o primeiro plano e o plano fundo usando uma janela de visualização
separada e desenhá-los em
diferentes camadas de tela ou tentar sempre desenhar a sala atual na origem
da cena do
jogo Essas soluções levariam
a outras complicações e limitações futuras
quando se trata desenhar o
mapa do jogo, por exemplo. Acho que escrever
soluções personalizadas como essa às vezes é mais fácil do que
usar os nós fornecidos. A solução também mantém tudo de uma
sala em um só lugar, o que
simplifica o projeto e construção das salas de
uma forma mais intuitiva Eu não preciso mais desse nó Tuti
da câmera, então vou excluí-lo Removendo as nuvens
do nó Parallax touti, podemos alterar o script
Parallax e
também rolar automaticamente as também Expandindo a região destruída, tudo o que precisamos fazer para mover
as nuvens para a direita
é diminuir o valor da
exposição ao Anexando o
script Parallax a esse nó, podemos primeiro definir
sua escala de rolagem uma
para que
corresponda ao movimento da câmera Isso fará com que as nuvens pareçam estar uma distância infinita
em comparação com as colinas Parallax Exportando outro vetor dois
para a velocidade de rolagem automática, precisaremos usar Delta
na função de processo agora e
podemos remover o sublinhado Acessando a
propriedade rect da região e sua posição, começando com o
X, subtrairemos autoscrollX
multiplicado Então, isso fará com que a
velocidade de rolagem automática seja de pixels por segundo. Em seguida, atribua o resultado
à posição X da região recs. Mas se executássemos isso
por muito tempo, esse número se
aproximaria dos limites de
um número de ponto flutuante
e poderia causar problemas. O valor da posição X
corresponde ao tamanho, o resultado é realmente o mesmo. Seria melhor redefinir
a posição X de volta para
zero quando isso acontecesse, que
possamos repetir isso
por um período infinito de tempo. Usando a função AP F, podemos fornecer um valor mínimo
e máximo para limitá-lo a estar apenas entre
zero e o tamanho rec Essa função
retornará um resultado que deve estar entre
esses dois valores,
mas, diferentemente da fixação, o restante ainda
será incluído no E podemos fazer a
mesma coisa se
quisermos usar a rolagem
automática vertical para Vou dar às nuvens
uma grande rolagem automática ao longo do X para demonstração. E quando rodamos o jogo, as nuvens rolam automaticamente para
a direita, girando infinitamente. Mamãe. Mamãe. Vou redefinir o valor da rolagem automática
para um valor razoável. Agora temos a
rolagem paralaxe em primeiro plano e em
segundo plano Mas as transições entre os
quartos são muito repentinas. Te vejo no próximo vídeo.
29. 4-1 Conteúdo: Olá, amigos. Nesta seção, permitiremos que o jogador se mova entre várias
salas em nosso jogo. Abrindo a cena inicial da sala, podemos ver que os componentes
visuais dessa sala ultrapassam
os limites da câmera. Se estivéssemos em uma sala
adjacente a esta, não
gostaríamos de
ver esses sprites desenhando quando deveriam
estar em uma sala diferente Além disso, se imaginássemos nosso jogo inteiro
cheio de muitas salas diferentes, seria um grande desperdício de
recursos ter todos os componentes visuais carregados quando estamos
vendo apenas um por vez. Então, adicionaremos outro
nó dois D à cena. Dê um nome ao conteúdo. Em seguida, redirecione todos esses outros nós
ao nó de conteúdo, exceto pela forma de colisão. Clicando com
o botão direito do mouse no nó de conteúdo, vamos salvá-lo como sua própria cena. Vou criar uma nova pasta na pasta Forest Rooms
para o conteúdo. Em seguida, nomeie a cena como conteúdo da sala
inicial. Em seguida, exclua o conteúdo
dessa cena. Quando o personagem do jogador
entra nesta sala, tudo o que precisamos fazer é carregar seu conteúdo e
adicioná-lo à cena. Em seguida, exclua o conteúdo
quando ele sair. Podemos detectar quando o personagem do
jogador entra na sala conectando
o sinal inserido pelo corpo, já que o nodo
Tutti do corpo do personagem é um corpo físico Conectando esse sinal
ao script da sala, ele adicionará automaticamente uma função para nós
no corpo inserido, aceitando o corpo
como parâmetro. Não precisamos do
corpo, então podemos continuar com um sublinhado
para marcá-lo como não usado Na parte superior do script, será útil dar a
esse script um nome de classe. Vamos chamá-lo de Room. Em seguida, exporte o conteúdo
visto como uma cena compacta. E preencha essa variável
clicando e arrastando a cena do conteúdo da guia do
sistema de arquivos para o guia do
sistema de arquivos para o Também declararemos uma
variável de conteúdo como um nó dois D. Declarando uma nova função
chamada load Se o conteúdo for nulo, atribuiremos a
ele o valor
do conteúdo visto instanciado Em seguida, adicione o nó de conteúdo
à cena quando criança. Quando o personagem do jogador
entrar nesta sala, chamaremos a função de carregamento de
conteúdo. Vamos imprimir temporariamente o valor do corpo para que
possamos ver o que é. Também precisaremos de
outra função para descarregar o conteúdo da sala
quando eles não forem mais necessários, embora não possamos
testá-la até o próximo vídeo Primeiro, verifique se há
algum conteúdo a ser descarregado. Se houver conteúdo, chame sua função livre Qu e
defina a variável como nula Liberar um nó
da árvore de cena não apaga automaticamente o conteúdo da
variável Então, se saíssemos de uma sala, descarregássemos seu conteúdo e entrássemos novamente na mesma sala, essa instrução
if, verificando se o valor do
conteúdo é nulo, diria, sim,
realmente há algo
nessa variável de conteúdo No entanto, o nó
que foi armazenado aqui foi previamente liberado
da árvore de cena, então isso causará um erro Portanto, definir a
variável como nula após removê-la da
árvore de cena corrige esse problema Durante o jogo,
nosso personagem está dentro da área de colisão da
sala inicial, então isso aciona o carregamento do conteúdo
da sala inicial No entanto, não queremos que
nenhum outro corpo
físico o sinal
e
carregue acidentalmente o conteúdo da sala Precisamos ter certeza de que
o personagem do jogador será o único corpo
capaz de fazer isso acontecer. Mudando para a cena do
personagem do jogador, podemos selecionar o nó Tutti
do corpo do personagem e expandir a seção de colisão nas propriedades herdadas
do objeto
de Aqui temos uma
camada de colisão e uma máscara de colisão, cada uma com 32 botões numerados Essas são máscaras de bits, que são apenas números inteiros
usados de uma maneira específica Como os números inteiros são armazenados como 32 zeros e uns binários, podemos usar cada
bit individual como uma camada Quando chega a hora de
verificar colisões, aplicando
operações lógicas simples entre máscara de colisão de
um objeto a camada de
colisão do outro objeto, podemos determinar se elas
devem colidir Somente se a
máscara do primeiro objeto tiver uma na mesma posição de bit
da camada
do segundo objeto, uma colisão
será desencadeada Caso contrário, ele simplesmente
passará como se não estivesse lá. Mudando a
camada de colisão do
personagem para qualquer outro número, ele agora existirá em sua
própria camada de colisão exclusiva separada de todo o
resto do jogo Como os números estão
em grupos de oito, gosto de usar as
primeiras oito camadas
para camadas de
colisão ambiental,
as próximas oito para
o personagem do jogador, as próximas oito para
inimigos, etc O corpo do personagem
ainda está mascarando a camada um, então ele ainda colidirá
com o terreno durante seu processo físico
quando chamarmos move Podemos nomear essas camadas nas configurações
do projeto sob os nomes das
camadas Física dois D. Nomearei a camada um como terreno e a camada
nove como jogador Esses nomes serão
exibidos ao passar
o mouse sobre os botões da camada no inspetor,
junto com seus valores em bits
e Na cena inicial da sala, podemos mudar a máscara de
colisão, então essa área de dois dende mascarará apenas a camada de colisão do
personagem do jogador, somente o personagem do jogador
desencadeará colisões Executando o jogo novamente,
nada mudará, mas podemos ter certeza de
que nenhum outro corpo carregará o conteúdo da sala. Agora temos nossa sala
carregando dinamicamente seu conteúdo quando o personagem do
jogador entra nela, mas ainda temos apenas uma sala Te vejo no próximo vídeo.
30. 4 a 2 quartos: Olá, amigos. Neste vídeo, adicionaremos uma segunda sala para
a qual o personagem pode se mover. Começaremos duplicando
a cena da sala inicial. Vou nomear esse quarto de 1 segundo. Em seguida, duplique também a cena de conteúdo da sala
inicial e abra-a para que eu possa editá-la, depois remova as
árvores e a copa para
que fique visualmente distinta
da Também podemos editar o
terreno e os limites se quisermos tornar as duas
salas ainda mais distintas Abrindo a cena da segunda sala, renomearei o nó raiz da cena para
corresponder ao nome do arquivo Não se esqueça de atribuir a cena de conteúdo da
segunda sala na cena do
espaço da segunda sala para
que ela carregue o
conteúdo correto quando inserida. Na cena do jogo, como meu mundo será
dividido em regiões, adicionarei um nó dois D
e o chamarei de floresta. Em seguida, faça dos meus dois quartos
filhos da região da floresta. Salve a região da floresta
como sua própria cena
na pasta rooms e abra a
cena da região da floresta para editá-la. No cenário da região da floresta, agora
podemos posicionar facilmente essas duas salas uma ao
lado da outra. Queremos posicionar as salas lado a lado para que possamos trocar de sala quando o jogador sair de uma sala e
entrar em outra. Ative o encaixe na grade,
expanda as opções de
encaixe e selecione configurar o Snap encaixe e Podemos definir a etapa da grade
para o tamanho do ladrilho de nossos ladrilhos de terreno em -32 pixels Isso torna muito
simples posicionar as salas exatamente alinhadas uma
ao lado da outra O sinal da área inserida pelo
corpo do nó Tutti será emitido assim que do personagem Tutti se
sobrepor
à forma de colisão da sala Para simplificar as coisas, precisaremos deixar um pouco de
espaço entre as salas, grande o suficiente para que o corpo do
personagem não
se sobreponha a mais de
uma sala por vez Caso contrário, precisaríamos
adicionar uma lógica extra para quando o personagem entra em uma sala sem sair totalmente
da anterior. corpo do personagem se sobrepõe às áreas
dos dois quartos
ao mesmo tempo, mas depois se vira e
volta para o primeiro É muito mais fácil se os
quartos estiverem espaçados. Quando o personagem
entra em uma nova sala, sabemos que ele já
saiu da sala anterior Isso também permitirá que o personagem se mova
completamente para fora dos limites da câmera antes de iniciar a
transição para a nova sala Como a
forma de colisão do meu personagem tem apenas 12 pixels largura e a lacuna entre as
salas tem 32 pixels de largura, tenho certeza de que
o personagem caberá entre essas duas salas sem tocar nas duas ao mesmo tempo Ter essa lacuna
significa que todos os nossos quartos também
precisarão estender a colisão de piso
o suficiente para fora dos limites da
câmera
da sala para evitar que
o personagem
caia antes de chegar
à sala adjacente Vou diminuir um
pouco o zoom da câmera e comentar a linha de código que liga a câmera aos limites da
sala atual Executando o jogo, podemos ver que o conteúdo da
sala inicial é carregado imediatamente
porque o personagem já
estava dentro dessa sala. Movendo-se para onde ficará a
segunda sala, seu conteúdo é
carregado assim que personagem
do jogador
cruza o limiar Mas também queremos descarregar o conteúdo da sala
anterior que acabamos de sair Será responsabilidade do gerente de jogo
lidar com as transições, pois isso envolverá
muitos componentes da cena do jogo
trabalhando juntos Precisaremos enviar um sinal
da sala em que foi acessada
para o gerente do jogo, que nem mesmo está na
mesma cena em nosso projeto. Também teremos muitas salas
diferentes em nosso jogo
e seria difícil ter que
conectar manualmente esse sinal para
cada sala, uma de cada vez. Portanto, seria mais fácil usar
nossos scripts para automatizá-lo. A partir do script da sala, adicionaremos um novo sinal na parte superior
do script que podemos emitir para dizer que o
personagem do jogador entrou nesta sala com a sala que
foi inserida como parâmetro Então, quando o
sinal inserido pelo corpo for recebido, emitiremos esse sinal
em vez de carregar o conteúdo e passaremos a própria
sala como argumento Quando esta sala estiver pronta, podemos acessar a raiz
das árvores de cena iniciando uma boneca ou assinando o
caminho do nó anotado com uma barra, depois a raiz da palavra e
outra Da raiz da árvore da cena, o primeiro nó que
queremos acessar é chamado jogo, pois é nomeado
na cena do jogo. Isso nos dá acesso ao script
do gerenciador de jogos com um ponto final. Então, podemos referenciar uma função
que ainda não escrevemos. Vamos dizer que o
jogador entrou na sala. Então, podemos escrever
essa função no script
do gerenciador de jogos com
um parâmetro de sala correspondente. Vou chamá-la de room Entered para ficar mais claro
neste contexto. Para descarregar o conteúdo da sala
anterior, precisaremos saber qual
era a sala anterior, então precisaremos de uma variável para armazenar
a sala em que o
personagem do jogador está atualmente Vou substituir esse nível
atual quarto atual
e deixá-lo vazio. Não preciso mais
da etiqueta pronta. A primeira coisa que devemos fazer
é verificar se a sala que está sendo
acessada é a mesma em que
o personagem do jogador
está atualmente. Nesse caso,
realmente não precisamos fazer nada e podemos simplesmente retornar
dessa função. Agora podemos supor
que a sala atual e a sala inserida
são salas diferentes. Ao iniciar o jogo pela primeira vez, não
há espaço atual. Primeiro, verificaremos se o quarto
atual não é nulo. Se houver uma sala atual, devemos pedir que ela descarregue seu conteúdo usando a função que escrevemos no vídeo anterior Em seguida, atribuindo
a sala atual à sala acessada, agora
podemos dizer a essa sala
atual que carregue seu conteúdo e, finalmente, vincule a câmera aos limites da sala
atual Mas vou comentar isso para que
possamos ver o que acontece
com o zoom reduzido. Agora, quando rodamos o jogo, entrar na segunda sala envia um sinal ao gerente do jogo para descarregar o conteúdo
da sala inicial antes de carregar o conteúdo
da segunda sala Agora temos várias
salas em nosso jogo, mas a rolagem
paralaxe de primeiro plano
e de fundo não
funciona em salas que não estão centradas Te vejo no próximo vídeo.
31. 4-3 Parallaxe: Olá, amigos. Neste vídeo, corrigiremos a rolagem
paralaxe do primeiro plano e
do plano de fundo Começando na cena da
segunda sala, copiarei todas as minhas cores de
modulação dos nós Parallax Tut
para seus nós Então, posso remover
os pais dos sprites e excluir nós
do Parallax Tut enquanto ainda mantenho Em seguida, anexarei um novo script
a qualquer um desses sprites, chamarei de Parallax e o
colocarei na Esse mesmo script pode ser anexado a todos os sprites que
eu quero no Parallax Para criar um comportamento personalizado, é bom dedicar
algum tempo para pensar sobre o que você está
tentando alcançar, quais referências de nós e outras informações
serão necessárias. Eu tenho vários sprites
diferentes. Quero me mover em quantidades
diferentes em relação à
posição da câmera e sei que a câmera está atualmente limitada
aos limites desta sala. Vou adicionar temporariamente uma câmera de
dois nós D à cena e ampliá-la em um fator de dois para fingir que essa
é a cena do jogo Se a câmera estiver exatamente
no centro desta sala, eu queria desenhar tudo
exatamente como está. Mas quando a câmera se
afasta do centro, movo todos os sprites
de
paralaxe uma quantidade relativa, com fundo se movendo
menos do que
a câmera e os elementos primeiro plano se movendo
na direção oposta Para fazer isso, cada sprite
precisará saber a posição da
câmera em relação ao centro da sala, bem
como sua própria posição
original No script Parallax, declararei uma variável
exportada para conter o fator
pelo qual o sprite se move em relação à câmera e nomearei sua escala
de rolagem como vetor dois Isso funcionará de forma semelhante
à variável de escala de rolagem
no nó Parallax two D. Quando esta sala é carregada
na árvore de cena, podemos usar a
tag on ready para obter sua posição e armazená-la em uma variável
como a posição original. Obter uma referência
à câmera atual é fácil graças à função Node
G Viewport Retornando a janela de visualização na
qual
esse nó existe, que também tem a função Get camera to D para obter a câmera Também podemos armazenar isso em
uma variável, usando a tag on ready. Substituindo a função do processo, não
precisamos do Delta e
podemos marcá-lo como não utilizado Vou apenas definir a
posição do sprite sua posição original mais a distância da
câmera do ponto médio da sala multiplicada
pela escala
de Agora, a câmera só precisa de uma função
pública que possa nos
dizer sua posição em relação ao ponto médio da
sala atual Passando para
o script da câmera, escreverei essa função,
deslocada do ponto médio, que será a posição da
câmera mais seu deslocamento menos o ponto médio da sala atual Declarando isso como
uma nova variável, posso calculá-la
como a média
dos cantos superior esquerdo e
inferior direito da sala
ao
aceitá-las da função set
bounds Poderíamos modificar essa função
para aceitar o ponto médio e tamanho do retângulo em vez cantos superior esquerdo e
inferior direito, mas isso não fará
nenhuma diferença na eficiência,
então não vou me preocupar Agora podemos definir a escala de
rolagem para cada um
dos sprites de paralaxe para
dar a cada um deles uma
distância diferente da câmera Ainda usarei apenas paralaxe
horizontal, dando às minhas colinas uma escala
de rolagem de um terço ao longo do eixo X, e às colinas mais
afastadas dois Para o primeiro plano,
eles precisarão se mover na
direção oposta à da câmera, eles terão uma escala de rolagem de
menos um terço e menos dois
terços Isso será suficiente
para criar a ilusão de
profundidade em nossos quartos Executando o jogo, podemos
passar para a segunda sala e ver que o efeito de paralaxe parece idêntico ao
da sala inicial, apesar de ser executado
por um script muito simples Como os sprites em primeiro plano estão se movendo na
direção oposta à da câmera, eles precisarão repetir e posição para
criar um loop infinito, ou podemos simplesmente tornar o
sprite maior do que a Tornar meus arbustos 1,5 vezes maiores que o quarto e a
grama dobrar o comprimento da sala deixará mais em
ambos
os lados
para que as bordas nunca
alcancem a visão da câmera R seria
possível usar o nó
Parallax two D para desenhar o primeiro plano e o plano fundo usando uma janela de visualização
separada e desenhá-los em
diferentes camadas de tela ou tentar sempre desenhar a sala atual na origem
da cena do
jogo Essas soluções levariam
a outras complicações e limitações futuras
quando se trata desenhar o
mapa do jogo, por exemplo. Acho que escrever
soluções personalizadas como essa às vezes é mais fácil do que
usar os nós fornecidos. A solução também mantém tudo de uma
sala em um só lugar, o que
simplifica o projeto e construção das salas de
uma forma mais intuitiva Eu não preciso mais desse nó Tuti
da câmera, então vou excluí-lo Removendo as nuvens
do nó Parallax touti, podemos alterar o script
Parallax e
também rolar automaticamente as também Expandindo a região destruída, tudo o que precisamos fazer para mover
as nuvens para a direita
é diminuir o valor da
exposição ao Anexando o
script Parallax a esse nó, podemos primeiro definir
sua escala de rolagem uma
para que
corresponda ao movimento da câmera Isso fará com que as nuvens pareçam estar uma distância infinita
em comparação com as colinas Parallax Exportando outro vetor dois
para a velocidade de rolagem automática, precisaremos usar Delta
na função de processo agora e
podemos remover o sublinhado Acessando a
propriedade rect da região e sua posição, começando com o
X, subtrairemos autoscrollX
multiplicado Então, isso fará com que a
velocidade de rolagem automática seja de pixels por segundo. Em seguida, atribua o resultado
à posição X da região recs. Mas se executássemos isso
por muito tempo, esse número se
aproximaria dos limites de
um número de ponto flutuante
e poderia causar problemas. O valor da posição X
corresponde ao tamanho, o resultado é realmente o mesmo. Seria melhor redefinir
a posição X de volta para
zero quando isso acontecesse, que
possamos repetir isso
por um período infinito de tempo. Usando a função AP F, podemos fornecer um valor mínimo
e máximo para limitá-lo a estar apenas entre
zero e o tamanho rec Essa função
retornará um resultado que deve estar entre
esses dois valores,
mas, diferentemente da fixação, o restante ainda
será incluído no E podemos fazer a
mesma coisa se
quisermos usar a rolagem
automática vertical para Vou dar às nuvens
uma grande rolagem automática ao longo do X para demonstração. E quando rodamos o jogo, as nuvens rolam automaticamente para
a direita, girando infinitamente. Mamãe. Mamãe. Vou redefinir o valor da rolagem automática
para um valor razoável. Agora temos a
rolagem paralaxe em primeiro plano e em
segundo plano Mas as transições entre os
quartos são muito repentinas. Te vejo no próximo vídeo.
32. 4-4 Transição: Olá, amigos. Neste vídeo, suavizaremos a transição entre salas com um
simples desbotamento para preto Na cena do jogo, a
maioria dos jogos começa com uma
tela de carregamento ou totalmente preta e depois desaparece quando
o jogo começa Adicionando um nó
à camada de tela, podemos usar um nó colorido destruído para desenhar cores simples Expandindo a seção de layout, alteraremos a
predefinição de âncoras para full Isso fará com que a cor destruída preencha toda a tela Atualmente é branco, mas o
preto é mais comum, então podemos mudar a cor
para preto na parte superior. Quando o jogo começa,
tudo o que precisamos fazer é mudar
gradualmente essa
cor de preto para transparente, revelando a
janela de visão da câmera atrás dela Com nossas salas pequenas e simples,
elas carregam instantaneamente. , o carregamento e o descarregamento do conteúdo da Atualmente, o carregamento e o descarregamento do conteúdo da
sala não causam nenhum atraso Mas se imaginarmos que
nossas salas consistirão em muito mais sprites e especialmente, no carregamento de efeitos sonoros e música de
fundo, isso fará com que o
carregamento da sala demore
mais do que um único quadro Podemos usar o mesmo efeito
invertido para escurecer, descarregar
e carregar nosso quarto e depois voltar
quando tudo estiver pronto Este projeto não ficará tão grande precisarmos de uma tela de
carregamento real. Vamos renomear esse node fade
e dar a ele um nome exclusivo. Precisaremos
garantir que esse nó permaneça na parte inferior
da árvore da cena para ser desenhado sobre todo o
resto ou aumentar seu índice Z. Ter esse grande retângulo
preto na cena
do jogo pode atrapalhar o trabalho
em outras coisas Talvez queiramos ter esse
nó oculto por padrão. Ao anexar um script a esse nó, vou chamá-lo de fade e
salvá-lo na pasta de scripts Substituindo a função ready, a primeira coisa que quero fazer é definir sua
propriedade visible como true, para que ela cubra
tudo em preto Precisaremos de duas funções
públicas para ajustar a cor para preto
ou transparente. Para ajustar o valor de
uma propriedade ao longo do tempo, a maneira mais fácil é
usar uma interpolação Então, vamos declarar
um como uma variável. Embora eu não espere permitir o desbotamento mais de uma vez
em rápida sucessão, ainda
é uma boa
ideia verificar se
a interpolação já existe
e eliminá-la por precaução Em seguida, crie uma nova interpolação. Não há necessidade de tipos sofisticados de transição
ou atenuação aqui, uma interpolação linear
funcionará perfeitamente E será entre
esse nó em si, sua propriedade de cor e a alteração sua cor para ficar transparente
ao longo de um período de tempo Por enquanto, vou colocar 1 segundo. Há uma
cor transparente definida na classe, mas se passarmos
o mouse sobre ela,
podemos ver que ela tem valores de vermelho, verde
e azul iguais a um, valores de vermelho, verde
e azul iguais a um, significa que é
branca transparente, não preta transparente Isso não criará
o efeito que eu quero, então vou definir minha própria cor
transparente como uma constante e chamá-la de clara. Usar todas as letras maiúsculas é convencional ao
nomear Essa será uma cor
com zero valores de vermelho, verde, azul e alfa. Também podemos definir uma
constante para a duração
da interpolação e substituir o 1
segundo por essa constante Isso torna um pouco mais fácil
alterar a duração sem
precisar examinar o script e sem
exportar uma variável para algo que você deseja
manter consistente todo o projeto Para a função feed to black, poderíamos copiar e colar
todo esse código, alterando
apenas o argumento do valor
final da chamada da
função de propriedade tween, mas seria melhor
evitar redundância Em vez disso, vamos fazer disso sua própria função
privada
chamada tween color, aceitando a
cor final como parâmetro e, em
seguida, passá-la para a
chamada da função de
propriedade tween como argumento Então, tanto o destino para preto
quanto duas funções claras podem chamar essa função,
passando argumentos diferentes. No script do gerenciador de jogos, obteremos uma referência
ao fade node na parte superior Quando o personagem do jogador entra em uma sala depois de carregar
o conteúdo da sala, podemos fazer com que o fade mude sua
cor para ficar claro Quando o jogo
começar,
não haverá espaço atual para descarregar, então isso desaparecerá imediatamente Depois de entrar na segunda sala, vamos querer escurecer
antes de descarregar o conteúdo da sala
atual e, em
seguida, continuar carregando a segunda sala e
retornando Mas essa função
não esperará que a interpolação termine antes de descarregar
o conteúdo da sala Isso será feito imediatamente. Para pausar essa função enquanto
a interpolação fica preta,
podemos usar a podemos usar A espera será seguida por
um sinal. O sinal que queremos aguardar é o sinal finalizado da interpolação
no script de fade Assim, podemos retornar esse sinal
da nossa função de interpolação. Alterando o tipo de retorno de nossa função de
vazio para sinal Passando o mesmo sinal de
retorno
novamente pelas funções de fade to
black e clear De volta ao script do gerenciador de jogos, o gerente do jogo agora pode acessar esse sinal sempre que
chamar essas funções Podemos esperar que o fade to black
ou aguardar o fade to clear, então essa função fará uma pausa e
aguardará o término da interpolação antes de Geralmente, não queremos que
o jogador tenha controle sobre o personagem
enquanto isso acontece. Assim, podemos chamar
player dot Disable na parte superior da
função antes de iniciar a transição e reativar o nó do player no final após a conclusão da transição
. Esqueci de atualizar
essa
variável de direção para mover a direção
quando a renomeei Embora essas salas
sejam bem pequenas e devam ser descarregadas e
carregadas rapidamente, ainda
podemos
ver um caso
em que a sala anterior descarrega e, como não
há terreno para o
personagem ficar de pé,
elas caem pelo chão antes
que
o ainda
podemos
ver um caso
em que a
sala anterior descarrega e, como não
há terreno para o
personagem ficar de pé,
elas caem pelo chão antes
que
o conteúdo da próxima sala seja
carregado para formar um Portanto, também devemos
desativar e habilitar o personagem ao mesmo tempo
que fazemos o nó do jogador. Outra forma de
ativar e desativar os nós é alterando sua propriedade de modo de
processo. Defina-o como desativado quando
a transição começa e,
em seguida, herde quando a
transição for concluída Agora, o jogador não pode
controlar o personagem, e o personagem
não será afetado pela gravidade durante a transição
entre as salas Em seguida, trabalharemos em desenhar
nossos quartos em um mapa. Te vejo no próximo vídeo.
33. Janela de visualização 4-5: Olá, amigos. Neste vídeo, começaremos a trabalhar para
desenhar nossos quartos em um mapa. Embora seja possível desenhar o mapa separadamente
do mundo do jogo, é muito mais complicado manter
a consistência entre o mundo e o mapa
se você precisar atualizar os dois separadamente toda vez
que mudar alguma coisa Posicionar ícones no mapa, especialmente ícones que podem se mover
como o personagem do jogador, pode se tornar uma tarefa ainda mais difícil. Um método muito mais fácil de criar
um mapa é simplesmente ter uma segunda câmera visualizando o mundo de uma perspectiva
ampliada, mas desenhar o mundo e seu
conteúdo de uma forma mais simples Então, vamos adicionar outra câmera à nossa cena do jogo e
renomeá-la para câmera de mapa Por padrão, somente a primeira
câmera será usada e ela desenhará a janela de exibição principal do
jogo Para desenhar o mapa, a câmera do mapa precisará desenhar uma janela de visualização
diferente, então adicionaremos uma como um
nó na árvore de cena,
que é um subnó da janela de visualização Renomeie-o para Map Viewport
e dê a ele um nome exclusivo. Em alguns de nossos scripts, já
usamos
a função G Viewport para obter a janela de visualização principal do jogo, que está sendo usada para desenhar
os dois mundos D do jogo Os dois mundos D
neste contexto
não são iguais ao nó ambiental
mundial. Ele contém todos os
nós TD atualmente no centro, incluindo o gerenciador de jogos. Se transferirmos a câmera do mapa
para a janela de visualização do mapa, essa câmera agora desenhará a janela de visualização do
mapa em vez da janela de visualização principal do jogo, mas não terá nenhum lugar
na tela para desenhá-la Portanto, precisaremos adicionar um nó destruído de textura à camada
da tela para dar
à câmera um lugar para
desenhar a janela Vamos chamar isso de textura do
Map Viewport. Vou remover todos esses nós de controle
fictícios
e garantir que o nó destruído de textura seja desenhado antes do
nó de esmaecimento,
colocando-o no topo
da colocando-o no topo Clicando na lista suspensa de
textura, podemos selecionar a textura da janela de visualização seguida, selecionar a janela de visualização do
mapa a ser desenhada como a textura dessa textura
molhada A textura retangular será
automaticamente redimensionada para corresponder ao
tamanho da janela de visualização Atualmente, ele está apenas desenhando a cor de
fundo cinza padrão porque a câmera do mapa e a
janela de visualização não conseguem ver nada Por padrão, cada Viewport
terá seu próprio mundo. Você pode pensar
nesses mundos como mundos paralelos ou
planos de existência. Eles podem ocupar
o mesmo espaço ao mesmo tempo, mas existem
independentemente um do outro. Mas queremos que essa janela de visualização
desenhe o mesmo mundo da nossa janela
de visualização principal No script do gerenciador de jogos, obteremos uma referência ao
nó Map Viewport Em seguida, na função ready, defina a
propriedade world two D da janela de visualização Podemos acessar a janela de visualização
principal
chamando os
nós do gerenciador de jogos, obtendo a função Viewport e, em
seguida, acessando sua propriedade D world
two. Agora, tanto a janela de visualização principal quanto visualização
do mapa
desenharão o mesmo mundo Geralmente, queremos que nossos mapas visualizem muito mais do mundo, então vou configurá-lo para
um oitavo de zoom Se quisermos alterar as
dimensões da textura do mapa, podemos definir as dimensões em
pixels
da janela de visualização
selecionando-a na árvore da cena Vou fazer com que seja metade
das dimensões do meu jogo de 640 por 360 pixels Em vez de desenhar essa
cor cinza quando não há nada, prefiro que o plano de fundo do meu Map Viewport seja transparente Vou ativar o fundo
transparente. No entanto, isso dificulta a leitura do
mapa Eu gostaria de ter essa textura do
mapa contida em um painel para que pareça
separada do jogo principal. Ao adicionar um contêiner de painel
à camada Canvas, vou refazer
a textura do mapa filha do nó do contêiner do
painel e, em
seguida, renomear o contêiner do painel para Mapa e dar a
ele um nome exclusivo Com o tema padrão, o contêiner do painel desenhará uma cor preta transparente
e, como é um contêiner, ele
se redimensionará automaticamente para conter seus filhos Isso deixa claro
que a textura do mapa está sendo desenhada na tela, não como parte do mundo, e podemos ajustar a
aparência do contêiner
do painel posteriormente por meio
do editor de temas. Vou usar as
âncoras dos
contêineres do painel para fixá-lo no
centro da Geralmente, queremos que a câmera do
mapa siga o personagem do jogador
como a câmera principal, mas sem nenhuma
interpolação ou outros recursos Ao contrário da câmera principal, a câmera do mapa nunca
precisará fazer mais nada, então é seguro
sempre fazer com que ela
corresponda exatamente à
posição do personagem do jogador. Não há como
ter a câmera do mapa associada ao personagem do jogador, pois ela deve permanecer filha da janela de visualização
do mapa
para desenhar o Poderíamos escrever outro
script para mover essa câmera, mas há um nó que podemos
usar para facilitar as coisas, a transformação remota de dois D. Com a transformação remota dois D como filho
do personagem do jogador, podemos definir seu
caminho remoto até a câmera do mapa. Agora, as propriedades de
transformação,
posição, rotação e escala da câmera serão atualizadas
automaticamente para serem iguais às do personagem do
jogador. Podemos desativar a rotação e
a escala expandindo
a seção de atualização Mesmo se estivéssemos editando a
rotação ou a escala do personagem do jogador, não
gostaríamos que o mapa
copiasse essas propriedades. Mamãe. Agora temos nosso mundo de jogos sendo
desenhado na tela, mas queremos desenhar uma versão
simplificada
do mundo em
vez de uma cópia exata. Te vejo no próximo vídeo.
34. 4-6 Visibilidade: Olá, amigos. Neste vídeo, faremos com que a câmera do mapa desenhe uma
versão simplificada do mundo. Começando pela sala inicial, vamos adicionar temporariamente
o conteúdo da sala. Não quero desenhar todos
esses sprites no mapa,
apenas um esboço da forma e do
terreno da sala Podemos usar quaisquer dois nós D para desenhar isso,
dependendo do estilo que queremos. Vou usar um nó da camada Tile Map. Dê a ele um novo conjunto de
blocos com blocos de 32 por 32 pixels. Vou importar um novo sprite, que é apenas um quadrado branco simples de 32
por 32 pixels Em seguida, adicione isso ao conjunto de blocos. Ao desenhar esse quadrado branco
na minha camada de Mapa de Azulejos, vou desenhar um
contorno da sala usando o terreno
como piso em
vez do limite da câmera e deixando portas para
se conectar a outras Queremos que a câmera principal
desenhe somente o conteúdo,
enquanto a câmera do mapa
desenhará essa nota da
camada de Mapa de Mosaicos em vez disso. Enquanto ambos estiverem
olhando para a mesma sala, eles verão duas versões
diferentes dela. Agora que tenho a
forma do meu quarto, excluirei o conteúdo
da cena. Como o nó da camada do Mapa Mosaicos sempre
será visualizado
pela câmera do mapa, ele sempre
permanecerá carregado em
vez de ser carregado e
descarregado como o conteúdo Expandindo a seção de
visibilidade, posso usar a propriedade de
cor modular para transformar meus quadrados brancos
em quadrados coloridos, se eu quiser Como isso faz parte
da região da floresta, vou desenhar seu mapa em verde. Para que a câmera do mapa desenhe
isso, mas não a câmera principal, alterarei sua camada de
visibilidade 1-2. A primeira
camada de visibilidade padrão
será tudo o que for desenhado
pela câmera principal do jogo, enquanto a camada dois será tudo o que eu quiser
desenhar no mapa. Assim como com as camadas de
colisão, podemos nomear essas camadas de
visibilidade nas configurações
do projeto, abaixo dos nomes das
camadas, renderização de dois D. Vou nomear o
mundo da camada um e o mapa da camada dois. Essas camadas de visibilidade
dependem das
camadas de visibilidade de seus pais. Se o Viewport não conseguir ver
o nó da área inicial da sala
, ele não se
preocupará em verificar se
consegue ver o nó filho da
camada de Mapa de Mosaicos O
nó principal da sala inicial precisará ter sua camada de visibilidade definida
como uma e duas, pois terá filhos que podem ser desenhados pelas duas janelas de visualização Prosseguindo pela hierarquia,
a região
da floresta precisa
ter sua visibilidade definida para usar
as duas camadas de visibilidade , assim como o nó raiz
das cenas do jogo O ambiente mundial Node não tem uma propriedade de
camada de visibilidade. Agora, selecionando o Map Viewport, podemos definir sua máscara de chamada Canvas para visualizar apenas a camada dois
e não a camada um Isso funciona de forma semelhante à propriedade
da máscara de colisão
para objetos de colisão. Somente se o bit da
máscara estiver definido como um, ele
será capaz de ver qualquer coisa cuja camada tenha o
mesmo bit definido como um? Mas não podemos acessar a janela de visualização principal
do editor para alterar sua máscara de chamada do Canvas para visualizar
apenas a camada um
e não a camada dois Por padrão, ele estará
mascarando todas as camadas. Então, precisaremos
editá-lo por meio de um script. Na função pronta para
scripts do gerenciador de jogos, podemos acessar a janela de visualização principal
com a função G Viewport e, em
seguida, definir sua propriedade de máscara de
chamada do Canvas Passando o mouse sobre a camada um, podemos ver que seu
valor inteiro também é um Podemos simplesmente definir o valor das máscaras de
chamada do Canvas como um. Agora, ele visualizará apenas a camada de
visibilidade um e não a camada dois ou qualquer
outra camada. Copiando o
nó da camada Tile Map na sala inicial, eu
o colarei na segunda sala para também
desenhar essa sala no mapa. Vou instanciar o conteúdo da
sala e, em
seguida, editar os blocos para refletir
com mais precisão a forma
dessa sala e excluir o
conteúdo quando terminar Lembre-se de definir que a camada
de
visibilidade dos nós principais exista em ambas as
camadas de visibilidade para os filhos sejam vistos por
suas respectivas janelas de visualização Agora, as duas salas estão
claramente visíveis no mapa com muito pouco esforço
, pois adicionamos mais salas, precisando
apenas adicionar o mapa cada sala em sua cena em uma camada de visibilidade
separada Podemos facilmente adicionar outras
coisas ao Mapa dois
adicionando mais sprites a elas
e colocando-as na camada de
visibilidade dois, como o ícone do mapa de um
personagem do jogador Abrindo a cena
dos personagens do jogador, vamos adicionar um Sprite para denodar
e chamá-lo de ícone de Vou preencher a textura
com uma textura de atlas, usar a mesma planilha de sprites e selecionar uma região para
usar como ícone do mapa Vou usar a
cabeça do personagem
em algum lugar da folha de sprite onde
a cauda não esteja no caminho Depois de preencher a propriedade da
textura, definiremos sua
camada de visibilidade como duas e não uma Então, o nó raiz
dessa cena
precisará ter as
camadas um e dois. Vou me ajustar ao
deslocamento do sprite, para que ele fique no chão
como o personagem Sabendo que o
zoom da câmera é de um oitavo, aumentarei esse ícone oito vezes, fazendo com que pareça
muito grande na cena Como não quero que
esse ícone cubra meu personagem sempre
que trabalho na cena, prefiro escondê-lo,
e isso vale tudo no meu jogo ao
qual eu quero anexar um ícone de mapa Vou adicionar um script a esse nó, chamando-o de ícone de Mapa. E vou fazer com que ele
defina a propriedade de visibilidade
como verdadeira quando estiver pronto. Agora, esse ícone de
mapa muito grande não
precisa ser desenhado no editor enquanto eu estiver trabalhando
no meu personagem, mas será desenhado
quando eu executar o jogo. Agora temos nosso mapa
desenhando contornos das salas e do
personagem do jogador com um ícone, mas talvez queiramos
ativar e desativar o mapa com um botão Te vejo no próximo vídeo.
35. Mapa 4-7: Olá, amigos. Neste vídeo, permitiremos que o jogador abra e feche o
mapa com um botão. Começando na cena do jogo, vou
ocultar o mapa por padrão,
alternando a visibilidade do nó do
contêiner que o contém Em seguida, anexe um novo script
ao contêiner. Embora eu esteja usando atualmente um contêiner de
painel para isso, não
precisarei acessar nenhum dos recursos
do contêiner de
painel neste script e posso herdar do
tipo de controle mais genérico Se eu quiser usar
um tipo diferente de nó de controle no futuro, não
precisarei
modificar meu script. Esse script precisará de funções
públicas para abrir
e fechar o mapa. Para simplificar as coisas, vou definir adequadamente a visibilidade
do nó como verdadeira ou
falsa. Também existem funções de mostrar
e ocultar definidas na
classe de item Canvas que fazem a mesma coisa. Embora possa parecer
inútil ter uma função que apenas
chama outra função, manter suas implementações
encapsuladas em funções
públicas como essa significa que podemos
atualizá-la facilmente Podemos adicionar lógica extra
nessas funções para fazer com que as coisas aconteçam quando o
mapa é aberto ou fechado,
ou podemos usar uma interpolação para
mover o mapa para fora da tela ou com que ele cresça e diminua, em
vez de apenas alternar Se eu quiser fazer essas alterações, só preciso editar esse script, em vez de também precisar editar o script do player ou
qualquer outro script
que esteja chamando
essas funções Como decidi usar um botão de alternância para ativar e desativar
o mapa, em
vez de chamar funções de abertura
ou fechamento, vez de chamar funções de abertura
ou fechamento prefiro ter uma única função de
alternância que alternância Adicionando uma variável privada para determinar se o mapa
está aberto ou não no momento, farei com que a
função de alternância feche o mapa se ele estiver
aberto ou abri-lo se estiver Então, as funções de abertura e
fechamento podem definir o valor de I
open adequadamente. Abrindo as configurações
do projeto, na guia Mapa de entrada, precisamos adicionar uma
nova ação de entrada para abrir e fechar o mapa. Vou usar a tecla backspace e o botão de seleção
no meu controle A maioria dos jogos com esse
tipo de mapa
de jogo também permite que
o jogador gire a câmera. Eu já pesquisei as entradas para cima
e para baixo. Vou apenas adicionar olhar para a
esquerda e olhar para a direita. Usando as
teclas de seta esquerda e direita ou o manípulo direito inclinado para a esquerda ou para a direita
no meu controle No script do player, podemos exportar uma variável para
manter uma referência ao nó
do mapa e
preenchê-la no inspetor Em seguida, na função de entrada, diga ao mapa para ativar ou desativar se o
botão do mapa for pressionado Executando o jogo, o
mapa começa oculto, mas pressionar o botão do mapa, exibe o mapa e,
pressionando-o novamente, o fecha Para deslocar a câmera do mapa, precisaremos apenas
ajustar seu valor de deslocamento Então, daremos ao
script do mapa uma referência
à câmera do mapa. Adicionando uma
função pública chamada pan, aceitando um argumento vetorial dois para a direção de
deslocar a câmera. Adicionaremos ao deslocamento da câmera essa direção multiplicada
pela velocidade Pan e poderemos acessar o Delta
mesmo que não estejamos em uma função de processo chamando a função Get
Process Delta t
da classe de nós Exportando essa variável de
velocidade de rotação, vou definir a minha para 1024 Isso pode parecer rápido, mas lembre-se que a câmera do
mapa está muito afastada, então ela parecerá se mover a um oitavo da
velocidade Para que o script do
player controle essa câmera
quando o mapa estiver aberto, ele precisará
saber se o mapa está aberto Em vez de tornar pública a variável
is open, permitindo que qualquer outro script
modifique seu valor, podemos escrever uma função que retorne o valor
da variável. Quando o mapa estiver fechado, reiniciarei o deslocamento
da câmera para zero, que ela
fique novamente centralizada no personagem do
jogador Passando para
o script do player, adicionaremos os controles para panorâmica do mapa
na função de processo Mas somente se o mapa estiver aberto. Se o mapa estiver aberto,
indicaremos que o mapa seja panorâmico. Assim como usamos o eixo G para obter o estado de duas
direções opostas como um flutuador, podemos usar o vetor G para obter um vetor dois de
quatro direções Só precisamos dar a
ele os nomes
das quatro ações de entrada
que correspondem aos eixos X e Y. Olhe para a esquerda, olhe para a direita, olhe para cima e olhe para baixo. O último argumento
é uma zona morta, que é o comprimento mínimo do vetor que será usado. Se o vetor for muito curto, podemos ignorá-lo, o que é útil para
manípulos analógicos ignorarem o desvio Embora isso não
cause problemas em um controle, já que estou usando
o controle analógico correto, controles do
meu PC estão usando as teclas de seta para
mover e olhar Então, se o mapa estiver aberto, colocarei o resto dos
controles de visão e movimento em um bloco para ignorá-los. Se você quiser permitir que o personagem do
jogador ainda se mova e olhe para cima ou para baixo
enquanto o mapa estiver aberto, você precisará alterar as
ações de entrada para que elas não se sobreponham Para evitar que o personagem
continue se movendo
depois de abrir o mapa, vou definir sua direção de movimento para zero quando o mapa for aberto. O jogador agora pode pressionar um
botão para acessar um mapa mundial, exibindo nossas duas salas e a posição
atual do jogador, e podemos deslocar a
câmera do mapa se quisermos. Na próxima seção,
começaremos a acompanhar as estatísticas
do jogador e
desenhá-las no heads-up display. Nos vemos na
próxima seção.
36. 5-1 HUD: Olá, amigos. Neste vídeo, começaremos a exibir
informações sobre o personagem do jogador
no heads-up display. Desde o início deste curso, o Godot 4.6 foi lançado Atualizar o projeto para Godot 4.6 não causou problemas, então continuarei as aulas
na versão atualizada Não recomendo atualizar para uma versão mais recente de nenhum motor de
jogo enquanto você estiver trabalhando em um projeto,
a menos que você tenha controle de
versão para
reverter, se necessário Precisarei importar
alguns sprites de interface de usuário para meu projeto para desenhar as estatísticas do
personagem na tela Na cena do jogo, temos uma camada de tela
configurada para a camada um
no inspetor A janela de visualização principal que desenha os dois mundos D do jogo
é considerada camada zero Portanto, tudo nos dois
mundos D do jogo será desenhado na camada zero
, independentemente do índice z. camada de tela, camada um, se sobreporá a tudo isso
para desenhar coisas como menus e a
exibição de cabeças erguidas de nossos personagens , como sua
saúde e magia. Os nós na camada Canvas geralmente
são nós de controle Goy
, todos com ícones
verdes para
diferenciá-los de dois
nós D que são azuis Vamos começar adicionando um nó de controle como filho
da camada Canvas, renomeá-lo para HUD, reordená-lo para ficar no
topo das camadas
filhas do Canvas e tornar o
mapa filho do Em seguida, podemos adicionar
quantos ícones, medidores e texto precisarmos a
esse nó principal para criar
nosso heads-up display Ajuda ter um nó de
controle básico atuando como pai de todo
o seu
HUD por vários motivos Algumas das propriedades
do nó
HUD pai serão herdadas
por todos os nós secundários Como o
nó da camada de tela não é um nó de controle, ele não tem as
mesmas propriedades,
portanto, não pode fornecer esse benefício. Se quiser dar a todos os elementos do HUD uma aparência
consistente, você pode adicionar um tema
ao nó principal e ele será aplicado
automaticamente a todos os nós secundários Ele também mantém naturalmente a transição
de esmaecimento na parte inferior da árvore da
cena, já que você só
adicionará crianças acima dela, então não precisará se preocupar em
reorganizar a árvore da cena toda Ao contrário de dois nós D, que usam sua propriedade de
posição de transformação para definir onde estão em relação
à origem da cena, os nós de
controle usam uma posição e um tamanho para definir sua localização
em um espaço definido. Normalmente, a janela do jogo, que é exibida como
esse retângulo azul Podemos ver que o
nó do HUD tem um tamanho de 40 por 40 pixels e está na posição 00, que é o
canto superior esquerdo da janela Embora possamos simplesmente mover e redimensionar o nó de controle
editando esses valores, essas alterações não serão bem
dimensionadas nem funcionarão forma eficaz se alterarmos o tamanho da janela nas configurações
do projeto Portanto, os nós de controle têm essas âncoras verdes que podemos usar para definir a
posição e o tamanho de cada nó de controle em
relação ao pai, com
a camada de tela representando a janela inteira Queremos que o Hud cubra toda
a janela para que
possamos definir sua
predefinição de âncora como totalmente destruída Isso coloca as âncoras em cada um dos quatro cantos
da janela e, em
seguida, atualiza automaticamente os
valores de tamanho e posição para que correspondam Se tornarmos o mapa visível, sua posição não
foi atualizada, então vou redefinir suas
âncoras para o centro Agora podemos ver que, como ele está ancorado no
centro de seu pai, mover ou redimensionar o nó do HUD
moverá o mapa Para desenhar a
saúde e a magia do personagem, adicionarei um novo nó de
controle para
agrupar esses elementos e chamá-los de vitais Vou deixar isso
ancorado no canto superior esquerdo, mas redefinir seu tamanho para zero Em seguida, adicionarei um nó destruído de
textura para desenhar uma textura simples, um perfil do personagem, e preencher sua propriedade de
textura arrastando o ativo
da guia do sistema de arquivos Adicionando outro nó destruído de
textura, vou nomear esse ícone de saúde
e preencher sua textura
com uma textura de atlas,
selecionando um sprite da minha planilha de sprites Precisarei ter
vários deles para representar a saúde total do meu
personagem. Então, vou duplicá-lo várias
vezes e posicioná-los
aproximadamente em sequência Seria uma boa ideia
manter esses ícones agrupados em
um único nó principal Então, adicionarei outro nó de
controle chamado Health Counter e repararei que todos os ícones
de saúde
sejam filhos desse nó Posicionar manualmente cada um
desses ícones é meio chato. Portanto, Godot fornece nós de controle chamados contêineres
para fazer isso por nós. Como quero que esses ícones
sejam organizados horizontalmente, alterarei o tipo
do nó pai para um contêiner de caixa
horizontal Isso organiza todos os nós
secundários automaticamente. Eles estão sendo esticados para preencher a altura vertical do contêiner
horizontal da caixa, que tem o
tamanho padrão de 40 pixels A redefinição desse valor
o forçará a cair até a altura
do maior filho Eu gostaria que eles
estivessem mais próximos,
então, sob o tema que substitui as constantes de
seção, definirei a separação para menos oito
pixels Adicionar mais ícones
a esse contador é tão simples quanto duplicar
o nó filho É uma boa ideia definir os elementos do HUD com seus limites
máximos em mente Então, terei nove ícones de saúde, que é a quantidade máxima que
pretendo incluir no meu jogo. Ao selecionar qualquer um dos nós secundários, seus valores de posição não podem
mais ser editados manualmente, pois o nó do contêiner agora
é responsável por controlar
sua posição. Portanto, tenha em mente essa limitação. Se você quisesse animar as posições dessas
texturas individualmente, não
conseguiria fazer isso enquanto elas estivessem dentro de um
contêiner principal Em seguida, adicionarei outro
nó destruído de
textura para desenhar o medidor mágico do
personagem Em seguida, preencha sua propriedade de
textura com o ativo na guia
do sistema de arquivos Embora essa textura não
funcione como um medidor real, ajuda desenhar tudo o
que você deseja incluir no capuz
para ter uma ideia de como deseja que ela seja disposta antes de começar
a implementação Assim como os ícones de saúde, quero ver como esse medidor
mágico se encaixará no meu layout quando estiver
no limite máximo Esticar essa imagem para
tornar o medidor mais longo alonga os pixels individuais da imagem, o que Vamos lidar com isso no
próximo vídeo, mas, por enquanto, precisamos apenas de uma ideia de quão grande ou pequeno o medidor
mágico pode ser Talvez você queira dedicar
algum tempo para obter o layout dos elementos
da cabana da maneira que você deseja. Esse layout parece bom. Mas quando eu executo meu jogo,
ele é muito pequeno e não corresponde à densidade
de pixels do resto do jogo. Como estou usando um zoom de
câmera de dois, todos os meus pixels têm o
dobro de tamanho Então, vou definir a escala do
meu nódulo vital para dois, dobrando o tamanho de
todos os seus filhos Isso é mais fácil de ler e combina melhor com a estética
do meu jogo. Alterando as predefinições
de âncora do nó principal dos sinais vitais, podemos
alterá-lo facilmente para definir sua posição em relação
a qualquer canto da tela ou ao
centro de Ou o centro da
tela, como o mapa. Você pode então ajustar
as posições
dos nós secundários em relação
ao pai ancorado, e eles manterão
suas posições relativas mesmo que você decida alterar a resolução
do seu jogo Vou manter o meu no canto
superior esquerdo e
colocar 20 pixels de preenchimento
na borda da janela Agora temos algumas texturas
desenhadas no heads-up display, mas elas ainda não estão
fazendo nada Te vejo no próximo vídeo.
37. Medida 5-2: Olá, amigos. Neste vídeo, implementaremos o
medidor mágico usando caixas de estilo Vamos começar alterando o
tipo do nó do medidor mágico. Existe um
nó de controle que faz exatamente o que precisamos:
uma barra de progresso. A alteração do tipo
remove a textura. A barra de progresso é desenhada como um retângulo
cinza semitransparente e tem uma porcentagem
exibida no texto Não quero esse rótulo de
porcentagem, então vou desativá-lo
no inspetor O botão indeterminado
não é aplicável a um medidor,
mas serve para barras de progresso
que, na verdade, não medem nenhum progresso na verdade, não medem Depois de definir os valores
mínimo
e máximo nosso medidor mágico, podemos definir o
valor para qualquer número intermediário para ver a barra de
progresso ser preenchida O valor da etapa é o menor
que o valor pode incrementar, forçando-o a passar para a etapa mais
próxima As outras propriedades
herdadas do intervalo não são realmente apropriadas para
um medidor e podem ser Também podemos mudar a
direção na qual a barra de progresso será
preenchida, se quisermos. Vou deixar o meu do começo ao fim. A aparência da barra de progresso
é determinada pelo tema. Como ainda não temos um tema, ele está usando o
tema padrão fornecido por Godot Se quisermos alterar apenas o tema desse
nó sozinho, podemos expandir a seção de
substituições de tema Como não estou usando a exibição
percentual de texto, as cores, constantes, fontes e tamanhos de fonte
são todos irrelevantes Mas você pode
usá-los para alterar
a forma como a fonte é escrita na barra de
progresso, se quiser. Na seção de estilos,
é onde podemos encontrar as caixas de estilo de como o fundo
e o preenchimento das barras de progresso são desenhados. Clicando no menu suspenso, podemos selecionar a caixa de estilo vazia, que simplesmente não desenhará nada. Linha de caixa de estilo para desenhar
somente uma linha simples, caixa de
estilo plana para desenhar um retângulo simples ou textura de caixa de
estilo para usar
um ativo de textura importado Ao clicar na textura da caixa de
estilo para expandir suas propriedades, podemos preencher a propriedade da
textura com um ativo na guia
do sistema de arquivos Se alterarmos o tamanho
da barra de progresso, a textura será
esticada para preencher o espaço, que não parece muito bom As caixas de estilo têm mais propriedades para alterar a forma como a imagem
será desenhada quando esticada As margens da textura
transformarão a textura
em nove
fatias, cortando a imagem duas vezes
na horizontal e
duas na vertical, para que ela seja Os cantos
não serão esticados. As bordas serão esticadas em apenas uma direção para
conectar os cantos, e o meio
será esticado em ambas as direções para preencher o
restante do espaço Ou podemos desativar o desenho do centro da textura
e desenhar apenas as bordas Se você não quiser que os segmentos individuais
sejam esticados,
as propriedades de alongamento do eixo
darão a opção de
usar ladrilhos em vez disso,
ou a opção de ajuste de ladrilho
usará uma combinação de ladrilho e alongamento para
melhor se ajustar ao espaço alocado Expandir as margens
desenhará a textura além do retângulo definido pela posição e tamanho dos nós Uma subregião pode ser usada para desenhar uma região
de uma planilha de sprites Modulate funciona exatamente como acontece com a visibilidade do
item Canvas, multiplicando a cor de
cada pixel por As margens de conteúdo são para caixas de
estilo usadas para
desenhar nós de contêineres,
portanto, elas não serão
aplicáveis aqui Adicionar outra textura de
caixa de estilo para o preenchimento das barras de progresso
e preenchê-la com
a textura apropriada Se você não quiser inserir os valores
da região de textura manualmente, o
editor de subregião também pode ser usado para editar visualmente
as margens da textura Usando esses recursos, o medidor mágico não deve
ser esticado Definirei sua altura
para ser a mesma dos ativos em 16 pixels. Mas usando as caixas de estilo, o medidor pode ser esticado quanto for necessário horizontalmente e será desenhado sem O valor também pode ser editado
e a textura de preenchimento
também se estenderá o quanto for necessário sem que as extremidades da
barra sejam esticadas Se quisermos que
essas caixas de estilo sejam aplicadas a mais do que
apenas uma barra de progresso, podemos tornar isso
automático editando o tema em vez de
usar substituições de tema Selecionando o nó do HUD e
expandindo a seção do tema, podemos criar um novo tema no
menu suspenso. Clicar no
recurso do tema abrirá o painel temático na
parte inferior da janela do editor. Aqui podemos ver a maioria dos nós de
controle que Godot tem a oferecer e como eles estão sendo
desenhados
atualmente pelo tema, incluindo uma barra de progresso aqui Ao clicar no botão Mais, podemos adicionar a barra de progresso a
esse tema e substituir suas propriedades
do tema da mesma forma
que fizemos com o inspetor do nó
da barra de progresso Todas as mesmas
propriedades do tema estão aqui para cores, constantes, fontes,
tamanhos de fonte e estilos Se clicarmos nos botões de adição ao lado do fundo e do preenchimento, podemos adicionar caixas de estilo a esse tema para
a barra de progresso. Como já criamos
essas caixas de estilo, podemos selecionar o nó da barra de
progresso. Em seguida, clique e arraste os recursos
da caixa de
estilo do inspetor
para o editor de temas A barra de progresso
na pré-visualização do tema é atualizada para usar
as caixas de estilo. Agora, cada barra de progresso herdada do
nó HUD herdará
esse tema e usará esse tema e usará essas caixas de estilo para desenhar a barra de
progresso automaticamente Isso nos dá a
opção de ter todos os nós de controle do
mesmo tipo desenhados da mesma forma ou usar substituições de tema para desenhar
nós de controle individuais Podemos remover as substituições de
tema nó
da barra de progresso pois essas caixas de estilo agora estão sendo herdadas
do Se você quiser usar
esse tema todo o
seu projeto sem precisar copiá-lo
em todas as cenas, você pode salvá-lo como
um recurso do projeto Em seguida, nas configurações do projeto, em Tema da GUI, podemos definir um tema personalizado selecionando
o recurso de tema salvo Isso exigirá a reinicialização
do editor para entrar em vigor. Agora, cada barra de progresso em cada cena de
todo o projeto será desenhada da mesma forma. Mas vamos imaginar
que você queira ter vários medidores mágicos que usem essas caixas de estilo e várias outras barras de progresso
que usem outras caixas de estilo Em vez de ter
vários temas, podemos usar variações
de tipo de tema. Ao clicar no botão Mais, podemos digitar um
nome personalizado para adicionar
ao tema, como Magic gauge Em seguida, clique no botão Ferramentas
e forneça um tipo básico de barra de
progresso digitando-a ou selecionando-a
na lista Agora, as outras guias contêm
as propriedades herdadas da Barra
de Progresso e podemos alterar os valores do fundo e
das caixas de estilo de
preenchimento Vou copiar as caixas
de estilo do meu nó do medidor mágico clicar no ícone do elo da
cadeia para desvinculá-las de
onde foram Mudando para as propriedades do tema da
barra de progresso, removerei as caixas de estilo, revertendo tudo
para o tema padrão Em seguida, selecione o nó do
medidor mágico na árvore da cena, expandindo a
seção do tema no inspetor Posso selecionar o medidor mágico
na variação de tipo para
pedir que eles usem propriedades
do tema
para o medidor mágico Agora, meu jogo pode ter
vários medidores mágicos, se eu precisar, sem precisar configurar os estilos
de cada um deles individualmente. Eu só preciso dizer ao tema que
use as propriedades do
tema do medidor mágico, e ainda posso ter
outras barras de progresso no meu jogo que
não sejam medidores mágicos, que também podem ser desenhadas usando estilos
diferentes Agora temos um medidor mágico
simples, mas ainda precisamos
implementar o contador de saúde Te vejo no próximo vídeo.
38. Ícone de 5 a 3: Olá, amigos. Neste vídeo, criaremos um ícone de
saúde que tem animações para
quando o personagem
se recupera ou perde Atualmente, temos os ícones de
saúde exibidos como nós destruídos de
textura organizados horizontalmente pelo nó horizontal do contêiner da caixa Se você quiser
animá-los como sprites, você pode pensar
em transformá-los em dois nós D do Animated
Sprite Mas misturar nós de controle com dois nós D causa problemas. Vou configurar rapidamente o
recurso Animation Sprite frames para que eu possa demonstrar Dois nós D não
se comportarão como nós de controle. Eles não ancorarão
suas posições em relação aos pais, não serão
organizados por nós de contêineres nem serão organizados por nós de contêineres nem redimensionados
automaticamente para
se adequarem à resolução da janela Em vez de alterar o
tipo de nó que estamos usando, precisaremos animar esse nó
úmido de textura como ele está Se expandirmos a lista suspensa de
propriedades de textura, podemos ver que há uma opção de textura
animada Esse recurso de textura animada só
pode conter uma
única animação . No entanto, ele realmente não atende às nossas
necessidades neste caso. Se quiséssemos usar isso
para animar o ícone, precisaríamos definir cada quadro
individual
da animação como
uma textura de atlas separada com duração em segundos por meio
dessa interface desajeitada E depois de tudo isso,
precisaríamos usar um script personalizado para controlar quais quadros da animação
estão sendo usados de qualquer maneira. Se quisermos ter
a mesma textura, reproduza várias animações. Portanto, seria melhor deixar essa propriedade de textura
como uma textura de atlas Embora pudéssemos escrever um script
personalizado para alterar o valor da
propriedade de região dessa textura de atlas, a quantidade de tempo e esforço necessários não valeria pena quando o nó do Animation Player já existisse Então, vamos adicionar um nó do
Animation Player como filho desse ícone de saúde. Antes de fazermos qualquer animação, seria uma boa ideia salvar primeiro
esse ícone como sua
própria cena Isso encapsulará o nó
Animation Player, já que não é realmente relevante para o contexto do HUD
do jogo Nesta cena, primeiro, vou definir a
região dos ícones para o que eu quero usar como seu estado padrão,
que estará vazio. Em seguida, crie uma nova animação
para quando esse ícone estiver cheio, definindo a taxa de quadros
para 12 quadros por segundo, ajustando o Zoom e
ativando o encaixe de quadros Em seguida, vou inserir
isso no início
da animação e
adicioná-lo à faixa de reinicialização. Embora eu não queira usar isso como o primeiro quadro
da animação, agora
é o estado padrão usado
pela animação de
redefinição. Em seguida, substituirei
a primeira chave da minha animação de preenchimento
pelo primeiro quadro real Em seguida, continue com o resto
dos quadros preenchendo o ícone. Vou definir a duração da
animação para oito quadros. Lembre-se de alterar
o modo de atualização para discreto ao usar animações de
quadro como Parece bom, então
vou duplicá-lo e fazer outra animação para quando o personagem sofrer dano, o que esvaziará o ícone Como sei que os
sprites das minhas planilhas de sprites estão todos uniformemente espaçados, posso simplesmente editar os valores
da região
codificada múltiplos de 32 pixels para
obter os Essa animação é mais curta
, com apenas seis quadros. É importante que essas
animações terminem com o quadro que será
persistente após o término Depois que essa animação vazia for reproduzida, o ícone permanecerá vazio até que a
animação de preenchimento seja reproduzida. Da mesma forma, após a
reprodução da animação de preenchimento, o ícone permanecerá preenchido até que a animação vazia seja reproduzida. Anexe um script ao nó raiz do ícone de saúde e salve-o em uma nova
pasta para scripts de interface Vamos supor que esse
script pode ser usado para qualquer ícone animado,
caso queiramos usá-lo para
algo diferente de saúde. Esse script só precisa obter uma referência ao
nó
Animation Player quando estiver pronto. Em seguida, forneça funções públicas para reproduzir cada uma das
animações quando necessário. De volta à cena do jogo, podemos excluir todos os
outros ícones de saúde. Vou renomear esse primeiro
para o ícone Health one depois duplicá-lo oito
vezes para recriar
o resto deles com o
Animation Player e
o script anexados o resto deles com o
Animation Player e
o script anexados Se quisermos testar isso, podemos usar o
script do player para fazer com que o ícone de saúde seja preenchido
ou esvaziado pressionando uma tecla Ao pressionar o botão Executar, usarei o caminho do
nó anotado
no cifrão para fazer com que esse
primeiro ícone de saúde seja Quando eu soltar o botão Executar, farei a mesma coisa
para fazer com que ele se esvazie. Como isso é apenas
para fins de teste, não
preciso me importar com o quão
ineficiente esse código é Executar o jogo,
pressionando o botão Executar, preenche todos os ícones, embora eu tenha dito apenas que
o primeiro preenchesse Isso ocorre porque Godot naturalmente tenta ser o mais eficiente
possível em termos de
recursos e criou apenas um recurso de textura de atlas para ser usado em todos os ícones Então, quando animamos um ícone, todos os ícones estão
usando a mesma textura, então todos eles são animados Na cena do ícone de saúde, podemos substituir esse comportamento
expandindo o
recurso de textura do atlas no inspetor Na seção de recursos, ative a opção local
para cena Isso dirá a Godot que cada instância
da cena precisará sua própria cópia exclusiva
desse recurso de textura do atlas
com sua própria propriedade de região Essa planilha de sprites ainda
será compartilhada por todos os ícones, mas a região
da planilha de sprites que eles desenham será exclusiva Executando o jogo novamente. Desta
vez, apenas o primeiro ícone é preenchido quando eu
pressiono o botão Executar e se esvazia quando eu
solto o Com o teste bem-sucedido, podemos remover ou comentar
as linhas extras de código. Agora temos ícones de
saúde animados, mas o contador de saúde não está realmente contando a saúde do nosso
personagem. Te vejo no próximo vídeo.
39. 5-4 Contador: Olá, amigos. Neste vídeo, escreveremos um
script que gerencia os ícones animados para refletir um valor e
um valor máximo. Temos nossos ícones animados aqui, mas precisamos anexar um script ao nó principal
que controlará como e quando eles são animados para refletir a contagem da saúde do personagem do
jogador Vou nomear esse contador de ícones e colocá-lo na pasta de scripts de
interface do usuário. Não há nada
nesse script usando
especificamente os recursos do contêiner
de caixa horizontal, então vou estender o tipo de
controle
mais genérico para permitir a alteração do tipo desse nó
posteriormente, se eu quiser. O script
precisará de dois números inteiros, um para a saúde
máxima do personagem e outro para sua saúde
atual Como quero que esse script seja útil para
contar qualquer coisa, não apenas saúde, usarei
o termo genérico valor. Por enquanto, podemos definir
o valor padrão de saúde máxima para ser igual ao número de filhos esse nó tem usando
a tag on ready. Em seguida, precisaremos
de duas funções
públicas que definirão esses dois valores, aceitando um parâmetro inteiro e substituindo o
valor antigo pelo novo Quando nosso
personagem sofrendo danos e
recuperando saúde, poderemos chamar
essas funções públicas para comunicar as
mudanças no valor da saúde ao jogador Será responsabilidade
desse script controlar
quantos ícones são
exibidos e quais
são preenchidos ou esvaziados com base nos valores
desses números inteiros e em
como eles mudam Começaremos definindo o valor de sua saúde
atual. A primeira coisa que devemos fazer
é validar se o número que estamos recebendo para definir o
valor é um número válido Não podemos mostrar o personagem com menos de zero saúde, nem nada
maior do que o número de ícones
disponíveis,
sua saúde máxima. Então, primeiro definiremos o
valor para o retorno do número inteiro da pinça entre
zero e a saúde máxima. Se tentarmos chamar essa função
com um número negativo, ela definirá
a saúde como zero. Da mesma forma, qualquer coisa acima do máximo será
limitada ao máximo Em seguida, se estivermos definindo o valor para o mesmo
número que ele já está, não
precisaríamos fazer nada, então poderíamos simplesmente retornar
dessa função. Depois de estabelecermos que
estamos alterando o valor exibido
por
esse contador de ícones para um novo número válido, o processo será diferente se o número estiver aumentando
ou diminuindo Se o novo valor for
maior que o valor antigo, solicitaremos que alguns
dos ícones sejam preenchidos. Mas quais ícones? Os ícones
são convenientemente desenhados pelo contêiner da caixa horizontal
na mesma ordem do
índice secundário na árvore de cenas Usando um simples loop de quatro, usando I como índice, podemos contar o
intervalo de valor até o novo valor. Range retorna uma matriz
contendo a sequência de números inteiros contados do primeiro número
para o segundo, mas exclui o segundo Então, se o valor antigo era um
e o novo valor é quatro, isso nos dará os
números um, dois e três. Como o índice filho
do primeiro filho é zero, não um, isso se alinha perfeitamente com os índices dos ícones
que precisam ser preenchidos Então, vamos pegar o nó filho no Índice I e pedir que ele seja preenchido. O processo para diminuir
o valor é muito semelhante. Somente porque sabemos que o novo valor é
menor que o valor antigo, precisamos fornecer
um argumento
extra para a função de intervalo, menos um, que fará com que ela
faça uma contagem regressiva. Se o valor antigo for quatro
e o novo valor for um, intervalo retornará 43 e dois. Eles não são
iguais aos
índices secundários dos ícones,
mas são um maior Portanto, podemos corrigir isso
subtraindo um de I na função get child e fazer com que esses ícones se
esvaziem Somente depois que tudo isso for feito, definimos o valor antigo
para o novo valor? Podemos testar isso
sem adicionar nenhum script extra
ou mapeamento de entrada Tudo o que precisamos fazer é adicionar uma função
de entrada ao script. Primeiro, verificaremos se
o evento de entrada foi uma tecla de evento de entrada e se o evento foi
uma tecla sendo pressionada. Em seguida, use uma declaração de partida
no código-chave do evento. Se a tecla
pressionada for qualquer uma das teclas numéricas, podemos definir o
valor do contador de ícones para esse número. Declarando uma
variável numérica como um número inteiro, podemos calcular o número
que foi pressionado simplesmente subtraindo a tecla zero
do código de eventos Isso funciona porque os
códigos-chave são uma enumeração, uma Qualquer que seja o código
da chave zero, o código da chave
sete
será o código da
chave zero Podemos imprimir uma declaração
dizendo algo como definir saúde
atual dois mais o
número convertido em uma string. Em seguida, chame a
função de valor definido passando o número. Se rodarmos o jogo, pressionar
qualquer tecla numérica definirá
o contador de ícones para esse número e animará os ícones de acordo com se eles estão sendo
preenchidos ou esvaziados E também podemos fazer a mesma coisa para definir o valor máximo. Embora já pudéssemos ter
o número
máximo de ícones na cena e apenas
ocultar os que não estamos usando, seria mais escalável
instanciar novos ícones
conforme Como isso não
acontece com muita frequência, isso não afetará o desempenho
e acomodará a adição quantas forem necessárias se
decidirmos contratar no máximo mais tarde. Então, vamos exportar uma
variável para manter a cena do ícone como
uma cena compactada. Copiar o conteúdo
da função de valor definido. Depois de alterar cada instância
de valor para o valor máximo, há apenas mais algumas
alterações que precisam ser feitas. Primeiro, não podemos validar o valor máximo
com base em si mesmo. Portanto, precisaremos definir algum limite para o quão alto o
valor máximo pode ser. Talvez você queira exportar esse limite em vez de
codificar um valor Em vez de preencher ícones, vamos instanciar novos ícones e adicioná-los como crianças. E em vez de esvaziar os ícones, vamos removê-los
da árvore de cenas ligando gratuitamente Para testar isso, usarei o mesmo sistema de entrada de
teclas numéricas, mas exijo que eu mantenha pressionada a seta para cima para definir
o valor máximo. Portanto, se a ação do ponto de entrada for
pressionada, olhe para cima, imprimirei Max
Health,
definirei esse valor e colocarei a
parte de saúde atual no bloco else. Durante o jogo, posso alterar o
valor máximo de saúde mantendo pressionada a seta para cima, pressionando
qualquer uma das
teclas numéricas e soltando a seta para cima Também
posso alterar o valor
atual da saúde Lembre-se de comentar a função
de entrada após o teste. Agora temos um contador de
ícones animado que pode
acompanhar os valores
máximos e atuais de
saúde dos personagens do jogador . Mas nem o contador de
ícones de saúde nem o medidor mágico estão realmente conectados ao personagem do
jogador Te vejo no próximo vídeo.
40. 5-5 caixa de dor: Olá, amigos. Neste vídeo, daremos um
pouco de saúde ao personagem para conectá-lo ao contador de ícones de
saúde. Poderíamos adicionar variáveis de saúde
ao script do personagem
e rastreá-lo dessa forma. Isso permitiria que
todos os personagens do
nosso jogo tivessem saúde
sem nenhum trabalho extra. Mas se considerarmos
que coisas que
não são personagens também podem
precisar ter saúde, como
paredes quebráveis, por exemplo, isso se torna menos benéfico, especialmente porque nosso
personagem é um personagem com corpo dois D e a
parede quebrável seria um corpo estático dois D. E talvez
tenhamos outro corpo rígido
a D que também Precisaríamos ter
as mesmas variáveis e funções em vários scripts
para cada um desses casos. Poderíamos reescrever nosso script de
personagem para herdar do corpo
físico dois D Tudo em nosso
jogo que precisa saúde também pode usar esse Mas há muitas coisas
nesse script que não
seriam aplicáveis
a esses outros objetos. Seria um desperdício
ter todas essas variáveis e
funções anexadas a uma parede quebrável
que nunca
precisaria usá-las e, da mesma forma, ter as variáveis e
funções destinadas a uma parede quebrável anexadas
ao nosso personagem Em casos como esse, talvez você queira usar o
padrão composto em vez herança orientada a
objetos para reutilizar seus scripts em todo Ao criar um componente de saúde, ele pode existir independentemente
do que está ligado a ele. Personagens podem ter um componente de
saúde e paredes
quebráveis também podem ter
um componente de saúde Na cena do personagem,
adicionaremos um novo filho,
um nodo D da Área dois, e o chamaremos de Hurt Box. Em seguida, adicione um nó TD em
forma de colisão como filho da Hurt
Box para definir sua forma Esta será a área aérea do personagem
em que, se for atingido,
sofrerá danos. Talvez você nem sempre
queira que essa seja a mesma forma de colisão do
corpo do personagem Além disso,
geralmente você sempre desejará que a
colisão corporal do personagem permaneça ativa, enquanto a Hurt Box geralmente
é desativada para evitar que
o personagem
sofra danos ao se o personagem
sofra danos esquivar ou durante
cenas cortadas Por isso, ajuda
dar à sua Hurt Box uma área de colisão separada Também farei da minha uma cápsula, mas um pouco menor que
o corpo do personagem e definirei sua cor de depuração para
verde para que eu possa
diferenciá-las mais facilmente Essa área não precisa ser responsável por
monitorar nada. Ele só precisa ser monitorável para caixas de acerto
possam detectá-lo Expandindo a seção colisão
sob a colisão Objeto dois D, podemos configurá-la para a camada dez e remover completamente sua
máscara Nas configurações do projeto, darei a duas camadas de física D dez o nome do jogador Hurt Box. Agora, qualquer coisa no jogo
que esteja monitorando e mascarando a camada dez
poderá ferir o personagem do
jogador Anexando um script a esse nó, vou chamá-lo de Hurt Box Esse script precisará
dos mesmos valores
máximos de saúde e saúde atuais do contador de ícones. Como vou indicar o valor da
saúde com ícones, eles precisarão ser números inteiros Se você estiver usando um medidor para a saúde do
seu personagem, você tem a opção de
usar carros alegóricos pois um medidor pode
indicar Por enquanto, vou definir a saúde
máxima para cinco e usar a tag on ready para
definir a saúde atual como Max Health. Ao contrário do script de contador de ícones, a principal forma pela qual uma Hurt Box modificará o valor da modificará o valor da saúde
atual
será recebendo danos da caixa de acerto
ou recuperando a Então, essas serão nossas funções
públicas, ambas
aceitando uma quantidade de saúde a ser perdida ou
ganha como um número inteiro Ao sofrer dano, simplesmente
subtrairemos a quantidade da saúde atual do
personagem Podemos então usar a função max para retornar
esse valor ou zero, que for maior, e
defini-lo como o novo
valor da saúde atual Isso evitará que sua saúde fique abaixo
de zero. Podemos tornar a função de
recuperação
multiuso dando ao
parâmetro um valor padrão Se chamarmos essa
função de recuperação sem argumentos, assumiremos que isso significa que
eles devem recuperar toda saúde até
o máximo configurando a
saúde atual para a saúde máxima. Se houver um argumento dado
à função de recuperação, adicione essa quantidade à saúde
atual
do personagem e use a função MIN
para retornar esse resultado ou a vida máxima,
o que for Portanto, a saúde atual nunca
excederá a saúde máxima. ambos os casos, o valor da saúde atual
está sendo alterado e precisamos que essa alteração seja refletida pelo
contador de ícones no HUD. Mas a Hurt Box está
na cena do personagem e o contador de ícones está
na cena do jogo. Na maioria dos casos,
sempre que você precisar
comunicar informações entre nós e cenas
diferentes, a melhor maneira será
usar sinais e formar sua conexão por meio
de seu ancestral comum mais próximo Na cena do jogo, o ancestral comum mais próximo
entre o personagem
e o contador de saúde
é o nó
raiz da cena do jogo , o gerente do jogo Vamos dar ao
balcão de saúde um nome exclusivo. Em seguida, pegue uma referência a ela
no script do gerenciador de jogos. Poderíamos tentar mandar
o contador de saúde monitorar
a Hurt Box do
personagem. Podemos usar a função Get node para recuperar a Hurt Box do
personagem Porém, nosso
script de contador de ícones dependerá certas funções ou variáveis existentes na entidade
que está monitorando Portanto, seria essencialmente útil apenas como um contador de saúde, que não é reutilizável como um script para contar
outras coisas Invertendo essa lógica,
seria melhor dizer
ao Hurt Box que fosse monitorado
por esse contador de ícones Em seguida, chame uma função que
ainda não escrevemos, como set counter, e passe ela o contador de saúde
como argumento. Lembre-se de que essa função get node falhará
se você alterar o nome do
seu nó do Hurt Box ou
reorganizar a estrutura da sua árvore de cenas para que
não seja mais um filho direto Eu prefiro essa dependência a
escrever uma nova função no script
do personagem para recuperar o nó Hurt Box, pois esse script
já é bastante De volta ao script Hurt Box, escreveremos essa nova função, aceitando um contador de ícones como
parâmetro de controle de tipo, já que não demos a ela
um nome de classe específico. Agora temos o Hurt Box e o contador de saúde
no mesmo script, para que possamos nos
comunicar facilmente entre eles. Mais importante ainda, o script do contador de
ícones ainda
pode ser usado para o que
quisermos, e qualquer Hurt Box em nosso jogo que não precise ser
monitorada por um contador pode simplesmente ignorar
essa função. Poderíamos chamar as funções dos
contadores de ícones diretamente, mas isso
faria com que cada Hurt Box do jogo
verificasse constantemente se tem
um contador de ícones monitorando-a antes de
chamar essas funções Seria melhor usar
sinais para comunicar
essas mudanças, um para quando a saúde
máxima mudar e outro para quando a saúde
atual mudar. Ambos precisarão de
parâmetros inteiros para seus novos valores. Também podemos querer outro para
quando a saúde chegar a zero, o que não exigirá
nenhum parâmetro. Agora, quando sua
saúde atual muda como resultado de sofrer
danos ou recuperar saúde, podemos emitir esse sinal passando a nova
saúde atual como argumento Se a saúde atual for zero
após sofrer dano, devemos emitir o sinal
tingido dois Agora, quando configuramos um contador
para monitorar essa Hurt Box, podemos simplesmente conectar
esses sinais às funções de valor
definido dos contadores de ícones, pois os parâmetros passados
pelos sinais correspondem aos parâmetros
das
funções dos contadores de ícones em quantidade e tipo Também seria uma boa
ideia emitir esses sinais
imediatamente para que o contador de ícones possa definir seus valores de acordo
com a Hurt Box Para testar isso, podemos escrever uma função de entrada simples
neste script. Se eu pressionar para cima, o personagem
recuperará uma vida. Se eu pressionar, o personagem
sofrerá um dano
e, se eu pular, o personagem
recuperará a saúde total. Executando o jogo,
pressionar para baixo faz com que
o personagem sofra um
dano a cada pressionamento do botão. Sofrer dano com zero pontos
de vida é ignorado. Pressionar para cima recupera uma vida, e recuperar a saúde
no máximo é ignorada. Voltando primeiro para um valor
mais baixo, depois
pularei e
recuperarei totalmente toda a saúde. Lembre-se de remover ou
comentar essa função de entrada
após o teste. Agora temos nosso personagem
capaz de sofrer danos e
recuperar saúde, mas a saúde dele
não está sendo salva. vejo
no próximo vídeo.
41. 5-6 Dados: Olá, amigos. Neste vídeo, criaremos um recurso personalizado
que pode acompanhar as estatísticas e
o progresso do jogador no
jogo
entre as sessões de jogo. Se quisermos que o jogador consiga
obter melhorias máximas de saúde
, mantenha-as
na próxima vez que O jogo precisará de uma
forma de saber o que eles têm e o que não
encontraram no jogo. Para fazer isso, podemos criar
nossos próprios recursos. Já usamos
vários recursos
neste projeto,
como o recurso vários recursos
neste projeto, Sprites
Atlas Texture do personagem
ou o recurso de máquina de
estado Animation Tree E o tema. Esses
recursos são todos os tipos definidos pelo mecanismo de
jogo Godot para fornecer funções específicas
para os nós que os usam. Mas também podemos criar nossos próprios para atender às nossas necessidades
específicas. Vamos criar uma nova pasta dentro da pasta chamada resources. Em seguida, podemos criar um novo
script nessa pasta chamado data em vez de
herdar do node, esse script
herdará do recurso Os recursos não são representados
como nós na árvore da cena. A primeira coisa que queremos
fazer ao criar um recurso personalizado é dar
a ele um nome de classe. Caso contrário, não poderemos
criar instâncias dele. Como o objetivo
desse recurso é acompanhar os dados
do jogador, podemos incluir quantas
variáveis precisarmos
para tudo o que queremos salvar
entre as sessões de jogo. Por enquanto, precisarei de variáveis
para a saúde
máxima dos caracteres e a
saúde atual como números inteiros Também adicionarei sua magia
máxima
e a magia atual como carros alegóricos Todas essas variáveis estarão acessíveis
publicamente
a outros scripts. Também podemos incluir
sequências de caracteres para coisas como seu nome ou booleanos para acompanhar se algo
está sendo ativado ou desativado As matrizes podem ser usadas para armazenar grupos de informações
relacionadas, como uma matriz de
booleanos para saber quais atualizações foram encontradas pelo jogador
e quais dicionários são muito úteis para armazenar classes inteiras
de informações, pois podemos usar nomes de
atributos como chaves
no dicionário com seus valores correspondentes Além dos tipos básicos de variáveis, também
podemos incluir
outras classes incorporadas em Godot, como vetores para
armazenar duas coordenadas D, cores ou até mesmo outras
classes personalizadas que criamos Qualquer variável que você
quiser salvar entre as sessões de
jogo precisará
ter a tag de exportação. Outras variáveis
que não têm a etiqueta de exportação ainda podem
ser úteis se, por exemplo, você não quiser salvar a saúde atual do
personagem, apenas a saúde máxima
e iniciar o jogador com a saúde total toda
vez que ele carregar o jogo. essas
variáveis não exportadas ainda permanecerão se o jogo mudar entanto, essas
variáveis não exportadas ainda permanecerão
se o jogo mudar de
cenário durante a
sessão de jogo Se você sair da cena do jogo
por qualquer motivo,
talvez para jogar uma cena cortada depois retornar à cena do
jogo mais uma vez, essas variáveis
manterão seu valor. Embora também possamos escrever funções
nesse script, isso geralmente não é necessário. Se você quiser realizar alguma inicialização
automatizada
do seu recurso, podemos substituir
a função init Essa função innit será
chamada automaticamente por Godot sempre que criarmos uma nova instância desse recurso por
meio
de Assim, podemos dar às variáveis
alguns valores padrão, definir os comprimentos das matrizes ou adicionar algumas chaves aos
nossos Certifique-se de salvar esse script com o nome da classe definido antes de tentar
usá-lo de qualquer forma. Então Godot reconhecerá
esse nome de classe. Precisaremos de outro script para acessar nosso recurso personalizado, que abordaremos
no próximo vídeo. Por enquanto, podemos testar
nosso recurso personalizado criando um na guia
do sistema de arquivos. Ao clicar, selecione
Criar novo recurso e,
em seguida, digite o nome da classe ou
selecione-o na lista. Em seguida, dê um nome a ele.
Ao criar esse recurso vamos abri-lo automaticamente
no inspetor, onde podemos ver e editar todas as nossas
variáveis exportadas Criar um recurso dessa forma não usa a função nit, mas usará valores fornecidos para variáveis atribuídas em
suas declarações Se você selecionar outra coisa e quiser voltar a
editar esse recurso, clique duas vezes nele
na guia do sistema de arquivos. Vou testar rapidamente a criação um recurso de dados no script do gerenciador de
jogos. Podemos criar uma
instância do nosso recurso declarando primeiro uma variável com o nome da classe como tipo Em seguida, atribua o valor
dessa variável para ser o nome da classe
seguido pelo ponto Nu. Podemos então acessar qualquer uma
das variáveis que
declaramos nessa classe, exportadas ou não exportadas, sobrescrever seus valores e usá-los conforme necessário
durante o jogo Lembre-se de remover
ou comentar esse código de teste e excluir
o arquivo de recurso de dados de teste. Agora temos um recurso de dados que inclui a
Saúde Máxima e a saúde atual de nossos personagens, mas ele ainda não foi salvo. Te vejo no próximo vídeo.
42. Arquivo 5-7: Olá, amigos. Neste vídeo, salvaremos e carregaremos os dados do player usando
nosso novo recurso personalizado. Para fazer isso, precisaremos de
outro script que gerencie o
acesso ao recurso que
criamos no vídeo anterior. Esse script precisará estar acessível de qualquer
lugar do projeto. O personagem
precisa conhecer suas estatísticas. Os quartos precisarão saber se
o jogador abriu uma porta, encontrou um upgrade ou
derrotou um chefe. Até mesmo a interface do usuário e o mapa precisarão
acessar os dados salvos. Podemos tornar alguns nós facilmente acessíveis dessa forma,
tornando-os globais. Vamos criar uma nova pasta dentro
da pasta de scripts
chamada Globals. Em seguida, crie um novo script
nessa pasta chamada file. O objetivo desse
script será fornecer acesso rápido e fácil aos dados salvos
dos jogadores todos os outros scripts que escrevemos
em todo o projeto, além de salvá-los
no sistema do jogador
e carregá-los também. Precisaremos de uma variável do
tipo do nosso recurso personalizado. Vou chamá-los de dados
com uma letra minúscula
D. Em seguida, precisaremos de
três funções públicas
para gerenciar esses dados,
iniciar um novo jogo,
salvar o jogo
e carregá-lo D. Em seguida, precisaremos três funções públicas
para gerenciar esses dados, iniciar um novo jogo,
salvar o jogo e carregá-lo Começar um novo jogo é simples. Só precisamos definir
o valor dos dados para ser o nome da nossa classe
seguido por dot neu Isso criará uma nova instância do recurso e inicializará Quando estivermos prontos
para salvar nosso jogo, precisaremos saber onde
queremos salvá-lo também. Para isso, declararei
uma constante de string, já que isso é algo
que nunca vou mudar, o caminho para o local em que quero salvar o arquivo de dados do
player Godot fornece uma abreviatura
simples que funciona em Windows, Mac, Linux, web e consoles podem usar isso Cólon do usuário avança a barra para frente. Do substituirá
isso automaticamente pelo caminho
apropriado para a plataforma, como um
local específico tanto para o usuário
do sistema quanto para o jogo. Declarando uma variável para o nome do
arquivo também como uma string, nomearei meu save seguido pelo ponto TRS, abreviação Agora, para salvar o jogo, podemos acessar uma
classe Singleton do Godot,
Resource saver, então
chamada Passando o recurso que
queremos salvar e o local em que queremos
salvá-lo anexando o
caminho e o nome do arquivo Se quisermos ter
vários slots de salvamento, tudo o que precisamos fazer é alterar
o nome do arquivo para cada slot. Carregar nosso jogo é
semelhante a salvar. Tudo o que precisamos fazer é usar o carregador
Godot Singleton. A função de carregamento
requer apenas a localização do
recurso que estamos carregando. E ele retorna o recurso. Então, vamos atribuí-lo à
nossa variável de dados. Como nosso jogo não
tem uma cena de título, presumo automaticamente que, se existir um arquivo salvo, vou querer carregá-lo ou se
ele não iniciar um novo jogo. Portanto, na função REDI, usarei o carregador de recursos para verificar se há um arquivo de
dados para carregar
e, em caso afirmativo, carregá-lo Caso contrário, comece um novo jogo. Mesmo com uma cena de título, é útil poder começar seu jogo diretamente
da cena do jogo sem precisar
passar pela tela de título toda vez que estiver
desenvolvendo e testando. Temos nosso recurso de dados aqui. Podemos criá-lo,
salvá-lo e carregá-lo. Agora, tudo o que precisamos fazer
é
facilitar o acesso a esse script de
qualquer lugar em nosso projeto. Abrindo as configurações do projeto
, vá para a guia Globals. Clique no botão da pasta
para abrir um navegador e navegar até o script de arquivo que
acabamos de criar. Em seguida, clique em Abrir. Podemos fornecer um nome
diferente para esse nó global se quisermos
ou usar o fornecido. Em seguida, clique em
adicionar para adicionar o script à
lista de nós globais. Agora, qualquer script que escrevemos pode acessar esse script de arquivo apenas
com seu nome. Da mesma forma
que usamos os singletons de entrada, economia de
recursos e
carregador de recursos Para testar isso, definirei a
saúde máxima do personagem para corresponder à que está
no Safle, em vez colocá-la na
parte superior do script Então, adicionarei uma função
inicializada a esse script depois de aceitar
um novo parâmetro de valor máximo, definindo o valor máximo antigo
para o novo valor máximo Em seguida, do valor atual
para o valor máximo, emitirei os dois sinais alterados Agora, o gerente do jogo,
depois de obter a Hurt Box do personagem pode inicializá-la com o valor máximo de saúde
do arquivo de dados do jogador Também adicionarei uma função de entrada
que, ao pressionar as teclas de seta para
cima ou para baixo aumentará ou diminuirá a saúde
máxima do personagem no arquivo de dados e
reinicializará
a Hurt Box de acordo com a correspondência Em seguida, salve o jogo
chamando o arquivo dot save game. Precisarei inverter
a ordem
dessas operações para exibir
os valores corretos. Executando o jogo, o personagem começa com cinco Max Health, mas eu posso alterar esse valor
pressionando as teclas de seta
para cima ou para baixo. Em seguida, fecharei o
jogo e o executarei novamente para ver se
sua saúde máxima foi salva e carregada. Para encontrar o arquivo de dados que
salvamos no menu do projeto, selecione Abrir pasta de dados do usuário. Isso abrirá uma janela do navegador de
arquivos e poderemos ver nosso arquivo dotTRS
salvo Clique com o botão direito do mouse nesse arquivo e abra-o usando qualquer editor de texto. Podemos ver que apenas a saúde
máxima foi salva. Godot acompanha quais
variáveis são usadas pelo jogo e só salvará as variáveis que
realmente usamos e modificamos Portanto, tenha isso em mente. Na verdade, podemos editar esse arquivo aqui, e o jogo
realmente o carregará com os valores editados,
desde que a formatação corresponda Isso é ótimo para nós enquanto estamos construindo e
testando nosso jogo. Mas talvez você não queira
permitir que seus jogadores editem
facilmente o arquivo seguro
quando estiver pronto para publicar. No script do arquivo,
basta alterar a extensão TRS no nome do
arquivo para dot RES Em vez de um recurso de texto, ele agora será salvo
como um recurso binário, que não pode ser aberto e
editado em um editor de texto. Executando o jogo novamente,
abrirei o
arquivo de pontos de salvamento que acabei de criar Agora é impossível
para mim editar isso. Agora temos a capacidade de
salvar e carregar dados sobre o
progresso do jogador em nosso jogo. Na próxima seção, adicionaremos nossas habilidades
desbloqueáveis Nos vemos na
próxima seção.
43. Salto duplo 6-1: Olá, amigos. Neste vídeo, daremos ao nosso personagem
a habilidade de pular duas vezes. Embora muitos personagens
em nosso jogo
precisem andar, correr, pular
e cair, as habilidades
desbloqueáveis geralmente
são exclusivas do personagem
do jogador No
script do personagem, em vez de
adicionar mais variáveis e
funções a esse script, que já é bastante longo, podemos criar um novo script que será usado apenas pelo personagem
do jogador. Certifique-se de que seu script de
personagem tenha um nome de classe e esteja
salvo antes de continuar cena do personagem, clique com o botão
direito do mouse no nó raiz do
personagem e selecione anexar script. Em vez
de herdar de CharacterBody dois D, podemos herdar do nome da classe
do nosso personagem
de script original Em seguida, dê
um nome a esse novo script e
salve-o na pasta apropriada. Como esse novo script
herda do caractere, ele tem acesso a todas
as mesmas variáveis e funções que criamos para essa classe, e todos os valores das variáveis exportadas e
das conexões de
sinal também são copiados para esse novo Mas agora podemos adicionar mais que são úteis apenas para
o personagem do jogador. Seguindo esse padrão
de herança, personagem é chamado
de superclasse e nosso personagem jogador
é Primeiro, precisaremos de uma variável
que nos diga se
esse personagem desbloqueou ou não a habilidade de pular duas vezes E para limitar o personagem a pular
duas vezes apenas uma vez, precisaremos de outra variável para saber se o
salto duplo está pronto Também pode ser útil emitir
um sinal quando realizamos com sucesso
um salto duplo para desenhar um
efeito de partícula, se você quiser, assim como fizemos
com o outro Como o salto duplo normalmente usa o mesmo botão
do salto normal, não
precisamos fazer nenhum
trabalho extra com o mapa de entrada nas configurações
do projeto nem editar o script do player para
chamar novas funções Podemos simplesmente substituir a declaração da função
Jump. Ao substituir uma declaração de
função, a assinatura da função
deve permanecer a mesma O nome da função,
seus parâmetros, quantidade, ordem e tipos, bem
como o tipo de retorno. Como a função de
salto original
no script de caracteres
não aceitava parâmetros e
retornava um booleano, essa substituição de salto também não deve ter parâmetros
e retornar um Ainda queremos que toda
a
funcionalidade original do salto aconteça. Portanto, esse personagem
poderá
pular se as
condições certas forem atendidas. Podemos acessar as funções da
superclasse usando a palavra-chave super e, em
seguida, usar um ponto, o nome da função e
parênteses, assim como
chamaríamos uma
função Como a
função jump da superclasse retorna um booleano, também
podemos retornar o resultado para
satisfazer a exigência
de retornar um Quando o jogador pressiona
o botão de pular, o script do jogador
chamará salto do personagem do jogador,
que então chamará a função mais genérica de salto do personagem Essa estrutura
nos permite interceptar o processo adicionando
código extra acima da linha de retorno, permitindo verificar se
esse personagem do jogador pode pular duas vezes em resposta
à solicitação de pular primeiro depois continuar com o
comportamento de salto padrão Portanto, se o personagem desse jogador
puder pular duas vezes e o salto duplo estiver pronto e o personagem
não
estiver no chão, devemos permitir que
ele dê
um salto duplo e volte à realidade. Se alguma dessas
condições for falsa, precisamos verificar se esse
personagem pode pular em condições
normais usando a função de salto condições
normais usando da superclasse
do personagem Podemos praticamente
copiar as linhas de código que implementam um salto ao
realizar um salto duplo, mas emitem um sinal diferente E precisaremos definir
a variável de salto duplo está
pronto para quedas para evitar que o personagem
do
jogador realize
mais de um salto duplo. Na maioria dos jogos com
salto duplo, a capacidade de realizar
o salto duplo é restaurada após o
pouso no chão. Como a
classe do personagem já tem uma função que será chamada
quando o personagem chegar, também
podemos substituí-la Sempre que esse personagem pousar, se o
salto duplo não estiver pronto, podemos definir a variável de volta
para verdadeira para prepará-la Em seguida, chame a função de
superclasse. Nesse caso, a ordem em que queremos executar
a função
de superclasse antes
ou depois não importará Para testar isso, adicionarei uma declaração impressa
quando o caractere pular
duas vezes com sucesso E outra quando o salto
duplo for restaurado. Em seguida, defina o valor padrão
do salto duplo C como verdadeiro. Durante o jogo, podemos pressionar o botão de pular
duas vezes para dar um salto duplo. Pressioná-lo três ou mais vezes não
produz mais saltos, e a capacidade de pular duas vezes
é restaurada ao pousar Agora tudo o que precisamos fazer é bloquear e desbloquear essa habilidade
de salto duplo. Então, vou definir o valor padrão de C double jump de volta para false. Nos dados salvos do player, removerei todas essas variáveis
desnecessárias. Precisaremos de variáveis para nos dizer quais habilidades o
jogador desbloqueou, que podemos armazenar em
uma variedade de booleanos As matrizes são indexadas
usando números inteiros Precisaremos que cada uma de nossas habilidades receba um
número em sequência, começando da contagem zero para atuar como seus
índices nessa Se você não quiser memorizar vários números inteiros,
podemos criar
uma enumeração para dar a cada inteiro um nome que
seja Eu gosto de colocar essas
enumerações em um script separado chamado Embora Godot nos obrigue a herdar de uma classe existente
ao criar o script, podemos remover essa linha do nosso script depois que ela for criada Em seguida, dê a esse script
um nome de classe para que
possamos referenciá-lo
em outros scripts. Normalmente, uso
o mesmo script para manter todas as enumerações de todo
o projeto Podemos declarar uma
enumeração usando palavra-chave num, Dentro das chaves,
podemos escrever os nomes de
cada uma de nossas habilidades em
uma lista separada por vírgulas Eu já criei
um salto duplo como minha primeira habilidade desbloqueável
e vou criar um salto na parede, uma
corrida, um chapéu e
atirar um projétil enumerações são
convencionalmente nomeadas em letras maiúsculas minúsculas, enquanto as
entradas de
enumeração As enumerações são
convencionalmente nomeadas em letras maiúsculas e minúsculas, enquanto as
entradas de
enumeração estão em maiúsculas. A enumeração
atribuirá o valor da primeira entrada
como zero, depois um, dois e assim por diante, o que
significa que podemos
usá-los como índices para nossa Eles não
precisam estar na ordem em que serão
desbloqueados pelo jogador A ordem é arbitrária e
serve apenas para atribuir a cada
habilidade um número único Ao inicializar os dados salvos do
player, podemos redimensionar a matriz para
corresponder ao tamanho
da enumeração, fornecendo
automaticamente
o número correto de booleanos e padronizando todos eles como false Lembre-se de que
as variáveis devem ter a tag de exportação para serem salvas. De volta ao script do player, podemos referenciar a matriz de
habilidades desbloqueadas e armazená-la em uma variável o mesmo nome usando
a tag on ready Observe que isso não
faz apenas uma cópia da matriz
em seu estado atual. Ele cria uma referência
à matriz,
portanto, qualquer alteração afetará ambas. Isso significa que, para desbloquear uma habilidade para
o personagem usar, precisamos apenas definir seu valor
no recurso de dados salvos. Agora podemos substituir a variável C double jump pela indexação da matriz de habilidades desbloqueadas com Enums dot abilities
dot Essa
matriz de habilidades desbloqueadas agora pode ser usada em todo o
script para cada habilidade No script do gerenciador de jogos, usarei a
função de entrada para testar o
desbloqueio da habilidade de salto
duplo ao pressionar a tecla de seta para cima Definindo arquivos, dados de pontos, habilidades de
pontos desbloqueados, pontos de
índice, enumerações, habilidades de pontos,
ponto Double Jump to true Em seguida, podemos salvar o jogo
para torná-lo permanente. Executando o jogo, meu
personagem não pode pular duas vezes. De volta ao Editor Godot, vou mudar para a guia
remota para ver
a árvore de cenas do jogo
que está sendo executado no momento Aqui eu posso ver o nó global do
arquivo, que tem um recurso de dados. Dentro desse recurso de dados, a matriz de habilidades desbloqueadas tem cinco booleanos, todos
falsos O nó do personagem do jogador também tem uma referência
à mesma matriz. Voltando à simulação, pressionar para cima desbloqueia a habilidade de salto
duplo Na árvore da cena remota, posso ver que o booleano
na matriz foi definido verdadeiro tanto no
recurso de dados quanto no caractere Fechando o jogo e
executando-o novamente. O salto duplo já está
desbloqueado desde que foi salvo. Podemos remover as
instruções impressas agora que
foi confirmado que o salto duplo está funcionando. Agora temos uma habilidade de salto
duplo desbloqueável, mas temos várias outras habilidades
desbloqueáveis Te vejo no próximo vídeo.
44. 6-2 Slide de parede: Olá, amigos. Neste vídeo, permitiremos que o personagem
deslize por uma parede, adicionando atrito para
retardar sua descida Primeiro, temos que decidir o que essa habilidade fará e
quando queremos que ela aconteça. Ao implementar um
novo recurso como esse, é uma boa ideia configurar primeiro
os testes que você
deseja passar. Vou começar na cena do conteúdo da
sala e esconder as árvores
para que eu possa ver melhor. Para criar uma mecânica de
deslizamento de parede, criarei duas
paredes no meu quarto Considerarei que minha mecânica
de
Wall Slide completa quando o
personagem pode pular e, em
seguida, deslizar por qualquer parede
com uma velocidade de queda reduzida Eu também gostaria de reproduzir uma animação diferente
enquanto isso acontece. O Wall Slide deve terminar quando o personagem não estiver
mais em contato com a parede, se
tocar no chão, ou se
pressionarmos a direção do
movimento para afastá-lo da parede. Então, implementar isso
alterará a física
aérea do personagem No script do personagem do jogador, substituiremos o processo de física
aérea do personagem Em seguida, chame o processo de Física
Aérea da superclasse a
partir do script do personagem Aqui podemos separar nosso código
em três blocos separados. Quando o personagem está
executando um Wall Slide, verificando quando ele pode começar a
executar um Wall Slide, e qualquer outro momento que chamamos aerofísica
da superclasse Precisaremos saber
quando o personagem está executando um Wall Slide, então devemos declarar isso
como uma variável booleana Também seria útil
exportar um flutuador para usar como multiplicador da gravidade do
personagem
ao executar um Wall Slide ao executar um Vou usar 10%. Voltando ao processo de
física do ar, agora
podemos ramificar
com base no fato a
variável de deslizamento da parede ser verdadeira ou falsa Se o personagem
já estiver deslizando na parede, podemos continuar
o deslizamento na parede ou
finalizá-lo , dependendo se
outras condições forem atendidas Se o personagem
não estiver deslizando na parede, precisamos verificar
se ele pode deslizar na parede
e, se as condições são atendidas para
começar a deslizar na parede, faça isso E, finalmente, se tudo
isso for falso, devemos prosseguir com a física do ar da superclasse
como padrão Escrever seu algoritmo em comentários de pseudocódigo como esse facilita muito o
preenchimento e a reorganização Também faz com que o
resultado final já tenha sido comentado. Vamos começar
iniciando um Wall Slide verificando se a
habilidade Wall Jump foi desbloqueada Em seguida, adicione também a condição que
esse personagem esteja em uma parede. A
classe do corpo do personagem fornece essa função que funciona
da mesma forma que está no chão. Eu também gostaria de acrescentar
mais condições para que sua velocidade Y seja
maior ou igual a zero Não quero que o personagem
comece a deslizar na parede
se estiver subindo, e o jogador deve pressionar entrada de direção
do movimento em direção à parede O corpo do personagem two denode também nos dá outra função Faça com que Wall fique normal. Isso retorna um vetor
apontando para longe da parede. Então, se usarmos a
porção X desse vetor, ela sempre será menos
um se a parede estiver à direita do personagem
ou positiva
se a parede estiver à esquerda do
personagem. Comparando isso com a direção de movimento do
personagem, multiplicarei cada
lado por menos um e exigirei que
os resultados sejam iguais Isso não permitirá que a
direção do movimento seja zero. Há várias condições
nessa instrução I e elas não
cabem na minha janela de script. Se quiser escrever as condições da declaração
if em várias linhas, você pode fazer isso
colocando-as entre colchetes Isso pode facilitar a
leitura e a depuração do
código , se você
preferir esse formato Embora minhas paredes estejam
perfeitamente verticais, talvez seja necessário usar o
seno das paredes normal X se
suas paredes estiverem inclinadas Se tudo isso for verdade, permitirei que o
personagem inicie um slide de parede
configurando I wall sliding true e limitando sua velocidade Y em zero
usando a Isso criará
uma breve reinicialização da velocidade de queda para fazer com que o deslizamento
da parede pareça mais lento Também imprimirei uma declaração
para fins de teste. Agora vamos supor
que o personagem já
está fazendo
um slide de parede e queremos ignorar
sua gravidade para retardar sua descida Simplesmente adicionando à velocidade Y do
personagem, gravidade vezes Delta vezes o multiplicador de
gravidade Wall Slide, que eu configurei para
10% da Pensando nisso do ponto
de vista da física, isso equivale a dizer que
há um coeficiente de atrito de 0,9 entre
o personagem e a parede E por último, podemos pensar em
quando terminar o Wall Slide. Se o personagem não estiver
mais na parede ou se o jogador
pressionar a direção oposta ,
afaste-se da parede Portanto, se não estiver na
parede ou se o sinal da direção do movimento for o
mesmo que o normal da parede X,
definirei Is wall sliding como definirei Is wall sliding false e imprimirei uma declaração de que o
Wall Slide terminou Seria mais simples
colocar o slide de parede continuando como o outro
bloco dessa declaração I, então vou recortá-lo e colá-lo aqui Há mais uma condição
que precisa encerrar um escorregador de parede quando o
personagem toca o chão Como já temos
uma função que é chamada
automaticamente quando
o personagem pousa, vou simplesmente adicionar outra
declaração I aqui que
encerra o Wall Slide. Se o caractere
estiver deslizando na parede, defina I parede deslizando como falso e imprima
outra declaração Ajuda se essas duas
afirmações forem diferentes para que
possamos ver quando cada uma está realmente
acontecendo durante nossos testes. Isso funcionará para o teclado, mas não para um controlador, pois a direção do movimento pode
ser um valor decimal Portanto, precisarei aplicar
a função de sinal a essas
duas verificações para trabalhar
com a entrada do controlador. A última coisa que
preciso fazer é adicionar uma animação Wall Slide
ao player de
animação do personagem. Então, vou duplicar a animação de caminhada
deles. Altere a posição Y
da região da
planilha que está sendo usada e exclua a
trilha de passos Adicionando essa animação ao recurso
da máquina de estado. Vou permitir que o personagem faça a
transição para esse estado de pular
ou cair se o deslizamento de I
Wall for definido como verdadeiro Em seguida, faça a transição
de um escorregador de parede para cair se o
deslizamento de parede estiver configurado para cair Ou para locomoção se
tocarem o chão. No script do gerenciador de jogos, vou mudar o desbloqueio
do salto duplo
para desbloquear o Wall Jump para desbloquear Isso deve ser
suficiente para passar meu teste, então vou rodar o jogo. O personagem
ainda pode pular normalmente, e pular contra a
parede não desliza na parede, pois essa
habilidade ainda está bloqueada Mas pressionando para
destravar o Wall Jump,
agora, se eu pular enquanto me
movo em direção à parede, eles deslizam para baixo e param
quando tocam o chão. Tentando isso na outra parede, o slide da parede termina quando eles alcançam a
parte inferior da parede. E outra tentativa contra
a primeira parede, o escorregador de parede não começa até que o personagem
comece a cair, e eu posso terminar o escorregador de parede mais cedo me
afastando da parede. O comportamento normal de
salto do personagem
não é afetado pela execução de
nenhuma dessas ações Com todos os testes aprovados, lembre-se de comentar
as declarações impressas. Agora temos nosso personagem
capaz de realizar um Wall Slide, mas ainda precisamos
implementar o Wall Jump. Te vejo no próximo vídeo.
45. Salto da parede 6-3: Olá, amigos. Neste vídeo, permitiremos que o
personagem pule da parede enquanto
executa um deslizamento na parede. No script do personagem, já
substituímos
a função de salto para fazer um salto duplo Quando queremos que o
personagem pule na parede, todas essas condições
no salto duplo também
podem ser verdadeiras. Portanto, precisaremos considerar
o salto na parede como uma possibilidade primeiro
e descartá-la antes de verificar
o salto duplo, pois as condições para o
salto na parede são mais específicas. Só precisaremos verificar se
a habilidade Wall Jump foi desbloqueada e se
o personagem está atualmente executando
um Wall Slide Se essas condições não forem atendidas, podemos verificar
se o personagem pode pular duas vezes. No entanto, isso não
permitirá que o personagem um salto na parede até
o início do Wall Slide, que é esperar até que
o personagem alcance o ápice do salto Se você quiser permitir o
salto na parede antes de iniciar o Wall Slide quando a
velocidade Y do personagem for negativa, também podemos adicionar
mais condições Ou os personagens estão deslizando na parede ou
não estão no chão
e estão na parede, e a direção do movimento
é em direção à parede. Com a ordem das
operações da lógica, precisamos colocar o
ou entre colchetes para que seja verificado
antes do primeiro e. Podemos usar vários
níveis de colchetes e recuo para definir
visualmente a ordem
das operações
de uma lógica complexa como essa,
para facilitar a compreensão, se necessário Agora que estamos prontos
para realizar um salto na parede, podemos fazer as mesmas coisas que faríamos com
qualquer outro salto. Em seguida, retorne true, para que
o manipulador de entrada saiba que o
pressionamento do botão de salto foi bem-sucedido Quanto à configuração da velocidade do corpo do
personagem, queremos que ele não apenas suba,
mas também se afaste da parede Então, em vez de apenas definir
a velocidade Y do personagem, definiremos todo o vetor de
velocidade, criando também um novo vetor Para o X, podemos usar o ponto vetorial normal X
das paredes
e, para Y, podemos usar um. Isso nos dá um vetor apontando para cima e para longe da parede, então temos a direção
correta. Multiplicando isso
pela força do salto, obteremos um vetor com
uma magnitude maior que nosso salto normal, pois o vetor original já
tinha um comprimento maior que Podemos normalizar esse
vetor de direção se quisermos, mas a forma como ele funciona agora realmente
produzirá
um resultado melhor, na minha opinião, com a altura
total do salto, mais a força extra sendo
aplicada longe da parede Mas como a força de salto
é um número negativo, isso inverterá
o normal da parede para
apontar para a parede em
vez de para longe dela Então, adicionarei um negativo
à frente do wallnormalt X para torná-lo um duplo negativo, que Para animar o Wall Jump, a máquina de estados do personagem
precisará de uma transição de
Wall Slide para pular sob a condição de que
o personagem esteja pulando Isso entra em conflito com a
transição para a queda já que o personagem não está mais deslizando
na parede ao mesmo tempo Portanto, a transição para o
salto precisará um valor de prioridade mais baixo
para ser considerada primeiro Em vez de o salto duplo estar pronto, precisaremos configurar Is wall sliding to falls ao
realizar o Wall Jump Se rodarmos o jogo, já
podemos realizar o salto na parede, pois ele foi desbloqueado no vídeo anterior Pulando contra a parede,
podemos pular dela. A quantidade de
velocidade lateral afastada da parede é igual à força
vertical aplicada Mas como a gravidade puxa
o personagem
para baixo constantemente,
ela é o personagem
para baixo constantemente, muito
menos perceptível do que a força que se afasta
da parede, que só está sendo reduzida pelo
controle aéreo
ou pelos freios pneumáticos do personagem Eu preferiria que
meu personagem tivesse muito menos
força lateral aplicada e pudesse retornar à
mesma parede depois de pular na parede e
continuar subindo Isso exigirá várias alterações
físicas
diferentes para funcionar corretamente, reduzindo a quantidade de força
lateral aplicada ao Wall Jump
longe da parede dando ao
personagem mais controle aéreo para retornar à
parede
em uma altitude maior Primeiro, vamos lidar com
a força lateral. Em vez de codificar um valor, é sempre melhor usar variáveis
exportadas para que elas
possam ser distorcidas Vou exportar um vetor dois
chamado
multiplicador de força Wall Jump e atribuir a ele um valor padrão de
menos um positivo Podemos então multiplicar o vetor de velocidade resultante por esse novo multiplicador de
força do Wall Jump Esse negativo
eliminará a necessidade aplicar o negativo
ao vetor normal da parede, que eu acho mais
intuitivo, pois penso no negativo como
se estivesse longe da parede. Ao multiplicar dois vetores, o resultado
será o produto de
ambos Xs e o
produto de ambos Com esses valores, isso funcionará da mesma forma
que funciona atualmente. Mas como o valor é exportado, posso alterá-lo na
cena do meu personagem para menos 0,5, reduzindo a velocidade X pela metade Se você quiser se lembrar de como
suas variáveis funcionam, adicionar um
sinal numérico extra na frente de um comentário acima da declaração da
variável
criará uma dica de ferramenta que
será exibida quando você o
mouse sobre a
variável no inspetor Executando o jogo
novamente, meu personagem tem toda a
força ascendente do salto, mas apenas metade da força do salto é aplicada na direção X. Mas ainda não consigo voltar para
a parede em um ponto mais alto
para subir mais alto. Para isso, precisarei dar ao meu personagem muito
mais controle aéreo, mas não quero que
ele tenha mais controle aéreo
em nenhum outro momento. Portanto, precisarei anular o valor do controle aéreo especificamente somente ao
realizar um salto na parede e, em
seguida, ajustá-lo de volta ao
valor normal Nas variáveis exportadas
para pular na parede, vou exportar um novo flutuador para controle aéreo do
Wall Jump e configurá-lo para algo
muito alto, Isso fará com que o personagem acelere quatro vezes
mais rápido do que no chão e oito
vezes mais rápido do
que durante um salto normal, com meu controle aéreo
padronizando para 0,5 Também vou armazenar isso em outra variável
usando a tag ready. Então, quando eu quiser voltar ao valor normal,
saberei o que é isso. Como não sei
se o jogador vai pular
da parede ou voltar para ela
ou qualquer outra coisa
que queira fazer,
a única maneira confiável de
voltar
ao controle aéreo para a configuração padrão
seria usar um cronômetro Adicionando um
nó temporizador à cena,
eu o chamarei de Wall Jump, darei a ele um nome exclusivo e, em
seguida, obterei uma referência a ele
com a tag 2 pronta Vou nomear essa anulação
do controle aéreo de Wall Jump para ficar um pouco mais
clara nesse contexto Agora, quando realizamos
o Wall Jump, podemos alterar o valor
do controle aéreo para o controle aéreo Wall Jump e iniciar o cronômetro de cancelamento do
controle aéreo Wall Jump Selecionando o nó do cronômetro, podemos definir sua propriedade one
shot verdadeira e dar a ela um
curto período de espera Vou usar meio segundo. Em seguida, conecte o sinal de
tempo limite do cronômetro ao script. Quando o cronômetro expirar, podemos ajustar o controle aéreo do
personagem de volta ao valor padrão Testando isso, está mais perto, mas ainda não
consigo subir na parede. Portanto, precisarei ajustar
meu
multiplicador de força do Wall Jump e os valores de
controle aéreo do Wall Jump até que funcionem Executando o jogo novamente, agora,
quando eu faço um salto na parede, meu personagem tem aceleração
suficiente para retornar à mesma
parede em um ponto mais alto, permitindo que eu
suba a parede. Agora temos nosso
personagem capaz de
pular na parede para aumentar as superfícies
verticais. Em seguida, adicionaremos uma habilidade
arrojada
completa com molduras de
invencibilidade Te vejo no próximo vídeo.
46. 6-4 Traçado: Olá, amigos. Neste vídeo, daremos ao personagem uma habilidade de corrida
desbloqueável Começando nas configurações do
projeto, a guia Mapa de entrada
precisará de um botão que possa
ser usado para traçar. Vou usar a tecla D ou o
botão do ombro direito no meu controle. Em seguida, no script do player
na função de entrada, se o botão do traço foi pressionado, tente correr e,
se não tiver sucesso, tampe a entrada do traço para
secar novamente no próximo quadro, assim como fizemos O traço precisará de uma direção, que podemos obter usando a entrada Singleton,
obter
o eixo, mover para a esquerda, mover para Para fornecer argumentos
para um chamável, usamos a função bind e, em vez disso
, passamos os argumentos
para essa função Portanto, seria melhor chamar
a função de entrada
get axis apenas uma vez
e armazenar o resultado. Como isso
só acontecerá durante os quadros quando o
botão do painel for pressionado, não
é tão ruim
declarar uma variável Quando a
entrada em buffer for chamada, ela passará os argumentos
vinculados Se o painel foi originalmente pressionado com o manípulo
esquerdo inclinado, ele será armazenado em buffer com a
mesma entrada direcional Agora podemos escrever
essa função de traço em nosso script de personagem de jogador, aceitando a
direção do traço como parâmetro e
retornando
um booleano, retornando false Antes de escrevermos essa função, precisaremos de algumas variáveis. A distância que queremos que
o personagem percorra, vou definir a minha em 128 pixels A quantidade de força
necessária para atingir essa distância calculada
usando a etiqueta on ready, podemos usar a
mesma fórmula do cálculo da altura do salto, a raiz quadrada da distância multiplicada pela força
negativa, que neste caso é
desaceleração vezes dois Eu também gostaria de suspender a gravidade enquanto a
corrida está acontecendo Então, também armazenarei a gravidade
padrão do personagem em uma variável usando
a tag on ready. Agora, para a função de traço, se a habilidade de traço
foi desbloqueada
, queremos que o personagem fique
voltado para a direção do traço, o que podemos fazer definindo a direção do
movimento para Em seguida, defina
a velocidade do
personagem como um novo vetor dois com a direção do traço multiplicada pela força do
traço como X
e zero para o Y.
Como o controle analógico esquerdo pode ser inclinado,
isso significaria que o
jogador pode correr mais devagar ou
mais rápido com base na inclinação do
manípulo isso significaria que o
jogador pode correr mais devagar ou analógico no controle a direção do traço multiplicada pela força do
traço como X
e zero para o Y.
Como o controle analógico esquerdo pode ser inclinado,
isso significaria que o
jogador pode correr mais devagar ou
mais rápido com base na inclinação do
manípulo analógico no controle. Não quero que isso aconteça, então vou usar a função seno para remover a inclinação
da equação Podemos suspender a gravidade enquanto
o traço está acontecendo, definindo o valor
da gravidade como zero e, em
seguida, retornar verdadeiro porque o traço foi bem-sucedido e
não precisa ser armazenado Quanto à direção do trajeto, há vários
casos a serem considerados, não apenas se o jogador estiver
dando uma entrada direcional, mas também se não
estiver e também se o personagem estiver
executando um slide na parede Como esse é o caso
mais específico, vou verificar esse primeiro. Se o personagem
estiver deslizando na parede, sobrescreverei o
valor da direção para
ser o sinal de ser o sinal de Se eles não estiverem
deslizando na parede e o player estiver fornecendo uma entrada direcional ao pressionar o botão do painel
, usarei o pecado da
direção como direção, removendo qualquer inclinação analógica da entrada para que eu possa removê-la
da Se o jogador não estiver fornecendo nenhuma entrada direcional ao
pressionar o botão do painel, presumo que ele
queira avançar Vou usar um ternário if para
definir a direção como negativa
se
o personagem estiver voltado para a esquerda
ou positiva se ele não estiver restaurando a
gravidade ao normal, precisaremos de outra função para chamar no final do traço Isso não precisa de nenhum
parâmetro nem retorna um valor. Vamos apenas colocar a
gravidade do personagem de volta ao padrão. Na cena do personagem, o traço precisará de uma animação no
nó Animation Player Definindo os quadros por
segundo e ampliando, adicionarei meus quadros-chave
para animar o Precisaremos adicionar uma faixa de
método de chamada e um quadro-chave
nessa faixa para chamar
a função end dash no final da animação Ou qualquer quadro que você queira para restaurar a gravidade do
personagem. Usando esse procedimento, se for possível interromper essa
animação por qualquer motivo, ainda
precisaremos chamar a função end dash para restaurar
a gravidade do personagem,
ao contrário
do cronômetro que usamos
para restaurar o controle de erros do
personagem Portanto, tenha isso em mente e faça um comentário para
se lembrar disso mais tarde. Adicionando essa animação
à máquina de estado, deve ser possível realizar
um traço a partir de qualquer um dos nossos estados de movimento
existentes Portanto, seria melhor
colocar essa animação
em uma nova camada. Salvando a
máquina de estado atual como um recurso do projeto, vou chamá-la de movimento e colocá-la na pasta de
cenas do personagem. Em seguida, crie um novo recurso
de máquina de estado para
a Árvore de Animação. Adicionando a máquina de
estado de movimento como um nó nessa
nova máquina de estado, vou renomeá-la para
movimento e criar uma transição do início para o movimento, então
é o padrão Adicionando uma nova animação de traço
a essa máquina de estado, podemos adicionar uma transição de movimento para traço e de
volta para Para reproduzir uma
animação uma vez, a transição que leva a ela
deve ser definida como ativada, e a transição
que sai
da animação deve
ter seu modo de alternância definido final e deixar o modo
avançado como automático. Podemos testar essa animação clicando no
botão play no estado. Com cada clique, ele é reproduzido
uma vez na íntegra e retorna ao estado de
movimento
quando termina Como a transição que leva
à animação não é automática, caberá a nós acionar essa animação manualmente
por meio de nosso script. Declarando uma nova variável, será usada para
várias habilidades diferentes, então vou colocá-la no topo e simplesmente chamá-la de
animação O tipo dessa
variável será uma reprodução da
máquina de estado do nó de animação É isso que Godot usa para navegar na máquina de estado
e reproduzir animações Selecionando o nó
na árvore de cena, podemos ver esse recurso de
reprodução em parâmetros playback Podemos recuperar esse
recurso clicando e arrastando o
nó Animation Tree para obter o caminho do nó Em seguida, use colchetes para obter um recurso
desse nó Clicar e arrastar
esse recurso do inspetor para os colchetes nos mostra
o caminho até o Se expandirmos o movimento
e a locomoção, você verá que cada camada
da máquina de estado tem seu
próprio recurso de reprodução Embora atualmente
só precisemos dessa para
acionar manualmente o traço, adicionaremos
mais habilidades em breve Esse caminho também mudará à medida que adicionarmos mais camadas
à máquina de estado,
portanto, ele precisará ser atualizado. Para acionar a animação do traço, ao
executar um traço com sucesso, podemos fazer com que essa
reprodução viaje para o estado do traço
especificando o nome da string
como argumento Essa linha de código
equivale a pressionar o botão play na
Árvore de Animação quando visualizamos a animação Também quero remover a habilidade
do jogador de controlar o personagem
enquanto a corrida está acontecendo Portanto, substituindo o processo
físico, podemos
interrompê-lo rapidamente e verificar
em qual estado a
máquina de estado de animação está atualmente a
máquina de estado de animação está atualmente usando a função
G current node Isso retorna o nome da string que
escrevemos no nó
na Árvore de Animação, que podemos comparar para ver
se é movimento ou não. Se for algo
diferente de movimento, definirei a direção
do movimento como zero antes prosseguir com o processo normal de física da
superclasse Isso evitará que
o personagem se mova ou fique voltado para uma direção
diferente enquanto
executa qualquer uma das habilidades na camada superior da máquina de
estado. No script do gerenciador de jogos, mudarei a tecla de seta para cima
para desbloquear a capacidade de arrastar Executar o jogo, pressionar
o botão do painel não faz nada. Depois de pressionar a tecla de seta
para cima para desbloquear a capacidade de arrastar, podemos correr, fazendo com que o
personagem avance Pressionar uma direção fará o personagem corra
nessa direção E se corrermos
enquanto a parede desliza, o personagem se
afastará Agora temos nosso personagem jogador capaz de correr
pelo ambiente, mas precisaremos adicionar um cronômetro de
resfriamento para evitar que o
jogador o use com muita frequência. Te vejo no próximo vídeo.
47. 6-5 Desaceleração: Olá, amigos. Neste vídeo, adicionaremos quadros de invencibilidade e um resfriamento à
nossa habilidade de traçar Antes de começarmos a adicionar quadros de
invencibilidade ao painel, seria útil
ter uma caixa de acerto em nossa cena para que possamos
testar Na cena inicial do
conteúdo da sala, vou adicionar uma área para denodar
e renomeá-la para Em seguida, adicione uma
forma de colisão quando criança. Dê a ele uma forma de retângulo como recurso e defina sua cor de
depuração Você pode imaginar que
isso representará um inimigo que danifica o personagem do
jogador ao entrar em contato. Vou fazer com que seja um ladrilho de espessura, 32 pixels, e dois
ladrilhos de altura, 64 pixels. Em seguida, mova-o para a esquerda. Considerarei meu teste aprovado se o personagem do jogador conseguir
correr por essa área
sem se machucar Para que essa
área de colisão cause dano ao jogador, ela precisará ser monitorada Não
precisa ser monitorável, embora deixar essa caixa marcada não faça
nenhuma diferença Não precisa
existir em nenhuma camada, mas deve estar mascarando a camada Hurt Box do
jogador Se isso ajudar você a entender melhor
as colisões, não há problema em considerar que
essa caixa de acerto existe em uma camada de caixa de impacto inimiga ou em uma camada de risco
ambiental Os únicos requisitos
são que ele
monitore e mascare
o jogador Hurt Box Ao anexar um script a esse nó, conectaremos seu sinal de área
inserida ao script Depois de verificar se a área
tem um método de sofrer dano, chamaremos esse método e consideraremos um como a
quantidade de dano. Isso garantirá
que a área que entra nesta tenha o
script Hurt Box que criamos anteriormente, que tem o método take
damage, aceitando a quantidade de
dano como parâmetro. Se outra área acionar o sinal sem
um script do Hurt Box, isso causará um
erro, pois não
haveria um método de take
damage a ser Para poder ver nossas
formas de colisão enquanto testamos o jogo, podemos abrir o menu de depuração e selecionar formas de colisão visíveis Se rodarmos o jogo,
podemos ver a caixa de acerto e o personagem do jogador sofre um dano toda vez
que entra nessa área. Há uma mensagem de erro porque o
conteúdo da sala está sendo carregado em resposta à entrada de
nosso personagem em
uma área de colisão, e Godot não gosta de adicionar outra área de colisão
durante um evento de colisão Ignoraremos isso por enquanto pois estamos apenas
realizando um teste, e isso não fará
parte do nosso jogo final. Na cena do personagem, selecione o nó Animation Player
e a animação do traço Para adicionar quadros de invencibilidade
à nossa animação de traço, tudo o que precisamos fazer é criar um quadro-chave do Hurt Box Podemos definir o quadro exato quando o Hurt Box é desligado e
quando é ligado novamente. Se quiser, você também
pode estruturar a visibilidade de sua
Hurt Box de acordo com sua
propriedade monitorável, para que você possa vê-la desligada e ligada
novamente enquanto joga Isso torna mais fácil saber quando seu personagem é
realmente invencível Também pode ser útil
desativar a visibilidade da forma de colisão
do
corpo do personagem ver melhor
a Executando o jogo, agora
podemos correr pela caixa de acerto
sem sofrer nenhum dano Entrar na
área ainda causa
danos , assim como terminar a
corrida dentro da Agora vamos adicionar um
Cooldown ao painel. Começaremos adicionando um nó de cronômetro à cena do
personagem Vou chamar esse cronômetro de
Cooldown e definir sua propriedade de um
tiro Vou deixar seu
tempo de peso como 1 segundo. Esse será o tempo de
resfriamento da habilidade. Considerando que essa é
a segunda habilidade com um nó temporizador associado, e talvez queiramos adicionar
mais no futuro,
convém considerar o uso nó normal como
uma
pasta recolhível para contê-los Mas ajudará
dar a ele um nome exclusivo caso queiramos
reestruturar a árvore de cenas Não precisamos
conectar o sinal
ao script para usar esse nó
temporizador como um resfriamento. Nas declarações de variáveis
para o Dashability, usarei a tag on ready para
obter uma referência a esse novo nó temporizador Tudo o que precisamos fazer é iniciar o cronômetro ao
iniciar, terminar ou correr Depende de sua
preferência, mas se você
quiser iniciar o
resfriamento mas se você
quiser iniciar o
resfriamento no final da corrida, outra condição
será necessária para evitar que o jogador corra duas vezes seguidas Vou iniciar o
cronômetro de recarga após o término da corrida. Em seguida, retorne à
declaração I, onde
verificamos se esse personagem
pode começar a correr. Podemos verificar se o nó
atual
da
máquina de estado de animação está em movimento. Isso também trará benefícios
adicionais posteriormente, já que não permitiremos que
o personagem corra
enquanto executa outras habilidades de ação
semelhantes Para aplicar o cronômetro de recarga, precisamos apenas verificar
se esse cronômetro está parado para saber se devemos
ser capazes Se a animação do traço já estiver sendo reproduzida ou o
cronômetro de recarga não estiver parado, isso significa que o Executando o jogo agora, pressionar o botão do traço permite que o
personagem corra apenas uma vez e, em
seguida, força um
resfriamento de 1 segundo antes que ele
possa correr Isso funciona, mas não está sendo comunicado ao
jogador de forma alguma Normalmente, jogos como esse
têm um indicador diagético, algo que
existe no jogo, não no HUD, para avisar ao jogador quando o
resfriamento termina Então, vamos adicionar um nó Animated
Sprite two D à cena
do personagem e
chamá-lo de efeito Dash Cooldown Criando um
recurso de molduras Sprite para esse nó, podemos importar uma planilha Sprite Vou colocar isso na
pasta dust por enquanto, em vez de criar uma nova pasta de ativos
para uma planilha Sprite E adicione os quadros Sprite
da planilha Sprite. Vou desativar o loop, definir
os quadros por segundo para 12 e também adicionar um quadro em branco
no final da animação Isso não está centrado
no personagem, então vou movê-lo para cima em 12 pixels Essa animação dura
mais de 1 segundo, mas a marca de 1 segundo é quando eu quero que o resfriamento
seja considerado concluído. Vou dar a esse nó
um nome exclusivo. De volta ao script,
tudo o que precisamos
fazer é pegar uma referência
a esse nó. E diga para ele jogar
quando a corrida terminar. Mas como minha animação é maior do que o cronômetro do Dash
Cooldown, na verdade
precisarei
interromper a animação antes de reproduzi-la, caso
ela ainda esteja Isso redefinirá a
animação de volta ao início. R Agora, quando rodamos o jogo e
usamos a habilidade de corrida, a animação é reproduzida,
mas não segue
o personagem Isso ocorre porque um nó normal
não tem uma transformação. Portanto, ele não
tem uma posição. Isso quebra a
linha de herança do nó raiz do personagem Portanto, o nó Animated Sprite
two D agora está iniciando sua própria ancestralidade
para duas transformações D, começando na Podemos alterar o tipo da pasta de
habilidades para
nenhum D para que ela
forneça uma linha de sucessão
na árvore de cenas,
e o Animated Sprite siga
o nó raiz Agora está claro para
o jogador que sua habilidade de corrida está
em Cooldown e exatamente quando ele pode correr
novamente sem precisar
adicionar nenhuma
informação extra no Agora temos nossa habilidade de corrida
capaz de percorrer as caixas de acerto sem ser atingida e esfriar antes de
poder ser usada novamente Em seguida, adicionaremos uma habilidade
passiva que muda a aparência do
personagem. Te vejo no próximo vídeo.
48. de 6 a 6 chapéus: Olá, amigos. Neste vídeo, implementaremos uma habilidade
passiva que altera a aparência do
personagem Começando na cena do
conteúdo da sala, duplicarei a área
de
colisão anterior para este teste Desta vez, a área de
colisão representará especificamente o calor
intenso de dentro de um vulcão Vou mudar a cor para laranja
para saber qual é qual. Quero que o jogador
não consiga passar por
essa área até
que tenha desbloqueado um chapéu mágico que permita que ele
continue ileso Mas usar o chapéu ainda
permitirá que eles sofram danos causados por caixas de ataque
normais. Então, em vez de mascarar a camada normal do
Hurt Box do jogador, vou usar uma camada diferente Vou usar a camada 14 como uma camada dedicada a esse efeito de calor
ambiental. Isso será fácil para mim
lembrar , pois está
diretamente abaixo de dez. Nas configurações do projeto, chamarei essa camada de calor. Então, na cena do personagem, farei com que a Hurt Box
também exista nessa camada. Agora, isso funcionará da mesma forma que a
área de colisão anterior, causando um dano
ao jogador toda vez
que ele entrar nessa área Só que está
verificando colisões na camada 14 em vez da camada dez Então, tudo o que precisamos fazer para tornar o personagem do jogador imune
aos danos causados pelo calor enquanto usa o chapéu é remover a camada 14 da propriedade da camada de
colisão Hurt Box Para alterar a aparência do
personagem, colocarei
sprites adicionais sobre o personagem Vou importar novas folhas de sprites para três atualizações diferentes, uma joia, uma capa e um chapéu Então, na cena do personagem, adicionarei um nó Sprite Tu
Di extra para cada um deles. Tudo com texturas de atlas,
assim como o body sprite. Em seguida, atribua as folhas de sprite como a propriedade do atlas
para cada Da forma como esses ativos foram desenhados, precisarei colocá-los em camadas especificamente na
ordem do gato, depois da capa, depois do
chapéu e da geleia por cima Começarei cada um com o primeiro sprite na
posição 00 com um tamanho de 32 por 36 pixels e darei
a eles o mesmo deslocamento para
movê-los para cima em 18 Esses ativos são
desenhados para serem animados forma síncrona com o sprite
normal do personagem Portanto, todos os
valores da região serão os mesmos para todas as camadas ao
mesmo tempo. Tudo o que preciso fazer é adicionar região de textura do atlas de
cada sprite à animação Em seguida, copie e cole
as teclas
da faixa
corporal do Sprite nas outras faixas E altere o
modo de atualização para discreto. Agora, a animação
também inclui todas as camadas de sprites em
perfeita sincronização Precisarei fazer isso em
todas as minhas animações, mas não será preciso
muito esforço Para inverter cada um
desses sprites, podemos definir todas as propriedades de flip H
sempre que eles
mudarem sempre que eles Mas há uma maneira mais fácil de usar a herança da
árvore de cenas Se fizermos de todos
os outros sprites filhos do sprite corporal, eles herdarão sua
transformação dele E podemos inverter um sprite usando sua transformação definindo sua escala
X para menos um. Observe que esse truque não
deve ser usado para nada que envolva
física ou colisões. Funciona bem aqui porque
estamos apenas desenhando sprites. Na função face left
em nosso script de caracteres, vez de definir o flip H, podemos definir o ponto
X da escala para menos um, se for deixado, caso contrário,
positivo Isso agora sincronizará a inversão
de todos os sprites Com toda a configuração
dos sprites concluída, desativarei a visibilidade dos outros sprites por padrão e, em
seguida, os
ativarei à medida que as
habilidades forem No script do personagem do jogador, precisaremos de uma função para
gerenciar quais camadas de Sprite são visíveis com base nas habilidades que
o jogador desbloqueou Vou chamá-lo de Update
Sprite visibility. Em seguida, dê a cada um dos sprites um nome exclusivo e defina sua visibilidade para corresponder ao valor
das habilidades desbloqueadas
para a habilidade correspondente O salto duplo
adicionará a capa. O chapéu é óbvio. E a habilidade de disparar
projéteis adicionará a gema. No script do gerenciador de jogos, quando começamos a
jogar, podemos chamar essa função para
atualizar
imediatamente a visibilidade do
Sprite do personagem , caso tenhamos carregado uma cerveja segura com habilidades
já desbloqueadas Durante o jogo,
também queremos chamar essa função sempre que o
jogador desbloquear uma nova habilidade Então, adicionaremos um sinal
a esse script para quando uma habilidade
for desbloqueada, com o
número inteiro da habilidade como parâmetro Em seguida, escreva uma função pública
para desbloquear uma nova habilidade, aceitando o mesmo número
de habilidade e omitindo o sinal Podemos então conectar esse sinal
ao personagem do jogador. No entanto, não
escrevemos a função de atualização de visibilidade do
Sprite
para aceitar nenhum parâmetro Portanto, quando conectamos o sinal, devemos desvincular um argumento para evitar causar erros Isso funcionará para mudar
a aparência do personagem, mas ele ainda sofrerá danos causados pelo
calor enquanto estiver
usando o chapéu. Ao atualizar a visibilidade do
sprite do personagem no caso específico
de adornar o chapéu, também
removerei a camada de colisão
causada danos causados
pelo calor para
torná-lo imune Para remover uma única
camada específica de uma máscara de bits, primeiro, passe o cursor do mouse sobre a camada e
anote seu valor camada 14 tem um valor de 8.192, que é dois elevado a 13 ou dois elevado
a 14 menos A camada de colisão é
na verdade um número inteiro, que em binário é uma
sequência de zeros Atualmente, tudo são zeros, exceto que o décimo
e o 14º bits Tudo o que precisamos fazer é alterar o 14º bit para zero para
removê-lo dessa camada Começaremos pegando uma
referência à caixa de água. Como essa função não está
sendo chamada com muita frequência, não há problema em usar um caminho de nó. Para remover a camada de colisão, podemos subtrair
seu valor No entanto, isso depende
da camada de colisão atualmente
existente na camada 14 Se chamássemos
essa função por algum motivo quando a camada 14
já estivesse desativada, subtração
simples não
funcionaria Usando o operador bit e na camada de
colisão da nossa caixa Hurt, se pudermos fornecer uma sequência de todas as unidades com apenas
o 14º bit como zero, o resultado será
definir o 14º bit 20, independentemente de
seu Para obter esse número,
podemos reverter os bits de 8.192, o valor das camadas Isso é feito com o operador naught
bit a bit, que em GDScript Essa é uma maneira
matematicamente eficiente de remover camadas de colisão. Se você quiser adicionar
uma camada de colisão, definindo seu bit como um, tudo o que você precisa fazer é usar o
operador ou em vez de
e remover o nó Mas não estamos interessados
em fazer isso aqui. No script do gerenciador de jogos, atualizarei minha
função de entrada para desbloquear cada nova habilidade em sequência ao pressionar a
seta para cima para fazer meu teste. Declarando uma nova variável aqui, para que ela seja empacotada com
meu código de teste Vou me lembrar de
excluir isso junto com a função de entrada quando não precisar
mais dela para testar. Vou chamá-la de próxima habilidade como um número inteiro que, naturalmente, tem como
padrão zero. Cada vez que pressiono a seta para cima, desbloqueio a próxima habilidade e imprimo o
nome dessa habilidade. Podemos usar a função keys em uma enumeração
para obter uma matriz de strings
iguais às que
escrevemos como entradas escrevemos Portanto, indexar a matriz de chaves com o número da habilidade obtém
o nome dessa habilidade Em seguida, aumentarei a
próxima habilidade, mas a manterei
entre zero e o tamanho da enumeração de habilidades menos mas a manterei
entre zero e o tamanho da enumeração de
habilidades menos
um para evitar erros. Excluirei o arquivo seguro
atual para que minhas habilidades comecem a ser bloqueadas e ativem formas de colisão
visíveis Executando o jogo,
começamos
sem nenhuma habilidade desbloqueada e com o personagem
padrão Sprite sem nenhuma habilidade desbloqueada e com o personagem
padrão Sprite Vou abrir a
árvore da cena remota e selecionar os personagens Hurt Box para verificar se eles
estão nas camadas dez e 14. Pressionando a seta para cima uma vez, a habilidade de salto duplo agora
está desbloqueada, então o personagem está
vestindo uma capa Pressionando a seta para cima novamente, o salto na parede é desbloqueado, mas a aparência do personagem
permanece inalterada, pois essa habilidade não foi
associada a uma mudança cosmética Tocar em qualquer área de colisão fará com que o personagem
sofra Pressionando mais uma vez, agora o painel
também está desbloqueado e o
personagem ainda tem a mesma aparência Volte para desbloquear
o chapéu mágico, e podemos ver que a Hurt Box do
personagem não
está mais na camada 14, mas ainda na camada dez. Tocar na caixa de
acerto normal causa danos, mas entrar na nova caixa de acerto de
calor vulcânico não, o que significa que o personagem está imune a ela enquanto usa o chapéu Pressionando uma última vez, desbloqueamos a
habilidade de atirar e adicionamos a gema, mas ainda não a
implementamos. Agora temos nosso
personagem trocando de roupa para acompanhar seu
progresso no jogo A última habilidade que adicionaremos
é disparar um projétil. Nos vemos no próximo vídeo.
49. 6-7 Projétil: Olá, amigos. Neste vídeo, adicionaremos um feitiço de
projétil que o jogador pode disparar
gastando seus pontos mágicos Primeiro, precisaremos dar pontos mágicos a
esse personagem para gastar. No script do personagem do jogador, adicionarei uma nova
categoria de exportação para lançar feitiços Em seguida, duas variáveis para sua magia máxima e sua magia atual,
ambas como flutuadores Também precisaremos emitir sinais
sempre que esses valores mudarem
para que possamos atualizar o Substituindo a função ready, podemos definir a mágica máxima para o valor dos dados salvos do
player Depois, iniciarei o
player com toda a magia,
definindo o valor atual para
o valor máximo e
emitirei definindo o valor atual para
o valor máximo e os sinais alterados
para atualizar o HUD cena do jogo, podemos conectar
facilmente os
sinais do personagem do
jogador ao medidor mágico pois eles existem
na mesma cena O medidor mágico não tem um script anexado,
mas não precisa de um Como a barra de progresso já fornece as funções de
que precisamos, basta
desativar somente os métodos de script A classe range nos fornece a função set max
aceitando um parâmetro flutuante Além da função de
valor definido, também aceitando um parâmetro
flutuante Agora, o medidor mágico
será
atualizado automaticamente com as variáveis mágicas do
personagem do jogador Nas configurações do projeto, a guia Mapa de entrada
precisará de um botão que possa ser pressionado pelo
jogador para lançar um feitiço Vou usar a tecla C ou o botão Face superior
no meu controle. Então, no script do jogador, podemos copiar o mesmo
formato do salto para tentar lançar um feitiço
e, se não for bem-sucedido, armazenar a entrada em buffer para
tentar novamente no De volta ao script do
personagem do jogador, podemos escrever a função cast, não
aceitando parâmetros
e retornando um booleano Tudo o que realmente precisamos fazer aqui é verificar se a habilidade foi desbloqueada e se o personagem
não está ocupado realizando
nenhuma outra ação, se o nó
atual da animação é movimento Em seguida, peça à animação que
viaje até a animação do elenco e retorne verdadeiro se a entrada bem-sucedida ou
falsa se não for. Caso não queiramos que o lançamento do nosso feitiço
seja instantâneo, todo
o resto precisará acontecer em uma função separada Vamos nomear esse projétil de um
tiro. Ela não precisa de nenhum argumento
ou retorno de nenhum valor, e ainda não temos nenhuma informação para escrever
essa função, mas precisaremos que essa
função seja declarada e salva antes de
incluí-la na animação de transmissão. Mudando para a cena do
personagem, começaremos adicionando
um Sprite animado ao dende para usar como efeito
de elenco Isso precisará de um recurso de
molduras Sprite. Antes de importar minhas
folhas de sprites para lançar feitiços,
criarei uma nova pasta
para sprites mágicos e moverei o efeito Dash
Cooldown Em seguida, importe os sprites para fundição, o projétil e
seus sprites de impacto Adicionando os sprites de
animação de elenco ao recurso Sprite frames Y Vou configurá-lo para 12 quadros por
segundo, sem loop E adicionarei um quadro em branco
no final da animação e, em
seguida, o moverei para cima em 18 pixels
com o deslocamento Y. Isso parece bom, mas se
inclinarmos isso para o
personagem Sprite, ele também virará para
a mesma direção do Ao selecionar o nó
Animation Player, podemos duplicar qualquer uma
das animações existentes para
criar uma animação de elenco Depois de remover faixas
desnecessárias e atualizar todos os quadros-chave da região de
Sprite, adicionaremos faixas do método de chamada ao nó
raiz do personagem e ao efeito de transmissão
Animated Sprite no two D. Para o efeito de transmissão, tudo o que precisamos fazer
é mandar ele tocar Para o personagem, adicionaremos um quadro-chave para disparar
o projétil Esses quadros-chave podem ser
facilmente ajustados para acontecerem a qualquer momento durante
a animação de transmissão Vou iniciar o efeito de lançamento
no segundo quadro e disparar o projétil
no terceiro quadro O resto da animação
funcionará como recuperação. Na Árvore de Animação, só
precisamos repetir o mesmo processo que
usamos com o traço A transição para o
elenco está ativada, e vamos voltar ao movimento no final
da animação Em seguida, vamos montar
o projétil real. Comece adicionando uma nota D de área dois à cena do
personagem. Em seguida, atribua a ele uma
forma de colisão e um recurso de forma. Usarei um círculo, mas reduzirei
seu raio para oito pixels e mudarei sua cor de
depuração para algo que ainda não
usei, como Em seguida, adicione um Sprite animado para denodar e forneça a ele um recurso de molduras de
Sprite Primeiro, adicionaremos
os quadros de sprite para o projétil conforme quisermos que
ele comece e os usaremos como
a animação Sprite padrão Isso será repetido e eu definirei minha taxa de quadros para 12
quadros por segundo Em seguida, clicaremos no botão Adicionar
animação para criar uma segunda animação Sprite e nomeá-la como
Impact Agora podemos adicionar mais quadros de
Sprite para uma animação de impacto
que será reproduzida pelo mesmo projétil
quando colidir Você também pode adicionar um quadro
vazio no final
dessa animação para permitir que o último quadro seja desenhado
por toda a duração. Lembre-se de definir a
animação padrão para reprodução automática,
então reproduziremos essa animação quando o projétil for
gerado Ainda dentro da cena do
personagem, reposicione o
projétil onde você quer que ele comece em
relação ao Você pode
facilitar isso selecionando o projétil e a árvore
da cena
e segurando a tecla Alt
enquanto o move O meu tem 12 pixels
à direita e acima
da origem do personagem. Em seguida, adicione um marcador de dois nós D como filho do projétil Isso garantirá
que sua posição corresponda exatamente ao projétil O marcador para o nó D é exatamente
o mesmo que um nó dois D, exceto que ele desenha
um pequeno dispositivo
no editor para que possamos ver
exatamente onde Isso nos dá a posição
em que queremos gerar o projétil em nossa cena
ao lançar o Assim, podemos nomear o nó Marker
Tutti adequadamente. Em seguida, redirecione o
nó Marker Tutti ao personagem Sprite Como é filho
do personagem Sprite, ele inverterá sua exposição quando o personagem mudar a direção do rosto automaticamente . Salve a ramificação do projétil como sua própria cena e salve-a em uma nova pasta de cenas
para projéteis Em seguida, exclua-o
da cena do personagem. Agora temos um projétil e sabemos onde
queremos gerá-lo, então retornaremos ao script do personagem do
jogador Podemos exportar o projétil como uma cena compacta e
preenchê-lo no inspetor Também podemos pegar uma referência
ao marcador de desova. Seria melhor se
tivesse um nome exclusivo. E precisaremos especificar
um custo mágico para disparar
esse projétil Vou definir o meu para
16 pontos mágicos. Antes de permitir que o jogador
comece a lançar o feitiço, também
devemos
verificar se ele tem pontos mágicos
suficientes, verificando se a magia atual é
maior ou igual ao custo mágico Então, quando a animação de lançamento chama a função de atirar
projétil, já que há uma janela de
tempo
muito breve entre o momento em que essas
duas funções são chamadas, não
é uma má ideia verificar se
o personagem
ainda tem magia
suficiente para
lançar o
feitiço novamente Portanto, ao verificar se a magia atual
é menor que o custo, retornar dessa função não
disparará o projétil Sabendo que esse não
é o caso, podemos subtrair o custo
de nossa mágica atual e emitir o sinal de
alteração mágica atual para
atualizar o Em seguida, criaremos
um novo projétil instanciando
a Não queremos que isso acompanhe
o personagem quando criança, e não como um
irmão no mundo, para que ele possa se mover sozinho Então, pegaremos o pai primeiro antes de adicionar esse
projétil quando criança Em seguida, defina sua posição
dentro do mundo para ser a do
marcador de desova do projétil Temos que usar a
posição global aqui porque a posição local do marcador está
em relação à posição do
personagem, mas o projétil
está sendo adicionado ao nodo mundial,
não ao Então, queremos a posição
do marcador em relação
ao mundo. E, finalmente, diremos esse projétil em que
direção ele está disparando podemos passar um argumento
como vetor de dois pontos contrário, podemos passar um argumento
como vetor de dois pontos
à esquerda se o caractere estiver voltado para a
esquerda ou para a direita. Agora precisaremos escrever essa
função para nosso projétil, abrindo a cena do projétil adicionando um script
ao seu nó raiz Vamos chamá-lo de Projétil e salvá-lo na
pasta Ajudará dar a esse script um nome de classe para que possamos
referenciá-lo posteriormente. Esse projétil precisará de
algumas variáveis exportadas, como a velocidade com que ele se move e a quantidade de dano que causa quando
atinge Vou nomear esse
dano padrão para que ele possa ser anulado e
atribuir-lhe o valor de um Também precisaremos de uma referência
ao nó Tu Di do Sprite Animado para dizer qual
animação reproduzir Ele precisa saber em qual
direção está sendo disparado e quanto dano
realmente causará, se não for o padrão, e se está se movendo ou não
no momento. Quando instruídos a disparar, podemos aceitar a direção como um vetor dois e a quantidade de dano como um número inteiro com um valor
padrão de zero, tornando-a um parâmetro opcional Definiremos a direção para
o parâmetro de direção e inverteremos o sprite se o ponto de
direção X for menor que
zero, ou seja, Em seguida, defina dano como dano se algum valor de
dano foi fornecido
; caso contrário, use o
dano padrão para danos
e, finalmente, defina
se é movido para verdadeiro. Substituindo a função do processo. Se esse projétil estiver se movendo, podemos definir sua
posição como mais
igual a direção vezes a
velocidade vezes Delta Esse projétil
precisará colidir com corpos e áreas Portanto, precisaremos
conectar os
sinais da área inserida e do corpo ao script. Os corpos com os quais esse projétil colidirá serão o terreno, enquanto as áreas
serão caixas feridas Ambos farão
muitas das mesmas coisas. Então, chamaremos uma função
privada separada de ambas e a nomearemos no impacto. Quando o projétil
atinge algo, fazemos com que ele pare de se mover e, em
seguida, desabilite mais colisões definindo sua máscara de
colisão Isso desativa todas as camadas
da máscara de colisão. Em seguida, reproduza a
animação de impacto e conecte o sinal finalizado
da animação à função de quarto remover
automaticamente o
nó da cena. Se o projétil
atingir uma caixa de dano, podemos fazer com que ela
sofra a quantidade de dano antes de provocar
o impacto Não estamos usando o parâmetro
body, então podemos marcá-lo como
não usado com um sublinhado Se o projétil
não atingir nada, ainda
precisamos limpá-lo. Uma maneira simples é fazer com que a sala a destrua
automaticamente ao sair da sala em
que foi gerada A partir do script da sala, em vez de conectar
esse sinal por meio do inspetor todas as
vezes para cada sala, seria mais fácil fazer
isso por meio de scripts Então, escreveremos uma função de saída na
área, aceitando uma área como número de
D e não retornando nenhum valor Se a área que saiu
desta sala fosse um projétil,
vamos colocá-la na fila para ser liberada
da árvore da cena Em seguida, conecte o sinal
de saída da área na função pronta Também podemos fazer isso
para
conectar automaticamente os sinais
inseridos pelo corpo. Lembre-se de que, se alguma das cenas da sua sala já tiver
esses sinais conectados, você deve
desconectá-los para evitar erros Mas, à medida que criamos
centenas de salas, fazer com que essas
conexões de sinal sejam
programadas automaticamente nos poupará muito
mais tempo e esforço Para que o colisor
da sala detecte um projétil
saindo dela,
ele precisará mascarar a camada de colisão na
qual
o próprio projétil Executando o jogo, eu já
começo com todas as habilidades desbloqueadas do vídeo anterior e meu medidor mágico está cheio Vou abrir a árvore da
cena remota para que eu possa ver meu projétil desovar
e me limpar Voltando ao jogo, pressionando o botão de atirar, lança um feitiço, que dispara o projétil O projétil colide com a parede e explode Meu medidor mágico é reduzido
pelo custo do feitiço. Mirando na outra direção,
o projétil
não tem nada a atingir
e, portanto, sairá
da sala atual Mas, em vez de
continuar avançando para o infinito, ela será destruída assim que sair
dos limites desta sala Agora temos todas as nossas
habilidades desbloqueáveis no jogo e estamos prontos para
começar a adicionar inimigos Nos vemos na
próxima seção.
50. Ritmo 7-1: Olá, amigos. Nesta seção, adicionaremos alguns
inimigos ao nosso jogo. Vou começar criando
uma nova pasta para armazenar meus sprites inimigos e
importar uma folha de sprites do meu primeiro inimigo, o mouse cego Também precisaremos de uma nova
pasta de cenas para inimigos. Podemos
facilitar as coisas se duplicarmos nosso personagem de jogador existente para usar como modelo
para criar nosso inimigo Em seguida, mova-o para
a pasta do inimigo. Abrindo a nova cena,
renomearei o nó raiz para
corresponder ao nome da cena Em seguida, analise a hierarquia da
cena e decida quais nós são necessários para o inimigo
e quais não são Ainda precisaremos de
uma forma de colisão para colidir com o terreno, uma caixa Hurt para sofrer danos e um sprite para Mas os filhos do
Sprite não são necessários, já que esse inimigo não tem nenhum outro sprite ou a
habilidade de disparar projéteis Manteremos os nós do
Animation Player, da árvore e do efeito sonoro, embora você
queira alterar os sons. O cronômetro Coyote
não será necessário. Se você
quer ou não que seus inimigos sejam desenhados no mapa,
depende de sua preferência, mas obviamente você
precisará alterar
a textura se decidir
manter o ícone do mapa. E também podemos excluir
todos os nós de habilidade. O nó raiz tem o script do
personagem do jogador anexado. Precisaremos substituí-lo script normal
do personagem, já que esse não é o personagem do
jogador e ele não tem nenhuma das habilidades do personagem do
jogador. Selecionando o nó Sprite Toti, podemos substituir a propriedade
atlas de
texturas do atlas por uma planilha Sprite Como a planilha de sprites é diferente da do meu personagem jogador,
precisarei examinar cada uma das
minhas animações no nó do Animation
Player e verificar se elas têm o número
correto de
quadros e os valores de região corretos digitados Esse inimigo tem menos animações do que o personagem do
jogador, então eu posso deletar tudo,
exceto ocioso e andar A animação ociosa funciona bem, pois
os valores da região codificada coincidem exatamente, mas a animação de caminhada
não corresponde, então precisarei corrigi-la para corresponder aos valores
da região da planilha de
sprites Vou atualizar rapidamente os valores
da região Y codificada para
fazer essa animação funcionar Ignoraremos as animações de sucesso
e morte por enquanto, pois ainda não
podemos testá-las A Árvore de Animação precisará uma
máquina de estado muito mais simples para esse inimigo, não a mesma que o personagem do
jogador está usando Então, criaremos um novo recurso de máquina de
estado. Em seguida, adicione as animações de marcha lenta
e de caminhada transição do
início para a marcha lenta por
padrão para caminhar se a
velocidade X não for zero e, em
seguida, voltar para a marcha lenta se a velocidade X for zero seguida, voltar para a marcha lenta se a Isso é tudo que esse inimigo
precisa fazer por enquanto. Dando uma olhada no
roteiro do personagem por um momento, o roteiro já
tem tudo o que
precisamos para fazer um personagem
andar de um lado para o outro. Porém, como eu não quero que meus inimigos tenham tempo de coiote, precisarei
mover qualquer código relacionado a ele
para que esteja apenas no script do personagem do
jogador, ou posso simplesmente
garantir que nenhum código
relacionado ao tempo
do Coiote seja executado
se não houver hora ou nó do
Coiote Como eu já usei o nó get ou a função null para verificar o nó temporizador do
Coyote,
essa variável será nula
se esse nó essa variável será nula
se esse nó A única vez que estamos usando o nó temporizador Coyote é
no processo físico, e podemos apenas
verificar se existe um nó temporizador Coyote
antes de tentar chamá-lo de função de início
para evitar erros Esse mesmo processo também pode ser usado se você não
quiser incluir todos
os mesmos nós em
suas várias cenas de personagens e inimigos para coisas como
sons ou efeitos de partículas Vamos mudar para qualquer uma de nossas cenas de conteúdo de sala existentes e adicionar esse novo
inimigo à sala. Meu plano para esse inimigo é fazer com que eles andem para
frente e para trás. Quando batem em uma parede,
quero que se virem, esperem um segundo e
andem na direção oposta. Então, vou editar meu
terreno para criar uma plataforma simples com
paredes em ambos os lados Então, esse inimigo vai e
volta aqui. Também adicionarei outra
plataforma sem paredes, e o inimigo deve sair
da saliência nesse caso Talvez você queira escrever
outro script, como o script do personagem do jogador
herdado do personagem, que também inclui
esse comportamento Mas é melhor pensar
nesse comportamento como uma alternativa ao
nó do jogador na cena do jogo, por meio do qual o jogador pode controlar o personagem do jogador. Em vez disso, escrevemos um script que controla o comportamento desse
inimigo. Então, criaremos um novo nodo
como filhos do inimigo. Vou chamar esse nodo de pace. Dessa forma, o mesmo script de
comportamento pode ser usado para vários inimigos
diferentes, e também o mesmo tipo de inimigo pode ter vários scripts de comportamento
diferentes. Incluir esse nodo na própria cena do
inimigo faria com que ele fosse aplicado automaticamente a
todos os inimigos do mesmo tipo. Ao colocá-lo no conteúdo da
sala, a cena
permitirá que os mesmos inimigos tenham comportamentos
potencialmente
diferentes. Vamos anexar um script
a esse nó e colocá-lo em uma nova
pasta de scripts para inimigos. Para dizer a um
inimigo o que fazer, precisaremos de uma referência
ao próprio inimigo
armazenada em uma variável. Podemos chamar a
função G parent para obter o pai direto desse nó e atribuí-lo
à variável usando
a tag ready. Observe que isso só funcionará se o nó de comportamento for filho
direto do inimigo. Também devemos
exportar uma variável para dizer em qual direção esse
inimigo irá primeiro. Então, vou chamá-la de
direção e dar a ela valor padrão de um,
ou seja, à direita. Substituindo a função de processo, tudo o que precisamos fazer é definir a direção de movimento do inimigo nessa direção para que
ele comece a andar Quando o inimigo está em uma parede, podemos dizer ao
personagem que fique virado para a esquerda e defina sua direção de movimento
para zero, para que ele pare. Para esperar por um curto período de
tempo, precisamos de um cronômetro. Como esse nó
não tem um tipo, podemos usá-lo como o próprio cronômetro
alterando seu tipo O tipo que esse script estende também
precisará mudar para
cronômetro para acessar qualquer um dos nós,
propriedades ou funções
do cronômetro Não precisamos conectar
o sinal de tempo limite, pois tudo o que realmente precisamos saber é se o
cronômetro está parado ou não Se o cronômetro parar, ajustaremos a direção do movimento do inimigo para a
direção Caso contrário, podemos defini-lo como zero porque esse inimigo
está esperando no momento. Quando o personagem atingir uma parede, definiremos o valor da
direção como o seno das paredes X normal
e iniciaremos o cronômetro Para fazer com que o personagem fique virado direita ao bater em uma
parede à esquerda, também
precisaremos fazer com que isso dependa
do seno das paredes X normal Também só queremos parar o personagem e
transformá-lo se
a direção atual do
ritmo
não for a mesma
das paredes normais Estamos chamando essa função
normal get Wall várias vezes, então seria mais eficiente armazená-la em uma variável local. Vamos fazer uma
refatoração de luz aqui. Na cena do conteúdo da sala, podemos ajustar a quantidade de tempo de espera e definir a propriedade one
shot como verdadeira. Vou duplicar o nó de ritmo e conectá-lo
ao outro inimigo Em seguida, dê aos meus dois inimigos valores
diferentes para sua direção
inicial de ritmo Agora, quando rodamos o jogo, com a ajuda do nosso script de
comportamento, os inimigos andam, um para a esquerda e
outro para a direita. O segundo inimigo
sai da saliência, mas o primeiro bate na parede, se vira e
espera um segundo
antes de se virar e
caminhar na outra direção E os dois repetem
esse comportamento. Mas você deve ter notado que suas animações nem
sempre coincidem com sua velocidade Na verdade, os dois personagens estão animados em sincronização Isso ocorre porque, assim
como os ícones de saúde, eles estão compartilhando um recurso. Na cena dos inimigos, precisaremos selecionar o nó D
Sprite two e tornar o recurso de textura do atlas
local para essa Agora, cada instância
desse inimigo terá sua própria textura de atlas e poderemos animar
independentemente um do outro No entanto, se alguma de
suas animações estiver alterando a propriedade
de textura do nó Sprite two D, isso poderá interromper as animações
que fazem Vou deletar essa faixa
da minha animação de reinicialização. Também não precisamos da conexão de
sinal, que foi copiada da cena do personagem do
jogador
, usada para
reproduzir os esforços de Jump Executando o jogo novamente, agora
podemos ver que eles
conseguem reproduzir suas animações inativas e de
caminhada corretamente Agora temos um inimigo que
pode andar para frente e para trás, virando contra as paredes, mas também precisamos garantir
que ele não possa sair da sala. vejo
no próximo vídeo.
51. 7 a 2 paredes invisíveis: Olá, amigos. Neste vídeo, vamos impedir que nossos inimigos
saiam da sala em que
foram criados Para fazer isso, precisaremos que nossos
inimigos tenham colisões com paredes invisíveis que não afetem o personagem do
jogador Temos o corpo do
personagem do jogador na camada nove de colisão, mascarando o terreno
na Na cena de nossos inimigos, definiremos a camada de
colisão corporal em algo diferente,
como
a camada 17 Eles ainda precisam mascarar
a camada do terreno, mas também faremos com que eles
mascarem uma segunda camada que
usaremos para paredes invisíveis Vou usar a camada cinco. Abrindo as configurações do projeto, camada nomeia Física dois D. Nomearei a camada 17 como inimiga e a camada
cinco como paredes invisíveis. Na cena da minha sala, copiarei
o nó da camada Tile Map, que está desenhando o mapa, já que ele já tem os
limites da sala. Em seguida, cole-o
na cena de conteúdo e
renomeie-o para Paredes invisíveis Com a nota da
camada Mapa de
Azulejos selecionada, clicando no recurso Conjunto de mosaicos, precisaremos adicionar uma
camada física a esse conjunto de mosaicos, existente na camada cinco
para paredes invisíveis. painel do conjunto de blocos, podemos pintar essa
camada física no ladrilho. Mudando para o painel Tile Map com a ferramenta de pintura
e o ladrilho selecionados, podemos fechar as portas desta
sala, selando
completamente a
sala por todos os lados com uma camada física mascarada
apenas pelos inimigos e não pelo personagem
do Não queremos que essas
paredes invisíveis sejam desenhadas no mapa, então elas não deveriam estar na camada de
visibilidade dois, e queremos poder
vê-las durante os testes. Vamos colocá-los na primeira camada de
visibilidade. Vou editar o terreno e mover meus inimigos para que eles possam andar
livremente
pela sala inteira Agora, quando rodamos o jogo, os inimigos caminham
em direção à borda
da sala, mas são
virados pelas paredes. Enquanto nosso personagem jogador
pode passar direto por eles. Eu preferiria que
essas paredes estivessem fora da
área visível da sala, então vou
tirar cada uma delas mais um ladrilho. Tudo o que precisamos fazer para tornar as
paredes completamente invisíveis para o jogador é desativar
sua propriedade visível, seja na árvore da cena
ou no inspetor Agora precisamos fazer com que esse inimigo realmente ameaçador
para o jogador, o que já fizemos antes. Tudo o que precisamos fazer
é adicionar uma área ao nó
D, chamá-la de hit Box. Dê a ele uma
forma de colisão ao nó D quando criança e dê ao nó Tut
da forma de colisão um Defina a caixa de acerto para mascarar
a Hurt Box do jogador. E deve ser monitoramento. Em seguida, anexe o script Hit box e conecte o sinal inserido na
área ativada. Agora, quando rodamos o jogo,
fazer contato físico com
um inimigo faz com que o
personagem do jogador sofra danos. Agora, quando rodamos o jogo, fazer contato físico com um inimigo faz com que o
personagem do jogador sofra danos. Falaremos sobre como
tornar o combate mais envolvente
na próxima seção. Por enquanto, vamos lidar com
essas mensagens de erro. Essas mensagens de erro acontecem quando carregamos o conteúdo de uma sala. Isso ocorre porque estamos carregando o conteúdo da sala
em resposta a um evento de colisão quando o
corpo do personagem do jogador entra em uma sala E Godot não gosta que adicionemos mais áreas ou objetos de colisão enquanto já está ocupado
resolvendo colisões
para este resolvendo colisões
para Portanto, se seguirmos o
conselho dado pelas mensagens de erro e
usarmos
o chamado deferred, isso fará com que o motor do
jogo carregue o conteúdo da sala após a conclusão da resolução
da colisão do
quadro atual O ciclo de Godot começa com tratamento
de entrada,
seguido pela física, que inclui colisões, depois processa e termina
com chamadas adiadas Portanto, podemos usar isso para
realizar qualquer ação
que quisermos como a última coisa
antes do final de qualquer quadro. Executando o jogo novamente, não
há mais mensagens de erro. Nosso inimigo agora ficará
nesta sala e poderá ferir
o personagem do jogador. Mas precisamos adicionar mais variedade de
inimigos ao nosso jogo. Te vejo no próximo vídeo.
52. 7-3 Detecção de borda: Olá, amigos. Neste vídeo, adicionaremos outro
inimigo que pode detectar cunhas e se virar em vez
de se afastar delas. Começaremos duplicando
nosso inimigo existente. Abrindo a cena do inimigo, mudaremos o
nome do nó raiz para coincidir com o inimigo. Importe sua folha de sprite e defina-a como atlas
no inspetor Todos os sprites
da ficha Sprite são iguais aos do primeiro inimigo, então não há nada para corrigir
em termos de Na cena do conteúdo do meu quarto, removerei os dois
inimigos e adicionarei
esse novo inimigo e, em seguida, editarei o terreno para que eles fiquem em um terraço elevado com uma saliência em cada lado
de diferentes Quero que esse inimigo pare
na borda mais alta, espere um momento, depois dê meia
volta e caminhe
na outra direção Mas então eles deveriam
sair da borda mais curta. Em relação às paredes, elas devem agir da mesma
forma que o inimigo anterior. Como esse comportamento
é muito semelhante, seria bom
usar o mesmo script. Então, vou adicionar uma nota de cronômetro
como filho do inimigo. Renomeie-o, anexe o script de
ritmo a ele e defina sua
propriedade one shot como verdadeira Portanto, esse inimigo deve se comportar
exatamente como o rato cego. Agora só precisamos
descobrir quando o inimigo está caminhando
em direção a uma saliência, que podemos fazer usando
um novo tipo de nó,
um nó D lançado com dois Vamos chamar esse detector de borda de
nodo. Em seguida, mova-o por uma curta distância para a direita e para cima do personagem. O raio tem uma máscara de
colisão que já
está configurada para a
camada 1 do terreno Expandindo a seção de colisão
com, nosso terreno é um corpo físico, então o raio colidirá Se estiver usando um
nó de transmissão de raios para detectar áreas, você precisará verificar as áreas
aqui antes que ele funcione. O raio lançado é representado
no editor como uma seta, mas ficará invisível
enquanto o jogo estiver em execução, assim como nossos nós da área de
colisão Ele dispara um raio
partindo de sua posição
na direção da seta e informa se atinge ou
não alguma coisa. Nesse caso, se atinge
ou não o terreno. Então, se atingir o terreno, o inimigo continuará
avançando
e, caso contrário, o
personagem precisa parar A distância à direita
do personagem
determinará a que distância ele
procurará a saliência A distância acima do
solo não terá muito efeito , desde que esteja acima do solo e abaixo da altura
do personagem. A posição do alvo deve apontar para
baixo para
detectar o solo, mas a distância que ele dispara
o raio afetará o que ele considera uma
saliência e o que não o faz Vou definir o meu para ter 64
pixels abaixo ou dois blocos. Isso significa que, se
o inimigo encontrar uma saliência com
apenas um ladrilho de altura, ele ainda se afastará Mas se tiver dois ou
mais ladrilhos de altura, o raio não atingirá o terreno
e, portanto, o
inimigo parará Ao contrário das áreas de colisão, no entanto, o nó de projeção de raios não emite nenhum sinal ao qual
possamos reagir Então, teremos que anexar nosso
próprio script a esse nó. Vou colocá-lo na pasta de scripts do
inimigo. Podemos começar declarando
nosso próprio sinal, que queremos admitir
quando uma saliência for detectada e passar na
direção da saliência em relação ao
inimigo como , não é tão
simples quanto saber se entanto, não é tão
simples quanto saber se
o raio está atingindo
alguma coisa Da mesma forma que fizemos com que
o cronômetro do Coyote só começasse no quadro exato quando o personagem
sai de uma saliência,
queremos detectar uma saliência apenas
uma vez durante o quadro exato quando o raio parar de colidir com
o terreno Portanto, precisaremos de uma variável booleana para saber se o raio atingiu ou não o terreno no último quadro e outras quatro se atingiu o
terreno neste Durante o processo físico, definiremos se estava colidindo com o valor anterior
de está colidindo e, em
seguida, eu colidindo com o valor atual
retornado pelo raio lançado Se o raio colidiu no último quadro, mas não está
colidindo com esse quadro, esse é o
momento exato em que
detectamos uma saliência e
emitiremos nosso sinal A direção da
borda pode ser apenas o sinal da
posição do nó Vamos conectar nosso sinal
detectado na borda
ao script de ritmo e chamar uma função chamada
wait and turnaround Podemos copiar essas três
linhas de cima, que mandam o inimigo parar,
mudar a direção do ritmo
e iniciar o cronômetro Em seguida, substitua-os
por uma chamada para nossa função. Mas precisaremos passar
o oposto do X
normal da parede como argumento de
direção para coincidir com o que está sendo
passado pelo detector de borda. O detector de borda envia a
direção em direção à borda. Então, aqui precisamos dar a
direção em direção à parede. A nova
direção de ritmo é, portanto, o oposto do parâmetro de
direção Isso funcionará
enquanto o inimigo estiver
se movendo para a direita, mas precisaremos reposicionar o nodo lançado à
esquerda do inimigo quando ele se virar Felizmente,
já emitimos um sinal toda vez que um
personagem muda de direção Então, tudo o que precisamos fazer é conectar esse sinal ao
detector de borda para reagir a ele. Vamos renomeá-lo em caso de
mudança de direção do inimigo. Como isso nos dá
sua nova direção, definiremos a posição
do
nó como o valor absoluto de sua posição multiplicado
por menos um se a
direção for menor que zero
ou positivo caso contrário Rastrear essa mudança de
direção sinaliza a omissão volta ao script do personagem Eu escrevi
isso originalmente passando a variável de direção do movimento
como parâmetro do sinal. No entanto, isso não funciona
no contexto em que estamos
usando esse personagem inimigo, já que o valor da
direção do movimento não corresponderá necessariamente à direção que estamos dizendo para ele se virar. Portanto, em vez de
passar na direção do movimento, é mais preciso
passar menos um se mandar o personagem virar para a esquerda ou positivo para a direita. Agora, o raio fundido
estará sempre na frente
do personagem,
esteja ele
voltado para a esquerda ou para a direita Vamos ativar as formas de
colisão visíveis para que possamos ver o raio lançado enquanto o
jogo está em execução e clicar em play O raio é desenhado em vermelho quando colide
com alguma coisa Nosso inimigo se
aproxima da primeira saliência. O raio lançado fica azul para indicar que não está
atingindo nada, e o inimigo
para por um curto período de tempo, depois se vira e
vai para o outro lado Ao se aproximar
da saliência mais curta, o raio lançado é longo o suficiente para ainda
atingir o terreno,
então o inimigo se afasta
e continua
na mesma então o inimigo se afasta e continua
na Eles finalmente atingem a parede
invisível nas bordas mais distantes da sala e se viram
como o inimigo anterior. Agora temos um segundo tipo de inimigo que se comporta
de forma diferente do primeiro, mas precisamos de muito mais variedade
para tornar nosso jogo divertido Te vejo no próximo vídeo.
53. 7-4 Voando: Olá, amigos. Neste vídeo, adicionaremos um inimigo voador
que salta pela sala Vamos começar importando uma nova planilha de sprites
para o inimigo voador Em seguida, duplicando uma
das cenas inimigas existentes. Depois de abrir a
nova cena inimiga, renomearemos o nó raiz para combinar e trocaremos o atlas pela folha de sprite
adequada Esses sprites têm
32 pixels quadrados, ao contrário dos outros inimigos até agora Então, vou ajustar a posição Y do Sprite agora para
abaixá-la um pouco Esse inimigo não tem animações de inatividade e
caminhada
separadas, então vou remover a animação de
caminhada e
editar a animação de inatividade para ter o
número correto Em seguida, edite os valores chave para que a animação ociosa tenha
a altura correta em pixels Agora, a animação inativa
parece correta. Ativando a visibilidade
da forma de
colisão do corpo do personagem, vou girá-la em 90 graus para que
a cápsula fique na horizontal, que é mais
parecido com o formato
desse inimigo, e ajusto seu
raio e altura Em seguida, faça a mesma coisa
com o Hurt Box. E o dano de contato atinge a caixa, certificando-se de que ela se ajuste ao
tamanho e formato do inimigo, para que qualquer dano infligido
ao jogador pareça justo Quanto à máquina de estado Animation
Tree, como há apenas uma
animação no momento, ela só precisa ter um estado
ocioso passando
do início para o inativo do início Com relação ao script anexado ao nó raiz desse
inimigo, não
precisamos que esse
inimigo ande ou pule, mas ainda precisamos que esse inimigo seja capaz de
virar para a
esquerda ou para a direita, ter aceleração
e desaceleração, ser afetado pela gravidade e pela velocidade
terminal Portanto, há
benefícios suficientes em continuar usando o mesmo script de personagem aqui em vez
de começar do zero. Mas há uma diferença suficiente
no comportamento de
um inimigo que pode voar para que possamos escrever uma nova subclasse que
herda do personagem Então, vamos criar um novo
script chamado Flying Enemy, herdado do personagem, e salvá-lo na pasta de
scripts do inimigo Nosso inimigo voador
precisará de uma direção para voar. Ao contrário de caminhar ou correr, que é representado como um flutuador, já que só precisa
se preocupar com o eixo X, uma direção de voo pode ser
qualquer direção no espaço D, então vamos armazená-la
em um vetor dois Também precisaremos de uma variável
booleana para saber se esse
inimigo está voando ou não no momento Podemos então anular
o processo de física para incluir uma nova verificação para ver
se o inimigo está voando
e, em caso afirmativo, chamar uma função de
física de voo Se o inimigo não estiver voando, podemos chamar a definição
de
superclasse do
processo físico como normal. Você também pode exportar
uma velocidade de voo como flutuador se quiser ter
um inimigo velocidades de caminhada
e voo
diferentes Eu lhe darei um valor padrão
de 100 pixels por segundo. Vou segurar Control ou command e clicar
nessa chamada de função para o
processo de física da superclasse para ir diretamente para sua declaração, para que
possamos dar uma olhada no
que ela contém Observe que a chamada da função move e
slide está dentro da definição
de superclasse do nosso processo físico Essa função deve
ser chamada para aplicar o corpo do personagem
à velocidade do Dnodes e verificar se há colisões Também ainda queremos que
nosso inimigo voador fique
voltado para a direção em
que está voando. Então, precisaremos fazer isso na função de física
do vôo. Vou copiar esse bloco
de código, retornar ao script
do inimigo voador e colá-lo na minha física de voo. Em vez de verificar o
valor da direção do movimento, precisaremos verificar o valor
do ponto X da direção do voo. Também
precisaremos
ainda chamar a função de movimento e deslizamento se
o inimigo estiver voando Podemos então aplicar uma
lógica semelhante à que usamos para controle
aéreo em nossos personagens
não voadores para fazer nosso inimigo voador voar. Se a direção do voo tiver um valor, moveremos a velocidade do
inimigo em direção à direção do voo
multiplicada pela velocidade do
voo a uma taxa de aceleração multiplicada
pelo controle aéreo multiplicado pelo Delta Ou, se nenhuma
direção de voo for fornecida, podemos mover sua velocidade
em direção ao vetor dois pontos zero a
uma taxa de desaceleração multiplicada pelos freios a ar multiplicada pelo O. Quando estávamos editando
apenas o Velocity dot X, que é um float, um tipo de dado
primitivo, tivemos que chamar Godot move to-function para Mas como o vetor
dois é uma classe, ele pode ter suas próprias funções. Segurar o controle ou o comando e clicar no
nome
da classe nos leva
à documentação dessa classe, onde podemos visualizar todas as
suas propriedades e funções, se necessário. Então, aqui temos a opção de chamar a velocidade do movimento do
ponto em direção, que difere do movimento da função
Godot em
direção, pois o
primeiro parâmetro já
é conhecido como
o próprio vetor Você também pode
exportar valores
diferentes aceleração,
desaceleração, controle
aéreo e freios pneumáticos
para seus inimigos voadores, se quiser que eles
usem valores diferentes enquanto não estiverem Também precisaremos de uma função
pública que diga a esse inimigo que voe, aceitando um parâmetro vetorial dois para a direção do voo. E outra para quando
parar de voar. Isso controlará a
variável está voando e definirá a
direção do voo ao mesmo tempo. Lembre-se de anexar esse script de inimigo
voador ao nó raiz do
inimigo em sua própria cena. Na cena do conteúdo da sala, assim como nossos inimigos existentes têm um nó separado que
lhes diz como se comportar, faremos a mesma coisa
com nosso novo inimigo voador. Vou deletar esse
inimigo da cena e adicionar dois desses
novos inimigos voadores. Em seguida, editarei o terreno
para colocar um deles
dentro de uma caixa de terreno para que
possamos ver como ele
se comporta Quero que esses morcegos voem na direção diagonal e
ricocheteiem em qualquer parede, teto ou piso com o qual
entrem em contato Então, anexando um
nó básico a ambos,
vou chamá-lo de ricochete Em seguida, anexe um script a esse nó e
salve-o na pasta de scripts do inimigo. Esse script precisará de
uma variável exportada para a direção inicial do voo Vou usar o vetor 21, que está à direita. Também precisaremos de uma
referência ao inimigo cujo comportamento estamos
controlando definido para esses nós, pai usando a tag on ready. Substituindo a função ready, seria uma boa ideia
normalizar a direção do voo A normalização de um vetor
garantirá que ele tenha um
comprimento de exatamente um Como um vetor com um valor
de 11 é maior que um, isso resultaria no morcego voando mais rápido do que
sua velocidade de vôo. Mas se normalizarmos o vetor, estamos usando apenas a
direção do vetor, não seu comprimento Substituindo a função de processo, podemos dizer ao inimigo que voe na direção de
voo desejada Mas antes de fazer isso,
precisaremos verificar se esse inimigo está atualmente em contato com
alguma parede, teto ou piso. Podemos então definir o ponto X da direção do
voo ou ponto e Y para o
valor apropriado em qualquer um desses casos. Para o teto,
o valor será o valor absoluto do ponto Y da direção do
voo, tornando-o sempre
positivo, que é baixo. E o piso é o oposto, multiplicando o valor absoluto por menos um, que é Para paredes, podemos simplesmente
multiplicar o valor absoluto do ponto X da direção da mosca pelo
sinal do ponto normal X da parede, que aponta para longe da parede Também vou anexar o
script de ricochete ao outro inimigo e clicar play Quando executamos o jogo, podemos ver que o morcego salta,
ricocheteando em cada parede, teto
e piso que toca, criando um obstáculo
interessante Agora temos um
inimigo voador para combater, mas devemos ter pelo menos mais
um tipo de inimigo para nossos
jogadores enfrentarem. vejo no
próximo vídeo.
54. 7-5 Rastreamento: Olá, amigos. Neste vídeo, criaremos um inimigo capaz de
rastejar por qualquer superfície, incluindo paredes e Vamos começar importando uma folha de
sprites para esse inimigo. Em seguida, duplique o inimigo voador. Depois de abrir a
nova cena do inimigo, vou renomear o nó raiz Em seguida, troque o atlas da textura
do atlas de dois
nós D do Sprite
pela folha pela No Animation Player do inimigo, atualizarei a
animação inativa para ter o número correto
de quadros fornecidos
pela planilha Sprite Atualizar os valores da
região codificada conforme necessário. Como queremos que esse
inimigo rasteje não apenas pelo chão, mas também pelas paredes e
pelo teto, seria útil se
pudéssemos girar Com a
origem do inimigo em seus pés, da mesma forma que criamos
todos os outros inimigos, girá-los mudará
tudo sobre esse ponto Para facilitar um pouco as coisas, seria melhor fazer com que o ponto de
origem dos inimigos rastejantes estivesse no centro para que
essas rotações parecessem mais Então, centralizarei o
sprite e todas as formas de colisão para serem
centralizadas no Agora, quando girarmos esse inimigo, ele permanecerá na
mesma posição relativa Vou ajustar rapidamente
a Hurt Box e a caixa de
acerto para melhor se adequar
ao formato desse inimigo. Para a forma de colisão do
corpo do personagem, no entanto, usarei um círculo
em vez de uma cápsula Como esse inimigo pode girar, o formato da colisão sendo um círculo significa que
as rotações
não resultarão em nenhuma mudança no que o inimigo
está Se você estiver usando rotações estritas de
90 graus, uma
forma de colisão quadrada também funcionaria, mas exigiria
algumas etapas extras quando se trata de cantos convexos Então, vou continuar usando um círculo. Na cena do conteúdo da sala, vou remover os morcegos e
substituí-los por dois caracóis O objetivo é fazer com que esses
caracóis rastejem pela superfície interna e externa dessa Assim como criamos
um novo script herdado do personagem
para inimigos voadores, escreveremos outro para inimigos rastejantes e o salvaremos
na pasta de scripts
inimigos Em seguida, substitua o script anexado
ao inimigo por esse novo script. Vou desacelerar meu
caracol definindo sua velocidade de caminhada para apenas
32 pixels por segundo Primeiro, precisamos saber
a direção em direção
à superfície em que esse inimigo está
rastejando atualmente como um vetor dois Em seguida, também a
direção de rastejamento para frente como outro vetor dois Também precisaremos lidar com nossas próprias colisões aqui,
em vez de confiar na função de
movimento e deslizamento do corpo do personagem para fazer toda a física por Assim, podemos armazenar
dados de colisão em outra variável do tipo colisão cinemática dois D. Substituindo o processo de
física, verificaremos se esse inimigo está atualmente preso a uma superfície
e, em caso afirmativo, chamaremos o Se eles não estiverem
presos a uma superfície, podemos chamar a superclasse de processo de
física Isso funciona porque um vetor dois com seus valores padrão de zero, zero será tratado
pela declaração if como falso e qualquer
outro valor como verdadeiro. Se eles não estiverem
presos a uma superfície, também queremos verificar se esse inimigo consegue
grudar em uma superfície. Chamando uma
função um pouco diferente de mover e deslizar, chamaremos de mover e colidir Essa função aceita o movimento do personagem como
primeiro parâmetro, que é sua velocidade
multiplicada por A função retorna uma colisão
cinemática de dois D, que podemos atribuir
à Da mesma forma que nosso vetor dois pode ser usado em
uma declaração if, acontece com esses dados de colisão Se nenhuma colisão ocorrer, ela será considerada falsa E se uma colisão ocorrer, ela será considerada verdadeira Se esse inimigo
colidir com alguma coisa
, presumiremos que ele queira
se ater a ela e definiremos o valor
de preso na superfície Podemos acessar as colisões normais chamando a função
get normal Esse é um vetor apontando para
longe da superfície com
a qual o personagem colidiu
no ponto de colisão Como queremos que o valor
dessa variável esteja
voltado para a superfície, não para longe dela,
podemos simplesmente girá-la 180 graus chamando
a função girada Mas as rotações em Godot
não usam graus. Eles usam radianos, e 180 graus é o
mesmo que Pi radianos Ah, se o inimigo não
colidir com nenhuma superfície, chamaremos a
superclasse de processo de física Mas o processo de
física da superclasse também aplica a velocidade do
personagem quando ele chama mover e Seguindo esse código, a velocidade do
personagem está sendo aplicada duas vezes a cada quadro , desde que ele não
toque em nenhuma superfície Podemos corrigir isso passando um segundo parâmetro opcional para a função move e
colide, que é um teste chamado booleano Se for verdade, essa função só
verificará colisões, mas
na verdade não moverá o personagem Agora que nosso inimigo se
fixará automaticamente em qualquer superfície, podemos entrar na física de rastejar por essa Primeiro, aplicaremos a gravidade na superfície em que
o inimigo está preso, já que não fizemos isso
no teste de colisões anterior, e isso também ajudará a manter o inimigo na superfície em
que está rastejando Chamando mover e colidir, passando na direção
em direção à superfície, multiplicado pela gravidade,
multiplicado pelo Delta, nossos dados de colisão agora
manterão a
colisão com a Podemos então ramificar com base na ocorrência ou não de uma
colisão Caso o ângulo da superfície mude,
podemos atualizar
a direção
em direção à superfície rastejante e, em
seguida, calcular a direção
para frente,
que é apenas a direção em
direção
à superfície girada Se Pi for 180 graus, então Pi dividido por
dois é 90 graus. No entanto, a direção
da rotação
dependerá se o inimigo
está voltado para a esquerda ou para a direita. Se eles estiverem voltados para a esquerda
, precisamos
girar no sentido Se eles estiverem voltados para a
direita, giramos no sentido anti-horário para obter
sua
direção voltada para frente como E se esses valores
mudaram desde o quadro
anterior, também
precisaremos atualizar
a rotação do inimigo
para desenhá-lo da maneira correta. Como o inimigo está voltado para a direita em sua cena
com uma rotação de zero, tudo o que precisamos fazer é usar a direção para frente e
chamar a função de ângulo. A função de ângulo
retorna o ângulo entre qualquer vetor dois e
o eixo X positivo. Mas como estamos usando a escala X
negativa
para virar o personagem
quando ele estiver voltado para a esquerda, também
teremos que corrigir isso na rotação,
girando outros 180 graus
ou Pi radianos se o
inimigo estiver voltado
para girando outros 180 graus a Agora que temos o inimigo
preso à superfície
e sabemos em qual direção
ele quer rastejar, se o inimigo estiver
sendo instruído a se mover, podemos finalmente usar a função de movimento e colisão
novamente para
movê-lo em
sua direção para frente, multiplicada pela
velocidade de movimento, multiplicada por Delta Se houver alguma colisão como
resultado desse movimento, isso significa
que eles colidiram
com um canto côncavo Tudo o que precisamos fazer aqui é recalcular a direção
em direção à nova superfície O próximo quadro de física
cuidará do resto. Se não houve colisão, o inimigo rasteja
suavemente ao longo de uma superfície plana Se não houver nenhuma
direção de movimento dada, eles permanecerão imóveis. Voltando à primeira afirmação
if, se
a gravidade em direção
à superfície não
resultou em uma colisão, isso significa que o inimigo de alguma forma
perdeu contato com a superfície em
que estava rastejando Portanto, devemos chamar uma
função que os
redefinirá para a orientação
normal. Vou chamá-lo de unstick e torná-lo público para que
outros scripts possam chamá-lo Essa função redefinirá a direção
da superfície para vetor 20 e a
rotação para zero, retornando-os a um estado de comportamento
semelhante ao de qualquer outro inimigo. No entanto, ainda falta uma coisa em nossa
física
de rastreamento, que é dizer ao inimigo que olhe para
a direção em que está
se movendo, já que isso estava sendo feito no das superclasses Em vez de copiar e
colar o mesmo código aqui, vamos mover isso para uma função privada
na classe de caracteres Então, podemos chamar essa função tanto
nesse script de personagem quanto no script de rastreamento de
inimigos Em vez de criar
um nó
e um script separados para simplesmente mandar
esse inimigo rastejar, vou exportar uma variável inteira
para a Em seguida, substitua a
função do processo e faça isso aqui. Para fins de teste,
também substituirei a função de
entrada para fazer com que
a seta para baixo os force a se
soltarem de qualquer
superfície em que estejam rastejando Quando executamos o jogo, o
caracol rasteja ao redor dessa caixa, girando nos cantos côncavo
e convexo para subir nas paredes e novamente para rastejar
no nas paredes e novamente para rastejar
no Pressionar a seta para baixo
faz com que eles se soltem
da superfície e caiam na gravidade
, como qualquer outro inimigo faria Agora temos nosso tipo
final de inimigo, um que pode rastejar
pelas paredes e tetos Mas nossos inimigos deveriam ser mais agressivos com
o personagem do jogador. Te vejo no próximo vídeo.
55. Visão 7-6: Olá, amigos. Neste vídeo, daremos a alguns de nossos
inimigos a habilidade de perceber e reagir
à presença do personagem do
jogador. Na cena do conteúdo da sala, removerei os caracóis
e a caixa de terreno Substitua-o por um
bloco nos dois lados e, em
seguida, coloque uma nota do mouse dentro dela que se mova
para frente e para trás entre eles. Vou adicionar o nó do cronômetro, anexar o script de ritmo e definir sua
propriedade one shot como verdadeira Para que esse inimigo aja agressivamente contra
o personagem do jogador, ele precisa de uma maneira de detectá-lo. Precisaremos usar várias
ferramentas para conseguir isso. Primeiro, adicionaremos um nodo D de área
dois ao nosso inimigo. E um
nó em forma de colisão para a área. Essa área representará todo
o alcance do campo de visão do
inimigo. Você pode usar
um quadrado girado 45 graus, uma cápsula ou um círculo Se você usar um polígono de colisão com
dois nós D em vez de um nó D com forma de
colisão, você pode realmente criar
um polígono personalizado em você pode realmente criar
um polígono personalizado em
vez de usar formas predefinidas. Basta clicar no editor para desenhar cada vértice
da forma desejada Isso nos permite fazer
um triângulo ou um ventilador, o que é uma melhor representação
de um campo de visão. Expandindo a
propriedade do polígono no inspetor, podemos ver as posições
de cada vértice,
editá-las e
reorganizá-las, editá-las e
reorganizá-las Seja qual for a forma que você
escolher usar, certifique-se de que ela
tenha apenas ângulos convexos Se seu polígono for côncavo, Godot o dividirá em várias formas
convexas menores e dobrará o custo dos cálculos de colisão se você decidir usar , se você decidir usar
uma forma de
colisão simétrica normal, No entanto, se você decidir usar
uma forma de
colisão simétrica normal, virar o inimigo para a
esquerda e para a direita é muito mais fácil, pois você pode simplesmente
usar o mesmo método que
usamos com o detector de
borda lançado, configurando sua propriedade de posição sempre Com o
polígono de colisão de dois nós D, no
entanto, o processo é um
pouco mais complicado Não podemos simplesmente mover sua posição e também não devemos alterar
sua propriedade de escala. Se abrirmos a documentação
desse nó, ele avisa especificamente contra isso, afirmando que
provavelmente não se comportará conforme Se decidirmos usar esses polígonos de colisão para formas
não simétricas
que precisamos inverter,
teremos que editar
manualmente posições de cada um dos o campo de visão não
será suficiente por si só, Porém, o campo de visão não
será suficiente por si só, pois
não há nada que o impeça de
atravessar paredes. Se quisermos que o inimigo detecte o jogador com uma linha de visão
desobstruída,
precisaremos de outro nó para verificar
se um raio lança dois Você deve
posicioná-lo perto dos olhos do inimigo, de onde realmente
estaria
observando, mas mantenha-o centralizado Vou renomear isso
para linha de visão. A linha de visão
colidirá com o terreno e com o corpo do personagem do
jogador, ambos Isso permitirá que o terreno
bloqueie sua linha de visão, mesmo que o personagem do jogador esteja dentro de seu campo de visão Com o campo de visão selecionado, só
precisaremos que ele seja monitorado, mascarando o corpo do jogador Vou remover o nó da forma e usar o polígono
como minha área de colisão Em seguida, dê nomes exclusivos
a ele e ao elenco. Anexando um script à área do
campo de visão para dende, nós o salvaremos na pasta de scripts
do inimigo Vamos pegar referências
à forma ou ao poligonal e ao nó da linha de visão usando a tag ready O que eu gostaria dessa
configuração é que o inimigo reagisse
ao
personagem do jogador depois
que ele entrasse
no campo de visão e o inimigo tivesse uma
linha de visão direta para o jogador. Se o
personagem do jogador sair do campo de visão e a
linha de visão for quebrada, eu gostaria que o inimigo
voltasse ao seu comportamento normal Considere como
queremos que esse nó se comunique com outros
nós por meio de sinais. Precisaremos desse nodo
para relatar duas coisas quando o inimigo adquiriu um alvo e quando
perdeu o alvo. Esses serão os
momentos exatos em que queremos mudar
seu comportamento do
ritmo padrão para frente e para trás
e, em vez disso, pedir comecem a agir de forma mais
agressiva ou vice-versa Podemos conectar os
sinais de entrada e
saída do corpo do
campo de visão ao script E isso nos
diz facilmente quando o personagem do
jogador entra e sai do campo de visão Precisaremos armazenar isso em
uma variável chamada target. Como o parâmetro
é um D sem dois, também
definiremos o tipo de variável como um D sem dois para
manter as coisas simples. Também precisamos de uma variável
booleana para determinar se o inimigo
está ou não mirando no momento, se o alvo está
atualmente dentro do campo de visão e se o inimigo atualmente tem uma linha de
visão do Quando um corpo entra
no campo de visão, defina o campo de visão verdadeiro e defina o alvo como corpo. Quando o corpo deixa
o campo de visão, podemos voltar a ser falso. Lembre-se de que estamos apenas
mascarando o personagem do jogador, então já sabemos que esse corpo é o personagem do
jogador Substituindo o processo de física, se ainda não houver um alvo, podemos simplesmente retornar, pois não
há nada a fazer Agora podemos supor que
o personagem do jogador tenha entrado no campo
de visão pelo menos uma vez. Em seguida, apontaremos a linha
de visão para o alvo. Podemos criar um vetor
apontando de para B subtraindo A de B. Então, a posição alvo
do raio emitido será a global
do alvo
menos nossa posição global Então, o valor de está na linha
de visão será verdadeiro se o que o colisor está atingindo for o
mesmo que o alvo Se o raio lançado atingir o
terreno ou não atingir absolutamente nada,
isso será falso Observe que, quando o processo
físico acontece, as colisões já
foram calculadas por Godot Então, quando apontamos a linha de visão para o
personagem do jogador na linha acima, os dados de colisão resultantes não
estarão disponíveis
até o próximo quadro O que estamos verificando aqui são os resultados
da colisão do quadro anterior Se, por algum motivo,
você absolutamente precisar que um elenco seja
atualizado imediatamente, você pode chamar sua função force
ryCastuDate Mas com o jogo rodando
a 60 quadros por segundo, o atraso não será perceptível e isso
funcionará perfeitamente do jeito que está. Agora, tudo o que precisamos fazer é emitir nossos sinais nos horários
corretos. Se o inimigo não estiver mirando no
momento, mas o alvo estiver em
seu campo de visão e ele tiver uma linha de
visão para o alvo
, o alvo
foi adquirido Então, definiremos sua segmentação como verdadeira e emitiremos o sinal adquirido do
alvo, passando o alvo
como argumento E no cenário completamente
oposto, se eles estão mirando no momento, mas o alvo não está
em seu campo de visão e eles não
têm linha de visão, então perdemos o alvo Nesse caso,
também seria uma boa ideia definir o valor do
alvo de volta como Nulo, impedirá
que o
processo físico verifique mais
nada até que eles
entrem novamente no campo de visão Também vamos imprimir quando esses eventos acontecem para
que possamos testá-los. A última coisa que
precisamos fazer é inverter nosso polígono de colisão quando
o inimigo muda de direção, o que podemos fazer conectando o
sinal de mudança de direção Se você estiver usando uma forma
simétrica, tudo o que você precisa fazer é
reposicioná-la no outro lado
do personagem Mas estou usando um polígono, que significa que precisarei editar
os vértices individuais Começarei pegando
a matriz existente do polígono e
armazenando-a em uma variável O tipo é uma matriz de dois
vetores compactados. Posso então percorrer
cada um dos vértices e usar a mesma estratégia para
inverter sua exposição
para o outro lado do personagem se ele
estiver voltado para
a A matriz de
vértices fornecida pelo polígono aqui é apenas uma cópia, não a matriz em si Então, quando editamos seus valores, isso não afeta realmente o
polígono de colisão Para que as alterações
realmente funcionem, precisamos sobrescrever a matriz
existente pela cópia editada Vamos ativar as formas de
colisão visíveis no menu
de depuração
e testá-las Podemos ver nosso inimigo andando para frente e para
trás entre as duas paredes e
o polígono de colisão vira
quando eles Ao entrar no campo de visão, o nó lançado por raios começa a
rastrear nossa posição, mas o inimigo ainda
não viu, pois sua linha de visão está
bloqueada pelo terreno Se pularmos para cima, a linha
de visão não estará mais obstruída e obteremos a saída da mensagem adquirida pelo
alvo Saindo do campo de
visão do inimigo e também de sua
linha de visão, a
mensagem do alvo perdido aparece e o elenco não está mais
rastreando nossa posição Agora temos nosso inimigo capaz de
detectar a presença do
personagem do jogador, mas ele ainda
precisa reagir a ela. Te vejo no próximo vídeo.
56. 7-7 Agressão: Olá, amigos. Neste vídeo, teremos o inimigo perseguindo
e atacando o jogador. Começando pela cena do inimigo, precisaremos adicionar um
ataque para esse inimigo. Duplicando a animação inativa, vou rapidamente definir os sprites adequados
para
a animação de ataque do inimigo Essa animação de ataque realmente
não comunica a área em que o
ataque atingirá. Mostra apenas o movimento do
inimigo em si. Precisaremos de um
sprite separado para isso. Vou criar uma nova pasta
Sprite para sprites efeitos e importar
uma folha de sprites para o efeito de
ataque desse inimigo Adicionaremos um Sprite Animado para representar como filho do Sprite
do inimigo, para
que ele gire automaticamente
na horizontal quando o inimigo se virar na horizontal Em seguida, crie um novo
recurso de molduras Sprite e adicione os sprites
da pasta Sprite Como sempre, adicionarei um sprite em branco ao
final da animação, definirei sua taxa de quadros para 12 quadros por segundo e não repetirei Vou colocar essa animação
em seu primeiro sprite, que mostra com precisão o
tamanho e a forma do ataque Em seguida, posicione-o na
frente do inimigo. Isso torna muito mais fácil
adicionar uma caixa de acerto a esse ataque. Então, vamos duplicar
a caixa de acerto existente. Vou renomear a caixa de acerto
original para causar danos de
contato e deixar
essa nova como caixa de acerto Agora podemos fazer com que essa caixa de acerto tenha forma de
colisão correspondente
ao efeito do ataque Ao contrário do Animated Sprite, não
devemos usar o truque de escala
negativa
para virar nossa Então, precisaremos conectar o sinal de
direção alterado do inimigo
ao script hit boox e
reposicioná-lo manualmente Como fizemos antes, vamos apenas pegar uma referência à forma
da colisão E defina sua posição como seu valor
absoluto multiplicado por um se a direção for menor que zero ou
positivo caso contrário No estado padrão desse inimigo, ele não estará atacando, então essa caixa de acerto não
estará ativa Então, vamos desativar sua
propriedade de monitoramento e visibilidade. Em seguida, volte para
a animação de ataque onde podemos enquadrar essas propriedades para
ativá-las durante a animação de ataque
e desativá-las novamente. Isso também adicionará
os dois
à faixa redefinida com
seus valores padrão. E também podemos dizer que o efeito de ataque deve ser
reproduzido ao mesmo tempo. Na cena do conteúdo da sala, atualmente
temos o comportamento
normal desse inimigo andando frente e para trás e uma forma de o inimigo ver
o personagem do jogador Quando esse nodo emitir o sinal adquirido pelo
alvo, queremos mudar o comportamento do inimigo de
andar para ser mais E quando perderem a
noção do alvo, devem retomar
o ritmo original Mas talvez não
queiramos necessariamente que isso se aplique a todos os inimigos ou outros personagens que estão usando o script de ritmo. Portanto, devemos criar
um nó separado para comportamento agressivo. Vou usar outro nó temporizador
e chamá-lo de agressão. Em seguida, anexe um
script a esse nó e salve-o na pasta de scripts do
inimigo. Assim como no script de ritmo, precisaremos de uma referência
ao inimigo que esse script está controlando usando
a tag ready. Também precisaremos armazenar uma
referência ao alvo em
uma variável contra a qual esse inimigo está
agindo agressivamente. E também precisaremos saber
a direção em direção ao
alvo como um vetor dois, bem
como a distância
até o alvo como flutuador Conhecer esses valores
permitirá que o inimigo se aproxime do alvo para
entrar no alcance de ataque
antes de atacar Mas também precisaremos especificar o alcance de ataque
desse inimigo como uma variável exportada,
que seria um flutuador Se quiser, você também
pode especificar um alcance mínimo de ataque. Se mudarmos o tipo
do alcance do ataque
para um vetor dois, podemos usar o valor X como o alcance mínimo e
o Y como o máximo. Definirei seu valor padrão
para estar a pelo menos 32 pixels de
distância do player e
até um máximo de 64 pixels. Então, se o inimigo estiver a mais de 64 pixels de distância do personagem do
jogador, quero que o inimigo
corra em direção a ele. Ou se o inimigo estiver a menos de 32 pixels do personagem do
jogador, quero que o inimigo
fuja deles. Mas dentro desse alcance,
o inimigo atacará. Substituindo a função de processo, podemos ignorar Delta
e, se não houver um alvo para
esse inimigo, podemos retornar Isso não deveria acontecer, mas
nunca é uma má ideia
ter um dispositivo à prova de falhas Podemos calcular
a direção até
o alvo subtraindo a posição do
nosso inimigo da posição
do alvo
e, em seguida, obter a distância
pegando o mesmo vetor e
calculando Se a distância até o alvo for maior que nosso alcance
máximo de ataque, esse inimigo deve se mover
em direção ao alvo, definindo sua direção
de movimento no sinal de direção do ponto X. Se a distância até o alvo for menor que nosso alcance mínimo de
ataque, esse inimigo deve
se afastar do alvo, fazendo exatamente o oposto Se ambas as
condições forem falsas, o alvo está
dentro do alcance do ataque. Portanto, o inimigo deve
se preparar para atacar. Vou garantir que o inimigo pare se
mover definindo sua direção de zero e também
voltado para o alvo,
caso ainda não esteja. Não quero que o inimigo
ataque imediatamente, pois minha animação de ataque é muito curta,
não é telegrafada Então, vou iniciar o cronômetro aqui e esperar que ele atinja o tempo
limite antes de atacar A propriedade
de disparo único desse cronômetro deve ser definida como verdadeira para fazer a contagem regressiva
apenas uma vez A propriedade de tempo de espera
será o tempo em que o inimigo permanece dentro do alcance de ataque
antes de atacar Conectando o
sinal de tempo limite ao script, aqui é onde vou mandar
meu inimigo atacar Também é uma boa ideia voltar para
o alvo caso algo tenha mudado desde o início do cronômetro Eu só quero iniciar o cronômetro se ele estiver parado no momento Também pararei o cronômetro sempre que o alvo estiver
fora do alcance de ataque Isso deve ser suficiente
para nosso comportamento. Agora, só precisamos
alternar entre nossos dois scripts de comportamento
nos momentos apropriados. Não queremos que nosso
script de agressão esteja ativo quando o
inimigo aparecer pela primeira vez, então definiremos o
modo de processo Selecionando o campo de
visão na árvore de cenas, conectaremos o sinal
adquirido do alvo ao script de
agressão e podemos renomear essa
função se quisermos Para manter as coisas consistentes entre meus diferentes scripts de
comportamento, vou chamá-lo de zoom. Essa função definirá
o valor do alvo, alterará o
modo de processo para herdar
e também mandará o inimigo correr, o
que fará
com que ele e também mandará o inimigo correr, o comece a agir agressivamente em relação ao Mas também precisamos
pausar o script de ritmo. Então, também conectaremos o
mesmo sinal ao nó de ritmo. E desta vez chame uma
função chamada pause, mas esse sinal
fornece um argumento, e não precisamos dele
para pausar esse comportamento Também podemos imaginar um cenário que gostaríamos de
pausar esse comportamento em outras circunstâncias
e não gostaríamos de fornecer um argumento arbitrário e
desnecessário para chamar a função de pausa Então, vamos desvincular o argumento
fornecido pelo sinal, para que a função conectada não
tenha Aqui, tudo o que precisamos fazer é definir o modo de processo como desativado. Quando o inimigo vê um alvo, ele interrompe seu comportamento de
ritmo
e retoma seu comportamento agressivo Então, quando eles perdem o alvo, podemos fazer o oposto, conectando o sinal aos scripts e chamando
as funções opostas. Configurar o modo de processo
como herdar para
ativá-los ou desabilitar para
desativá-los Ao ativar o comportamento
de ritmo, também queremos
dizer ao inimigo que ande Agora, no roteiro do personagem, precisaremos acionar
a animação de ataque quando mandarmos o
inimigo atacar. Para fazer isso,
precisaremos de uma referência à reprodução
da máquina de
estado da Animation Tree Mas isso causará um erro no script
do personagem do jogador se
tivermos outra variável
com o mesmo nome, já que o personagem do jogador
herda do personagem Então, haveria uma variável de
animação herdada do personagem, mas também outra declarada
no personagem do jogador, que não é permitido, mas estamos usando para
o mesmo propósito, então podemos simplesmente removê-la script do
personagem do jogador De volta ao
roteiro do personagem, quando instruídos a atacar, basta
dizer a essa reprodução para viajar até a animação de
ataque Na Árvore de Animação, adicionaremos a animação de ataque
e faremos a transição para ela de Idle com Advance Enabled e retornaremos à inatividade no
final da Se você não quiser que
o inimigo consiga
se mover ou mudar de
direção ao atacar
, podemos adicionar
verificações rápidas para ver se o nó
atual da reprodução da animação é E defina a direção do movimento para zero ou retorne totalmente para fora
da função. Agora, quando começamos o jogo, quando o inimigo nos tem em seu campo de visão
e em sua linha de visão, seu comportamento muda
de ritmo para mais agressivo Eles nos perseguirão e
atacarão após uma breve pausa. Agora temos um inimigo muito
mais agressivo para nosso personagem
, mas nosso personagem não
consegue realmente revidar Nos vemos na
próxima seção.
57. Combo 8-1: Olá, amigos. Neste vídeo, daremos seus
próprios ataques ao
personagem do jogador para que ele possa
lutar contra nossos inimigos. Já atacamos o
mouse Knight, e o processo
será muito semelhante No entanto, nosso personagem jogador
tem dois ataques diferentes. Podemos copiar alguns
dos nós da cena noturna
do mouse
para economizar tempo, caixa de sucesso e
o nó
Animated Sprite two D. Passando para
a cena do personagem, podemos colar esses
nós na cena reorganizá-los conforme necessário O nó Animated Sprite two D pode ser classificado sob o Sprite do
personagem, então ele se inverterá automaticamente para
coincidir com a direção em que
o Vou renomeá-lo para efeito de ataque. Eu sei qual sprite
animado específico é esse. A caixa de sucesso, geralmente coloco ao lado da
Hurt Box como irmã Para que a caixa de acerto do
personagem do jogador cause dano à Caixa de Dor do
inimigo, precisaremos garantir que as camadas e
máscaras de colisão estejam configuradas adequadamente Como meu personagem jogador
está na camada de colisão nove e seu Hurt Box está
na camada de colisão dez, eu terei meus inimigos
na camada de colisão
17 e suas caixas de Hurt
estarão na camada de colisão Abrindo as configurações do projeto, adicionarei a Hurt Box inimiga aos meus dois
nomes de camada de física D como camada 18. Então lembre-se de editar
todas as minhas
cenas de inimigos existentes para colocar suas
caixas de Hurt nessa camada também. A
caixa de acerto do personagem do jogador pode então ser configurada para mascarar a camada 18
a fim de causar danos a eles. Para virar a caixa de acerto, precisaremos reconectar
o sinal nesta cena,
já que essa conexão de sinal
não terá sido copiada
da outra Mas a função que escrevemos anteriormente no
script Hit box à qual queremos
conectar esse sinal é
nomeada no inimigo que conectar esse sinal é mudou de direção. Isso não importa,
mas se você quiser ser
consistente com a forma como
nomeia as coisas no seu jogo, convém alterar o nome
dessa função para um personagem que
mudou de direção. Isso adicionará outra
função ao script, e podemos facilmente mover o código para essa nova função
e excluir a antiga, pois ela
fará a mesma coisa. No entanto, agora precisamos
entrar na cena dos inimigos e editar sua conexão de sinal para nos conectarmos à nova função. Quanto mais cedo em seu projeto você puder identificar esses problemas, menos tempo e
esforço
precisará gastar na
refatoração posterior De volta à cena do
personagem do jogador, selecionaremos o nó Animation
Player
na hierarquia da cena e
adicionaremos uma nova animação Chamaremos esse ataque de
um, pois há duas animações de ataque diferentes e precisaremos
diferenciá-las Depois de adicionar as molduras de Sprite do
personagem. Vou copiar os quadros-chave para as outras faixas para as roupas do
personagem Também podemos ativar a propriedade de monitoramento da
caixa de acerto. E a visibilidade também, se você quiser vê-lo ligado e desligado
no modo de depuração Dando uma olhada
no efeito do ataque, isso não corresponde à animação
do ataque. Então, vou importar os sprites de
efeito adequados para esse ataque. Em seguida, adicione uma nova animação
ao recurso Sprite frames. Vou chamá-lo de ataque um, desligar o loop,
definir a taxa de quadros e adicionar um
quadro vazio no final Agora, a animação de ataque
pode indicar o efeito do ataque.
Animated Sprite, dois nós D para
reproduzir o primeiro efeito do ataque A
chamada de função com quadro-chave é just play, que tem funcionado
bem desde nosso nó D Animated Sprite tenha
apenas uma animação Mas agora temos duas animações
diferentes e precisamos especificar
qual delas queremos jogar Clicando no quadro-chave, podemos editá-lo no inspetor Expandindo a seção de argumentos, podemos ver que
a função play na verdade tem três argumentos, todos opcionais. Estamos preocupados apenas
com o primeiro argumento, o nome da animação, que podemos digitar
no campo de texto. Se você estiver curioso, os outros
argumentos são para ajustar a velocidade da animação ou reproduzi-la
ao contrário A grafia deve corresponder exatamente
ao nome da
animação Vou renomear a animação
padrão para atacar dois de acordo com o que
eu coloquei na animação Duplicando a animação de
ataque um, também
podemos fazer uma animação de
ataque dois Depois de alterar os quadros de sprite do
personagem, copiarei os quadros-chave
para as outras faixas Em seguida, altere o argumento que
está sendo passado para o efeito de ataque para jogar ataque dois em vez
do ataque um. Ao selecionar
o nó Animation Tree,
podemos adicionar as animações de ataque 1
e 2 de ataque. Ao selecionar o nó Animation Tree, podemos adicionar as animações de ataque 1
e 2 de ataque Em seguida, adicione uma transição do
movimento para o ataque um, depois do ataque
um para o ataque dois. Ambos terão modo
avançado definido como ativado, o que significa que acionaremos essas transições a partir do nosso script Adicionando transições,
deixando qualquer uma
das animações de ataque
voltando ao movimento, elas terão seus modos de
troca definidos para o final A transição do
ataque um para o ataque dois também
terá seu
modo de troca definido como final. Isso nos permitirá
fazer a transição para ataque um se o
botão de ataque for pressionado
e, em seguida, do ataque
um para o ataque dois se o botão de ataque for
pressionado pela segunda vez durante a animação do primeiro
ataque. Para adicionar um
botão de ataque ao nosso jogo, precisaremos acessar as configurações
do projeto, a guia Mapa de entrada e adicionar um novo
evento de entrada para atacar Vou usar a tecla X
no teclado e
o botão esquerdo no meu
controle, que também é X. Então, no script do player, podemos adicionar outro
bloco I para ataques, armazenando a entrada em buffer da mesma forma que fazemos com
todas as Como o botão para acionar o primeiro ataque e o
segundo ataque é o mesmo, o script do jogador
deve
se preocupar apenas em mandar
o personagem atacar, não qual
ataque específico realizar. No script do personagem do jogador, podemos adicionar essa função de ataque, retornando um booleano como
qualquer outra entrada armazenada em buffer Isso não será bloqueado e
não terá nenhum custo, ao contrário da função de transmissão. Se a reprodução da
animação do personagem estiver atualmente no estado de
movimento
, permitirei que ele ataque Se for bem-sucedida, podemos fazer que a
reprodução da animação viaje até o ataque uma
animação e retorne verdadeira ou falsa se o personagem estiver ocupado
fazendo outra coisa Há um erro porque
a função de ataque está substituindo a função
de ataque da classe de personagem, mas a assinatura
não corresponde Isso significa que
os parâmetros ou o tipo de retorno são diferentes,
o que não é permitido. Manter o controle ou o comando pressionado
e clicar na
função nos leva
à definição
de superclasse dessa função onde podemos ver que ela
retorna nula, não um Para usar essa estrutura de
herança com nossos inimigos e
nosso personagem de jogador,
sem deixar de permitir entradas em
buffer, sem deixar de permitir entradas em
buffer precisaremos que a função de ataque da
superclasse também retorne com nossos inimigos e
nosso personagem de jogador,
sem deixar de permitir entradas em
buffer,
precisaremos que a função de ataque da
superclasse também retorne um booleano. Apenas retornaremos true para
satisfazer esse requisito
e, voltando ao script do personagem do
jogador, o erro será resolvido. Mas e o
segundo ataque? Podemos adicionar um
bloco else if e verificar se a reprodução da animação está atualmente na animação de
attack one Em seguida, diga a ele que viaje até a
animação de ataque dois. Vamos ativar as
formas de colisão visíveis no menu Depurar, clicar em Reproduzir e experimentar Pressionando o botão de ataque, nosso personagem reproduz o
ataque One Animation. A caixa de acerto é ativada e a animação do efeito é reproduzida. Pressionar o
botão de ataque novamente durante o primeiro ataque também
executa o segundo ataque. Voltando ao editor, podemos abrir a árvore remota para ver nosso jogo atual rodando. Explorando a árvore de cenas até
encontrarmos a noite do mouse, podemos selecionar sua Hurt Box e ver suas propriedades
no inspetor, incluindo sua saúde atual De volta ao jogo, podemos
atacar nosso inimigo e ver cada ataque atingi-lo uma vida de cada vez
até chegar a zero. Vá lá. Agora temos nosso personagem capaz de
atacar inimigos, mas nossos personagens e inimigos
não reagem ao serem atingidos. Te vejo no próximo vídeo.
58. Hit 8-2: Olá, amigos. Neste vídeo, faremos com que nossos personagens
reajam ao serem atingidos por ataques. Começando na cena do
personagem do jogador, selecionando o nó
Animation Player, precisaremos adicionar uma nova
animação para sermos atingidos. Para facilitar as coisas, vou duplicar a animação do
traço
para criar a animação de sucesso Depois de atualizar os quadros-chave do
Sprite, vou copiá-los e colá-los
nas outras faixas para também animar
as roupas do personagem Como eu dupliquei a animação
do traço,
essa animação de sucesso agora também inclui quadros de
invencibilidade Isso é muito útil para
evitar que personagens
sofram danos causados por várias caixas de acerto em rápida sucessão, que geralmente parece injusto
para o jogador e também faz com que o personagem
sofra danos repetidamente causados por caixas de acerto
persistentes, como
riscos ambientais, por exemplo, porque uma nova colisão
será acionada quando a Hurt Box for reativada
no final do animação, se a Hurt Box ainda estiver
sobreposta à caixa de sucesso Também temos o
método track chamando a função end dash,
que, se você se lembra, da forma como foi implementada
na seção anterior, deve ser chamada se o
hífen for interrompido Seria uma boa ideia mover essa chamada de função para o
início da animação de sucesso. Vamos dar uma
olhada nessa função no script do personagem do jogador. Dependendo de quais quadros você ativa ou desativa o Hurt Box, pode ser possível
que o
personagem seja atingido enquanto a do traço está sendo reproduzida
e, portanto, interrompa a animação do O que significa que a
função final do traço nunca seria chamada, a gravidade do personagem
nunca seria reiniciada
e o tempo de recarga do traço nunca começaria Obviamente, isso é problemático, mas podemos corrigi-lo facilmente Tudo o que realmente precisamos
fazer é rastrear quando o personagem está correndo
com uma variável booleana Quando o traço começar,
vamos defini-lo como verdadeiro. Então, quando a
função end dash for chamada, verificaremos se o personagem
está correndo primeiro e, em caso afirmativo, faremos as mesmas Em seguida,
defina como falso depois. Agora podemos chamar essa
função sempre que
precisarmos , independentemente de o personagem estar correndo ou
não Se o personagem não estiver arrojado, a função simplesmente
não fará nada Ao selecionar o nó
Animation Tree e dar uma olhada
na máquina de estado, gostaria que a
animação de sucesso pudesse interromper qualquer uma dessas animações de ação
existentes, bem
como qualquer animação de salto ou
movimento Portanto,
seria uma boa ideia usar outra máquina de estado. Então, vou salvar essa máquina de estado como fiz com
as anteriores. Vou chamá-la de ações e salvá-la na pasta do meu personagem
junto com as outras. Em seguida, substitua essa máquina de
estado por uma nova e carregue a máquina de
estado de ações como um nó. Ok. Em seguida, você pode adicionar a animação de sucesso a
essa máquina de estado. Adicionar uma transição do início às ações o torna
o estado padrão. Em seguida, uma transição
de ações para hit com o
modo avançado definido como ativado e outra de hit back para ações com o
modo switch definido como final. Isso nos permite acionar a animação
a partir de
qualquer estado existente, reproduzi-la de uma só vez e depois
retornar aos outros estados. No script do personagem, como eu quero que isso
se aplique a todos os personagens, não apenas ao meu personagem de jogador, precisaremos criar
uma nova variável para manter a reprodução
dessa nova máquina de estado Podemos duplicar a variável
existente e renomeá-la para algo
como animações de Hurt O caminho para essa propriedade de
reprodução são os parâmetros Playback, pois é a raiz da Árvore
de Animação Se selecionarmos a Árvore de
Animação
na árvore de cenas e expandirmos
sua seção de parâmetros, podemos ver as reproduções de
cada uma de nossas máquinas de estado Portanto, o caminho da propriedade de
reprodução da máquina de estado de ação mudou e
precisamos atualizá-lo Para esclarecer melhor o uso
dessa reprodução em relação
às animações de Hurt,
vou chamá-la de animações de ação de reprodução Em seguida, use o
recurso de substituição para alterar todas as instâncias dessa
variável com seu novo nome. Como o
script do personagem do jogador herda essa variável, também
precisarei
substituir todas as instâncias do nome
antigo pelo novo nome nesse script Isso funcionará para
o personagem do jogador, mas para que
funcione para os inimigos, também
precisaremos atualizar suas máquinas de estado da
Árvore de Animação para corresponder a esse novo formato. Só vou atualizar meu mouse à noite pois esse inimigo está
na minha sala de partida, e o processo será
o mesmo para todos os inimigos. Vou fazer a animação de sucesso
no nó Animation Player. Em seguida, salve a máquina de estado
da Animation Tree como um recurso do projeto. Substitua-o por uma
nova máquina de estado. Adicione a
máquina de estado antiga como um nó, adicione a animação de sucesso, adicione as transições com o mesmo avanço
e alterne os modos Renomeie as ações para que
correspondam ao que o script
procurará Agora, esse inimigo tem a
mesma estrutura de animação do personagem do jogador, então os scripts
funcionarão da mesma forma, tendo duas
reproduções separadas para reproduzir a animação de sucesso e
outra para ações Depois que a
máquina de estado estiver configurada, a máquina de estado salva
poderá ser excluída. Isso fará com que a
máquina de estado seja localizada na cena, em vez de
um recurso compartilhado entre várias cenas Agora que temos acesso à reprodução da
nossa máquina de estado, precisamos acionar
a animação Começaremos com o roteiro de
Hurt Box. Temos um sinal que é emitido quando a saúde do
personagem muda, que estamos usando para
atualizar o elemento HUD. Mas esse sinal
também é emitido quando inicializamos a
saúde do personagem no início, bem
como sempre que o
personagem recupera a Portanto, não é o melhor sinal
a ser usado para receber danos. Vamos declarar um novo
sinal para isso. Se você quiser que
o personagem reaja a diferentes quantidades
ou tipos de dano, você pode fornecer
esses parâmetros de sinal. Vou adicionar um parâmetro
para a direção de onde
vem o dano, como um fator dois. Mas não podemos obter essa
informação daqui. Só temos acesso
à Hurt Box e não à caixa de acerto
que causou o dano. Então, passando para
o script Hit box, aqui temos acesso tanto
à hit box quanto à Hurt Box. Então, vamos adicionar isso como outro argumento passado
pela função take damage. Podemos calcular a
direção de A para B subtraindo A de B e, em
seguida, normalizar Normalizando, ignoraremos
a distância entre A e B definindo o
comprimento do vetor como um De volta ao script Hurt Box, adicionaremos o parâmetro de
direção. Quando nossa caixa de rebanho
receber danos, emitiremos o sinal e passaremos na
direção com Nosso script de personagem
agora pode reagir a esse sinal. Vou renomear a função
conectada para nenhum dano recebido
para simplificar Ok. Primeiro, diremos reprodução
da animação Hurt que chegue
ao estado de sucesso Em seguida, adicione também uma força
ao corpo do personagem na
direção do dano. Como a direção
está normalizada, ela terá um
comprimento de um pixel Podemos multiplicar isso
por qualquer número que quisermos para alterar o impacto da força de
retração. Você pode até querer
exportar isso como uma nova variável para que possa ser ajustado para cada caractere
individual Também precisaremos fazer essa conexão de sinal em
todas as cenas de nossos personagens. Vamos experimentá-lo.
Meu personagem agora pode atacar o inimigo e o
inimigo reage ao ser atingido
tanto pelo jogo quanto pela animação,
e uma força de
repulsão também é aplicada O mesmo acontece com meu personagem quando o
inimigo me ataca. Agora temos nossos personagens
reagindo ao receber danos, mas nosso combate não
parece muito interessante. Te vejo no próximo vídeo.
59. Suco: Olá, amigos. Neste vídeo, adicionaremos alguns efeitos de
partículas ao
nosso combate para torná-lo
mais impactante Começando na cena do nosso
personagem de jogador, adicionaremos um novo tipo
de nó à nossa cena, um nó emissor de partículas Godot tem dois
tipos diferentes, CPU e GPU. O nó de partículas da CPU
renderizará as partículas da mesma forma que
desenhamos os sprites de nossos personagens usando o processador
central do dispositivo, que é menos eficiente, mas mais
compatível com dispositivos mais antigos Já um
nó de partículas da GPU delegará desenho dessas partículas inteiramente à placa gráfica do dispositivo,
que é mais eficiente, mas
apenas em O nó de partículas da GPU pode lidar com número
muito maior de partículas sem sacrificar Eu só recomendaria
usar partículas de CPU se você estivesse focando especificamente em um telefone ou tablet para seu jogo Caso contrário, você deve
usar partículas de GPU. Adicionando um
nó D de partículas de GPU à cena do nosso personagem, vou apenas chamá-lo de partículas, movê-lo para cima para ficar
no centro
do personagem e dar uma
olhada em suas propriedades
no inspetor Antes que um emissor
de partículas extraia qualquer coisa, ele precisa de um material de processo Esse é um recurso que informa
ao emissor como gerar partículas e como as partículas devem se comportar depois de
serem Há duas opções diferentes
para nosso material de processo,
um material de processamento de partículas
ou um material Shadum O
material do processo de partículas será criado como um recurso do projeto que
podemos editar aqui mesmo
no inspetor, enquanto um
material sombreador nos permitirá escrever um script de Shader
para fazer a Os scripts de sombreamento
não são escritos em GDScript como todos os
nossos scripts Eles são escritos no sombreador GD, que não será
abordado neste curso Então, em vez disso, usaremos um
recurso de material
de processamento de partículas vez disso, usaremos um
recurso de material
de processamento Clique no recurso para visualizar
e editar suas propriedades. Agora que nosso nó
emissor de partículas tem um material de processo, ele gera pixels
brancos individuais de seu ponto de origem
que caem devido à gravidade Para tornar as partículas
mais fáceis de ver, vou esconder o sprite do meu personagem Antes de entrarmos em cada propriedade
individual, é útil
desligar primeiro a gravidade, que está abaixo da seção de
aceleração. E como essas
partículas
serão usadas para causar impacto
durante o combate, vou definir sua
explosividade Eu tenho uma folha de sprite que gostaria de usar
para minhas partículas, então vou importá-la para minha
pasta de efeitos atribuí-la como minha propriedade de textura de
emissores de partículas Mas isso apenas desenha a folha de sprite
inteira
para cada partícula Para animar uma partícula, precisamos fornecer a ela
um material personalizado acordo com as propriedades
herdadas do Criaremos um novo material de item do
Canvas e ativaremos sua propriedade de
animação de partículas. Agora podemos alterar o número de quadros de animação
horizontal e
verticalmente na As partículas agora estão desenhando
apenas o primeiro quadro. Expandindo a seção
de animação do material do
processo de partículas, podemos definir a
velocidade de animação das partículas Quero que minhas partículas
tenham uma velocidade consistente, então vou definir o
mínimo e o máximo como um. Uma curva também pode ser
usada aqui para alterar
a aleatoriedade da velocidade de animação de cada
partícula E os mesmos valores
também podem ser fornecidos para
dar a cada partícula seu
próprio deslocamento de animação Expandindo a seção de extensão, podemos editar a posição em que
as partículas serão geradas, seu ângulo de rotação e
sua velocidade inicial Podemos mudar a forma
da emissão de um único ponto para uma variedade de outras formas e alterar o tamanho
da forma, se quisermos. As formas de emissão pontual
geralmente são as mais apropriadas
para partículas de combate. O ângulo permite a randomização
da rotação das partículas Para torná-lo completamente aleatório, basta definir o máximo para 360. Como estou usando pixel art, não
quero que minhas
partículas sejam giradas A velocidade inicial fará nossas partículas pareçam
mais explosivas A quantidade de força
será aleatória para cada partícula
entre mínimo e máximo, fazendo com que as partículas
pareçam menos O spread
criará uma forma de leque. Maximizando a 180 graus, a direção será
completamente aleatória A seção de velocidade animada contém variáveis
que você pode usar para aplicar uma variedade de velocidades constantes
diferentes às
suas partículas ao longo
de sua Angular fará com que eles girem. Directional
continuará a
movê-los em qualquer direção em que já
estejam se movendo Orbital fará com que
orbitem em torno do ponto de desova. O rádio os afastará
do ponto de desova. E o limite de velocidade usa uma curva para limitar a
velocidade de cada A
seção de acelerações contém variáveis
semelhantes que você pode usar para afetar
gradualmente a velocidade de cada
partícula ao longo de sua vida útil, que fará com que
pareçam mais realistas A gravidade é uma força constante em uma direção para todas as partículas. Linear é a direção que a partícula já
está se movendo Radial está longe do ponto
de desova. E tangencial é
semelhante ao orbital. O amortecimento é uma
força útil que fará com que as partículas desacelerem ao
longo de sua vida útil, que é útil para partículas explosivas
ou de impacto,
como as como Os atratores de partículas
não estão disponíveis para dois D, então essa configuração não
fará nada Expandindo a seção de exibição, podemos mudar a forma como
cada partícula é desenhada A escala fará com que as partículas
randomizem seu próprio tamanho. Se adicionarmos uma curva de escala, isso mudará a
forma como cada partícula muda sua escala
ao longo de sua vida útil Examinaremos o editor de
curvas em breve. Em vez disso, a escala sobre a velocidade fará com que a escala das partículas seja relativa à sua velocidade e não à
sua Isso é particularmente útil para criar nuvens de poeira
que se dissipam As curvas de cores têm várias propriedades
diferentes, começando com uma
cor base para todas as partículas A rampa de cores nos permitirá fazer um gradiente com cada partícula progredindo da cor para a esquerda para a
cor à direita
ao longo de sua vida útil Essa cor é multiplicada
pela cor base para
produzir o resultado rampa inicial de cores
randomizará a cor inicial de cada
partícula no gradiente A curva de emissão
pode ser usada para fazer com três partículas D emitam quantidades
diferentes de luz
ao longo de sua vida útil, o que não é usado em duas D. A curva Alfa é
útil apenas para editar o Alfa de suas
partículas durante sua vida Vamos criar um novo recurso de
textura de curva aqui. Esse recurso de textura de curva
requer outro
recurso de curva próprio. Clicar aqui abre
um editor de curvas que
podemos usar facilmente para criar uma
grande variedade de efeitos. O eixo X desse gráfico é tempo, com zero sendo
quando a partícula é gerada e um sendo o fim da vida útil
da partícula. Não, 1 segundo. O eixo Y é o
valor que estamos editando,
que são as
cores das partículas Alfa, uma sendo opaca e
zero sendo Podemos editar os valores mínimo e
máximo do nosso eixo, mas não precisamos
fazer isso nesse contexto. Basta clicar
no gráfico para adicionar um ponto que podemos
arrastar conforme necessário. Quero que minhas partículas comecem
opacas e se tornem invisíveis ao
longo de sua vida útil Isso é ótimo para
fazer com que as partículas
desapareçam em vez de simplesmente desaparecerem tangentes são aplicadas
automaticamente aos pontos para criar uma curva Selecionando qualquer ponto
no gráfico, podemos editar as tangentes para criar qualquer tipo de
curva que precisarmos Também podemos
editar manualmente os pontos e tangentes expandindo a seção de
pontos na parte inferior variação de matiz pode ser usada para aleatorizar a tonalidade das cores das partículas,
o
que faz com que pareçam menos uniformes. O resto das
propriedades não são muito aplicáveis ao nosso projeto tot, mas vou dar um breve
resumo de para que servem A turbulência pode ser aplicada para simular como as correntes de ar
afetariam suas partículas Você pode editar o padrão de
ruído usado para calcular a turbulência
quando ele é ligado As partículas podem ser interrompidas
ou mortas por colisões. As colisões aqui não são
as mesmas que usamos até
agora, porque as partículas estão sendo manipuladas
pela placa gráfica Eles só podem colidir com oclusores de
luz, não E se suas partículas escalarem
, seu raio de colisão também
pode ser escalado com elas. E um subemissor pode ser usado para criar efeitos
como fogos de artifício, gerando Para fazer com que minhas partículas correspondam às outras taxas de quadros do
meu jogo, definirei a
vida útil das partículas oito quadros divididos por
12 quadros por segundo. Agora que o
emissor de partículas está configurado, devemos definir sua propriedade de
disparo único Agora, ele só emitirá
partículas em uma única explosão, que podemos acionar
por meio de nosso script Vou ativar o
sprite do meu personagem novamente e, em
seguida, abrir o script do meu personagem Dando ao
nó de partículas um nome exclusivo, podemos armazená-lo em uma variável
com a tag on ready. Então, quando o personagem
sofre dano, podemos fazer com que a neve emita partículas definindo sua propriedade
emissora Observe que isso não funcionará
se usado em rápida sucessão, pois o emissor de partículas já
estará
emitindo já
estará Portanto, apenas definir a emissão como verdadeira não
gerará mais partículas momentos como esse,
convém gerar um novo nó de partículas de GPU para cada ocorrência ou chamar a função de
reinicialização reinício forçará o emissor de
partículas a interromper sua emissão atual e recomeçar com um novo
conjunto de Lembre-se de copiar esse nodo para as
cenas inimigas conforme necessário. Vamos experimentá-lo.
Atacando o inimigo, eles agora emitem partículas
quando são atingidos E o personagem do jogador também emite partículas ao
receber dano Agora temos efeitos de partículas
desencadeados por nossos ataques, mas
podemos fazer mais para tornar combate ainda mais crocante Te vejo no próximo vídeo.
60. 8-4 Agite: Olá, amigos. Neste vídeo, adicionaremos uma
vibração de câmera que pode tornar o combate
ainda mais impactante Começando no script da câmera, precisaremos de uma variável que
possamos usar para sacudi-la, que será um vetor dois. Embora existam várias maneiras
diferentes de criar
um efeito de vibração da câmera, acho que faz
sentido usar uma interpolação, pois é uma alteração de propriedade que ocorre em
um período específico Então, vamos declarar uma nova
variável de interpolação chamada shake tween. Em seguida, declare também uma
nova função que
estará acessível ao público e
que pode sacudir a câmera Primeiro, verifique se a câmera já
está tremendo, verificando se a interpolação de vibração já
existe e, em caso afirmativo, mate-a Podemos então criar uma nova interpolação. Não há
necessidade real de tipos especiais de transição ou flexibilização para isso Não queremos interpolar uma propriedade uniformemente de
um valor para outro, mas apenas chamar um método várias vezes
em um curto período Precisaremos declarar a
função que chamaremos,
mas vou chamá-la de set shake
como uma função privada Em seguida, precisamos
fornecer um argumento para passar para a função
do início ao
fim da interpolação Essa será a intensidade do efeito
de agitação
medida em pixels Podemos aceitar isso
como um parâmetro
da função de vibração para que qualquer script que
deseje
acionar a vibração da câmera possa
especificar a intensidade. Então, ao longo da duração
da trepidação da câmera reduza
gradualmente a
intensidade até zero. Opcionalmente, você pode
querer
tornar esse outro
parâmetro se quiser
permitir tremores de câmera que tenham
uma intensidade consistente ou
crescente O argumento final é
a duração de between, que também podemos
transformar em outro parâmetro. Em seguida, escreveremos a função
set shake, que aceita a
intensidade como parâmetro. Essa função será chamada cada quadro
durante a vibração, com a intensidade
mudando gradualmente do valor fornecido na chamada da
função original para zero. Então, tudo o que precisamos fazer é definir o valor de shake
para um novo vetor dois. Se começarmos com o
vetor de dois pontos à direita, rotacione-o em uma direção
aleatória Um ângulo de rotação aleatório pode ser uma flutuação aleatória
entre zero e tau Podemos então multiplicar os
resultados pela intensidade. Se, por algum motivo, sua
interpolação não terminar com a definição do
valor da vibração como zero, você
precisará fazer isso
no final da Podemos conectar o sinal finalizado da
interpolação de trepidação
à função de vibração definida e
vincular zero como Isso garantirá que o
valor da vibração a qualquer momento após a câmera terminar tremer seja
redefinido para zero Para fazer com que o vetor de vibração
realmente mova a câmera, tudo o que precisamos fazer é adicioná-lo
à posição da câmera em
nossa função de processo. Como em nossa cena de jogos, agora
podemos conectar qualquer
sinal que desejamos para acionar a vibração da câmera à função de vibração da
câmera. Como, por exemplo, quando
o personagem do jogador ataca um inimigo ou
quando ele recebe dano. No script do personagem do jogador, podemos adicionar sinais
para esses eventos. Então, de volta à cena do jogo, podemos conectar esses sinais à função de vibração da câmera. Para adicionar argumentos
a uma conexão de sinal, precisamos expandir a seção
avançada. Em seguida, podemos selecionar
float na lista de tipos de argumentos, já que
o parâmetro de intensidade é um float em nosso script Em seguida, clique no botão Adicionar. A vibração também precisa de uma duração, que também é do tipo flutuante Assim, podemos clicar no botão Adicionar novamente para adicionar outro flutuador Os valores que fornecemos
para o Argumento 1
alterarão a intensidade da
vibração medida em pixels, e o Argumento 2 será a duração da
vibração em segundos. Vou fazer com que meus personagens de jogadores ataquem e façam a câmera tremer com uma intensidade de quatro pixels em um
quarto de segundo. Mas quando eles recebem danos, eu vou sacudir a câmera
com uma intensidade de oito pixels em
meio segundo. Passando para a cena do personagem do
jogador, precisamos emitir esses sinais
nos momentos apropriados,
começando com o sinal de
dano recebido de nossas caixas de ferimento, que já está
conectado a uma função chamada de dano recebido
no script do personagem Se substituirmos essa função no script do personagem do jogador, podemos chamar a função de
superclasse emitir
o sinal Em seguida, podemos selecionar
a caixa de acerto e adicionar outra conexão de sinal
ao sinal
inserido na área ativada e fazer com que
ela chame uma nova função. Vamos nomear isso
em Attack Landed. Isso não
precisa se preocupar com o outro nó de área, então podemos usar a seção
avançada para desvincular esse argumento
da conexão do sinal Como desvinculamos
o argumento da área, a função não tem parâmetros Tudo o que essa função precisa fazer é emitir o sinal para
fazer a câmera tremer Não, vamos experimentar. Se eu atacar o mouse Knight, isso aciona o sinal inserido
nas caixas de acerto, que percorrerá o personagem
do jogador até a cena do jogo e
acionará
o tremor Deixar o mouse Knight
bater no personagem do jogador aciona o sinal recebido
danificado da caixa Hurt, que causa uma trepidação mais
intensa Agora temos nossa câmera
tremendo em resposta ao personagem
do jogador atacar inimigos e receber danos, mas nossos personagens não morrem
quando ficam sem saúde vejo
no próximo vídeo.
61. 8–5 Morte: Olá, amigos. Neste vídeo, nossos personagens morrerão quando ficarem sem saúde. Começando na cena noturna
do mouse, selecionando o nó
Animation Player, farei rapidamente uma
nova animação morta duplicando a animação de
sucesso Depois de mudar o sprite para a moldura correta
na folha de Sprite, é uma boa ideia desligar
a Hurt Box para que ela não receba
mais danos e
não a ligue novamente O mesmo pode ser feito em todas as outras áreas
dos nós Di, desativando o dano de contato
e a caixa de acerto dois, para que o inimigo morto não possa mais causar dano ao personagem
do jogador. Selecionando o nó
Animation Tree, podemos adicionar essa animação morta
à máquina de estado e fazer a transição automática para ela se esse personagem estiver morto. Ao contrário de outras animações,
não há necessidade de uma transição para
fora do estado morto Agora só precisamos adicionar essa variável Is dead ao script do
personagem. Vou colocá-lo no topo
do script como um booleano. E também declare um sinal de
morte dois, caso
queiramos
que alguma coisa reaja
à morte de certos
personagens Em seguida, escreva uma função pública
chamada die que definirá o valor dessa variável como
true e emitirá o sinal Em qualquer lugar neste script
em que um personagem possa realizar qualquer ação que não
deveria ser permitida
depois de morrer, podemos simplesmente verificar primeiro o valor da variável is dead. Então, se o personagem for
instruído a ficar de frente para uma direção, mas ele estiver morto, ele
deve ignorar esse pedido. Da mesma forma que ignoramos
se eles estiverem atacando. Da mesma forma, se esse personagem
for instruído a pular, mas ele estiver morto,
ele não deve pular. O mesmo acontece com o ataque. E no processo de física, também
definirei
a direção de
movimento deles para zero se estiverem mortos, para que nunca
se movam enquanto estiverem mortos, mas sejam afetados pela física. No script Hurt Box, já
criamos o
sinal tingido e o emitimos quando o personagem fica
sem saúde quando
escrevemos o roteiro na seção
anterior Mas para reproduzir
uma animação de morte e não uma animação de sucesso
quando o personagem recebe dano e
morre como resultado, precisamos ter certeza de que
emitimos apenas o sinal tingido naquele
momento Então, vamos mover o sinal de dano recebido
para um bloco se, dando prioridade ao sinal tingido Tudo o que precisamos fazer é conectar o sinal tingido da Hurt Box à função de dados
do inimigo
para acionar a animação Seja na cena do inimigo
ou na cena do conteúdo da sala, onde quer que você tenha os nós de IA do seu
inimigo, você também pode
conectar o
sinal did do inimigo à
função livre desses nós. Como alternativa, você pode fazer isso
nos próprios scripts. Substituindo a função de prontidão, o inimigo morto pode ser
conectado ao ure. Isso evitará que você
precise conectar o sinal manualmente centenas de vezes
em todo o projeto. Vamos experimentá-lo. Se eu atacar o rato
Knight cinco vezes, sua saúde chega a
zero e ele morre, que reproduz a animação da morte, e interrompe todas as ações Também posso tocá-lo
sem sofrer nenhum dano. Agora, para o personagem do jogador, eu realmente não tenho sprites de
animação de morte para esse personagem Em vez disso, o que farei é
reutilizar a animação de sucesso, duplicando-a para criar
uma animação de morte,
pois sei que, quando
esse personagem morrer, a cena do jogo desaparecerá e será
reiniciada de qualquer maneira Como o inimigo,
é uma boa ideia também desligar todas as
caixas feridas e as caixas de acerto. A única mudança real que farei
aqui é fazer com que a
animação seja repetida. Na Árvore de Animação, adicionarei a animação morta, a mesma de antes, com uma transição automática
se o personagem estiver morto. Mas desta vez, adicione também
uma transição para fora
do estado morto sob a condição de que eles não
estejam mais mortos, já que o personagem do jogador será revivido após sua morte Depois de conectar o sinal de
morte do Hurt Box ao script do
personagem, vou mudar para o script do personagem do
jogador. Precisaremos escrever uma função de
reanimação que possa ser usada para trazer o
personagem do jogador de volta à vida, redefinindo a
variável I dead como falsa Também podemos pedir ao Hurt Box que recupere a saúde total ao
mesmo tempo. Para adicionar mais à animação de morte do
personagem do jogador, vou substituir a função de dado no script do personagem do jogador Começarei chamando
a função de superclasse depois farei outras coisas específicas para o personagem do
jogador Reutilizando o nó de
efeitos de partículas, definirei sua
propriedade de disparo único como falsa, sua explosividade E está emitindo a
propriedade em verdadeira, transformando a explosão instantânea de partículas em
um Além disso, também vou interpolar a cor de modulação do personagem para aumentar a intensidade Depois de criar uma nova interpolação, vou interpolar a cor de
modulação desse nó para
uma nova cor com
valores RGB Então, na função de reviver, vou colocar tudo isso de volta
em seus valores normais Assim como na cena do jogo, a câmera também pode reagir à morte
do jogador com outro tremor de câmera
ainda mais intenso. O gerente do jogo
também precisará reagir
à morte
do personagem do jogador para reiniciar tudo. Assim, podemos conectar o sinal dD do
personagem do jogador ao script do gerenciador de jogos. Vamos nomear essa
função no Player DD. Quando o jogador morre, primeiro, podemos desativar o manipulador de entrada para que ele não possa mais
controlar o personagem Vou esperar 1 segundo primeiro para deixar a animação de
morte do meu personagem ser reproduzida, o que pode ser feito mandando a árvore de cenas
criar um cronômetro Podemos obter a
árvore de cena a qualquer momento usando a função get tree e chamar
a função create timer, que aceita um argumento
para a duração do Isso retorna o cronômetro já iniciado para que possamos aguardar
o sinal de tempo limite Isso pausará a execução
dessa função nessa linha
por exatamente 1 segundo Depois de ficar preto, precisaremos reposicionar personagem
do jogador para onde
queremos que ele responda Como ainda não temos sistemas
adequados para lidar com isso, vou colocá-los na origem da cena
do jogo e deixar um comentário de que isso precisa ser
implementado posteriormente. Agora podemos reviver o
personagem do jogador, voltar
e reativar o manipulador de entrada
para que o jogador possa
continuar jogando Se você quiser
exibir algum texto, você pode adicionar um nó
de rótulo na camada Canvas. Vou nomear Mind game over
e dar a ele um nome exclusivo. Em seguida, preencha-o com
algum texto e centralize-o. Dê a ele um tamanho de fonte maior. E fixe-o no
centro da tela. Antes de ficar preto, também
criarei
uma interpolação que
desbotará o
Alpha da etiqueta em até Vou modular seu Alpha para zero, que fique invisível por padrão Sem esperar,
isso acontecerá ao mesmo tempo em que a
tela estiver ficando preta A etiqueta precisará
ser desenhada na frente do desbotamento
para ficar visível Depois de reposicionar
o personagem do jogador, espero mais 1 segundo antes de ler o texto Mas vou fazer com que seja
mais rápido do que desapareceu. Depois de reviver o personagem do
jogador, exibirei uma mensagem diferente à medida que o jogo volta Vou duplicar a mensagem existente do
game over, nomear esta como revive e alterar o Antes que o esmaecimento fique claro, usarei outra interpolação para
fazer esse texto desaparecer Aguarde mais 1 segundo e,
em seguida, diminua o texto novamente. Vamos experimentá-lo. Vou deixar a noite do Mouse matar
meu personagem jogador. Agora temos nossos
personagens morrendo e o gerente do jogo reagindo à morte do personagem do jogador, mas nosso jogo ainda não
tem um chefe Te vejo no próximo vídeo.
62. Chefe 1: Olá, amigos. Neste vídeo, criaremos um chefe para nosso jogo que seja
mais complexo do que nossos outros inimigos. Começarei criando uma nova pasta de ativos para armazenar
os ativos desse chefe. Em seguida, importe os sprites. Em seguida, criarei uma
nova cena na minha pasta de
cenas inimigas chamada Mac Mouse
com um nó raiz do tipo CharacterBody two D. Esse chefe é composto por vários componentes de sprites
diferentes que precisarei montar
e sobrepor um ao outro Primeiro, adicionarei um D
normal sem dois que eu possa usar para inverter todos os
componentes visuais
do chefe quando eles se
virarem e chamá-lo de flip componentes visuais
do chefe quando eles se
virarem e chamá-lo Em seguida, adicione vários sprites
para os vários componentes. Vou precisar de um sprite para
a blindagem, que terá a textura de um E depois de preencher
a textura, selecionarei a
região apropriada na planilha de sprites Isso será
compensado em 48 pixels. Duplicando esse nó de sprite, renomearei este para engrenagens e mudarei seu tipo para Animated Sprite two
D. Dando
ao nó um recurso de quadros de
Sprite,
adicionarei os sprites de engrenagem à Em seguida, altere a
velocidade da animação para 12 quadros por segundo. Isso deve ser desenhado
atrás da blindagem,
então vou reordenar então vou reordenar Duplicando novamente o nó do sprite
blindado, criarei outro sprite para o fundo por das Depois de tornar a
textura do atlas exclusiva desse nó, posso selecionar uma região
diferente para desenhar e reordenar esse nó para ser
desenhado atrás dos Esse fundo também
serve para prender as engrenagens para que qualquer coisa fora
do corpo não seja desenhada Podemos fazer isso
colocando as engrenagens como filhas do nó de
fundo Em seguida, selecionando o plano de fundo na
seção de visibilidade, altere os filhos do clipe de
desativado para recortar e desenhar. Agora, as engrenagens
só entram no corpo. Há também uma
tecla de ativação que é animada. Então, vou duplicar meu nó de
engrenagens para criar
outro nó de
tout do Animated Sprite e chamá-lo de key Depois de tornar o recurso Sprite frames
exclusivo para esse nó, substituirei os frames Sprite de engrenagem pelos quadros
principais de sprite Em seguida, reposicionarei
a chave para ficar
na posição apropriada na parte de trás
do corpo do mouse Mc Vou precisar de mais
dois nós D do Animated Sprite para as rodas, então vou duplicar a chave
para criar uma roda animada Depois de tornar o recurso Sprite
frames exclusivo,
trocarei as
principais molduras Sprite
pelas molduras de sprite de roda Em seguida, coloque a roda em uma boa posição e
coloque-a no chão O. Para desenhar as rodas atrás do corpo, vou reordená-las para que fiquem acima
do corpo na árvore da cena Vou duplicar a roda
dianteira para fazer uma segunda roda
e reposicioná-la O último componente visual
desse chefe é um barril que
se estende de sua boca, que será apenas
um sprite comum Depois de atribuir a textura do
sprite, vou movê-la para ficar ao redor da boca do mouse Mc e
colocá-la atrás
dos sprites corporais I Quando esse cano dispara projéteis, quero que ele saia
da boca do mouse Mc, para que tenha um deslocamento Vou adicionar uma área do
nó Tutti nesta posição, que será o projétil Em seguida, forneça a ele um nó Animated
Sprite Tutti com o recurso Sprite frames e adicione os
dois quadros de sprite de bola de fogo Depois de definir a taxa de quadros, também
terei essa reprodução
automática por padrão. Isso precisará de uma forma de
colisão, que será apenas um círculo Para funcionar
como um projétil, ele precisará do
script do projétil anexado O script do projétil espera que o projétil tenha
uma animação de impacto, então vou adicionar uma usando os mesmos sprites
de impacto do meu Isso precisará monitorar
e mascarar a camada
Hurt Box do jogador Podemos conectar os sinais da área inserida
e do corpo ao script do projétil para
acionar a animação do impacto e os danos O. Com a bola de fogo montada, podemos salvá-la como sua própria cena
na pasta do projétil Vou adicionar um marcador de
nó Toti como filho da bola de fogo para atuar como
o local onde
os
projéteis aparecerão, assim como fizemos Em seguida, reordene o
marcador Tutti node para ser irmão da bola de fogo,
mantendo sua posição
relativa e exclua a bola mantendo sua posição
relativa para ser irmão da bola de fogo,
mantendo sua posição
relativa e exclua a bola de fogo. Em seguida, redefina o
deslocamento dos cilindros para sua posição
padrão Além de virar
o corpo para a esquerda e para a direita, também
quero que o corpo
do mouse Mc faça barulho
, mas não as rodas Então, vou colocar tudo o que
quero dizer como filho de outro corpo
sem dois nomes D. Sempre que o mouse Mc estiver se movendo, quero que poeira e pedras sejam levantadas do
chão pelas rodas Então, vou adicionar um nó D de
duas partículas GP para as rochas. Em seguida, atribua um sprite de rocha como textura e faça um material de processamento de
partículas OK. Faça as pedras
se levantarem do chão, tudo o que eu realmente preciso fazer é mudar a direção da velocidade para cima e dar a cada pedra uma velocidade aleatória de 32 a 64
pixels Para poeira, vou começar
duplicando o
emissor de partículas de rocha e Em seguida, atribua a mesma folha de sprite de
partículas que usei para impactos de ataque como propriedade
de textura Como essa é uma folha de sprite que deve ser animada, esse nó precisará de um material de item de
tela com sua
propriedade de animação de partículas
ativada com o
número correto de quadros Depois de tornar o material do
processo de partículas único, manterei a mesma velocidade,
mas removerei a gravidade e adicionarei amortecimento suficiente para neutralizar
a Na tela, adicionarei uma velocidade
de animação de 1 para animar as partículas e uma curva alfa para fazê-las
desaparecer com o tempo. Eu quero isso desenhado na frente, então vou definir sua
propriedade de ordem como 1. Isso deve ser suficiente, então vou duplicar os
dois nós de partículas e adicioná-los à outra roda Não quero que eles
emitam por padrão, então vou agrupar todos eles e desativar suas
propriedades de emissão Assim como qualquer outro inimigo, este precisará de uma
forma de colisão para colidir com o ambiente, além de
caixas feridas e caixas de acerto Como esse inimigo tem uma forma
mais única,
usarei um polígono de colisão em
vez de uma vez Adicionando alguns vértices
ao polígono para obter a forma geral do corpo
do chefe, precisarei garantir que o polígono de colisão entre em contato com
o Eu também não quero me
preocupar em inverter esse polígono, então vou Isso será suficiente para colisões
com o ambiente, mas também permitirá que o personagem do jogador fique
em cima do inimigo Para a Hurt Box,
estou um pouco menos preocupado em
combinar o formato do inimigo tão de perto, então vou usar uma cápsula comum. Se você quiser combinar várias formas padrão para
criar uma Hurt Box mais complexa, basta adicionar mais nós de formas de
colisão Vou adicionar uma segunda cápsula acima da primeira para
cobrir mais partes do corpo. Eu também não quero preocupar em virar
essas caixas Hurt, então ajuda que elas
sejam O nó D da área dois
emitirá seus sinais como se todas as formas estivessem
combinadas em uma forma Mas lembre-se de que, se
as formas estiverem distantes,
você pode fazer com que algo
entre em uma forma de colisão,
depois saia dela e, em seguida, entre outra forma de colisão
causando várias Também adicionarei uma Hurt
Box separada para a tecla wind up. Dar a essa chave sua
própria Hurt Box significa que ela não precisa estar
conectada à saúde do chefe, mas pode emitir sinais quando
o jogador a ataca Isso pode ter apenas uma forma simples de colisão
circular, mas precisará ser invertido Então, vou me certificar de que
a exposição
do nó de forma é o que determina de que lado
a Hurt Box está E, finalmente, esse
inimigo precisa de uma caixa de sucesso. Isso será usado quando o mouse
Mc for carregado para frente. Eu quero que isso machuque o personagem do
jogador
se ele estiver na frente ou
em cima do chefe. Então, vou usar uma cápsula girada em
90 graus que se estende além do polígono de
colisão do corpo
na frente e acima dele, mas
não atrás dele Ao selecionar o nódulo raiz
do
corpo do personagem, o inimigo precisará
ser considerado terreno para que o
personagem do jogador fique nele, mas também
exista na camada
inimiga e mascare apenas o terreno Nenhuma das caixas Hurt
ou das caixas de sucesso
precisará ser monitorada ou
monitorável por padrão Nós os ativaremos por
meio de scripts ou animações quando
precisarem ser ativados Mas as caixas Hurt podem ser configuradas para
a camada de
colisão da Hurt Box inimiga, e as caixas de acerto podem ser
configuradas para mascarar a camada de colisão da
Hurt Box do jogador camada de colisão da
Hurt Box para que, quando
ativadas, funcionem Agora temos um chefe
montado para o nosso jogo, mas ele ainda não tem nenhum
script que o controle. Te vejo no próximo vídeo.
63. Chefe 2: Olá, amigos. Neste vídeo, mostraremos ao nosso chefe alguns comportamentos
mais complexos do que nossos inimigos normais. mecânica real da progressão
será abordada na próxima seção Mas, por enquanto,
ajudará pensar em como nosso chefe deve existir em
relação à sua arena. Então, vamos colocar esse inimigo chefe em uma arena simples com uma
parede em cada lado. modo geral, chefes em Metroidvania prendem o
jogador em uma arena
e, uma vez que o jogador entra, ele deve derrotar o chefe antes de poder sair Este é um evento que
precisará ser acionado pelo personagem
do jogador que entra no
nodo D da Área dois, então adicionaremos um à cena
e o chamaremos de chefe Encounter. Em seguida, dê a ele uma forma de colisão. Vou usar um retângulo e fazer com que ele cubra uma área muito
grande para que o jogador não possa contorná-lo e fazer com que ele monitore o corpo do personagem do
jogador Isso precisará de um
script anexado, mas eu o criarei
na guia
do sistema de arquivos em uma nova
pasta de scripts inimigos para chefes, que podemos chamar de
Boss Encounter, estendendo a Área dois D. Esse script
será responsável por controlar o
fluxo geral do encontro com o chefe, incluindo quando ele
começa, quando termina
e qualquer transição de fase, como cartões de título, mudando a música, etc. Precisaremos dar a
isso um nome de classe para que possamos estendê-lo posteriormente. Para reagir à
entrada do personagem do jogador nesse encontro com o chefe, podemos escrever a função
on body entered, que aceitará
um parâmetro chamado body do tipo no two D
e não retornará nada. O personagem do jogador entra
nesse encontro com o chefe. Primeiro, devemos desativar
todas as colisões futuras com essa área
usando set deferred para definir a
propriedade de monitoramento Lembre-se de que quando uma função é chamada por um evento de colisão, não
devemos alterar nossos
objetos de colisão ao mesmo tempo, então adiamos isso até que as colisões
tenham sido Podemos então fechar a arena, prendendo o jogador lá dentro e realizar qualquer
inicialização necessária Mas vamos falar sobre isso mais tarde. Por enquanto, declararemos uma variável
exportada que mantém o próprio chefe inimigo e outra para o
personagem do jogador como Quando o personagem do jogador
entra no encontro com o chefe, podemos definir o valor do
alvo como o corpo, bem
como uma
variável de fase local como um número inteiro Em seguida, adicione uma função inicial,
uma função final e também uma função de
transição de fase, aceitando a fase
como parâmetro e atualizando a variável
para seu novo valor. Na função de início,
podemos definir a fase como uma e chamar nossa função de
tomada de decisão para
iniciar a luta. Também precisaremos de uma função que diga ao chefe o
que fazer a seguir. Por enquanto, chamarei a função Start quando o personagem do jogador
entrar na arena do chefe. Certifique-se de salvar esse script para que o nome da classe seja registrado. Agora que temos a estrutura
básica pronta, vamos anexar um novo script
ao nosso nó de encontro com o chefe. Vou nomear isso em homenagem ao meu chefe, Neck Mouse Encounter Extending Boss Encounter e salvá-lo
na pasta apropriada Com o script anexado, podemos atribuir o chefe inimigo
à variável exportada, definir a máscara de colisão na camada do personagem
do jogador e conectar o sinal
inserido pelo corpo Como a função on body
entered já existe na superclasse Boss
Encounter, não
precisamos nos
preocupar com isso neste script No entanto, substituiremos a
função de tomada de decisão e daremos esse chefe em particular seu próprio algoritmo para decidir
o que ele fará Estruturar o encontro com o chefe dessa
forma torna mais fácil alterar o comportamento de um
chefe com
base na fase em que ele
está atualmente ou adicionar riscos ambientais
à arena em reação às ações do chefe
ou sincronizar o comportamento de vários
chefes em Qualquer novo encontro com chefes que quisermos criar também pode
estender a classe de
encontro com chefes e fornecer suas próprias implementações exclusivas
para cada Primeiro, é uma boa ideia verificar
se o chefe está morto antes de deixar que ele
decida o que fazer a seguir. Então, se eles já estão mortos
, podemos simplesmente voltar. Também é uma boa ideia
espaçar as ações de um chefe com uma breve pausa aguardando o sinal de tempo limite do
cronômetro Podemos torná-lo menos previsível aleatoriamente a duração do
cronômetro e até mesmo fazer
com que a cadência da luta aumente
a cada fase dividindo
pelo E não importa o que o
chefe decida fazer, eles provavelmente deveriam estar
voltados para o alvo. Assim, podemos chamar uma função para
dizer ao chefe que fique virado para a esquerda se a exposição global do alvo
for menor que a deles Usando uma declaração de correspondência
na variável de fase, podemos facilmente fornecer diferentes opções de ação
para diferentes fases. Como meu chefe é tão simples, optarei por aumentar
a intensidade das ações por fase, em
vez de introduzir novas. Com outra declaração de partida
em um número inteiro aleatório de 0 a 1, criarei uma chance uniforme de
decidir entre duas ações
diferentes Ou o chefe se moverá para uma posição aleatória na arena, que será a posição
global desse nó
de encontro do chefe mais um número aleatório entre 300 negativos
e 300 positivos, ou o chefe atirará
bolas de fogo no jogador Vou randomizar o número de
bolas de fogo com base
na fase atual Também quero que o chefe
tenha uma terceira ação, que é atacar o personagem do jogador
em uma velocidade maior, mas somente sob
certas condições. Portanto, se o mouse Mc estiver pronto para carregar, ele será carregado. Se não estiver carregando, a
ação será aleatória. E eu darei o sinal da posição global
do alvo menos
a
posição global do Mc Mouse como direção Planejar quais
ações você deseja seu chefe use
e quando fornece exatamente quais
variáveis e
funções públicas você precisará
escrever em seus scripts. Então, podemos ver nesse script que o script do nosso chefe precisa de
uma variável morta,
uma variável pronta para carregar, e também com a face esquerda,
carregar, mover para a posição e disparar bolas de fogo Essa é uma maneira fácil de abordar o encapsulamento ao
escrever scripts complexos Podemos escrever o script que
precisa interagir com ele
primeiro, para que já saibamos
exatamente do que precisamos. O encapsulamento também nos ajuda a
obter abstração. Como nos concentramos apenas no que precisa ser acessível ao público, também
podemos supor que todo
o resto
deve ser privado. Em seguida, vamos anexar um script ao nó raiz
do MCMus e salvá-lo na pasta de scripts do
inimigo Podemos declarar todas as
variáveis e funções aceitando os parâmetros
correspondentes do script
de encontro do Boss Se declararmos um sinal e o chamarmos de
concluído
, podemos emitir esse
sinal de todas
as ações que foram selecionadas na função de
tomada de decisão Por enquanto, vamos imprimir o que esperávamos que
o chefe fizesse Podemos primeiro verificar se esse
inimigo está morto e, em caso afirmativo, emitir o sinal finalizado imediatamente e retornar
para que nada aconteça Em seguida, aguarde 1 segundo antes de emitir o sinal
finalizado Em seguida, selecione o nó chefe inimigo na
cena de conteúdo, que podemos transferir para o próprio
chefe , se quisermos e
conectar o sinal
finalizado à função de tomada de decisão. Agora, toda vez que esse chefe inimigo concluir qualquer uma das ações, ele
decidirá automaticamente o que fazer a seguir Isso deve ser suficiente
para demonstrar o fluxo de nossa batalha contra chefes.
Então, vamos experimentar. Podemos ver na saída a
cada segundo ou dois que
o inimigo está tomando uma decisão
sobre o que fazer a seguir. Agora temos nosso chefe inimigo sendo controlado por um script de
encontro com chefes, mas ainda precisamos
implementar como tudo funciona
internamente na cena do chefe vejo no
próximo vídeo.
64. Chefe 8-8 3: Olá, amigos. Neste vídeo, mostrarei como escrevi as funções do
meu chefe para que você possa comparar meus métodos a forma como
implementou os seus. Primeiro, anexei
os scripts Hit box e Hurt Box à caixa sucesso
do chefe e às
Hurt Boxes, respectivamente. Em seguida, comecei com os scripts do
chefe inimigo. Eu declarei sinais para qualquer coisa que
fosse usada para iniciar ou encerrar a luta contra o chefe ou
causar uma transição de fase. Outra para quando
o chefe muda direção
para que eu saiba quando mudar as coisas, e mais algumas para saber
quando o chefe chegou
ao destino pretendido
ou bateu em uma parede Depois, há também o sinal, que será omitido quando a
ação decidida atual pelo chefe for concluída, e ele precisa decidir
o que fará a Eu conectei o sinal de mudança de
direção
à caixa de acerto e às
teclas de enrolamento Hurt Box para que elas pudessem
ser giradas Na verdade, o script Hurt Box não tinha essa função, então eu o copiei
do script Hit boox No entanto, as teclas de
ativação Hurt Box estão atrás do chefe, então precisei adicionar
uma variável exportada para reverter a direção
desse caso específico De volta ao roteiro do Mac Mouse, eu precisava de uma referência
ao corpo do chefe
para fazê-lo tremer. Então, isso é armazenado
em uma variável, já que vou
usá-lo com muita frequência. E, claro,
precisarei saber se o chefe está vivo ou morto. Eu gostaria que a luta do meu chefe
começasse com o Mcmuse
desligado e fizesse com que o jogador atacasse a tecla de ativação várias
vezes para iniciá-la Então, declarei uma variável para
saber se o motor
está ou não ligado mais uma
velocidade para a tecla de aceleração, iniciando-a em um
oitavo da velocidade normal, e uma interpolação que posso usar para
alterar a velocidade
gradualmente ao longo do Para criar esse efeito, fiz com que a animação das teclas de enrolamento fosse
reproduzida automaticamente, mas com uma escala de velocidade de zero e seu Hurt Box
monitorável por padrão Em seguida, conectei o
sinal danificado ao script do meu chefe, chamando uma função
chamada on key attack. Para garantir que a
Hurt Box da chave nunca morra, eu a chamo de função de recuperação, já que isso não é um reflexo
da saúde do chefe, apenas outro alvo para o personagem do
jogador atacar Depois de definir a
escala de velocidade de animação das
teclas de enrolamento para dobrar, usei a interpolação para reduzi-la
gradualmente de
volta
ao valor esperado ao longo de 1 segundo Se o motor
já tiver sido ligado
, atacar a
tecla de ativação fará com que o mouse
do Mac carregue em direção ao personagem
do
jogador na próxima ação Caso contrário, dobrei
a velocidade da tecla e verifiquei se ela havia atingido
o valor de pelo menos um Com o
valor padrão de um oitavo, isso acontecerá
após a terceira vez
em que a tecla de encerramento for atacada Quando isso acontece, chamei uma função para ligar
o motor do mouse Mc. Tudo o que essa função faz é fazer a animação das engrenagens comece a tocar, iniciar um cronômetro, que está configurado para um
12º de segundo, o motor dê
partida de
forma variável para verdadeiro e cada 12 de segundo, quando o cronômetro atinge o tempo limite,
eu mudei a posição Y
do corpo para um número inteiro aleatório
entre menos um e um positivo, para
que o corpo suba
e desça eu mudei a posição Y
do corpo para um número inteiro aleatório
entre menos um e um positivo, para
que o corpo suba
e que o corpo suba Fazer o chefe virar esquerda foi muito semelhante
ao que foi feito com o personagem do jogador,
com a exceção de que esse chefe inimigo está
voltado para a esquerda por padrão. Para fazer o chefe
dirigir e avançar em direção ao personagem
do jogador, usei muitas das mesmas variáveis de
locomoção no script
do personagem, mas com nomes diferentes, e também incluí o destino do
chefe e a distância até seu
destino como carros alegóricos, que eu possa usá-las
para determinar aonde o chefe precisa ir no Também incluí a gravidade
por precaução e
defini a velocidade de movimento como
a velocidade de condução por padrão. Salvei as rodas em uma matriz para poder
sincronizá-las facilmente. Embora isso possa parecer desnecessário
para apenas duas rodas, escrevê-lo dessa forma funcionará
para qualquer número de rodas. Usei uma
variável pública para dizer se esse mouse Mc
teve
ou não sua tecla de ativação atacada e está pronto para
realizar um ataque de carregamento e um número inteiro para
contar o número de vezes que ele
colidiu com uma parede Quando o script de encontro com o chefe decide que o
mouse Mc deve se mover para uma posição na arena
do chefe e fornece a posição para a qual se
mover como parâmetro, verificando
rapidamente se o chefe está
morto para verificando
rapidamente se o chefe está que a
solicitação possa ser ignorada, eu armazenei o destino, defini a direção do movimento, a velocidade do movimento e o movimento
está se movendo para verdadeiro. Liguei para uma função privada
para animar todas as rodas e
aguardar meu sinal de chegada
antes de emitir o
sinal antes de emitir o O sinal recebido será emitido posteriormente pelo processo
físico O argumento passado para girar as rodas controla a
rapidez com que elas serão animadas, bem
como se a animação será reproduzida para frente ou para trás Portanto, se o mouse do Mac
estiver voltado para a esquerda e se movendo para a esquerda ou voltado para a
direita e se movendo para a direita, reproduzirei a animação
com a velocidade de um. Caso contrário, uma velocidade negativa reproduz as
animações ao contrário Atacar o personagem do jogador faz basicamente as mesmas coisas. No entanto, quero que o mouse
Mc esteja sempre
voltado para a direção que está carregando e gire
as rodas em velocidade dupla. Usando uma pequena pausa, isso telegrafará
a carga para
o jogador para que ele possa reagir
e sair do Como a carga é um ataque, a caixa de acerto tem sua
propriedade de monitoramento definida como verdadeira. Depois que a configuração estiver
carregando como verdadeira, aguardo o sinal que será emitido após o
Mcmuse bater em uma parede e uso outra breve pausa para manter
o chefe atordoado por um breve o chefe Lembre-se de conectar
o sinal
inserido na área da caixa de acerto para
realmente causar dano. Girando as rodas
e aceitando a direção do
giro como parâmetro,
percorri
cada uma das rodas na
minha matriz de rodas e pedi a cada uma
que reproduzisse sua animação padrão usando o valor absoluto
da direção como a velocidade da animação
e se a direção
era negativa ou não para determinar se a animação
deveria ser reproduzida Também iniciei os
emissores de partículas de rocha e poeira conectados a cada roda ao mesmo tempo, se o valor da direção fosse diferente
de zero Caso contrário, eles
serão desativados. Agora, para o processo de física, que tornará
essas duas ações possíveis, se o chefe já estiver morto, ele não poderá se mover voluntariamente, então sua direção de movimento
será definida como zero Em seguida, apliquei
aceleração ou desaceleração à velocidade X do
chefe, bem
como gravidade à velocidade Y, antes de
chamar
a função de movimento e
deslizamento para
aplicar a velocidade ao corpo do personagem Se o chefe estiver dirigindo no
momento, precisarei verificar se ele
chegou ao destino ou se está carregando e tocando uma parede, então eu sei que ele caiu Para saber se o chefe
chegou ao destino
pretendido, primeiro
preciso saber a
distância até o destino, que é o valor absoluto do destino menos
a exposição global atual do chefe Invertendo a fórmula
da altura do salto, podemos determinar se
o chefe está perto o suficiente do destino para começar
a desacelerar Se a distância for
menor que a velocidade quadrado dividida pela
desaceleração Quando isso é verdade, eu paro de
girar as rodas, defino a direção do movimento
para zero, dirijo para falso e emito
o sinal de chegada Quando o chefe
bate em uma parede, eu fiz a maioria das mesmas coisas, mas também adicionei velocidade de
afastamento da parede para que eles
ricocheteassem nela E desligou a caixa de sucesso. Também contei o número
de vezes que isso acontece
e, no terceiro acidente, danifiquei a blindagem
do mouse Mc para que eles
entrassem na segunda fase Quando a armadura é danificada
por bater muitas vezes, aumentei a velocidade da tecla de
ativação para Para danificar a blindagem, tudo o que eu precisava fazer era
mudar a região da
folha do sprite que estava sendo desenhada
pelo nó do sprite da armadura Também dobrei a velocidade da
tecla de ativação e animações
do equipamento, bem como do cronômetro para tornar a cena
do chefe ainda mais instável cena
do chefe E eu transformei a propriedade
monitorável da Hurt Box em verdadeira para que o personagem do jogador agora
possa atacar o corpo do mouse Mc
para causar dano a ele Em seguida, emitiu o sinal para
acionar a transição de fase. Para atirar nas bolas de fogo, eu precisava de uma cena cheia
para as bolas de fogo, assim
como para as novas bolas de fogo Eu estaria instanciando o marcador de onde instanciá-las,
mais o
cano e uma interpolação para movê-las mais o Quando o chefe é instruído a
atirar várias bolas de fogo, primeiro
esperei
estender o cano,
depois dei uma volta várias vezes, parando um quarto de segundo antes de cada tiro e depois atirando uma bola de primeiro
esperei
estender o cano,
depois dei uma volta várias vezes,
parando um quarto de
segundo antes de cada tiro e depois atirando uma bola de fogo. Depois de atirar em todas as bolas
de fogo, esperei retrair o cano
antes de emitir o antes Estender ou
retrair o cano era uma simples interpolação: entrelaçar canos deslocava X para
o número desejado ao longo de um quarto de
segundo Disparar uma única
bola de fogo é quase o
mesmo que com os projéteis do
personagem do jogador Basta adicioná-lo como irmão colocá-lo na posição
correta e atirar na direção
voltada para frente No meu roteiro de projéteis, ao mandar uma Hurt
Box sofrer dano, eu também precisarei fornecer
a direção do dano Finalmente, quando o chefe
fica sem saúde, eu uso set deferred para
desligar a caixa de sucesso e as
duas caixas de Hurt e interromper todas as animações antes de emitir
o sinal tingido para encerrar
o encontro com Na cena do conteúdo da sala, conectei o
sinal de partida do motor à
função de partida dos
encontros do chefe e o sinal de morte
para encerrar o encontro dois Também conectei o sinal danificado da
armadura à função de fase definida, vinculando dois como argumento para acionar a
transição para a fase dois Comentei a chamada
para a função de partida para
que eu pudesse acionar o
início da
batalha após a
partida do motor. Sim. Ah. Agora
temos nosso chefe executando
uma sequência complexa de ações com
intensidade crescente em várias fases Mas nosso jogo carece de qualquer tipo
de progressão significativa. Nos vemos na
próxima seção.
65. 9-1 Save Point: Olá, amigos. Nesta seção, transformaremos essas duas plataformas
D em uma Metroidvania
rastreando adequadamente o progresso do jogador Começaremos adicionando um ponto de
salvamento ao nosso jogo. Mudei meu
encontro com o chefe para sua própria sala e o
movi para o lado do meu mapa em uma região vulcânica separada, e também criei uma nova sala de salvamento para minha
região florestal à esquerda Eu deixei meu
personagem de jogador aqui. Vou apenas redefinir a
posição deles de volta à origem. Vamos começar com os dados
salvos dos jogadores, onde precisaremos armazenar o local em que
o jogador
salvou o jogo pela última vez. forma como você armazena essas informações varia de acordo com a
estrutura do seu jogo. Mas para o meu jogo, vou
usar uma variedade de cordas. Embora possa ser
mais eficiente
armazenar pontos de salvamento como números, essa é apenas uma única variável,
portanto, o impacto
será insignificante Também ajuda a manter o arquivo salvo legível
por humanos para fins de depuração O primeiro elemento
da matriz será o
nome da região e o segundo será
o nome da sala. Esse padrão segue a
estrutura da minha árvore de cenas. Quando carrego os dados salvos do
jogador, tudo o que preciso fazer é encontrar a região que corresponde à
primeira string, depois encontrar a sala que
corresponde à segunda string e posicionar o personagem do
jogador no ponto de salvamento dessa sala. Observe que esse ponto de salvamento deve existir
no jogo no momento os dados salvos
estão sendo carregados e nenhum conteúdo da sala
foi carregado ainda. Portanto, o
objeto Save Point deve estar na cena
da sala e não na cena
do conteúdo da sala. Vou adicionar um nó dois D à cena da
minha sala de salvamento e
chamá-la de ponto de salvamento Para simplificar as coisas, colocarei esse nó
na posição em que eu
quero gerar o personagem Como precisaremos
ter vários desses
pontos
de salvamento em nosso jogo, ele deve ser salvo
como sua própria cena. Em seguida, podemos
editá-lo isoladamente. A forma como você deseja ativar seu ponto de
salvamento depende de você. Vou usar apenas um evento de
colisão simples. Portanto, sempre que o jogador
tocar em um ponto de salvamento, seu progresso será Então, adicionarei um nó D de área dois
à cena e o deslocarei do chão em 96 pixels para que o jogador tenha que pular
para tocá-lo Importei alguns ativos
para meu ponto de salvamento, que é um livro e também um sprite de efeitos que vou desenhar atrás do livro
para fazê-lo brilhar Vou adicionar um Sprite two D no ao nó
da área para
desenhar o brilho primeiro Em seguida, adicione um
Sprite animado dois D para o livro. Forneça a ele um recurso de molduras de Sprite e preencha-o com
os sprites do livro Reproduzindo a animação para frente
e depois novamente para trás. A área precisa de uma forma de
colisão, então vou dar a ela um círculo e
usar o raio do brilho, que é Como isso está na cena da sala, não na cena do conteúdo da sala, ela precisará ser ordenada na frente do conteúdo da sala. Ele precisará monitorar o corpo
do personagem do jogador. Ao anexar
um script ao ponto de salvamento,
podemos então conectar
o sinal
inserido no corpo da área ao script. Ao anexar um script ao ponto de salvamento, podemos então conectar
o sinal
inserido no corpo da área ao script Quando o personagem do jogador
tocar no ponto de salvamento, definiremos o valor
do último valor salvo
em seus dados de salvamento como uma nova matriz, com o primeiro elemento da
matriz sendo o nome da região e o segundo
elemento, o nome da sala Podemos automatizar esses nomes
usando a tag on ready, já que o pai
do ponto de salvamento sempre
será a
sala em que ele está, e o pai da sala sempre
será a região A natureza da árvore de cenas que exige que os irmãos
tenham nomes exclusivos garantirá que isso
seja suficiente para determinar exatamente em qual
sala eles foram salvos pela última vez Também podemos pegar uma referência
ao nó D do Animated Sprite two e pedir que ele reproduza sua animação
quando isso acontecer Não se esqueça de pedir
ao arquivo global node que salve o jogo sempre que quiser tornar
algo permanente Passando para o script do gerenciador de
jogos, precisaremos carregar a última posição salva do
jogador. Depois que toda a
inicialização estiver concluída, chamaremos uma função para
posicionar o personagem do jogador Se os dados salvos do jogador tiverem
um valor para o último salvamento em
, podemos obter a região pelo nome, pois sabemos que ela é
filha do nó mundial. E então faça o mesmo
para recuperar o quarto, sabendo que o quarto é
filho da região Podemos então posicionar
o personagem do jogador
na posição global do ponto de
salvamento naquela sala. Isso fará com que o
jogador entre na sala, carregue seu conteúdo e
apareça conforme o esperado Se o jogador ainda não
chegou a um ponto seguro, eu o colocarei na
origem para iniciar o jogo. No entanto, surge um problema quando o
jogador morre, pois também queremos colocar o personagem do jogador na última posição
salva naquele momento. Tanto a sequência do evento de morte
quanto o jogador que entra uma sala manipularão
o fade ao mesmo tempo Existem várias maneiras de
resolver esse problema, mas para simplificar, vou verificar se o personagem do
jogador está trocando de quarto quando morre. Se eles morrerem e reaparecerem
na mesma sala, o jogador que entrou na
sala não será acionado,
então a sequência de morte
pode lidar com o Caso contrário, vou substituí-lo
por uma simples pausa
de 1 segundo Para saber se o reposicionamento do personagem do jogador
mudou de sala, farei com que essa função
retorne um booleano E retorne se a
nova sala for
igual à sala atual ou
falsa como padrão. Vamos experimentá-lo. Quando
eu carrego meu jogo pela primeira vez, meu personagem começa
na posição padrão
na minha sala inicial. Se eu for para a esquerda, encontrarei o ponto de salvamento. Saltar para o ponto de salvamento
aciona o salvamento do meu jogo. Se eu fechar o jogo
e jogar novamente, agora meu personagem de jogador
começa no ponto de salvamento. Para tornar meu ponto de salvamento
um pouco mais mágico, farei com que ele flutue para cima e para baixo. Exportarei algumas
variáveis para a faixa e
velocidade de oscilação com um padrão de 16 pixels e uma
oscilação O que se
moverá é o nó da área, que também moverá os
sprites quando são filhos Precisarei saber sua posição Y
inicial e quanto tempo passou. Substituindo a função do processo, definirei T como sendo ele
mesmo mais o Delta multiplicado pela velocidade de oscilação entre zero e
tau Isso permitirá que a oscilação
se repita infinitamente sem nunca chegar
ao máximo de um número
de ponto flutuante A posição Y da área
pode então ser definida para sua posição inicial
mais o seno de T multiplicado pela faixa de
oscilação Para desenhar o
ponto de salvamento no mapa, podemos simplesmente adicionar
um Sprite two D à cena
do ponto de salvamento e dar a textura que
queremos desenhar Aumente-o bem para
que fique visível
para a câmera do mapa, depois oculte-o para que não atrapalhe e anexe
o script do ícone do mapa. Ele precisará estar
na camada de visibilidade dois, não na camada um, e todos os seus ancestrais
na árvore da cena devem estar visíveis na
camada um e na camada dois. Também quero testar o problema da
morte, então adicionarei uma função de
entrada simples ao script do meu personagem de jogador. Então, quando eu pressiono a
barra de espaço, o personagem morre. Agora, quando eu executo o jogo, o ponto de salvamento está
flutuando para cima
e para baixo, e eu posso vê-lo no mapa. Quando eu pressiono a barra de espaço, o personagem morre e
responde no ponto de salvamento Se eu me mudar para outra sala, posso fazer isso de novo e responder no ponto de
salvamento mais uma vez. Agora temos um ponto de salvamento
que lembrará a última posição salva do jogador e a carregará no local
correto. No próximo vídeo,
adicionaremos a habilidade desbloquear itens que
definem uma Te vejo no próximo vídeo.
66. 9-2 Metroidvania: Olá, amigos. Neste vídeo, adicionaremos itens para
o jogador coletar que desbloquearão suas habilidades de
Metroidvania Começarei criando uma nova pasta de cenas
chamada Upgrades Em seguida, duplique minha cena de
save Point, chame-a de Gem e coloque-a
na nova pasta Upgrades Em seguida, abra-o para editá-lo. Ao contrário do ponto de salvamento, não
quero que isso
seja desenhado no meu mapa, então excluirei o ícone do mapa. Não há necessidade de que isso
seja deslocado de sua origem, então vou redefinir a posição dos nós da
área Em seguida, torne a área dois nós
D, o nó raiz, renomeie-a como GEM e
exclua o antigo nó do Save Point em dois D. Vou substituir os quadros
Sprite do livro por novos
desenhando uma gema giratória.
Depois, faça com que essa
animação seja reproduzida automaticamente e faça um loop de 12 Em seguida, podemos anexar um novo
script para nossas atualizações. Reconectando o sinal do corpo do corpo
dos
dois nós D ao script, podemos desbloquear a
nova habilidade do personagem do
jogador quando ele
toca nessa atualização Para fazer isso,
exportaremos uma variável do tipo Enums dot abilities, fazendo referência ao
script Enums que criamos anteriormente Isso cria uma
lista suspensa conveniente no inspetor que nos
permitirá selecionar uma de nossas habilidades para desbloquear esse item de
atualização Mas lembre-se de que uma enumeração é apenas um número inteiro com um nome No meu jogo, a gema desbloqueará a habilidade do personagem do
jogador disparar projéteis De volta ao script, quando o
corpo do personagem do jogador entra nessa área, podemos definir o valor do
arquivo de dados de pontos pontos. Habilidades desbloqueadas indexadas como
habilidade verdadeira Em seguida, salve o jogo para tornar
essa atualização permanente. Para que isso pareça
mais impactante, provavelmente
desejaremos
fazer muitas coisas
sofisticadas antes
e depois disso e, eventualmente,
remover
esse nó quando terminarmos Podemos garantir que apenas
um único evento de colisão aconteça com esse nó usando set
deferred para desativar sua propriedade de monitoramento
após a Na cena do conteúdo da minha sala de salvamento, vou colocar isso em algum lugar
para que eu possa testá-lo. No entanto, eu queria flutuar para cima e para baixo,
como faz o Save Point Em vez de copiar e colar
o código de um
script em outro, devemos torná-lo
um componente que possa ser anexado a
qualquer nó dois D, assim como os scripts de
comportamento do inimigo. De volta à cena da gema, adicionarei apenas um nó normal
e o chamarei de float Em seguida, copie e cole o código do
script save Point nesse script. Em vez de um sacola de área, esse será apenas o pai do nó
flutuante, embora deva
ser um no tutti ou algum ancestral de um
no tutti para Em seguida, podemos copiar esse nó
na cena do Save Point e remover o código
do script Save Point. Esses três scripts
são muito mais reutilizáveis quando escritos para servir apenas a um único propósito, além de serem mais fáceis de entender e
depurar Outra coisa que
devemos fazer é não ter esse item de atualização B aqui se o jogador já tiver
desbloqueado essa habilidade Substituindo a função pronta, verificaremos o valor das habilidades desbloqueadas nos dados salvos do
jogador para ver se essa habilidade já está desbloqueada e colocaremos esse
nó na fila para ser liberado verificaremos o valor das
habilidades desbloqueadas nos dados salvos do
jogador para ver
se essa habilidade já está
desbloqueada e colocaremos esse
nó na fila para ser liberado, se estiver.
Agora vamos experimentar. Quando eu executo o jogo, posso ver meu item de upgrade
flutuando lá. Pressionar o botão para
disparar projéteis
não funciona, pois eu ainda não
desbloqueei essa habilidade Ao pular para pegar
o item de atualização, ele desaparece e
agora eu posso atirar Fechando o jogo
e jogando novamente, o item de atualização não está lá, pois eu
já o coletei, e eu ainda posso
atirar projéteis porque a habilidade foi desbloqueada
permanentemente Agora, queremos fazer com que a
coleta desse item seja muito mais
impactante para o jogador Para testar isso, precisaremos excluir
nossos dados salvos. No menu do projeto, selecione Abrir pasta de dados do usuário para abrir essa pasta em
seu gerenciador de arquivos, onde podemos ver
os pontos de salvamento e excluí-los. Agora, quando rodamos o jogo, o jogador não tem a
última posição salva e nenhuma habilidade desbloqueada Vou voltar para
a sala de salvamento,
clicar no meu ponto de salvamento
e fechar o jogo. Se você quiser tentar
criar a sequência de eventos para coletar o
item sozinho, provavelmente
desejará adicionar efeitos de
partículas ou outros
nós para obter seu resultado Pause o vídeo aqui e depois veremos
o que eu fiz Depois de implementar
minha sequência de eventos, aqui está a aparência
dos meus resultados. Primeiro, declarei uma
cor branca brilhante constante. Isso não é apenas branco, mas
tem uma intensidade máxima, o que significa que também deixará outras
cores próximas ao branco. Quando o personagem do jogador
toca no item, eu imediatamente
paro de flutuar para cima e para baixo e congelo o personagem do
jogador desativando o processamento Em seguida, iniciei um
emissor de partículas emitindo as partículas ao redor do item que se moviam
para Em seguida, alterne o item para a posição do personagem do jogador mais até a metade para ficar ao redor do centro do corpo, ao
mesmo tempo que ajusta as cores do item
e do
personagem Adicionar paralelo a
uma função de interpolação significa que tudo isso acontecerá ao mesmo tempo,
em vez de
esperar que uma termine antes de
iniciar a próxima Em seguida, eu desbloqueio a habilidade e salvo o jogo
como antes. E depois que a
habilidade for desbloqueada, esconda todos os elementos visuais, pare as partículas internas, inicie uma
explosão externa de partículas e atualize o sprite do
personagem para incluir o Depois de ajustar a cor do
personagem do jogador de
volta ao branco normal, eu ligo o processamento
do
personagem e removo esse
item da árvore da cena As partículas internas estão reutilizando os mesmos sprites das partículas de poeira do
chefe. Eles estão emitindo
de uma esfera com um raio de 32 pixels As partículas têm uma velocidade radial
negativa para atraí-las em direção ao ponto
central, sem gravidade Alpha com curva de 1 a 0 e animado. As partículas de explosão externa
são basicamente as mesmas, exceto que é uma explosão de um tiro com
explosividade Emitindo de um ponto com propagação
máxima e
amortecimento suficiente para cancelar
a velocidade inicial Agora temos
itens colecionáveis em nosso jogo que darão ao jogador novas
maneiras de explorar o mundo Mas nosso jogo
seria muito mais divertido explorar se tivesse atalhos Te vejo no próximo vídeo. E
67. Atalho 9-3: Amigos. Neste vídeo, adicionaremos um atalho que o
jogador pode desbloquear para tornar a exploração do nosso jogo mais
fácil e gratificante Vou usar a segunda sala à direita da minha sala inicial para criar meu atalho na cena de conteúdo da
segunda sala Dividi a sala
em duas metades distintas e colocarei meu atalho
no meio para que o jogador não possa passar por essa sala se
entrar pela esquerda Começando com um corpo estático para denodar para fornecer detecção de
colisão
e um nó Sprite Toti Vou usar uma textura de atlas e preencher meu
terreno florestal como o atlas,
depois usar os três
ladrilhos verticais para Adicionando uma forma de colisão como uma caixa e cobrindo a parede
com a colisão do terreno, o jogador não
conseguirá passar Podemos então adicionar outro nó
Sprite tutti usando uma textura de atlas, e eu já importei uma nova folha de sprite
para uma Vou usar o primeiro sprite
não danificado e posicioná-lo no lado
direito da parede Portanto, se o jogador entrar nesta
sala pelo lado direito, ele poderá
atacar essa chave, danificá-la e destruir a
parede para abrir o atalho A cinta precisará de
uma área de Hurt Box dois nós D com uma criança de dois nós D em
forma de colisão Vou usar outro formato de caixa
e fazer com que cubra o sprite. O. Seria uma boa ideia colocar isso em uma
camada de colisão diferente para que possamos controlar cuidadosamente
o que pode danificá-lo Vou usar a camada dois
para meus atalhos. Não se esqueça de nomear
suas camadas físicas nas configurações
do projeto para que
você possa lembrar para
que elas servem. Precisamos fazer com que a
caixa de ataque masculina de nossos
personagens mascare essa camada para que eles possam danificar
a chave Assim como qualquer projétil
que eles possam atirar. De volta à cena de conteúdo da sala, devemos fazer desse
atalho sua própria cena, já que provavelmente teremos
vários deles em nosso jogo Esse atalho será feito
especificamente somente
para a região da floresta. Então, vou salvá-lo nessa pasta e precisarei criar outras cenas de
atalho para
minhas outras regiões Abrindo essa cena, podemos anexar o script
Hurt Box
ao nó Hurt Box e também anexar um novo script ao nó raiz para
o comportamento dos atalhos O objetivo principal desse script será salvar quando
esse atalho for destruído e mantê-lo
destruído ao carregar o conteúdo
desta sala Para fazer isso, usaremos
algo comumente chamado sinalizador exportando uma variável de string
para o nome do sinalizador Na cena do conteúdo da sala, precisaremos especificar um nome de
bandeira para esse atalho Podemos nomear essa bandeira como
quisermos, mas ela deve ser exclusiva para
cada atalho do nosso jogo Vou nomear meu atalho Forest
second Room. Passando para
o script de dados, precisaremos de uma nova variável
exportada para manter nossos sinalizadores
em um Usando a string como chave, o valor
será um booleano De volta ao script de atalho, quando esse atalho é destruído, podemos definir o valor dos sinalizadores de pontos dos dados do arquivo com a chave sendo o nome do nosso sinalizador
e definir o valor Em seguida, salve o jogo para torná-lo permanente e depois de
fazer algumas coisas visuais, remova o atalho
da árvore da cena Substituindo a função ready, podemos verificar o
valor da nossa bandeira para ver se o atalho já
foi destruído e removê-lo da árvore
da cena, se estiver No entanto, se o atalho ainda não
tiver sido destruído,
o dicionário ainda não terá nenhum valor para esse nome de
sinalizador Então, na verdade, precisamos verificar se o valor existe primeiro
antes de tentar acessá-lo. Vamos conectar o sinal de
dano recebido da caixa Hurt à função de
destruição dos atalhos, desvinculando o argumento Vou mover a segunda
sala para a esquerda
da sala de salvamento
para que eu possa testá-la. Entrando nesta sala
pela direita, a parede impede que meu personagem
passe. Eu posso atacar a
cinta para destruí-la, o que destrói a parede, e eu posso atravessá-la Fechando o jogo e
executando-o novamente, o atalho permanece aberto No entanto, há
um pequeno problema. Vou reorganizar meus quartos para que o segundo quarto fique
novamente à direita e, em
seguida, excluo meu arquivo seguro
para restaurar o atalho Executando o jogo novamente. A parede impede que meu personagem
prossiga No entanto, ainda posso abrir o atalho
desse lado Portanto, precisaremos
evitar que nosso personagem consiga
atacar através das paredes. Abrindo a cena do personagem, podemos adicionar dois nós
D lançados à caixa de sucesso. Usaremos a mesma estratégia que usamos para atacar inimigos para verificar se há uma linha clara de acerto e
a caixa de ferimento Para fazer isso, o raio deve estar do centro do
personagem,
e precisaremos mascarar tudo o que essa caixa de sucesso pode
atingir , além de qualquer coisa que possa
obstruí-la, como o terreno, incluindo corpos e O raio também pode se originar dentro de alguns
desses aceleradores, então ele também precisará
ser capaz de atingir áreas e corpos de dentro de
suas formas No script Hit box, podemos obter uma referência a esse nó de conversão com
uma tag on ready, mas vou alterar o caminho do nó
para usar get node ou null Dessa forma, nem toda caixa de sucesso em nosso jogo precisa ter
um raycast acoplado Quando ocorrer uma colisão, verificaremos se o
raio existe primeiro e,
em
seguida, diremos ao raio que aponte para a Hurt Box que foi atingida
pela caixa de acerto e forçá-la
a ser atualizada imediatamente Se o raio estiver
atingindo algo e esse algo for
diferente da área, isso significa que há
algo mais no caminho A devolução evitará que os
danos ocorram. Se rodarmos o jogo agora, atacar o atalho lado errado será bloqueado
pelo colisor de paredes Se eu mover esta sala para o lado esquerdo e
entrar pela direita,
posso atacar a cinta e
destruir a parede, já que
o raio disparado da caixa de
acerto
do personagem não está obstruído Se quiser, você pode fazer uma pausa
aqui e adicionar efeitos de partículas, sacudir e até mesmo exigir vários ataques para quebrar
a cinta antes de
destruir Agora que adicionei meus efeitos, aqui está a aparência
dos meus resultados. Após um ataque, a parede
emite partículas de poeira, treme e a cinta
fica Após um segundo ataque, a cinta
se quebra em vários pedaços, a parede é removida e as
partículas são Para conseguir esse efeito, adicionei
partículas de GPU ao nó
emitindo as mesmas
partículas de poeira usadas anteriormente, mas desta vez emitindo em forma
de caixa Eu adicionei um
nó de detritos como uma pasta contendo três
peças diferentes como corpos rígidos E um temporizador de vibração que
emitirá um sinal 12
vezes por segundo Conectando o sinal recebido
danificado da caixa Hurt a uma função de recepção danificada, reiniciei o emissor de
partículas verifiquei
se é a primeira vez que ele
está sendo Se já estiver danificado, eu desligo detecção de
colisão na Hurt Box e destruo a parede Caso contrário, defina o dano como
verdadeiro, atualize a chave, sprite para desenhar a versão
danificada, inicie o cronômetro de agitação
e pare-o 1 segundo
depois O sinal de tempo limite do temporizador de vibração chama essa função de vibração, que apenas desloca a parede um pixel em uma
direção aleatória Quando a parede é destruída, atualizei os
dados salvos como antes, mas também espalhei alguns detritos, escondi a parede
e a cinta Em seguida, espere que as partículas terminem antes de remover
a cena inteira. Para espalhar os detritos,
eu os tornei visíveis, depois descongelei todas
as peças e adicionei forças de impulso a elas
iguais às suas posições
em relação à mãe Agora temos um atalho que
o jogador pode abrir, facilitando muito o retrocesso medida que ele explora nosso mundo Mas o mapa inteiro está claramente visível para eles verem
desde o início do jogo Te vejo no próximo vídeo.
68. Mapa 9-4: Olá, amigos. Neste vídeo, ocultaremos nosso mapa
do jogador e só revelaremos as salas quando
o jogador entrar nelas. Começando em nosso script de
salvamento de dados, podemos usar a mesma
estratégia que usamos com o ponto de salvamento para rastrear quais salas o
jogador entrou. Exportaremos uma nova variável
chamada map of type dictionary. As chaves desse dicionário
serão os nomes das regiões e os valores serão
outro dicionário. As chaves do
segundo dicionário serão os nomes das
salas naquela região, e os valores serão booleanos rastreando se o
jogador entrou ou não naquela sala Se olharmos em qualquer
uma das cenas da nossa sala, o mapa será desenhado por
alguma forma do nodo Tu Di. No meu jogo, eles estão sendo desenhados por um nó da camada Tile Map. Seja qual for o nó, alternar sua visibilidade é
bastante Descreveremos uma referência a esse nó em nosso script de sala. Você pode usar a tag ready se o nó do mapa for uniforme
para todas as salas em todo o projeto ou uma tag de exportação se
quiser mais flexibilidade, mas precisará
atribuí-la manualmente a cada sala. Também precisaremos que cada sala saiba o nome da região em que está,
o que podemos automatizar
com uma etiqueta pronta, obtendo o nome do nó principal da
sala
na árvore da cena Podemos então escrever uma função
para atualizar a visibilidade do mapa com base no fato de o jogador ter
entrado ou não nesta sala antes. Verificar os dados de
pontos do arquivo
O mapa de pontos indexado no nome da região nos
fornece outro
dicionário para a região, que podemos indexar
pelo nome da sala Isso será um booleano
para determinar se o jogador entrou ou não
nesta sala anteriormente E se for verdade, definiremos visibilidade
dos mapas como verdadeira. No entanto, assim como com
o dicionário de bandeiras, precisamos ter cuidado para
não tentar acessar entradas do dicionário
que não existem. Mas isso oferece uma
oportunidade extra nesse caso, pois podemos usar a ausência da entrada
do dicionário como informação
adicional. Por exemplo, podemos
verificar se o
dicionário de mapas tem uma
entrada para essa região. Caso contrário, isso significa que o jogador nunca
entrou nessa região antes. Da mesma forma, se a
entrada da sala não existir
, o jogador nem sabe que essa sala existe. Primeiro, precisaremos verificar se entrada
da região existe
no dicionário de mapas. Caso contrário, o jogador não poderá
ver este mapa e podemos simplesmente retornar
dessa função. Em seguida, faça o mesmo com a entrada da sala no dicionário da
região. Se a entrada não
existir, ocultarei o mapa. No entanto, se ela existir
, podemos definir
a visibilidade verdadeira e verificar o
valor do booleano Se o booleano for verdadeiro, definirei o módulo
Alpha dos mapas para opacidade total Mas se for falso, vou
configurá-lo para ser semitransparente. Isso significa que posso diferenciar
as
salas no mapa o jogador conhece das que
o jogador conhece das que ele
já acessou Como alternativa, talvez você queira usar um nó diferente para desenhar esses estados diferentes e alternar a visibilidade de
cada nó individual Podemos inicializar a visibilidade do mapa durante
a função pronta Podemos escrever outra função para descobrir uma sala e
revelar seu mapa. Para criar nossos dois estados de mapa
diferentes, podemos aceitar um parâmetro
booleano para determinar se essa sala está sendo
descoberta ao inseri-la Tudo o que essa função
precisa fazer é definir o valor dos dados de
pontos do arquivo Mapa de pontos, indexado no nome da região, indexado no nome
da sala com o valor de Mas se esse valor já existir e tiver sido definido como verdadeiro, não
queremos
redefini-lo como falso. Podemos usar a
operação lógica ou
defini-la como falsa somente se
ela ainda não for verdadeira. Em seguida, chame a função Atualizar visibilidade do
mapa para começar a desenhá-lo adequadamente. Se a região ainda não
existir no dicionário de mapas
, essa é a primeira sala o jogador descobriu
nessa região. Essa seria uma boa oportunidade para fazer algo interessante, como mostrar uma carta de
título ou jogar uma cena de atalho para apresentar ao jogador a nova região Vou chamar uma função ainda não escrita para a região
chamada Discover. Ele será responsável por inicializar a
entrada do dicionário de mapas para a região Passando para o script do gerenciador de
jogo, quando o personagem do jogador
entra em uma nova sala, podemos descobrir essa sala com um argumento verdadeiro para
desenhá-la opaca no mapa Na cena principal do jogo, podemos anexar um script
às regiões do nosso jogo. Escrevendo a função de
descoberta, ela será chamada
na primeira vez um jogador entrar em qualquer
sala dessa região. Assim, podemos começar criando a entrada
do dicionário de mapas para essa região nos dados salvos do
player. Também vou aproveitar esta
oportunidade para adicionar a região ao mapa do jogador chamando a função
de revelar mapa. Isso simplesmente percorrerá
todas as salas desta
região e as descobrirá,
mas com um argumento falso,
então será desenhado de forma
semitransparente todas as salas desta
região e as descobrirá,
mas com um argumento falso,
então será desenhado de forma
semitransparente Esse script precisará ser
anexado a todas as regiões. Em cada uma das cenas da minha região, também
adicionarei um nó de rótulo para exibir o nome
dessa região no mapa. Para que isso seja legível
na câmera do mapa, ele precisará ter um tamanho de fonte
muito grande Vou definir o tamanho da fonte para 256. Em seguida, defina a cor da fonte para
combinar com a cor dos quartos. Para destacá-lo mais, também
adicionarei uma sombra
e um contorno Ele precisará estar
na camada de visibilidade dois para que a
câmera do mapa o veja. Vou copiar essa nota de etiqueta para região do
meu vulcão e alterar a cor do texto
para corresponder a essa região Adicionando uma camada de tela
à cena da região dois, podemos criar um cartão de
título simples para exibir quando o jogador entrar
pela primeira vez em cada região. Com outro nó de rótulo, exibirei o nome
dessa região
no centro da tela
com um tamanho de fonte grande. Vou tornar isso invisível
por padrão e só exibi-lo quando o jogador entrar nessa região
pela primeira vez. No script de região, vou animar essa
tela com uma interpolação,
interpolando o Alfa do nó do
rótulo em até um, esperando 1 segundo e depois
interpolando de volta para zero Ele precisará ter um Alfa de zero para começar e
ficar visível. Isso pode ser copiado para minhas outras regiões e
atualizado com seus nomes Quando a região for descoberta, salvarei o jogo e tornarei visível
o rótulo do mapa. Isso também precisará ser inicializado na função
ready com base na
existência ou
não da entrada da região no dicionário de mapas Agora que as regiões têm
crianças que não são quartos, precisarei verificar
se as crianças são realmente quartos
antes de ligar as funções de descoberta.
Vamos experimentar. Quando o jogo começa, o jogador entra na
região da floresta automaticamente. Então, o cartão de título da região da
floresta é exibido. Os dados do mapa são revelados, mas somente a
sala inicial é opaca pois é a única
sala em que entrei Quando entro em cada quarto, os quartos mudam de
transparentes para opacos Eu removi o atalho da outra sala para
facilitar as coisas A região do vulcão ainda
não foi acessada, então ela não está
revelada no mapa E quando eu entro
na região do vulcão, ele exibe seu cartão de título e seus quartos são
adicionados ao mapa Embora eu ainda não tenha
construído nada apropriado para esta região. Voltando à região da floresta, a região já
foi descoberta
e, portanto, não
exibe seu cartão de título. Agora temos um sistema
para revelar o mapa do
nosso jogo gradualmente medida que o jogador
explora nosso mundo Mas as regiões do
nosso jogo pareceriam
muito mais distintas com um pouco de música de fundo. Nos vemos no próximo vídeo.
69. Música de 9 a 5: Olá, amigos. Neste vídeo, adicionaremos algumas músicas de fundo que mudarão em
cada região do nosso jogo. Isso não só
ajudará a enfatizar
a aparência única de cada região,
mas também proporcionará a aparência única de cada região, uma
sensação extra de progressão. Ao importar
música de fundo para seu projeto de jogo, selecione os arquivos na
guia Sistema de arquivos,
abra a guia Importar e
altere o modo de loop para avançar. Caso contrário, sua música tocará
apenas uma vez e depois parará. Isso exigirá uma
reimportação dos ativos. Em cada uma das cenas da nossa região, poderíamos colocar um nó reprodutor de
streaming de áudio para reproduzir essas faixas de música. Mas isso exigiria que
gerenciássemos qual deles está
jogando a qualquer momento, o que é meio incômodo Normalmente, não queremos ter mais de uma
faixa de música de fundo tocando ao mesmo tempo. Portanto, seria mais fácil
ter apenas um nó reprodutor de
streaming de áudio dedicado à reprodução de música de
fundo que possamos acessar de
qualquer lugar do jogo. Mas cada região
ainda precisa saber qual música de fundo
deve ser tocada para ela. Em nosso script de região, podemos exportar uma variável para manter a música de fundo dessa
região como um fluxo de áudio. Em seguida, preencha a variável
exportada para cada região em suas cenas
individuais
com arquivos de música diferentes Em seguida, podemos criar
um script global para gerenciar nossa música de fundo, herdada do
Audio stream Player Em seguida, abra as configurações
do projeto, a guia Globais, e adicione esse script à
lista de nós globais Voltando ao script, nós realmente precisamos apenas de
duas funções públicas, uma que dirá
ao script para tocar uma faixa de música e aceitar o fluxo de
áudio como parâmetro, e outra para parar de
tocar música. Mas parar a música de repente
seria meio chocante. É bastante comum diminuir
o volume da música reduzindo seu volume
gradualmente antes de parar Começando com a função de
reprodução de faixa, podemos definir o fluxo que
está sendo reproduzido para o parâmetro de faixa e chamar a função de reprodução dos reprodutores de fluxo de áudio para
começar a
reproduzi-lo. Mas se algo já estiver tocando,
precisamos pará-lo primeiro. Então, se esse script já está reproduzindo alguma coisa e o que está tocando é o mesmo que
queremos jogar,
podemos simplesmente retornar. Se não for o mesmo,
podemos esperar que o volume
diminua primeiro
e, depois disso, podemos mudar para a nova faixa
e voltar Para diminuir o volume gradualmente,
precisaremos de uma interpolação e uma função para
interpolar o volume, aceitando o valor final
do volume como parâmetro Depois de verificar se a interpolação já existe e eliminá-la, criaremos uma nova interpolação e
interpolaremos o volume até seu
valor final por algum tempo Vou usar apenas 1 segundo. O volume geralmente é
medido em decibéis, o que não é uma
unidade linear de medida Portanto, não é recomendável interpolar o volume em
decibéis. Em vez disso, usamos o valor do volume
linear, que é uma flutuação simples que
varia de zero para mudo a um
para volume normal Podemos retornar o sinal
finalizado de interpolação para que
possamos aguardá-lo Para parar de tocar música, basta esperar que
o volume chegue a zero,
depois ligar para parar e retornar
o sinal finalizado. E depois de trocar de faixa, devemos reduzir o volume para um para que possamos
ouvir a nova música Agora só precisamos dizer a esse nodo qual
faixa de música tocar e quando. Para simplificar, presumo que, quando o
conteúdo de uma sala é carregado, eu quero tocar a música eu quero tocar a música
associada a essa região. Então, chamando music play Track, vou passar pela região, que é a mãe
da sala dot Music. Se for instruído a tocar a mesma música
que já está tocando, o nó global da música
simplesmente ignorará a solicitação. Portanto, não há necessidade de verificar
o que já está sendo reproduzido. Vamos experimentá-lo.
Executando o jogo, eu começo na região da floresta, e então o tema da
música da floresta toca. Vestiários, a música
não muda enquanto eu
ainda estiver na região da floresta. Mas se eu fizer a transição para
a região do vulcão, o tema da região da floresta desaparece
e o
tema da região do vulcão toca em seu lugar Provavelmente haverá
momentos em que você desejará
tocar temporariamente uma
faixa musical específica, como durante uma
cena ou uma briga de chefe. Então, vamos adicionar mais duas
funções ao nosso roteiro musical. Um para substituir a faixa de música
atual e outro para reverter para
a faixa de música anterior Precisaremos de uma variável para armazenar a música de
fundo da região atual. Quando instruídos a substituir a música de fundo
por uma nova faixa musical, primeiro
armazenaremos a música de fundo da
região em nossa variável Então espere o fade out
e toque nossa nova faixa. Após a conclusão do evento, podemos voltar à música de fundo de
nossa região desaparecendo depois tocando a faixa de música
antiga Em nosso script de encontro com o chefe, podemos exportar uma variável para conter uma faixa musical especial
para a música do nosso chefe. Então, no encontro com o
chefe do Mc Mouse, podemos dar a essa luta contra chefes
sua própria faixa musical especial. O
nodo global musical pode ser instruído a tocar essa música quando o encontro com o
chefe começar. E volta para a música de fundo da
região
quando a luta termina E, finalmente, esse nó musical deve ser informado a qual
barramento ele pertence
no barramento de áudio para que possamos controlar seu volume em outras
configurações com mais facilidade. Portanto, substituindo a função
ready, podemos definir manualmente o
valor do bus como música Agora temos um sistema global de
música que
podemos usar para tocar qualquer música
necessária para nosso jogo,
mas nosso encontro com o chefe
ainda precisa ser melhorado. Te vejo no próximo vídeo.
70. 9 a 6: Olá, amigos. Neste vídeo, concluiremos o
encontro com o chefe em uma arena e impediremos que o chefe
reapareça quando for derrotado Eu reorganizei meus
quartos para que o jogador comece na sala de salvamento ao
lado da sala do chefe Abrindo o conteúdo da sala do chefe, eu construí
a cena de conteúdo da sala do chefe com várias camadas de paralaxe Para que o nó D da camada
dois do Mapa de Mosaicos pudesse
rolar em Parallax, tive que criar um novo
script herdado da camada do Mapa de Mosaicos sem
a Como o nó D da
camada dois do Mapa não tem a propriedade de região
destruída, ele não pode usar o mesmo método se quisermos rolar automaticamente Cada um dos nós da
camada do Mapa de Mosaicos para Di tem uma escala de rolagem diferente e modula mais em direção
à cor de fundo Para acompanhar quais chefes
o jogador derrotou, vamos abrir o script de
dados e adicionar uma nova variável chamada
Boss is defeated Uma alternativa ao uso de um
dicionário é uma matriz. Sempre que um chefe é derrotado, podemos simplesmente acrescentar seu
nome a No script de encontro com o chefe, podemos substituir a função
ready para verificar se esse chefe
já foi derrotado Se o arquivo dot data dot boss for derrotado tiver uma entrada
que corresponda ao nome do chefe, então o jogador
já derrotou esse chefe e podemos remover
esse encontro com o chefe. Quando o chefe é derrotado, podemos acrescentar o nome do chefe
à série de chefes à série de Em seguida, salve o jogo para
torná-lo permanente. Ao contrário dos dicionários, as matrizes
podem ter duplicatas. Portanto, quando você estiver armazenando
informações dessa forma, talvez queira verificar se a entrada já existe
antes de adicioná-la. Remover o
nó de encontro do chefe da
árvore de cena neste momento também removerá o
próprio chefe , o que eu
não quero fazer. Mas se o jogador
sair da sala e voltar, o chefe será removido
pela função de prontidão. Isso será suficiente para
fazer com que o chefe continue derrotado, mas o encontro em si
poderia precisar de algumas melhorias. A primeira coisa que quero fazer
quando a batalha contra o chefe começar é fechar a porta que tranca o
jogador dentro da arena Assim como com o atalho, usei um corpo estático para denode, reutilizando o mesmo
sprite de parede E uma forma de colisão retangular. No entanto, o sprite e
a forma de colisão estão posicionados muito acima do ponto de origem da
porta, então a porta está aberta Quando instruída a fechar, a porta reposiciona
a forma de colisão, depois ajusta a
posição do sprite para coincidir, e a abertura da porta retorna a forma de colisão
e
o sprite a porta reposiciona
a forma de colisão,
depois ajusta a
posição do sprite para coincidir,
e a abertura da porta retorna a forma de colisão
e
o sprite
de volta às suas posições originais. Dando a essa porta um nome único, podemos fechá-la
no script de encontro do chefe quando a batalha começar e abri-la
quando a batalha terminar Lembre-se de chamar as funções da
superclasse para também fazer todo o resto nas funções
inicial e final. Também quero fazer
o chefe lutar mais, derrubando
pedras flamejantes Então eu fiz outra cena
para as pedras flamejantes, que são um
corpo rígido com dois nós D. Isso
lidará automaticamente com a gravidade para mim. Eles estão sendo
desenhados e animados por um
Sprite animado com dois nós D, percorrendo automaticamente os sprites
importados a 12 quadros O corpo rígido está em uma nova camada de
colisão reservada especificamente para riscos e não
está Portanto, eles não colidirão com nada,
incluindo o terreno Eles simplesmente cairão de cima para baixo
da arena, e há uma caixa de sucesso anexada, monitorando a Hurt Box do
personagem do jogador. Não se esqueça de se conectar ao sinal
da área inserida para causar dano. No meu script de encontro com o Mc Mouse, exportei uma variável para manter essa pedra flamejante
como uma cena compacta, que posso instanciar como um Quando fui instruído a gerar pedregulhos
flamejantes, passei várias vezes
aleatoriamente entre o número da fase e o número da
fase
vezes dois para que
o número de pedregulhos aumentasse aleatoriamente entre o número da fase e o número da
fase na segunda na Instanciei uma nova pedra, eu a adicionei à cena
e a posicionei acima
da arena em uma posição aleatória entre as Para tornar o evento do acidente
ainda mais impactante, também
adicionarei uma vibração da câmera Godot facilita muito o
acesso à câmera atual de qualquer lugar Primeiro, precisamos apenas chamar
a função Get Viewport e, em
seguida, chamar a função D
Get camera two da janela Podemos então chamar nossa
função de vibração para sacudir a câmera. Vou dar uma intensidade de dois pixels por um
quarto de segundo. Posso então conectar o sinal de falha do
mouse Mc
ao script de encontro para
acionar a geração das pedras flamejantes em resposta
a Como os pedregulhos
são corpos rígidos, eles cairão naturalmente
devido à gravidade Então eu posso
limpá-los depois de terem caído abaixo do fundo
da arena usando uma área dois D. Essa área de coleta de
lixo é apenas uma
área retangular que cobre o
fundo da arena,
longe o suficiente para que
qualquer coisa que entre nessa área não seja
visível para a câmera O nó da área está monitorando e mascarando a camada de riscos. sinal inserido pelo corpo
se conecta de volta
ao script do contador do mouse Mc para removê-los
da árvore da cena. Com as mudanças feitas na caixa de sucesso do
nosso personagem, exigindo que o lançamento da caixa de sucesso para a Hurt
Box fosse desobstruído, tive que reorganizar a tecla Hurt Box do meu mouse
Mac Então, agora a Hurt Box está
determinando a posição e a forma da colisão está em
sua posição de origem local Como o nó D da Área dois está determinando a
posição em si, o script não precisa mais
referenciar a forma da colisão e, em vez disso inverte sua própria posição em resposta à
mudança de direção do personagem Vamos experimentar. Vou entrar na sala do
meu chefe e encontrar meu inimigo
chefe sentado lá. Eu posso atacar a chave para
ativá-la e começar o encontro com o
chefe. Isso desencadeia o início
da minha luta contra o chefe, que muda a música e fecha a porta da
arena, me prendendo Enquanto eu luto contra o chefe, sempre que ele bate em uma parede,
ele dispara um tremor de câmera e
deixa cair pedras flamejantes deixa cair pedras flamejantes Embora não possamos ver
o que acontece com
as pedras em chamas quando
elas caem abaixo da câmera, elas estão sendo limpas pela
área de coleta de lixo Quando o chefe entra em
sua segunda fase, o número de
pedras flamejantes geradas aumenta,
e derrotar o chefe
encerra o encontro, mudando a música de volta para a música da região do vulcão e abrindo
a Saindo da sala
e voltando, o encontro com o chefe não
está mais lá. Agora temos
tudo o que precisamos para criar um jogo
Metroidvania inteiro No próximo vídeo,
veremos nossas próximas etapas. Nos vemos no próximo vídeo.
71. 9–7 Finais: Olá, amigos. Parabéns
por concluir o curso. Agora você tem todas as
ferramentas e habilidades necessárias para criar um jogo
básico de Metroidvania, completo com
habilidades desbloqueáveis que gradualmente
darão ao
jogador acesso a mais partes
do mundo para explorar
um mapa que mostra a localização atual do jogador e economizar pontos para
acompanhar seu Tudo o que resta fazer
agora é repetir muitas
das lições ensinadas ao longo do curso para criar mais delas. Mais salas,
preenchendo mais regiões com mais inimigos para combater e
mais atalhos para desbloquear Siga estas etapas para aproveitar melhor este
curso e continuar aprendendo mais habilidades
que você pode usar para criar seu próprio jogo
Metroidvania Primeiro passo. Se este for seu primeiro
grande projeto de jogo, você deve ser capaz de
criar um jogo seguindo este modelo com pelo menos
três regiões diferentes, cada uma com várias salas contendo diferentes tipos de
inimigos, desafios de
plataforma, e essas regiões devem parecer
distintas umas das outras Seguindo os princípios de design de
jogo Metroidvania, seu jogo deve demonstrar
ao jogador obstáculos
que ele não consegue superar antes de desbloquear a
habilidade O
caminho crítico do jogo deve exigir um
retrocesso nas áreas
anteriores e
dar ao jogador várias novas oportunidades de
explorar com suas
novas habilidades Tente criar um jogo que
leve pelo menos 10 minutos para concluído do início ao fim, sem ser
muito repetitivo Segundo passo, depois de
terminar o jogo e
querer mais desafios, talvez
você queira pensar algo que
queira mudar. Talvez você não goste da forma como
o salto na parede funciona ou queira adicionar força de recuo
ao ataque do
personagem do jogador Tente criar uma maneira de ajustar a mecânica
para funcionar da maneira você preferir e mudar a forma como ela é
implementada no Tente evitar criar
algo totalmente novo ainda. Apenas se concentre em
fazer ajustes no que já está lá. Etapa três. Quando você conseguir
fazer alterações na mecânica
que já existe, sua próxima etapa deve ser adicionar uma nova mecânica que use
as ferramentas já fornecidas Algumas coisas que você
pode querer adicionar
ao jogo podem ser um item
colecionável que aumenta a saúde
máxima do jogador ou um novo feitiço que cura
o personagem do Adicionar essas mecânicas
ao jogo não requer novas habilidades, mas exige que você
aprenda a integrar vários sistemas existentes
de uma nova maneira Você também pode procurar novos recursos
para usar em sua nova mecânica
ou tentar criar seus próprios Etapa quatro. Agora que você pode fazer
com que a
mecânica existente funcione da maneira
que quiser e
integrá-la a novos sistemas, é hora de projetar e construir uma nova mecânica
do zero Essa pode ser uma habilidade totalmente
nova de Metroidvania que permite ao jogador
acessar mais do mundo, adicionando NPCs para o jogador conversar por meio de um sistema de
diálogo,
fazendo com que os inimigos soltem dinheiro
para o jogador coletar e permitindo
que eles gastem esse dinheiro em uma loja para
atualizar Antes de começar,
reserve um tempo para
pensar em todos os sistemas existentes que
precisarão se comunicar
com o novo mecânico Considere quais partes do
seu design devem ser abstraídas ou o que pode ser herdado dos scripts existentes Etapa cinco. Se você conseguir criar um sistema
totalmente novo e
integrá-lo com sucesso a este jogo, então você deve estar pronto para
criar um novo jogo do zero. Encontre um pacote de ativos
diferente on-line ou crie seus
próprios ativos para usar
ao criar um jogo Metroidvania completamente
novo do zero, inteiramente
criado por você mesmo Você pode compartilhar seu
trabalho em nosso servidor discord enquanto continua aprendendo e
desenvolvendo suas habilidades
com este projeto Etapa seis. Quando o jogo estiver pronto, você poderá compartilhá-lo em
plataformas como o Ich para obter feedback dos
jogadores e até mesmo vender o jogo quando
ele estiver concluído. Você provavelmente não ganhará muito dinheiro
vendendo jogos no IH, mas o feedback será inestimável para melhorar suas habilidades de desenvolvimento de
jogos Se você tem um jogo que
teve um bom desempenho no Ich, tente vendê-lo no Steam para alcançar um público muito
maior. Mas o nível de
qualidade para que um jogo tenha sucesso no
Steam é muito maior. E você precisará
ter uma estratégia de mercado se quiser que seu jogo
seja notado pelos jogadores. Boa sorte na conclusão do
seu projeto. Estou ansioso para
ver seu trabalho.