Crie um Metroidvania no Godot! | Thomas Yanuziello | Skillshare

Velocidade de reprodução


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Crie um Metroidvania no Godot!

teacher avatar Thomas Yanuziello, Indie Game Developer

Assista a este curso e milhares de outros

Tenha acesso ilimitado a todos os cursos
Oferecidos por líderes do setor e profissionais do mercado
Os temas incluem ilustração, design, fotografia e muito mais

Assista a este curso e milhares de outros

Tenha acesso ilimitado a todos os cursos
Oferecidos por líderes do setor e profissionais do mercado
Os temas incluem ilustração, design, fotografia e muito mais

Aulas neste curso

    • 1.

      Trailer 0-0

      2:01

    • 2.

      Download 0-1

      2:34

    • 3.

      Editor 0-2

      4:42

    • 4.

      0 a 3 cenas

      6:48

    • 5.

      0-4 Física

      4:51

    • 6.

      de 0 a 5 Scripts

      5:43

    • 7.

      Jogo de 0 a 6

      5:44

    • 8.

      PersonagemCorpo 1-1

      5:15

    • 9.

      Mapa de entrada 1-2

      8:47

    • 10.

      1–3 Movimento

      7:15

    • 11.

      Salto 1–4

      7:23

    • 12.

      1-5 Caindo

      7:25

    • 13.

      1-6

      4:40

    • 14.

      Coyote de 1 a 7

      8:41

    • 15.

      Sprite 2-1

      7:36

    • 16.

      2-2 Reprodutor de Animação

      9:56

    • 17.

      2 a 3 árvore animada

      10:02

    • 18.

      2-4 Efeitos sonoros

      8:58

    • 19.

      2–5 Sprite animado

      7:54

    • 20.

      2-6 Instanciar

      11:27

    • 21.

      Bus de áudio 2-7

      6:13

    • 22.

      Mapa de mosaico 3-1

      8:05

    • 23.

      3-2 Terreno

      8:15

    • 24.

      Câmera 3-3

      6:46

    • 25.

      3-4 Olhar para frente

      9:24

    • 26.

      3-5 Olhe para cima

      10:41

    • 27.

      3-6 Limites

      11:05

    • 28.

      3-7 Parallaxe

      10:06

    • 29.

      4-1 Conteúdo

      6:58

    • 30.

      4 a 2 quartos

      8:29

    • 31.

      4-3 Parallaxe

      10:06

    • 32.

      4-4 Transição

      7:38

    • 33.

      Janela de visualização 4-5

      7:05

    • 34.

      4-6 Visibilidade

      7:49

    • 35.

      Mapa 4-7

      7:46

    • 36.

      5-1 HUD

      9:38

    • 37.

      Medida 5-2

      10:27

    • 38.

      Ícone de 5 a 3

      8:00

    • 39.

      5-4 Contador

      8:40

    • 40.

      5-5 caixa de dor

      10:57

    • 41.

      5-6 Dados

      6:10

    • 42.

      Arquivo 5-7

      8:27

    • 43.

      Salto duplo 6-1

      10:37

    • 44.

      6-2 Slide de parede

      10:16

    • 45.

      Salto da parede 6-3

      10:28

    • 46.

      6-4 Traçado

      10:45

    • 47.

      6-5 Desaceleração

      11:34

    • 48.

      de 6 a 6 chapéus

      13:32

    • 49.

      6-7 Projétil

      18:21

    • 50.

      Ritmo 7-1

      12:03

    • 51.

      7 a 2 paredes invisíveis

      6:41

    • 52.

      7-3 Detecção de borda

      9:24

    • 53.

      7-4 Voando

      11:48

    • 54.

      7-5 Rastreamento

      14:44

    • 55.

      Visão 7-6

      12:48

    • 56.

      7-7 Agressão

      14:25

    • 57.

      Combo 8-1

      12:21

    • 58.

      Hit 8-2

      11:35

    • 59.

      Suco

      12:51

    • 60.

      8-4 Agite

      7:39

    • 61.

      8–5 Morte

      13:28

    • 62.

      Chefe 1

      15:37

    • 63.

      Chefe 2

      10:13

    • 64.

      Chefe 8-8 3

      13:48

    • 65.

      9-1 Save Point

      11:55

    • 66.

      9-2 Metroidvania

      10:45

    • 67.

      Atalho 9-3

      13:19

    • 68.

      Mapa 9-4

      11:19

    • 69.

      Música de 9 a 5

      8:14

    • 70.

      9 a 6

      9:54

    • 71.

      9–7 Finais

      5:42

  • --
  • Nível iniciante
  • Nível intermediário
  • Nível avançado
  • Todos os níveis

Gerado pela comunidade

O nível é determinado pela opinião da maioria dos estudantes que avaliaram este curso. Mostramos a recomendação do professor até que sejam coletadas as respostas de pelo menos 5 estudantes.

6

Estudantes

--

Sobre este curso

Aprenda a criar um jogo de Metroidvania no Godot do zero.  Dar aos jogadores habilidades desbloqueáveis que eles podem usar para acessar gradualmente e explorar mais do mundo do seu jogo, um mapa que mostra sua localização e salvar pontos para acompanhar seu progresso.

Neste curso, você vai aprender a:
Usar o mecanismo de jogos Godot para criar jogos
Escrever scripts em GDScript
Princípios de design de programação orientada a objetos
Dividir um projeto complexo em componentes individuais

Construir um jogo Metroidvania inteiro por conta própria pode parecer uma tarefa assustadora, mas este curso ensina como dividi-lo em partes pequenas que são muito mais fáceis de gerenciar, ao mesmo tempo em que ensina a estrutura de design que junta todas as peças.

Este curso é para estudantes de todos os níveis de habilidade.
Se você for iniciante, é recomendável que acompanhe o curso exatamente como mostrado.  Cada linha de código será digitada na tela e cada etapa do processo demonstrada.
Estudantes intermediários podem querer usar outros recursos ou adaptar algumas mecânicas do jogo para dar seu toque pessoal no que é fornecido.
Estudantes avançados devem ser capazes de usar seus próprios recursos para projetar, e construir seu próprio jogo do Metroidvania usando este projeto, um modelo para estrutura geral e inspiração.

Todos os recursos usados nos vídeos serão fornecidos para você poder acompanhar, mas fique à vontade para usar outros recursos ou fazer o seu próprio se preferir.

Conheça seu professor

Teacher Profile Image

Thomas Yanuziello

Indie Game Developer

Professor

Habilidades relacionadas

Desenvolvimento Mais desenvolvimento
Level: All Levels

Nota do curso

As expectativas foram atingidas?
    Superou!
  • 0%
  • Sim
  • 0%
  • Um pouco
  • 0%
  • Não
  • 0%

Por que fazer parte da Skillshare?

Faça cursos premiados Skillshare Original

Cada curso possui aulas curtas e projetos práticos

Sua assinatura apoia os professores da Skillshare

Aprenda em qualquer lugar

Faça cursos em qualquer lugar com o aplicativo da Skillshare. Assista no avião, no metrô ou em qualquer lugar que funcione melhor para você, por streaming ou download.

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.