Crie um jogo de plataforma de pixels completo no Godot 4! | Thomas Yanuziello | Skillshare
Pesquisar

Velocidade de reprodução


1.0x


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

Crie um jogo de plataforma de pixels completo no Godot 4!

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.

      Introdução

      1:23

    • 2.

      0-1 Introdução à programação

      8:03

    • 3.

      0-2 Constantes e variáveis

      9:11

    • 4.

      0-3 Declarações e condições de If

      9:46

    • 5.

      0-4 Loops e operadores

      9:23

    • 6.

      Matrizes de 0 a 5 e para loops

      10:32

    • 7.

      0 a 6 pilhas e funções

      10:53

    • 8.

      0-7 partida e volta

      9:34

    • 9.

      Árvore de cenas e herança

      10:21

    • 10.

      0-9 Abstração e encapsulamento

      10:41

    • 11.

      Polimorfismo 0-10

      8:01

    • 12.

      Dicionário 0-11

      8:54

    • 13.

      Depuração 0-12

      9:08

    • 14.

      Configuração 1-0

      10:21

    • 15.

      Personagem 1-1

      6:44

    • 16.

      1-2 Entradas

      8:58

    • 17.

      1-3 Locomoção

      8:32

    • 18.

      1-4 Salto

      6:45

    • 19.

      Animação de 1 a 5

      5:53

    • 20.

      Máquina de estados de 1 a 6

      6:05

    • 21.

      1-7 efeitos

      10:21

    • 22.

      Tilemap 2-1

      6:07

    • 23.

      2-2 Decorações

      6:17

    • 24.

      2-3 câmeras

      9:04

    • 25.

      2-4 Tebrão

      7:07

    • 26.

      2-5 Fundo

      9:55

    • 27.

      2-6 Água

      11:16

    • 28.

      2-7 Limites

      9:09

    • 29.

      Dados 3-1

      8:07

    • 30.

      3 a 2 moedas

      8:57

    • 31.

      Interface do usuário 3-3

      9:01

    • 32.

      3-4 vidas

      10:24

    • 33.

      3-5 Peito

      10:20

    • 34.

      3-6 Bloqueio e chave

      10:02

    • 35.

      Mapa 3-7

      10:10

    • 36.

      4-1 Dano

      9:55

    • 37.

      4-2 Reação

      9:59

    • 38.

      4-3 Recuperação

      9:51

    • 39.

      4-4 Ponto de verificação

      9:30

    • 40.

      4-5 Morte

      10:05

    • 41.

      4-6 inimigos

      10:27

    • 42.

      4-7 Game Over

      13:17

    • 43.

      Espada 5-1

      11:24

    • 44.

      Ataque 5-2

      12:03

    • 45.

      Ataque aéreo 5-3

      9:43

    • 46.

      Patrulha 5-4

      9:28

    • 47.

      Agressão 5-5

      9:45

    • 48.

      Projétil 5-6

      14:01

    • 49.

      Chefe de 5 a 7

      13:52

    • 50.

      6-1 Pausa

      8:59

    • 51.

      Título 6-2

      9:49

    • 52.

      Selecione 6-3 níveis

      9:19

    • 53.

      6-4 Salvar

      8:40

    • 54.

      6-5 Desbloqueio

      10:35

    • 55.

      6-6 Música

      9:43

    • 56.

      6-7 Exportação

      7:33

  • --
  • 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.

368

Estudantes

1

Projetos

Sobre este curso

Aprenda como construir um jogo de plataforma de pixels completo no Godot 4 seguindo este curso!  Quer você seja novo no desenvolvimento de jogos, novo no motor Godot ou queira melhorar suas habilidades com alguns princípios de design de alto nível, você vai aprender muito aqui!  O início do curso se concentra em como escrever roteiros e na linguagem GDScript.  Se você já está familiarizado com Godot e GDScript, você pode pular essas lições e pular diretamente para a aula de Configuração.

Clique no link do meu site no meu perfil para participar do nosso servidor do discord!

Cada seção do curso geralmente se concentra em 1 aspecto do jogo; personagem, níveis, tesouros, inimigos etc.  As seções são divididas em 7 videoaulas, cada uma focada no ensino de 1 característica do motor Godot, 1 script ou 1 parte específica do desenvolvimento de jogos.  No final de cada seção, você terá um modelo para construir os vários aspectos do seu jogo.

Há uma tarefa que você vai precisar concluir antes de prosseguir com o resto do curso, repetindo muitas das lições ensinadas ao longo da seção para implementar mais dos ativos do jogo, ao mesmo tempo em que fornece desafios extras para aqueles que querem experimentá-los.  Os desafios são opcionais e não são necessários para prosseguir com as aulas.

Este curso inclui scripts na linguagem de script Godot.  Se esta é sua primeira vez usando scripting, você pode acompanhar e vou explicar itens individuais à medida que avançamos.  Para evitar sobrecarregar novos estudantes, vou tentar não explicar tudo de uma vez, mas focar em elementos individuais que são relevantes para cada aula.  Se você tem experiência com script em outras linguagens, o script do Godot é extremamente fácil de aprender e você será capaz de apreciar como ele é otimizado para o desenvolvimento do motor e de jogos em geral.

Os ativos usados neste curso estão disponíveis gratuitamente em itch.io e FreeSound.org.

Conheça seu professor

Teacher Profile Image

Thomas Yanuziello

Indie Game Developer

Professor
Level: Intermediate

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. Promo V2: Você começou a aprender Deus. Você fez tutoriais e fez projetos menores, mas está pronto para ir para o próximo nível e criar um jogo completo com nível profissional, código, estrutura e design Este curso ensinará como criar uma plataforma de pixels completa do zero e como criar um jogo escalável com código reutilizável que pode ser aplicado a jogos de Você aprenderá como criar um personagem que o jogador possa controlar e criar níveis, acompanhar o progresso do jogador no jogo e responder nos postos de controle, criar um sistema de combate com inimigos e uma luta contra chefes e aprender princípios de design escaláveis para Gadot que você pode aplicar a qualquer Quando terminar, você terá um modelo de jogo completo que poderá preencher com mais níveis, mais mecânicas, mais itens e mais inimigos Se precisar de ajuda, nosso servidor de discórdia está cheio de outros estudantes e desenvolvedores de jogos que podem responder a quaisquer perguntas que você possa ter Clique no link do site e no meu perfil para entrar. Começaremos com um projeto em branco na versão 4.2 do Godot e usaremos ativos gratuitos de seu dot IO Mas você pode acompanhar seu próprio projeto usando ativos diferentes. Notas e vídeos adicionais também foram adicionados para atualizar novos recursos na versão 4.3 do Godot Vamos começar a criar seu primeiro jogo completo. 2. 0-1 Introdução à programação: Olá amigos. você precisará baixar o GDOGameEngine em gdongine.org Se ainda não tiver feito isso, você precisará baixar o GDOGameEngine em gdongine.org . O motor é gratuito, mas você pode doar para apoiar o projeto, se quiser Não há processo de instalação. Você pode simplesmente extrair o arquivo compactado e abri-lo. Certifique-se de realocar o executável para um local melhor. A janela de lançamento inicial é uma lista dos seus projetos atuais. Mas se você ainda não tiver nenhum projeto, você será solicitado a explorar projetos de demonstração Podemos ignorar isso e simplesmente criar nosso próprio novo projeto clicando nesse botão na lista de projetos ou no botão Criar na parte superior da janela. Aqui podemos dar um nome ao nosso projeto, que normalmente seria o nome do seu jogo. Vou apenas colocar uma introdução à programação. O projeto precisa ser armazenado no disco rígido do nosso computador e criaremos uma nova pasta com o mesmo nome do projeto. Por padrão, ele deseja armazenar tudo na pasta de documentos, mas seria melhor criar uma nova subpasta para projetos Godot O renderizador altera a forma como certos dois objetos D e três D são renderizados, mas não vamos desenhar nada, então podemos ignorar essas opções O renderizador também pode ser alterado posteriormente. E a compatibilidade do controle de versão com o Github está incluída por padrão se você quiser usá-la para fazer backup do seu projeto ou compartilhá-lo com outras pessoas. Quando estiver pronto para começar, clique em Criar e editar. A janela do GdoEditor abrirá nosso projeto vazio recém-criado O editor está dividido em cinco docks principais. Uma prévia do nosso jogo está no centro. O dock inferior esquerdo contém um navegador de arquivos mostra o conteúdo da pasta do projeto que acabamos de criar. Atualmente, ele contém apenas o ícone Gadot. O encaixe superior esquerdo contém a árvore de cenas, uma lista de tudo o que está em nossa cena atual, que está vazia no momento, então ele quer que criemos uma raiz para a árvore de cenas. Não vamos desenhar nada, então não precisamos especificar se essa cena tem dois D ou três D ou uma interface de usuário. Então, podemos simplesmente selecionar outro nó. Podemos criar muitos nós diferentes, mas só estamos interessados em aprender a escrever scripts, então usaremos apenas um nó padrão. Podemos renomear nosso novo nó clicando nele depois selecionado ou clicando com o botão direito do mouse para abrir o menu de contexto e selecionando renomear Vamos chamar esse nó de Lição 1. Selecionar qualquer nó na árvore da cena revelará suas propriedades no inspetor, que está encaixado no lado direito da janela Podemos ver o nome do nó selecionado e suas propriedades organizadas em categorias expansíveis, mas nenhuma dessas propriedades aplicável ao que estamos fazendo Antes de fazermos qualquer outra coisa, devemos salvar nossa nova cena, selecionando Salvar cena no menu da cena ou usando o atalho Control S ou Command S. Isso abre uma caixa de diálogo onde podemos especificar um nome para nossa cena com o TSCNetension e uma pasta devemos salvar nossa nova cena, selecionando Salvar cena no menu da cena ou usando o atalho Control S ou Command S. Isso abre uma caixa de diálogo onde podemos especificar um nome para nossa cena com o TSCNetension e uma pasta de destino. Vamos criar uma nova pasta para a Lição 1 e depois salvar a cena nessa pasta. Agora podemos ver na guia do sistema de arquivos que nossa nova pasta foi criada para a Lição 1 e contém a cena da Lição 1, marcada com o ícone Clapperboard Em seguida, anexaremos um script ao nó raiz da nossa cena, selecionando o nó raiz e clicando no do script anexado ou clicando com o botão direito nele e selecionando o script anexado. A linguagem é GD Script, que é a linguagem de programação que vamos aprender Cada script herdará do tipo de nó ao qual está anexado por padrão Como o nó raiz é um tipo de nó padrão, nosso script herda do nó Não estamos usando um modelo nem um script incorporado, e podemos especificar onde esse script será armazenado no projeto. Vamos colocar isso na mesma pasta. Lição um. Ao nomear scripts, é importante não ser arbitrário, mas descrever o tipo de objeto ou comportamento que estamos criando por meio do Então, vamos chamar isso de olá. Os scripts têm a extensão de arquivo dotGD. Em seguida, clique em Criar para criar o script. Isso mudará nossa visualização para visualização de script, exibindo nosso script de saudação recém-criado. Também podemos ver nosso script na guia do sistema de arquivos indicada com um ícone de engrenagem, e o nó raiz da Lesson one tem o ícone do script para nos mostrar que ele tem um script anexado que, quando passarmos o mouse sobre ele , nos dirá o nome do Clicar nesse ícone também abrirá o script, caso ele ainda não esteja aberto. Nosso script tem apenas uma linha, que descreve sua herança do tipo de nó básico usando a palavra-chave extends Isso significa apenas que nosso script pode fazer tudo o um nó pode fazer, além de tudo o que escrevemos aqui. Também nos permite substituir os comportamentos do nó que já existem por novos comportamentos próprios Por exemplo, os nós têm uma função chamada ready, mas ela não faz nada. Então, se quisermos que nosso script substitua esse comportamento de não fazer nada, podemos declarar nossa própria função o mesmo nome usando a palavra-chave Funk é então seguido pelo nome da função, normalmente escrito em minúsculas, o que significa todas as letras minúsculas separando palavras com sublinhados que significa todas as letras minúsculas separando Muitas das funções definidas pelos nós são precedidas por um sublinhado, e o nome deve ser uma correspondência exata para substituir o comportamento O nome da função deve ser seguido por parênteses e Examinaremos o porquê mais tarde. Pressionando Enter após essa linha, a próxima linha é automaticamente recuada em um nível É assim que o GD Script sabe quais linhas estão contidas na função e onde ela termina A linha é destacada em vermelho porque as funções não podem ficar vazias. Portanto, é uma boa ideia escrever a palavra pass para dar às novas funções um corpo que não faz nada. Agora que o erro desapareceu, podemos ver esse ícone de seta azul aparecer na frente da declaração da função, que é o símbolo de substituição, indicando que esse script agora está substituindo o comportamento pronto do nosso Em vez de não fazer nada, queremos que nosso nó diga olá, o que podemos fazer com uma declaração de impressão, substituindo a linha que dizia passar anteriormente. A instrução print é semelhante a uma declaração de função com um nome seguido por parênteses porque está chamando uma função incorporada Essa função requer um argumento, que é o que está dentro dos parênteses E esse argumento é o que será impresso. Usando aspas, podemos escrever o que quisermos, e isso será impresso pelo nosso script quando o nó estiver pronto Como o script se chama hello, o comportamento que queremos criar é que o nó diga hello. Com nosso script pronto, podemos executar nosso jogo usando o botão executar cena atual no canto superior direito ou usando o atalho F six Isso exibirá uma janela vazia, já que nosso jogo não desenha nada, mas também abre o quinto dock, exibindo o painel de saída. E em nossa saída, podemos ver que nosso nó imprimiu as palavras hello world quando estava pronto. Podemos finalizar essa simulação fechando a janela, clicando no botão parar ou usando o atalho F oito Podemos alterar o texto impresso para dizer o que quisermos e executá-lo novamente para ver se nosso nó pode imprimir tudo o que pedimos. Agora sabemos como anexar scripts aos nós e executá-los. Na próxima lição, aprenderemos sobre constantes e variáveis Te vejo na próxima aula. 3. 0-2 Constantes e variáveis: Olá, amigos. Começaremos cada lição criando primeiro uma nova pasta para a lição. Em seguida, criando uma nova cena nessa pasta com o mesmo nome. Clique duas vezes em uma cena na guia do sistema de arquivos para abri-la. Com várias cenas abertas, podemos alternar entre elas clicando em suas guias no documento de visualização Hoje, discutiremos as diferenças entre constantes e variáveis usando dias como nosso quadro de referência Então, vamos anexar um novo script ao nó raiz da cena e nomear seus dias. Vamos começar com constantes e declarar uma na parte superior do script usando a palavra-chave const, seguida pelo nome da nossa nova constante, seguida pelo nome da nossa nova constante, que é convencionalmente escrita Uma constante é como um contêiner onde podemos armazenar informações, mas essas informações nunca podem ser alteradas. Algo que consideraríamos constante pode ser o número de dias na semana. Como não pode ser alterado, ele deve receber um valor imediatamente, é por isso que temos um erro. Devemos seguir o nome com um sinal de igual, o operador de atribuição para dar um valor à constante O número de dias na semana é sete. É razoável supor que sempre serão sete e que seja o mesmo para todos. Portanto, ele nunca deve precisar alterar seu valor. Por outro lado, temos variáveis, que também são contêineres para armazenar informações, mas projetadas para serem alteradas Podemos declarar uma variável da mesma forma usando a palavra-chave VR e, em seguida, atribuindo a ela um nome convencionalmente escrito em minúsculas Isso facilita a visualização da diferença entre constantes e variáveis em nossos scripts Algo que muda com frequência pode ser o valor de hoje. Ao contrário das constantes, as variáveis podem estar vazias. Vamos substituir a função ready do nosso nó base e imprimir os valores do número de dias da semana e de hoje Podemos ver que o número de dias na semana é sete, mas o valor de hoje é impresso como nulo, o que significa vazio ou nenhum valor Vamos corrigir isso inicializando hoje como quinta-feira. E podemos tornar nossa saída mais legível adicionando algum contexto, começando com algo como hoje, deixando um espaço depois de um sinal de adição e, em seguida, nossa variável Nesse caso, o sinal de mais está sendo usado para acrescentar duas partes da frase se tentarmos fazer a mesma coisa No entanto, se tentarmos fazer a mesma coisa com nossa constante, isso causará um erro porque nossa constante é um número, não uma palavra. Quando declaramos nossa constante, atribuímos a ela um valor de sete, que é um número sem nenhum ponto decimal, que em matemática é chamado de inteiro Portanto, nossa constante tem um tipo de número inteiro. Hoje, por outro lado, foi atribuído um valor de alguns caracteres entre aspas Em programação, chamamos isso de string. Portanto, nossa variável tem um tipo de string. O operador plus só pode ser usado quando os tipos de ambos os operandos são compatíveis Podemos contornar isso usando uma função embutida para alterar o tipo que está sendo usado aqui para uma string, passando a constante como argumento para a função. Isso não mudará o tipo da constante original, apenas como ela está sendo usada aqui no contexto da operação de acréscimo. E também podemos continuar adicionando mais contexto com outra string anexada, lembrando de adicionar um espaço extra na frente Então, agora podemos imprimir nossa constante e variável usando-as em frases fáceis de entender. Depois dessas linhas, vamos fingir que um dia passa. Podemos adicionar contexto extra aos nossos scripts que nunca serão vistos pelos jogadores, mas que existem apenas para nos ajudar, como desenvolvedores, a entender nosso próprio código ou código escrito por outras pessoas. Eles são chamados de comentários e são criados usando o sinal ou hashtag OctathorpPound Qualquer texto escrito após esse símbolo será colorido em cinza e não afetará de forma alguma a forma como o script é executado. Eles podem estar em suas próprias linhas ou no final de uma linha de código. Então, vamos usar um comentário para explicar que estamos fingindo que passou um dia entre o código acima dessa linha e o código abaixo Mudaremos o valor de hoje para sexta-feira e imprimiremos outra frase. Hoje é mais Hoje, que agora tem um valor diferente. Podemos ver que o valor de hoje foi impresso primeiro como quinta-feira e depois alterado e impresso como sexta-feira na próxima linha. O comentário não teve efeito na execução do script. Se tentarmos alterar o valor da nossa constante, obviamente, isso causará um erro porque as constantes não podem ser alteradas Se não quisermos mais usar algumas linhas de código em nosso script, podemos alterá-las facilmente para comentários destacando-as e pressionando Control K ou Command K, adicionando o símbolo de comentário na frente de cada linha destacada Pressionar novamente removerá os comentários. Podemos especificar o tipo de variável ou constante adicionando dois pontos após o nome Seguido pelo nome do tipo, também queremos restringir essa constante ou variável. Vamos restringir nossa constante para ser do tipo int e hoje do tipo string. Além de strings e números inteiros, existem dois outros tipos primitivos que podemos usar para armazenar Se um número tiver pontos decimais, ele não será mais um número inteiro e em vez disso, um tipo diferente chamado número de ponto flutuante, que usa o nome de tipo Vamos adicionar outra variável para a data de hoje e atribuir a ela um tipo de número de ponto flutuante com um valor de 12,05, que é a data de hoje, 5 de dezembro E o último tipo é chamado Boolean usando o nome abreviado Boole, que pode ser verdadeiro ou Então, adicionaremos outra variável para determinar se hoje é feriado ou não. Vou restringir isso para ser um booleano, mas não vou dar a ele um valor inicial Vamos adicionar mais duas instruções de impressão para imprimir os valores dessas variáveis com contexto. A data de hoje é mais uma data e hoje é feriado. Colon plus é feriado. Quando executamos isso agora, podemos ver nossa data impressa, mas se um feriado diz falso, apesar de não lhe dar um valor. Isso ocorre porque todos os tipos primitivos têm um valor padrão, mas o valor padrão só pode ser atribuído se especificarmos o tipo de variável Como especificamos que um feriado é um booleano, ele foi atribuído ao valor padrão um booleano, que é falso O valor padrão para um número inteiro e um número de ponto flutuante são zero, e o valor padrão para uma string é apenas uma string vazia, que não é o mesmo que null, mas é uma string sem caracteres Se não especificarmos o tipo de uma variável, seu valor padrão será nulo, mas ela poderá receber um valor de qualquer tipo, e seu tipo poderá mudar a qualquer momento Vamos remover o tipo da data. Em seguida, atribua um novo valor de 13 de dezembro e imprima-o pela segunda vez. A variável começa recebendo um valor de um número de ponto flutuante, é usada pela instrução print e, em seguida, recebe um valor de string antes de ser impressa novamente. Isso é permitido porque o GD Script é uma linguagem de digitação livre Isso oferece maior flexibilidade ao escrever nossos scripts, mas também maior responsabilidade de evitar erros de compatibilidade de tipos, como vimos com o operador plus. É recomendável que você sempre forneça um tipo às variáveis, não apenas para evitar erros, mas também para melhorar a eficiência da execução de seus scripts. Se o mecanismo souber o tipo de suas variáveis , ele também saberá exatamente quanta memória precisa ocupar. Isso também se aplica ao uso constantes no lugar de variáveis Se o motor souber que o valor não pode mudar, ele poderá ser usado com mais eficiência. Na próxima lição, aprenderemos sobre como controlar o fluxo de nossos scripts. Te vejo na próxima aula. 4. 0-3 Declarações e condições de If: Olá, amigos. Eu já criei uma nova cena em uma nova pasta para esta lição. Hoje, aprenderemos como controlar o fluxo de nossos scripts para executar diferentes linhas de código, fazendo escolhas sobre se podemos ou não ver. Então, vamos anexar um novo script ao nó raiz da nossa cena e chamá-lo de visão. Começaremos nosso script substituindo a definição dos nós básicos da função pronta O método mais básico de controlar o fluxo de nossos scripts é a instrução I, que começa com a palavra-chave I. I é seguida por uma declaração condicional que deve ser verdadeira ou falsa Por enquanto, vamos colocar verdadeiro, que é seguido por dois pontos Semelhante aos dois pontos no final de nossa declaração de função, isso marca o final da declaração e, continuando até a próxima linha, ela é automaticamente recuada em outro nível Qualquer linha de código após essa instrução if, que esteja indentada, só será executada se a condição da instrução if for verdadeira Então, vamos imprimir algo como se a condição fosse verdadeira e, em seguida, executar a cena atual para ver nossa declaração impressa funcionando. Se alterarmos verdadeiro para falso, podemos ver que a declaração de impressão é ignorada dessa vez Podemos adicionar outra linha após o corpo recuado das declarações if no mesmo nível de recuo instrução I simplesmente com a palavra-chave se seguida por dois pontos Isso cria outro corpo condicional que será executado somente se a condição da instrução I original não for atendida Vamos duplicar a declaração impressa e alterá-la para dizer algo diferente Como a condição era falsa, o bloco se foi executado em vez do bloco I. E se mudarmos a condição para verdadeira, o inverso acontecerá. Isso não é muito útil se sempre soubermos que o resultado da declaração condicional é verdadeiro ou falso, mas podemos substituí-lo por uma variável Vamos declarar uma variável booleana, que é se a luz está acesa ou não na sala Os booleanos são convencionalmente nomeados tal forma que implicam seu uso Nesse caso, a luz acesa está implícita como verdadeira ou falsa com base na forma como é nomeada Agora, nossa declaração if pode definir sua condição para ser se o valor de nossa variável é igual ou não a verdadeiro. Ao comparar dois valores para ver se eles são iguais, usamos um sinal de igual duplo, conhecido como operador de igual, que é diferente de um único sinal de igual, como usamos anteriormente como operador de atribuição. Em seguida, imprimiremos se consigo ver ou não consigo ver, como resultado de a luz estar acesa ou não ser igual à verdadeira. Como o valor padrão de um booleano é falso, podemos ver a saída como eu não consigo ver Mas se definirmos a variável como verdadeira, ela muda para Eu posso ver. Como a variável em si é um booleano, verdadeiro ou falso, podemos remover completamente a operação de comparação e apenas usar o booleano como condição e obter exatamente o Podemos reverter o valor de qualquer booleano, ou seja, se for verdadeiro, ele se torna falso ou, se for falso, ele se tornará verdadeiro usando a palavra-chave not Assim como a função STR que usamos na lição anterior, isso só muda a forma como ela está sendo usada no contexto local e, na verdade, não altera o valor armazenado na variável Então, se não, a luz está acesa, então não podemos ver, e então podemos ver. Nada também pode ser representado por um ponto de exclamação. Vamos alterar o valor das luzes acesas e executá-las novamente. Em seguida, reverterei essas mudanças para o que eram antes Podemos tornar nossas condições muito mais complexas combinando várias condições usando operadores lógicos. Vamos criar outra variável chamada Has dark vision. Essa variável implica que devemos ser capazes ver mesmo que a luz não esteja acesa. Portanto, podemos adicionar às nossas declarações if a condição que a luz esteja acesa ou que tenhamos uma visão escura. E se alguma dessas condições for verdadeira, então podemos ver. Somente se ambas as condições forem falsas, isso resultará na impossibilidade de enxergarmos? E se, em vez de ter visão escura, usássemos óculos de visão noturna, pois eles só nos permitem ver no escuro, mas não na luz Alterando o nome da variável, a condição da nossa declaração I precisa mudar. Uma vez que, se ambas as condições forem verdadeiras, não deveríamos ser capazes de ver. Somente se os valores dessas duas condições forem diferentes, devemos considerar a condição a ser atendida? Podemos usar o operador não é igual para verificar se os dois valores não são iguais entre si Se você estiver familiarizado com operações lógicas, isso é conhecido em outras linguagens como exclusivo ou. Agora, somente se a luz estiver acesa ou se estivermos usando óculos de visão noturna e não ambos, poderemos ver Em seguida, vamos considerar que nossa pessoa hipotética pode não ser humana e adicionar uma variável para o número de Is que ela tem, que deve ser representada como um Por enquanto, daremos a ele um valor de dois Is. Ignorando as outras variáveis, qual seria a condição que definimos para poder ver com base nessa variável Se o número de olhos que temos for maior que zero, então devemos ser capazes de ver. Também podemos expressar isso usando outro operador, maior ou igual a, e mudar o lado direito para um. Portanto, eles devem ter olhos maiores ou iguais a um. Esses são operadores de comparação que retornarão um resultado booleano comparando o valor dos números nos lados esquerdo e direito Podemos concluir logicamente que deveria ser impossível para qualquer criatura humana ou não ter um número negativo de olhos O valor da nossa variável deve ser apenas zero ou algo maior que zero. E a condição para poder ver realmente se resume a essas duas opções Temos olhos zero ou olhos diferentes de zero? Assim como a variável booleana pode ser usada implicitamente como uma condição, um inteiro também pode ser usado dessa forma, com zero sendo considerado uma condição falsa e qualquer coisa diferente de zero sendo A mesma lógica também é aplicada aos números de ponto flutuante. Podemos declarar uma variável flutuante, vamos chamá-la de alcance de visão e atribuir ela um valor arbitrário de Podemos usar nossos operadores de comparação para determinar se esse número é maior que menor ou igual a um determinado valor, ou podemos usá-lo implicitamente em sua própria condição com zero sendo considerado falso e qualquer outra coisa sendo considerada verdadeira E quanto às cordas? Vamos mudar um pouco as coisas e declarar uma variável de string para o que ouvimos e atribuir a ela o valor de solavancos durante a noite Então, podemos logicamente usar isso como uma declaração if como se o que eu ouvi não fosse uma string vazia, então podemos dizer, eu ouvi alguma coisa Caso contrário, eu não ouvi nada. E, assim como os outros tipos de variáveis, podemos descartar a comparação e usar a própria variável como condição. Com todas as variáveis, seus valores padrão são considerados falsos, e qualquer outra coisa é sempre considerada verdadeira quando usada como condição. Se declararmos uma variável sem um tipo, vamos chamá-la do que estou vendo, mas não atribuirmos um valor a ela, então já sabemos que seu valor padrão será nulo Mesmo sem um tipo ou valor, qualquer variável pode ser usada como condição de bullying Qualquer variável vazia, o que significa que seu valor é nulo, é considerada falsa Se preenchêssemos essa variável com um objeto , seu valor como condição seria considerado verdadeiro No momento, não temos outros objetos com os quais brincar, mas sempre podemos nos usar. Então, vamos definir o valor do que eu estou vendo como a palavra-chave self. E isso resulta em ser capaz de ver. Na próxima lição, usaremos loops para repetir linhas de código várias vezes. Te vejo na próxima aula. 5. 0-4 Loops e operadores: Olá, amigos. Hoje, aprenderemos a repetir linhas de código várias vezes com loops, imaginando uma senhora que se apaixonou pela primeira vez segurando uma flor Então, vamos escrever um novo roteiro e chamá-lo de flor. Em seguida, substitua a definição dos nós básicos da função pronta Nossa senhora imaginada está segurando uma flor com várias pétalas, que armazenaremos em uma variável e restringiremos seu tipo a um Em seguida, atribua um valor de algum número arbitrário, digamos cinco Também declararemos outra variável chamada He Loves Me, como booleana, na qual acreditamos ter seu valor padrão de false Podemos começar nosso roteiro imprimindo uma história sobre a mulher apaixonada segurando sua Ela remove cada pétala da flor, uma por uma, afirmando que ele me ama ou não me ama Primeiro, precisamos reduzir o número de pétalas na flor em uma Então, começaremos com a variável número de pétalas e, em seguida, usaremos o operador de atribuição para atribuir um novo valor à variável O valor que queremos atribuir é o número que ele já tem menos um Em seguida, queremos alterar o valor da variável de booling. Ele adora que eu seja o oposto. Então, ele me ama, não dá para nada. Ele me ama, invertendo o valor da falsa verdade ou vice-versa Em seguida, podemos imprimir os resultados. Ele me ama. Talvez queiramos encapsular essa parte entre aspas, mas se tentarmos colocar uma aspa dentro de nossa string, ela marcará o final da Alguns caracteres especiais, como aspas, podem ser criados dentro de uma string usando uma barra invertida Se escrevermos aspas de barra invertida, isso agora representa um caractere de aspa, não o final da string E podemos incluir outro após a declaração das senhoras. Vamos duplicar essa linha e mudar a declaração para dizer: Ele não me ama Outro exemplo de caractere especial que podemos escrever usando a barra invertida é a própria barra invertida Também podemos combinar as duas linhas acima e separá-las com a barra invertida N, que representa uma nova Portanto, eles são impressos em duas linhas de saída a partir de uma única declaração de impressão. Agora temos duas possibilidades que queremos imprimir com base no valor da nossa variável booleana Portanto, parece que devemos envolvê-los em uma declaração if. Se ele me ama, então imprima isso. Se ele não me ama, então imprima isso. Mas nos casos em que as declarações dependem de uma única variável booleana para fazer uma pequena alteração, existe um método mais eficiente Então, vamos voltar ao formato original. Nossa declaração será que ele me ama, se ele me ama, contrário, ele não me ama. Isso não é o mesmo que uma instrução if, apesar de usar as mesmas palavras-chave, mas é chamado de operação ternária Como ele não cria um novo bloco de código com um recuo, ele é executado com mais eficiência e é recomendado para ser usado em casos simples como este Na verdade, podemos reduzir ainda mais o tamanho da variação alterando-a apenas para um ponto de exclamação ou um espaço seguido pela palavra não e depois pelo ponto de exclamação Isso funciona no caso de ele me amar, mas se alterarmos o valor para verdadeiro por padrão , só veremos o que não acontece no outro caso. Assim como na matemática, há uma ordem específica de operações na qual nossos scripts executarão várias operações na mesma linha. Como tanto a string append quanto o ternário I são operadores, um deve ser executado antes do outro e, nesse caso, será o string append E, assim como na matemática, os colchetes são sempre os primeiros a serem executados Assim, podemos colocar qualquer operação entre colchetes para garantir que ela seja executada primeiro na ordem das operações Colocando nossa declaração ternária entre colchetes, ela agora será executada antes da sequência ser anexada e nos dará o resultado e Agora temos nosso bloco de código que precisa ser repetido enquanto a flor ainda tiver pétalas. Usando a palavra-chave WW, assim como uma instrução if, podemos repetir um bloco de código indentado , desde que a condição permaneça verdadeira A condição neste caso é que o número de pétalas na flor não seja zero Qualquer que seja o número de pétalas na flor, ele será reduzido em uma a cada vez Depois da instrução de impressão, o fluxo lógico desse script retornará ao início do WWLoop para verificar a condição novamente. Quando o número de pétalas chega a zero, a condição não é mais atendida e o loop é interrompido, continuando com o restante do script, se houver Então, vamos escrever uma breve conclusão para nossa história com base nos resultados. Ela se levanta com lágrimas nos olhos. Mas com base no valor final de Ele me ama, ela está feliz ou triste, e imprimiremos a frase final diferente. Executando essa cena, podemos ver nossa história impressa no painel de saída e, com cinco pétalas, a senhora está feliz Se mudarmos o número de pétalas para seis, obteremos um resultado diferente, pois o loop se repetiu seis vezes em vez de cinco Mas o que acontece se mudarmos o número de pétalas da flor para zero O ciclo não funciona de jeito e o amor estava condenado desde o Não recomendo seguir este exemplo, mas observe o que acontece se dermos à flor um número negativo de pétalas. Embora isso seja realisticamente impossível, em nosso código, é muito Como a condição de nosso laço de parede nunca será atendido, ele nunca se quebrará e o script ficará preso dentro dele, nunca terminando Esse é um loop infinito e deve ser evitado a todo custo. Nesse caso, podemos evitar o loop infinito alterando nossa condição para ser se o número de pétalas for maior que zero, pois um número negativo ainda quebrará o loop Podemos usar outro operador ao reduzir o número de pétalas como atalho Eliminando a necessidade de escrever o nome de nossa variável duas vezes, podemos realizar operações matemáticas simples em nosso número de variáveis usando um operador de atribuição especial Nesse caso, o operador menos igual a um pode alterar essa linha de código para número de pétalas menos igual a número de pétalas Esses atalhos existem para todas as operações aritméticas básicas mais multiplicar é igual ou dividir é igual e podem ser usados com qualquer número ou variável como e podem ser todas as operações aritméticas básicas mais iguais, multiplicar é igual ou dividir é igual e podem ser usados com qualquer número ou variável como o outro operando. Também existe mais um operador para aritmética básica, o operador de módulo, representado pelo Modulus executa uma operação de divisão, mas não retorna o quociente como resultado, como faz o operador de divisão Em vez disso, ele retorna o restante da divisão. Todo esse roteiro, além da história que está sendo contada, está apenas determinando se o número de pétalas na flor é um número par ou ímpar, mas está fazendo isso da maneira mais ineficiente possível, contando cada Então, vamos comentar todo o loop da parede e, em vez disso, usar o módulo para acelerar o processo Sabendo que todos os números pares são divisíveis por dois, podemos usar o módulo número de pétalas O único resultado possível como restante dessa divisão será zero se o número de pétalas for par ou um se o número de pétalas for ímpar Nosso script pode ser simplificado para que, se o número de pétalas do módulo dois for igual a um, a dama Caso contrário, ela está triste. Como entendemos como números inteiros são interpretados como condições, nem precisamos realizar a operação de comparação aqui e podemos simplesmente encurtá-la para I, número de pétalas O resultado da operação do módulo pode ser atribuído diretamente à variável booleana para obter o mesmo resultado sem a necessidade de uma instrução if, e o zero ou um será automaticamente convertido em falso ou verdadeiro de acordo Poderíamos ir mais longe removendo a variável e usando apenas a operação de módulo diretamente dentro da instrução turny Na próxima lição, aprenderemos sobre coleções de variáveis relacionadas. Te vejo na próxima aula. 6. Matrizes de 0 a 5 e para loops: Olá, amigos. Hoje, consideraremos como podemos organizar grandes quantidades de variáveis, especialmente quando elas contêm informações relacionadas. Eu já criei um script chamado censo e substituí definição de nós básicos da função pronta Para nosso cenário hipotético nesta lição, estamos imaginando um funcionário do censo que precisa registrar quantas pessoas moram em cada casa em uma única estrada em Podemos declarar uma única variável para conter todas essas informações, vamos chamá-la de Main Street E o tipo dessa variável será uma matriz. Uma matriz pode conter uma lista de variáveis de qualquer um dos outros tipos. Nesse caso, o tipo de variável que procuramos são números inteiros, representando o número de pessoas que moram em cada casa Podemos especificar o tipo de conteúdo de uma matriz usando colchetes após a matriz do nome do tipo e colocando o tipo do conteúdo dentro dos colchetes Agora, essa matriz só pode conter números inteiros como seu conteúdo. Antes de podermos acessar o conteúdo de uma matriz, ela precisa ter um tamanho, o número de variáveis contidas nela. Ao contrário de outras variáveis, as matrizes são mais complexas e têm suas próprias funções Podemos acessar essas funções seguindo o nome da variável com um ponto e, em seguida, o nome da função. Nesse caso, a função de redimensionamento, que define o número de endereços dentro dessa matriz, representando o número de casas na Main Street, que diremos que é seis Nossa cidade imaginária é um pouco incomum, pois os números das casas na Main Street começam em zero Então, nosso funcionário do censo começa na casa, no zero da Main Street, e bate na porta para perguntar ao morador da casa quantas pessoas moram na Podemos armazenar um valor em uma matriz começando com seu nome e, em seguida, usando colchetes para marcar o endereço do inteiro específico, nesse caso, endereço zero e, em seguida, usando o operador de atribuição Podemos atribuir um número inteiro a esse endereço. Então, digamos que a casa número zero na Main Street tenha cinco pessoas morando nela. Passando para a próxima casa no endereço número um da Main Street, alguém atende a batida na porta e diz ao funcionário do censo que há duas pessoas morando naquela Na próxima casa, endereço número dois, a casa está em construção e tem uma placa de venda, que significa que esta casa está claramente desocupada, e nosso funcionário do censo registra o número de residentes como zero No número três da rua principal, ninguém abre a porta, apesar do fato de haver um carro na garagem e sinais de ocupação O que podemos considerar o funcionário do censo deve registrar como o número de residentes Podemos pensar que pode ser zero. Mas como diferenciaríamos entre um número desconhecido de ocupantes e uma casa desocupada Se considerarmos que o número de ocupantes de uma casa nunca deve ser considerado um número negativo, poderíamos usar o número menos um para significar que o número de ocupantes da casa é um valor desconhecido E no número quatro da Main Street, novamente, não há resposta na porta. Mas a casa também parece estar abandonada e, provavelmente, ninguém mora lá há algum Podemos assumir que o número de ocupantes é zero talvez usar o mesmo valor de menos um para um número desconhecido de ocupantes ou criar mais códigos de valor negativos para situações diferentes, como usar menos dois para significar provavelmente desocupado, mas O endereço número cinco na Main Street nem tem uma casa, mas é apenas um terreno baldio Então, novamente, isso pode ser representado com um zero ou outro valor negativo para codificar algum tipo de reunião Vamos imprimir os resultados do censo e ver como eles se parecem Podemos ver nossa matriz representada como uma lista separada por vírgulas de números encapsulados Isso representa um trabalho decente ao representar o número de pessoas que moram em cada casa na Main Street. Mas e se quiséssemos usar esses dados para obter um número total de ocupantes de todas as casas na Main Street ou em média Se calculássemos a soma de todos esses números, os números desconhecidos representados como negativos distorceriam os resultados Um dos melhores benefícios de usar matrizes para armazenar informações relacionadas dessa forma é a facilidade de percorrê-las Usando a palavra-chave quatro, escrevemos em seguida o nome de uma nova variável, que representará cada elemento individual dentro da matriz, seguida pela palavra-chave in e, em seguida, pelo nome da matriz. Assim como as funções, se as instruções forem loops wa, isso será seguido por dois pontos e um bloco de código recuado que será repetido Essas linhas de código serão repetidas uma vez para cada uma de nossas seis casas na Main Street, e podemos nomear a variável house, pois ela será usada para acessar cada casa individual dentro do loop. Digamos que primeiro queremos encontrar o número médio de ocupantes que moram em uma casa ocupada Isso significaria somar todos os números positivos e depois dividir pelo número de casas ocupadas Então, precisaremos de três novas variáveis, uma para o número total de ocupantes, outra para o número de casas ocupadas, ambas como números inteiros, e um número de ponto flutuante para a média Para cada casa na Main Street, podemos verificar se a casa está ocupada, se o número armazenado na matriz desse endereço agora armazenado na variável casa é algo maior que zero. Se isso for verdade, o número total de ocupantes em casas ocupadas pode ser aumentado por casa e o número de casas ocupadas incrementado Depois que todas as seis casas na Main Street foram verificadas, o circuito é interrompido e temos nossos dois números inteiros Assim, podemos calcular a média dividindo o número total de ocupantes pelo número de casas ocupadas Em seguida, imprima os resultados. Há mais casas ocupadas, mais casas ocupadas na Main Street, com uma média de mais ocupantes médios mais ocupantes Mas se executarmos esse código, a média é representada como um número inteiro, três, que sabemos que não está correto, já que há um total de sete ocupantes em duas casas ocupadas, a média deve ser 3,5 Isso aconteceu porque realizamos uma operação de divisão com dois números inteiros, e o resultado da operação também será um número inteiro, mesmo que o estejamos atribuindo a uma variável de número de ponto flutuante Godot também fornece um aviso contra o uso de números inteiros em operações de divisão Para resolver isso, podemos alterar nossas variáveis inteiras para números de ponto flutuante em suas declarações ou podemos alterar seu tipo localmente antes de realizar a divisão Da mesma forma que transformamos números inteiros em strings antes de anexá-los, podemos transformar um inteiro em um número de ponto flutuante antes de realizar uma Alterando também o resultado da divisão para um número de ponto flutuante. Alterar o tipo de uma variável dessa maneira é chamado de conversão. Estamos convertendo um número inteiro em um flutuador. Agora podemos ver os resultados que esperávamos com uma média de 3,5 ocupantes por casa ocupada Uma vantagem do GD Script, por ser uma linguagem de tipos vagos, é que não precisamos especificar os tipos de nossas variáveis, incluindo os tipos contidos em Se permitirmos que nossa matriz contenha qualquer tipo de variável, podemos alterar a forma como nosso funcionário do censo registra as informações Vamos supor que o endereço zero permaneça o mesmo com cinco ocupantes Mas o endereço um também forneceu os nomes dos dois residentes que moram lá. Em vez de registrar os ocupantes como número dois, poderíamos gravar seus nomes em uma string Portanto, o endereço número um da Main Street é ocupado por Jordan e Ashley Smith A casa número dois estava desocupada, o que poderíamos representar como zero Mas também podemos considerar registrá-la como um booleano e atribuir a ela um valor falso para significar que a casa está em construção e não pode ter ocupantes No número três, ninguém estava em casa, mas definitivamente há pessoas morando lá. Nós simplesmente não sabemos quantos. Também podemos armazenar esse valor como um booleano e atribuir a ele um valor verdadeiro No número quatro, realmente parece que ninguém mora lá. Talvez queiramos marcá-lo como zero ocupantes. No endereço número cinco, como não há nem mesmo uma casa lá, podemos realmente considerar o uso de nulo como valor, já que nulo representa a ausência de qualquer Podemos usar a palavra-chave null para atribuir isso à matriz no endereço cinco Agora, nossa matriz impressa parece bem diferente, contendo variáveis de todos os tipos diferentes em vez de apenas números inteiros E podemos discernir mais informações a partir disso. As matrizes podem até conter outras matrizes como seu conteúdo. Então, vamos mudar nossa lista de nomes de uma única string para uma matriz de strings. Podemos criar essa matriz ao mesmo tempo em que ela está sendo atribuída usando colchetes e, em seguida, preenchendo-a com uma lista de strings separada por vírgulas Então, se quiséssemos saber quantas pessoas estão morando no endereço um na Main Street, poderíamos imprimir isso como Mainstreet one dot Na próxima lição, aprenderemos mais usos de matrizes para criar coleções de dados mais dinâmicas Te vejo na próxima aula. 7. 0 a 6 pilhas e funções: Olá, amigos. Hoje, continuaremos trabalhando com matrizes de maneiras diferentes configurando um jogo antigo Eu já criei um script chamado Old Made e substituí a definição de nós básicos da função ready Para jogar antiquado, precisamos de um baralho de cartas, que é uma coleção de variáveis que podemos manter dentro de uma matriz. Como o jogo Old Made realmente não se importa com os naipes das cartas, podemos ignorar essa informação, e cada elemento da matriz só precisa conter as cartas classificadas do ás ao rei como um número inteiro Para gerar nosso deck, podemos usar quatro loops. Mas, em vez de usar o loop de quatro para percorrer uma matriz, ele pode ser usado apenas para contar a classificação de nossas cartas Começando com quatro, podemos declarar uma variável para representar a classificação de uma carta, seguida pela palavra-chave in e, em seguida, especificar um número Se considerássemos King um número, seria o 13º posto Por enquanto, vamos apenas imprimir a classificação para que possamos ver o que acontece. O quatro loop começa com um valor de classificação em zero e conta até 12, repetindo esse loop e imprimindo a declaração 13 vezes Por uma questão de sanidade, pode ser uma boa ideia considerar que a carta número dois seja representada pelo nível dois e, portanto, Ás seria um e rei seria 13 Embora iniciar um loop de quatro em zero seja realmente útil para iterar por meio de matrizes, já que primeiro número de índice é zero, não é muito útil nesse caso Podemos mudar a forma como um loop de quatro é contabilizado substituindo o 13 por uma chamada de função, range. As chamadas de função são seguidas por parênteses contendo argumentos. Os argumentos para essa função são os limites inferior e superior do intervalo. O limite inferior será incluído no intervalo, mas o limite superior não será incluído. intervalo 114 conterá todos os números de 1 a 13, podemos ver que estão impressos na saída Outra forma de adicionar informações a uma matriz em vez de usar os colchetes e número do índice é usar uma função chamada append Essa função de acréscimo aceita um argumento do valor que está sendo adicionado à matriz Isso posicionará o valor que está sendo adicionado ao final da matriz, onde quer que esteja. E como há quatro de cada valor em um baralho de cartas, um para cada naipe, devemos repetir essa linha de código quatro vezes para cada valor. Podemos fazer isso com mais quatro voltas, desta vez começando em zero e contando até, mas sem incluir quatro. Imprimindo o baralho, podemos ver que nossa matriz tem quatro de cada número de 1 a 13, totalizando 52 cartas Mas para jogar antiquado, queremos remover três das rainhas, ou neste caso, 12 Então, em nossos quatro ciclos que percorrem os naipes das cartas, vamos verificar se a classificação é 12 E nesse caso específico, queremos permitir que apenas 112 seja adicionado, usando a palavra-chave break para sair instantaneamente desse loop. quebra encerrará apenas o loop mais recuado em que se encontra atualmente Então, terminaremos o naipe por loop, mas não o rank por loop. Isso aumentará a classificação para 13 e prosseguirá com a adição de quatro treze ao baralho E testando isso, podemos ver que há apenas 112. A primeira coisa que acontece em nosso jogo é embaralhar o baralho de cartas, que no script GD é uma simples de rayse Só precisamos chamar essa função e podemos ver que as cartas são embaralhadas em nosso baralho Também precisaremos de outra variável, uma série de mãos de cartas para representar nossos jogadores. Cada mão dentro da matriz de mãos precisa conter várias cartas, então elas também são matrizes, que precisaremos inicializar antes de podermos usá-las Portanto, contando de zero a quatro, mas não incluindo quatro, podemos acrescentar uma nova mão à matriz Nossa mão começa como uma matriz vazia representada por colchetes. Se imaginarmos nosso baralho de cartas, a frente das cartas sendo o lado com o anel e o naipe, o verso da carta em branco, então também podemos imaginar o baralho virado para baixo A frente da matriz é a parte inferior da plataforma e a parte de trás da matriz é a parte superior da plataforma. O processo de distribuição das cartas pode ser feito iterando nosso baralho, mas na verdade não precisamos referenciar cartas específicas, pois na verdade não importa o que sejam, apenas que a carta seja retirada do topo do baralho e entregue a um jogador Então, para remover uma carta do topo do baralho, podemos chamar outra função. Esse é chamado de pop back. Ele não apenas retorna o último elemento na matriz, mas também o remove da matriz. Em seguida, queremos adicionar essa carta à mão do jogador e começaremos com o jogador um, supondo que o jogador zero seja o dealer Assim como podemos usar o pop-back para remover um cartão, também podemos adicionar um cartão com pushback A carta que estamos colocando na parte de trás da mão do jogador é a mesma carta que estamos tirando da parte de trás do baralho Podemos simplesmente colocar essa chamada de função dentro dos colchetes da chamada de função e usar seu valor de retorno como argumento para a função push Usar pushback é exatamente o mesmo que anexar. A função append é um legado de strings, já que elas geralmente são armazenadas como matrizes de caracteres, enquanto push e pop vêm do uso de pilhas ou cues Para distribuir nossa próxima carta, precisaremos incrementar a mão que está sendo distribuída. Vamos armazenar isso em uma variável como um número inteiro e atribuir a ela o valor inicial de um Substituindo aquele em nosso índice de matriz por nossa variável, precisaremos incrementá-lo um após cada carta ser distribuída Mas, obviamente, isso contará apenas até 51, e não há tantas mãos. Então, precisaremos que esse número retorne a zero toda vez que chegar a quatro. Isso pode ser feito usando nosso operador de módulo fiduciário, atribuindo mão como módulo igual a quatro Mas se quisermos permitir que nosso código funcione com qualquer número de jogadores, seria melhor substituir quatro pelo tamanho da nossa matriz de mãos. Para ver onde estamos até agora, vamos imprimir nossas mãos iterando a matriz de mãos e imprimindo cada uma Em seguida, imprima o baralho. Podemos ver nossas quatro matrizes e o baralho está vazio. Podemos até mudar o número de jogadores e as cartas serão distribuídas para o número correto de mãos. Nossa função pronta está ficando bem grande. Podemos organizar melhor nosso código declarando nossas próprias funções Separando nossa lógica em pequenos pedaços, temos uma seção que cria nosso baralho inicial de cartas, uma que cria as mãos do jogador e outra que distribui as cartas. Usando a palavra-chave funk, podemos dar a cada um desses blocos de código um nome seguido por parênteses Inicializou o baralho, inicializou as mãos e negociou. Então, a função ready pode chamar cada uma dessas funções em sequência. Nossas funções também podem aceitar argumentos, como o número de mãos que queremos ter. Vamos passar quatro como argumento. Para escrever nossa função para aceitar o argumento, precisamos adicionar um parâmetro correspondente dentro dos parênteses da declaração da Assim como declarar uma variável, ela tem um nome e, opcionalmente, também um Como estamos usando isso para redimensionar uma matriz, é uma boa ideia restringi-la a um número inteiro Podemos então usar o parâmetro dentro da função da mesma forma que usaríamos qualquer outra variável. A última coisa que precisamos fazer para começar a jogar seria remover todos os pares da mão de cada jogador. Então, iterando cada mão na matriz de mãos, podemos chamar outra função para remover os pares dessa mão, passando a mão como argumento Dando uma definição a essa função, podemos então aceitar uma mão como um parâmetro de matriz. Precisaremos iterar com a mão com uma variável. Vamos chamá-lo de cartão um. Mas podemos parar antes de chegarmos à última carta. Então, vamos apenas de zero até o tamanho da mão menos um Podemos então iterar uma segunda vez da mesma forma, mas desta vez, começar com a carta após a primeira carta e ir até o final do tamanho da mão Dentro desses 24 loops, carta um e a carta dois agora contêm cada par de cartas exclusivo em nossa mão, então podemos comparar facilmente as duas cartas para ver se elas combinam Se estiverem, eles podem ser removidos da mão, começando com a carta dois. Se removêssemos a carta um primeiro , o índice da carta dois realmente mudaria como resultado, já que todas as cartas se moveriam em uma posição. Se encontrarmos uma correspondência, não queremos continuar esse loop ou qualquer um deles, mas queremos reiniciar todo o processo novamente. Uma maneira simples de fazer isso seria com um loop while, uma variável booleana para determinar se encontramos ou não um par com um valor padrão verdadeiro Embora um par tenha sido encontrado, podemos defini-lo imediatamente como falso. Isso nos permite entrar no loop, mas não ficar aqui, a menos que um par seja encontrado. Em outras linguagens, você pode fazer isso com um loop do Wile em vez disso Se encontrarmos um par, podemos definir a variável como verdadeira e, em seguida, sair dos dois loops, redefinindo o loop while Se os quatro loops concluídos sem encontrar um par correspondente, par encontrado será falso e o loop while será interrompido Podemos executar nossa simulação repetidamente e ver que nenhuma das mãos de nossos jogadores jamais conterá pares iguais, e os jogadores estão prontos para começar a jogar Old Maid Na próxima lição, usaremos outra forma de controle de fluxo. Te vejo na próxima aula. 8. 0-7 partida e volta: Olá, amigos. Hoje, usaremos outra forma de controle de fluxo para simplificar condições complexas. Eu já criei um script chamado months e substituí a definição dos nós básicos da função ready Vamos começar declarando uma variável para manter o mês atual e defini-la janeiro e uma segunda variável para manter o número de dias no mês, que será deixado como zero por padrão Podemos imprimir uma frase simples informando que o número de dias em janeiro é 31 Mas primeiro, queremos preencher nossa variável com o número de dias com base no valor do mês Então, vamos escrever uma função que pode fazer exatamente isso. Atribua o número de dias do mês a serem retornados de uma função que escreveremos, que aceitará o mês como argumento. Dando uma definição a essa função, aceitando o mês como um parâmetro do tipo string, ela também precisa de mais uma informação, um tipo de retorno. O tipo de valor retornado por uma função é definido após os parênteses com um hífen e uma letra maior em uma seta, seguido os parênteses com um hífen e uma letra maior em uma seta, seguido pelo nome do tipo. Nesse caso, é um número inteiro, representando o número de dias no mês Se não especificarmos um tipo de retorno, o tipo de retorno para qualquer função que escrevermos será nulo por padrão Dentro de nossa função, precisamos retornar um número inteiro, o que significa que devemos declarar um inteiro no topo dela, e ele precisará conter o número de dias do mês Em seguida, na parte inferior da função, retornaremos o valor mantido nessa variável. Entre essas duas linhas, precisamos preencher nossa variável com o número correto de dias com base no mês Se o mês for janeiro, o número de dias será 31. Aprendemos anteriormente que podemos fornecer uma alternativa com a palavra-chave se, mas isso só nos fornece duas opções das 12 de que precisamos. Podemos usar outra palavra-chave, if, abreviação de se if, para fornecer outra condição que será verificada se a condição original for falsa. Caso contrário, se o mês for fevereiro, o número de dias será 28. E podemos repetir isso quantas vezes precisarmos, fornecendo um caso para cada possibilidade. Mas muitas dessas opções têm o mesmo resultado, 30 dias ou 31 dias. Poderíamos melhorar consideravelmente a eficiência dessa declaração if combinando o resultado mais comum, 31 dias para ser o caso padrão, e substituindo todos eles uma única palavra-chave else no final Portanto, se o mês não for fevereiro ou qualquer mês com 30 dias , o número de dias deverá ser 31. Todos os casos resultantes em 30 dias também podem ser combinados em uma única declaração usando o operador or. Se o mês for setembro ou se o mês for abril ou se o mês for junho, ou se o mês for novembro, o número de dias será 30. Mas a declaração é bem longa, com mais casos, ela pode sair da tela. Para declarações simples, caso a caso, como essa, há uma palavra-chave mais limpa e fácil de usar do que a instrução I chamada match. A correspondência é seguida pelo nome de uma variável, dois pontos e depois por um bloco de código recuado Dentro de um bloco de correspondência, podemos especificar qualquer número de casos específicos para o valor da variável. Vamos começar com fevereiro. O caso também é seguido por dois pontos e outro bloco de código recuado Esse código só será executado se o valor do mês for fevereiro. Podemos agrupar casos em uma lista separada por vírgulas. Portanto, nossa condição de declarações I pode ser reduzida para apenas uma lista de quatro meses Se o valor do mês for setembro, abril, junho ou novembro, o número de dias será definido como 30, e nosso bloco poderá ser substituído por uma caixa curinga representada por um sublinhado, definindo o número de dias como 31 se o valor do mês não for especificado acima Isso é o mesmo que usar o padrão em outros idiomas. Cada um desses blocos de código é chamado de ramificações. E no script GD, uma instrução de correspondência só executará a ramificação superior cuja condição foi atendida cuja condição foi atendida Em outras linguagens, isso é semelhante a uma instrução switch, mas difere porque as instruções switch podem executar mais de uma ramificação se várias condições forem atendidas. Por causa dessa restrição, não há necessidade de incluir quebras nas ramificações da partida Se quiséssemos imprimir o número de dias em cada mês, provavelmente usaríamos um loop, mas não podemos simplesmente contar ou incrementar uma sequência de caracteres como janeiro para, de alguma forma, virar fevereiro Portanto, é comum no código, ao representar coisas que existem em uma ordem sequencial, colocá-las em uma lista numerada chamada Uma enumeração no script GD é apenas um grupo Podemos ter uma constante para janeiro com um valor de um, outra para fevereiro com um valor de dois, etc Mas usando a palavra-chave Enum, podemos nomear o grupo de constantes, vamos nomeá-lo em meses seguidos por Dentro das chaves, podemos agrupar as constantes e cada uma receberá um número automaticamente com base em sua posição nessa lista Qualquer coisa contida nas chaves não precisa ficar em uma linha e pode ser dividida em qualquer formato que você preferir para torná-la mais legível recuo não importa aqui, mas geralmente ao escrever algo entre colchetes, a maioria dos codificadores recua no conteúdo, então parece semelhante a então Embora eu prefira que as chaves sejam alinhadas verticalmente, muitos codificadores preferem colocar a chave de abertura na linha de declaração Assim como Constance, as entradas de enumeração são convencionalmente nomeadas em maiúsculas e minúsculas. Agora que temos uma enumeração, o mês pode ser restrito ao tipo dessa Também podemos atribuir a ele um valor a partir da enumeração, começando pelo nome, seguido por um ponto e, em seguida, pela entrada na lista O mês que está sendo anexado à saída da string não é mais uma string em si e deve ser convertido em uma string antes que possa ser anexado O argumento que está sendo passado para o número de dias não é mais uma string e agora é um mês, e podemos alterar nossa função para aceitar um mês como parâmetro também. Como mês agora é um mês, não uma string, precisaremos alterar nossas condições para que correspondam usando o nome da enumeração seguido por um ponto e, em seguida, as entradas na lista Mas quando imprimimos os resultados, vemos que, em vez de janeiro, nosso mês é escrito como o número zero. Embora o tipo de nossa variável seja um mês, que é uma enumeração, o valor real é tratado como um número inteiro, sua posição na Como janeiro é a primeira entrada, seu valor como número inteiro é zero Fevereiro seria um, etc. Isso nos permite modificar o valor do mês com aritmética simples, então janeiro mais um Se envolvermos esse código em um loop que se repete 12 vezes, podemos iterar todos os 12 meses com facilidade Mas que tal escrever o nome do mês como uma string? Poderíamos fazer isso de duas maneiras diferentes. Nosso tipo de enumeração tem uma propriedade chamada keys, que consiste em todas as nossas entradas como uma matriz de Se indexarmos essa matriz usando nossa variável inteira, ela nos dará o nome da entrada como uma string correspondente a esse número Mas seguindo a convenção de nomenclatura de maiúsculas e minúsculas de Upper Snake, talvez não queiramos imprimir o nome dessa poderíamos renomear todas as nossas chaves de Em vez disso, poderíamos renomear todas as nossas chaves de enumeração no caso Pascal ou declarar uma constante contendo a matriz de strings, mantendo todos os nomes dos nossos meses ou declarar uma constante contendo a matriz de strings, mantendo todos os nomes dos nossos meses em um formato mais apresentável. Em seguida, use o mês como um índice nessa matriz. Outra coisa que podemos fazer com as enumerações é definir manualmente os valores das entradas usando o operador de entradas usando o operador Digamos que queremos que janeiro seja um em vez de zero. O restante das entradas atualizará automaticamente seus valores para incrementar a partir de um, então fevereiro agora é dois Mas isso não corresponde mais aos índices constantes da matriz. Então, se quisermos usar isso para escrever o nome dos meses, precisaríamos adicionar uma entrada vazia para o índice zero ou subtrair uma do mês conforme ela está sendo usada para indexar a matriz Na próxima lição, aprenderemos mais sobre como o mecanismo usa e executa nossos scripts Te vejo na próxima aula. 9. Árvore de cenas e herança: Olá, amigos. Hoje, aprenderemos sobre como o mecanismo usa a árvore de cenas para executar nossos scripts. Ainda não anexei um script ao nó raiz da árvore de cena, mas, em vez disso, começaremos esta lição adicionando mais nós. Clicando com o botão direito do mouse no nó raiz e selecionando adicionar nó filho, ainda apenas um nó normal, podemos renomeá-lo para presidente e fingir que nossa árvore de cenas é a estrutura de uma empresa O nó presidente é indentado porque é filho do nó raiz da cena Com um nó selecionado, também podemos usar o atalho Controle A ou Comando A para adicionar outro nó filho Vamos nomear esse gerente de operações, e ele é recuado outro nível porque é filho do presidente Agora vamos anexar um novo script ao nó do presidente e nomeá-lo funcionário. Substituindo a definição dos nós básicos da função ready, podemos simplesmente imprimir o nome desse nó e anexar está pronto. Esse script pode ser anexado a mais de um nó. Então, vamos anexar o mesmo script ao nó do gerenciador de operações arrastando-o da guia do sistema de arquivos para a árvore da cena Em seguida, execute a cena para ver o que acontece. Podemos ver que o gerente de operações está pronto, então o presidente está pronto. Os dois nós que têm o script anexado executam o script e, como eles têm nomes diferentes, a saída foi diferente. Também podemos ver que o gerente de operações estava pronto antes que o presidente estivesse pronto. Para entender por que precisaremos adicionar mais funcionários. O gerente de operações supervisionará vários operadores Vou adicionar outro nó filho ao gerente de operações e chamá-lo de operador 1. Em seguida, anexe o script do funcionário. Podemos clicar com o botão direito do mouse em qualquer nó, exceto no nó raiz, e selecionar duplicado para criar uma cópia dele O nome das duplicatas incluirá automaticamente um número crescente, para que possamos ter o operador dois, três e quatro, etc Como o nó que duplicamos tinha um script anexado, as cópias criadas também têm o mesmo script anexado Como os operadores têm o mesmo nível de indentação e são todos filhos do gerente de operações, eles são chamados de irmãos, e os irmãos não podem Nossa empresa deve ter mais de um departamento, então vamos duplicar todo o departamento de operações duplicando o gerente de operações Todos os nós secundários também são duplicados. Como os operadores não são irmãos diretos, eles podem manter seus nomes originais Vamos renomear o gerente para gerente de marketing, e eles terão apenas dois profissionais de marketing trabalhando em sua equipe Os nódulos parentais também podem ser reduzidos para esconder seus filhos ou expandidos para mostrá-los. Todos os funcionários dessa empresa têm o mesmo script de funcionário anexado a eles. Então, vamos rodar a cena e ter uma ideia melhor da ordem em que os scripts serão executados. Podemos ver que o primeiro operador é o primeiro a ficar pronto, seguido por cada operador em sequência e, finalmente, pelo gerente de operações. O mesmo acontece com o departamento de marketing. Então, finalmente, o presidente da empresa é o último a estar pronto. Como Gadot está decidindo essa ordem de execução? O motor começa no topo da árvore de cena e desce, mas não considera que nenhum nó esteja pronto até que todos os seus filhos estejam prontos. Portanto, o presidente não está pronto porque o gerente de operações não está pronto. O gerente de operações não está pronto porque os operadores não estão prontos. Os operadores estão prontos em sequência, pois não têm filhos. Quando todos os operadores estiverem prontos, o gerente de operações estará pronto. Mas o presidente ainda não está pronto porque o presidente tem outro filho que não está pronto. O gerente de marketing não estava pronto até que todos os profissionais de marketing estivessem prontos e, finalmente, o presidente é o último a estar pronto Como o nó raiz não tem um script anexado, sua função pronta é a de um nó padrão, que está vazio. Além de prontas, existem outras funções do nó que podemos substituir para serem executadas posteriormente, depois que um nó estiver pronto O mais comum é o processo, também precedido por um sublinhado O mecanismo fará o possível para executar a função de processo de cada nó na árvore da cena 60 vezes por segundo usando a taxa de quadros padrão do projeto. Portanto, o processo usa um parâmetro chamado Delta, que é um número de ponto flutuante para representar o número de segundos que passaram desde o quadro anterior. Então, na maioria das vezes, será um 60º, mas nem sempre. Não precisamos usar esse parâmetro para nada hoje, então podemos continuar com o nome desse parâmetro com um sublinhado, para que Gudo saiba que não precisamos usá-lo e não devemos nos preocupar Mas, para substituir a função do processo, ela deve ter o mesmo número e tipos de parâmetros Vamos pedir aos nossos funcionários que trabalhem em cada quadro, imprimindo uma declaração dizendo que seu nome anexado a funciona Nessa cena, vemos que todos os nossos funcionários estão trabalhando muito, escrevendo suas declarações impressas 60 vezes por segundo. Isso não é o mesmo que um loop infinito, pois o trabalho está realmente sendo feito da maneira pretendida e nada está quebrado. Vamos tornar isso um pouco mais fácil de entender , permitindo que cada funcionário faça apenas uma unidade de trabalho usando uma variável Bolan que tenha feito um trabalho com um valor padrão de false Na função de processo, se o funcionário não tiver feito nenhum trabalho , ele trabalhará e alterará o valor para verdadeiro. Um 60º de segundo depois, como a variável é verdadeira, eles não funcionarão mais. Mas se declararmos essa variável dentro da função de processo , ela existirá somente dentro da função de processo e somente para uma única iteração No próximo quadro, quando a função do processo é executada pela segunda vez, a variável é declarada novamente e ainda assume o padrão false. Então isso não terá efeito. Para que nossa variável persista, ela precisa existir fora do contexto da função do processo Então, vamos declará-lo fora da função sem qualquer recuo As variáveis declaradas aqui podem ser acessadas em qualquer lugar em todo o script. Esse conceito é chamado de escopo e é um dos principais motivos pelos quais usamos recuo em nossos scripts Assim, podemos ver quais variáveis existem dentro de qual escopo. Comandando a cena agora, podemos ver cada um de nossos funcionários declarar que está pronto para trabalhar Então, somente quando todos estiverem prontos, cada um fará uma unidade de trabalho, mas agora em uma ordem diferente. A ordem na qual os nós e a árvore de cena executam suas funções de processo segue a ordem exata da árvore de cena de cima para baixo. Os pais não precisam esperar por seus filhos como se estivessem prontos. Talvez queiramos que todos os funcionários da nossa empresa sejam parecidos, mas não exatamente iguais. O trabalho de um gerente não é realmente o mesmo que o de um trabalhador. Podemos usar a herança para criar comportamentos diferentes para objetos semelhantes Da mesma forma, estamos escrevendo scripts que estendem o node, mas mudando a forma como eles se preparam e como são processados. Primeiro, precisamos dar a esse script um nome que possamos usar como referência, usando a palavra-chave nome da classe, seguido por um nome que descreva o comportamento do script, geralmente igual ao nome do script, mas escrito em maiúsculas em Pascal Agora que o motor sabe que se trata de um funcionário, vamos criar um novo script e nomear esse gerente. Mas em vez de herdar do nó, desta vez podemos herdar do funcionário Como nosso script de gerente estende os funcionários, tudo o que está escrito no script de funcionário ainda se aplica a este, mas podemos adicionar mais ou fazer alterações. Um gerente ainda é um funcionário, mas a forma como ele trabalha é diferente. Devemos substituir o script anexado aos nossos nós gerenciadores pelo novo script gerenciador. Vamos substituir a definição do funcionário sobre a função pronta Então, quando um gerente estiver pronto, ele não apenas dirá que está pronto, mas dirá que todo o departamento está pronto. Para que nossos dois gerentes possam gerar o nome de seus departamentos, eles precisarão de uma variável para manter o nome do departamento como uma string. Mas como podemos preencher essa variável para manter valores diferentes para departamentos diferentes Se prosseguirmos com nossa declaração de variável com a tag na exportação, essa variável se tornará acessível por outras partes do mecanismo Gadot, ou seja, o painel do inspetor Para que uma variável seja exportada, ela deve ser declarada no nível do escopo do script Selecionando o gerente de operações e o cenário, agora há um campo no painel do inspetor em que podemos atribuir à variável do departamento um valor de string Dessa forma, o gerente de operações e o gerente de marketing podem ter seu próprio valor para essa variável que podemos controlar facilmente. Executando a cena, podemos ver que os nós que têm o script do gerente anexado agora declaram que seu departamento está pronto, enquanto todos os outros funcionários usam a definição anterior no script do funcionário A função de processo no script do funcionário também é herdada pelos gerentes e é executada da mesma forma que antes Então, vamos mudar a função de processo do nosso gerente. Os gerentes dirão algo diferente. O Name plus gerencia os trabalhadores para fazerem seu trabalho. A variável has done work do script do funcionário também foi herdada e não precisa ser declarada aqui para ser usada Na verdade, não podemos declarar uma variável com esse nome, pois isso causaria um conflito com a variável herdada com o mesmo Vamos examinar a cena novamente e ver como nossos gerentes agora fazem seu trabalho de forma diferente dos outros funcionários. Na próxima lição, aprenderemos mais sobre o uso de nós na árvore de cenas e os princípios de design orientado a objetos. Te vejo na próxima aula. 10. 0-9 Abstração e encapsulamento: Olá, amigos. Hoje, exploraremos como escrever aulas que sejam mais fáceis de usar e entender. Imaginando um carro como nosso quadro de referência. Vamos criar dois nós em nossa cena, um motorista e um carro como filho do motorista. Em seguida, anexe um novo script a cada um com o mesmo nome. Os carros são máquinas muito complexas, e a maioria das pessoas que os dirigem não tem ideia de como eles realmente funcionam. Eles só sabem como operar o carro. Vamos começar no script do carro e dar a ele o nome de classe car e, em seguida, adicionar uma variável para o ano do carro como um número inteiro Outra para a marca do carro como corda e outra para o modelo também como corda. Exportando tudo isso, configurarei meu carro para ser um Honda Civic 2007 Ao criar uma nova classe, não se esqueça de salvar o script antes de tentar usá-lo. No script do motorista, o motorista precisará de uma referência ao carro, que podemos armazenar em uma variável do tipo carro. Os nós podem acessar outros nós na árvore de cena, maioria das vezes seus filhos usando outra tag semelhante à exportação chamada de ready. Usando a tag on ready, podemos atribuir o valor da variável depois que o nó estiver pronto, que significa que todos os seus filhos também estão prontos, mas antes de chamar a função ready desse nó. Podemos atribuí-lo ao valor de retorno de um nó G embutido na função, que aceita um caminho de nó como parâmetro. Se especificarmos o nome do nó filho entre aspas, agora temos uma referência ao nó filho armazenado em uma variável e podemos acessar suas propriedades e funções, incluindo aquelas no script anexado Substituindo a definição da função pronta, podemos acessar o nó do carro e imprimir seu ano, marca e modelo A função ready é executada após as tags on ready. Existe um atalho para a função get node para facilitar isso, o cifrão, seguido pelo mesmo caminho do nó Vamos voltar para o script do carro e adicionar outra variável. Este especificando se o motor está funcionando ou não como um booleano Como motorista, sabemos se o motor está funcionando e temos controle sobre se o motor está funcionando ou não, pois podemos optar por ligar ou parar o motor usando a chave. Portanto, consideraríamos essa variável pública. Outra propriedade do nosso carro pode ser o número de cilindros no motor como um número inteiro, e vou atribuir a ele um valor de quatro Isso é algo que o motorista não precisa saber, não pode acessar facilmente e nunca deve ser autorizado a mudar. Portanto, ao contrário da variável pública, essa seria considerada privada, e podemos marcá-la como privada fazendo seu nome continue com um sublinhado No script do motorista, podemos definir o valor do motor ligado como verdadeiro colocando a chave na ignição e girando-a Mas primeiro, devemos apertar o pedal do freio. Vamos usar uma função para definir a pressão aplicada ao pedal do freio, que assumiremos que seja de até 20 kg de Então, para ligar nosso carro, provavelmente deveríamos ajustar a pressão do freio para algo em torno de 10 kg De volta ao script do carro, precisaremos definir essa função que define a pressão do freio Como o mecanismo está em uma variável, isso seria chamado de função pública, já que está sendo usado por outro script. Essa função aceitará um número de ponto flutuante como parâmetro que representa a quantidade de pressão aplicada ao pedal Mas o que o carro realmente faz quando aplicamos pressão no pedal do freio Do ponto de vista do motorista, o motorista escolhe aplicar uma certa quantidade de pressão no pedal sem nunca saber a posição exata Do ponto de vista do carro, a posição do pedal é o que está sendo medido e usado para parar o carro O carro usa a posição do pedal do freio para ajustar a quantidade de pressão aplicada às pinças que prendem as pastilhas de freio contra as rodas do carro, sem mencionar a complexidade dos freios antibloqueio Então, se estivéssemos realmente programando um carro real, precisaríamos escrever várias funções complexas aqui que convertam a simples ação do motorista aplicando pressão no pedal do freio na complexa mecânica de apertar Isso faz parte das funções internas do carro e nada que seja controlado ou acessível ao motorista por qualquer meio que não ou acessível ao motorista por qualquer meio seja aplicar pressão no pedal do freio Portanto, consideraríamos que essas funções são privadas, uma vez que devem ser usadas apenas pelo próprio carro. E podemos marcar nossas funções privadas usando um sublinhado em seus nomes Observe como isso é o mesmo que o processo e as funções prontas. A forma como o GDScript usa variáveis e funções privadas é mais parecida com a forma como outras linguagens usam as protegidas pois são acessíveis aos GD Script não aplica essas regras de privacidade No entanto, o GD Script não aplica essas regras de privacidade e os scripts ainda podem acessar membros privados Essas convenções existem apenas para facilitar uma melhor estrutura e design de classes Outra forma de usar comentários no GD Script é criar regiões de nossos scripts que estejam relacionadas, usando a palavra-chave region seguida pelo nome da região Podemos finalizar uma região usando a palavra-chave e a região. Então, vamos criar uma região pública e uma região privada em nosso roteiro de carro, separando o que deve ser acessível ao motorista e o que não deve Para simplificar, digamos que o motorista só precise ligar ou desligar o motor, aplicar pressão no acelerador, aplicar pressão no pedal do freio ou girar o volante O que realmente acontece dentro de qualquer dessas funções públicas é a mecânica interna do próprio carro. O motorista não precisa saber como nada disso funciona para operar o carro. Por exemplo, ao pressionar o acelerador, o que realmente acontece é que o carro abre uma válvula de entrada de ar no motor, deixando mais ar e oxigênio entrarem no Portanto, o carro precisa usar um sensor para medir a quantidade de fluxo de ar e a quantidade de oxigênio que agora está fluindo para o motor Em seguida, use isso para ajustar a quantidade de combustível que está sendo injetada nos cilindros do motor Todas essas funções são privadas, pois não precisamos saber o que elas realmente fazem para dirigir o carro. forma como nosso carro se move estaria na função de processo, e precisaremos de outra variável privada chamada fase para representar em qual das quatro fases cada cilindro está atualmente. Na função de processo do carro, se o motor estiver funcionando, podemos passar por cada um dos cilindros do Somando o cilindro e a fase, depois o módulo quatro, obtemos uma fase diferente para cada cilindro Combinando esse número, podemos dizer a cada cilindro que execute uma fase diferente, o curso de admissão, o curso compressão, o curso de combustão ou o curso de escape, cada um aceitando o cilindro como argumento Em seguida, aumente a fase e volte para zero quando atingir quatro. Cada uma dessas funções pode então controlar as válvulas de admissão, válvulas de escape, injetores de combustível e velas de ignição de cada A quantidade de força produzida pelos cursos de combustão de cada cilindro moveria o carro para frente enquanto as pastilhas de freio tentavam parar o carro, e a posição do volante mudaria de direção A posição do carro seria então movida pela direção, velocidade e tempo Delta. Não se preocupe se nada disso fizer sentido para você porque esse é exatamente o objetivo desta lição. Você não precisa entender isso. Como tudo isso está na região privada do roteiro, o motorista não precisa saber como isso funciona para dirigir o carro. Eles só precisam saber como usar a região pública do script. A separação entre público e privado impõe dois princípios importantes da programação orientada a objetos encapsulamento é a região pública, fornecendo acesso a variáveis ou funções públicas que são fáceis de usar e simples de entender, e a abstração é a região privada, ocultando os detalhes de sistemas ou mecânicos complexos que não precisam ser entendidos para serem entendidos para Você saberá se suas aulas seguem esses princípios se puder ocultar todo o conteúdo privado e ainda entender facilmente como ele deve ser usado. Assim, nosso motorista agora pode simular a condução do carro acessando apenas as regiões públicas do script do carro, desde pressionar o freio e ligar o motor até soltar o freio, pressionar o acelerador, girar o volante, acessando apenas as regiões públicas do script do carro, desde pressionar o freio e ligar o motor até soltar o freio, pressionar o acelerador, girar o volante, etc. Esses princípios não são importantes apenas para nossos próprios scripts, mas também nos permitem usar scripts escritos por outros desenvolvedores sem entender completamente como eles funcionam internamente Eles também tornam os scripts R mais flexíveis. Imagine se trocássemos nosso carro a gasolina por um carro elétrico Alguma coisa no script do motorista precisaria ser alterada? Somente o script do carro precisaria ser alterado para um script de carro elétrico, já que todas as variáveis e funções públicas ainda existiriam no script dos carros elétricos. Da mesma forma, também podemos alterar o script do motorista para um script de piloto automático, que só precisa receber um destino e será capaz de operar o carro automaticamente Na próxima lição, aprenderemos ainda mais sobre os princípios de design orientado a objetos. Te vejo na próxima aula. 11. Polimorfismo 0-10: Olá, amigos. Hoje abordaremos o último dos princípios de programação orientada a objetos, o polimorfismo Estendendo os conceitos de herança e abstração, podemos escrever classes que representam um conceito mais abstrato, uma coleção de classes mais específicas relacionadas Vamos usar animais como exemplo criando um script chamado animal que estende o nó, mas não precisamos anexar esse script a nenhum nó na árvore da cena. Aqui podemos dar ao script um nome de classe e, em seguida, definir propriedades e comportamentos que são comuns a todos os animais, como uma variável para manter o plural do animal como uma string e outra para o nome de um agrupamento desse E também vamos definir uma função para o animal se mover, comer ou falar. Embora possamos definir facilmente o plural de animal como animais, não há uma palavra para um grupo de animais Também não podemos definir como um animal se move ou come sem saber que tipo de animal ele é Portanto, os corpos dessas funções podem permanecer em branco. Mas podemos considerar que alguns comportamentos são comuns o suficiente para que tenham um padrão, como falar. Embora existam muitos mamíferos diferentes que fazem uma grande variedade de ruídos, a maioria dos animais não o faz, incluindo peixes A maioria das pessoas não os descreveria como falando. Portanto, ao dizer a qualquer animal aleatório que fale, podemos considerar que o comportamento padrão é o silêncio. Então, vamos adicionar alguns animais diferentes à nossa árvore de cenas, começando com um gato. Agora podemos usar a herança, como fizemos antes, para criar vários scripts de animais diferentes que herdam de animais Em seguida, substituiremos a função ready para dar às variáveis herdadas do animal um valor apropriado para um gato O plural seria gatos, e um grupo de gatos é chamado de Clouder As funções de comportamento também podem ser substituídas para mudar o comportamento de falar em silêncio para miar Os gatos andam sobre quatro patas para se movimentar, e eu direi que comem peixe. O conteúdo real dessas variáveis e funções não é relevante, mas o foco está em como elas são herdadas do conceito abstrato de animal para uma instância mais específica de gato Podemos repetir esse processo para criar muitos outros tipos diferentes de animais para adicionar à nossa árvore de cena, como um pássaro ou um peixe. E dando a cada um novo script herdado do animal, cada um pode fornecer seus próprios valores exclusivos para as variáveis e implementações das funções que O plural de pássaro é pássaros. Um grupo de pássaros é chamado de rebanho. Eles voam para se movimentar, comem minhocas e cantam para falar. Vou começar meu script fish copiando o conteúdo do script cat. E o plural de peixe é peixe Um grupo de peixes é chamado de cardume. Eles nadam para se movimentar, comem algas, mas não falam Ao omitir a função de fala, peixes usarão a definição herdada da escrita animal Até agora, tudo o que fizemos foi usar os princípios orientados a objetos que já conhecemos para herdar, abstrair e encapsular as propriedades e comportamentos Mas tudo isso nos permite usar o polimorfismo tratando todos os animais como se fossem iguais e intercambiáveis iguais e intercambiáveis Primeiro, vamos adicionar um script ao nó raiz da nossa cena e chamá-lo de Zoo, herdando do nó Nosso zoológico está cheio de animais diferentes, mas não importa o que esses animais realmente sejam. Substituindo a definição da função pronta para nosso zoológico, podemos facilmente percorrer nossa lista de animais e tratar todos eles como se fossem apenas animais Uma maneira rápida e fácil de armazenar todos os nossos animais em uma única variável. Vamos chamá-lo de animais é usar uma função de nodo chamada Get children. Isso retorna uma matriz de nós, todos os nós filhos desse nó convenientemente organizados em uma matriz na mesma ordem da árvore de cena Como isso depende das crianças, devemos usar a etiqueta em on ready Como sabemos que todos os animais têm as mesmas propriedades e comportamentos, podemos analisar cada animal em nossa variedade de animais e fazer com que cada um fale E apesar de tratar todos eles como animais, cada um falará de uma maneira única, conforme definido por seus próprios scripts específicos, ou usará a definição herdada de animal se não tiver a sua própria Podemos criar quantos níveis de herança quisermos Então, vamos criar outro script abstrato para mamíferos, herdado mamíferos são uma subcategoria de animais, incluindo todos os animais que têm glândulas mamárias e as usam para Essas são propriedades e comportamentos únicos dos mamíferos que não se aplicam a outros Assim, podemos adicionar uma nova variável ao script dos mamíferos para o número de glândulas mamárias que esse animal tem e escrever uma nova função chamada Novamente, o conteúdo das funções não é relevante para esta lição. Esse script também precisará de um nome de classe para ser herdado Passando para o script do gato, já que gatos são mamíferos, podemos atribuir ao número de glândulas mamárias um valor para gatos, que deve ser oito E também podemos adicionar novos mamíferos ao nosso zoológico, como um Os macacos também são mamíferos, mas só têm dois Mais uma vez, copiarei o conteúdo de outro script para tornar as coisas mais rápidas. O plural de macaco é macacos. Um grupo de macacos é chamado de tropa. Eles se movem subindo em árvores. Eles comem bananas, e eu vou dizer que eles dizem oh. Nosso script Zoo agora pode aproveitar essa nova estrutura de herança para aplicar condições exclusivas especificamente para aplicar condições exclusivas especificamente animais que são Podemos usar diretamente nomes de classes em declarações condicionais para dizer que, se o animal atual for um mamífero, executaremos algum código extra exclusivamente para Vou imprimir algumas linhas extras descrevendo nossos mamíferos E podemos ver que nossa produção é consistente para todos os animais, mas também tem algo único específico para os dois mamíferos Você pode imaginar como poderíamos mudar nossa lista de animais em nosso zoológico para qualquer tipo diferente de animal, e poderíamos alterar nossa estrutura de herança para categorizá-los com a precisão necessária Na próxima lição, aprenderemos sobre outra coleta de dados que podemos usar para agrupar informações relacionadas. Te vejo na próxima aula. 12. Dicionário 0-11: Olá, amigos. Hoje, usaremos uma alternativa à matriz que às vezes é usada como uma classe sem nenhuma função chamada dicionário. Imagine uma fileira de armários como você encontraria em uma escola secundária ou em um ginásio Se declararmos uma matriz de variáveis, podemos considerar que o índice da matriz de cada uma é o número dos armários Digamos que haja dez armários e possamos acessar cada armário individual para colocar algo dentro, começando no armário zero, começando no armário zero, um e O que colocamos dentro de cada armário não importa. Pode ser um número inteiro, flutuante, string, booleano, nulo ou uma instância de uma classe E podemos imprimir o conteúdo dos armários para vê-los. Agora imagine que, quando colocamos algo em um dos armários, não apenas fechamos a porta do armário, mas também colocamos uma trava nela Esse cadeado requer uma combinação de números de três dígitos para Anteriormente, se quiséssemos recuperar o conteúdo do armário, precisávamos apenas saber o número dos armários, ir até ele e retirar o Agora podemos ignorar o número dos armários e, em vez disso, precisamos saber a combinação para abrir o cadeado Digamos que a combinação seja 149. Como uma matriz, atribuir algo ao número 149 significaria que a matriz teria que ter 150 Se mudássemos o tipo de nossa matriz para um dicionário, isso ainda funcionaria, exceto que não precisamos definir um tamanho para o dicionário antes de podermos acessar seu conteúdo. Observe como a saída mudou. dicionários são representados por chaves em vez de colchetes, e cada entrada é um número representando uma chave seguida por um valor do que está contido no armário trancado por essa Também não há entradas no dicionário para nenhuma chave à qual não tenha sido atribuído um valor. Como dicionário, esse número não é um índice ou endereço. É uma chave que usamos para abrir uma fechadura. E assim como o conteúdo do armário pode ser de qualquer tipo de dados, as chaves que usamos para bloqueá-lo também podem ser qualquer tipo de dados Cada chave deve ser exclusiva. Caso contrário, não conseguiremos encontrar o armário que corresponda à chave Então, vamos tentar trancar um armário com um tipo diferente de fechadura, que usa letras em vez de números Portanto, a chave dessa entrada do dicionário é uma string, mas seu valor é um número. O oposto completo desse armário, cuja chave é um número e o valor é uma string Vamos trancar o próximo armário com uma trava giratória, que requer três números para desbloqueá-lo, que poderíamos armazenar em uma matriz Portanto, nossa chave de entradas do dicionário é uma matriz representada por colchetes contendo uma lista separada por vírgula de três Talvez esse número de bloqueio inclua um ponto decimal, então a chave é um flutuador E, de alguma forma, esse armário está trancado pela fotossensibilidade e só pode ser aberto se as luzes estiverem apagadas Portanto, sua chave é um booleano. Podemos até usar classes personalizadas como nossas chaves ou valores nos dicionários Vamos escrever uma nova classe para chave, que não precisará ser herdada de nada, pois não será anexada a um nó nem herdada Nossa classe chave precisa um nome de classe e terá uma variável que descreva seus dentes. A implementação dessa classe não é relevante, mas podemos fingir que é uma chave De volta ao script do locker, podemos armazenar uma instância da nossa chave em uma variável Vamos chamá-la de key one do tipo key atribuindo-a ao nome da classe da chave Nunu cria uma nova chave, que é atribuída à nossa variável Agora podemos usar essa chave para criar uma entrada no dicionário. Também podemos criar mais chaves para criar mais entradas. Como cada chave que criamos é considerada única. A saída agora exibe as teclas como contagem de recifes seguida por um número longo Os nomes que usamos em outras classes foram herdados do node Mas como a chave não herda do node, ela não tem um nome Ref count é a abreviação de objeto contado por referência e é a classe base para o script GD Se escrevermos qualquer classe que não herde de nada, ela herdará da contagem de recifes e receberá um número longo aleatório Podemos ignorar isso e entender que nossas chaves são objetos com contagem de referência, o que significa que Gadot acompanha automaticamente cada instância única de cada objeto que criamos Mas o que queremos guardar nos armários? Assim como as matrizes podem conter outras matrizes, os dicionários também podem conter outros dicionários Combinando a forma como os dicionários são impressos, podemos criar nossos próprios dicionários rapidamente usando chaves Cada entrada começa com uma chave seguida por dois pontos e, em seguida, o valor que corresponde a essa chave uso comum de dicionários não é criar nada parecido com esse cenário de armário, mas sim criar algo mais parecido com uma classe, embora sem nenhuma função, apenas variáveis Digamos que esse armário contenha um brinquedo de pelúcia, que representaremos com um E este brinquedo de pelúcia pertence a um conjunto de brinquedos de pelúcia colecionáveis que são semelhantes, mas variados à sua maneira Cada um dos brinquedos de pelúcia é um tipo diferente de animal com uma cor e um nome Cada uma delas pode ser uma chave no dicionário. Digamos que esse armário contenha Bruno, o urso pardo. E o próximo armário contém Arthur, o Bode Branco. Podemos ver nosso dicionário de brinquedos de pelúcia dentro do dicionário de armários Acontece que a cor também é uma classe já definida em Gadot Então, em vez de armazenar nossas cores como strings, elas podem ser armazenadas como cores usando a cor do nome da classe Como você pode ver, há muitas cores predefinidas para usarmos, e podemos dizer pela forma como elas são nomeadas em maiúsculas e minúsculas, que essas são constantes da classe de Poderíamos até mesmo dizer isso e fingir que os brinquedos de pelúcia contêm uma etiqueta NFC ou de comunicação de campo próximo, tornando-os a chave para acessar o armário E podemos colocar o que quisermos dentro do armário como antes, incluindo outro pelúcia Vamos fazer outro brinquedo de pelúcia para guardar dentro do armário, que é destrancado usando Arthur como Desta vez, é fofa, o elefante cinza. Então, imaginando esse cenário, há um leitor NFC perto dos armários e seguramos um pelúcia com uma etiqueta NFC dentro, algo parecido com o que você pode encontrar em uma algo parecido com o que você pode Se segurarmos o brinquedo de pelúcia contra o leitor, precisamos verificar qual armário combina com o brinquedo de pelúcia e desbloqueá-lo, se houver algum armário Mas se tentarmos acessar uma chave em um dicionário à qual não foi atribuído um valor, causaremos um erro. Da mesma forma que faríamos se tentássemos acessar um índice de matriz fora do intervalo. Podemos verificar se um dicionário contém uma entrada correspondente a uma chave específica usando a função has e, em seguida, passando a chave como parâmetro. Isso nos permite verificar se existe uma entrada no dicionário antes de tentar acessar seu valor, evitando o erro. Se o dicionário não tiver a chave, imprimirei uma mensagem diferente. Em vez de definir o mesmo dicionário duas vezes, seria melhor armazenar em uma variável e usar a variável duas vezes. Na próxima lição, exploraremos algumas técnicas diferentes que você pode usar quando tiver dificuldades ou precisar de mais informações. Te vejo na próxima aula. 13. Depuração 0-12: Olá, amigos. Hoje, abordaremos algumas estratégias diferentes que você pode usar para ajudá-lo quando você inevitavelmente ficar preso Eu já anexei um script ao nó raiz da cena chamado debug Você provavelmente já percebeu o recurso de preenchimento automático que está disponível se você especificar o tipo de suas variáveis Isso não só permite que você veja todas as propriedades e funções da classe, mas depois de selecionar uma função, você também pode ver os tipos de todos os parâmetros da função para que você possa fornecer argumentos correspondentes. , quando você conhece os tipos de todas as suas variáveis, isso torna os erros de incompatibilidade claramente aparentes, e você será avisado do erro sem precisar executá-lo Sem tipos rígidos, o motor não sabe o que é incompatível até tentar executar a linha Se você quiser navegar por uma classe embutida, como a cor, podemos acessar facilmente as informações clicando em qualquer um dos botões no canto superior direito do painel. Online Docs abre uma guia em seu navegador padrão para a API GADO correspondente à versão do editor que você está usando Aqui você encontrará informações básicas sobre Gdo, dicas para começar, tutoriais detalhados sobre o básico, links da comunidade onde você pode encontrar recursos adicionais e uma Como você pode ver, há muitas aulas. E selecionando qualquer um deles, podemos ver do que eles herdam e por quais outras classes eles são herdados Cada um tem uma descrição do que faz. Links para tutoriais sobre como usá-lo, uma lista de propriedades e métodos Quando falamos sobre classes, tendemos a nos referir às variáveis como propriedades e às funções como métodos. Também existem sinais, algo que Gadot usa para comunicação automática entre nós, enumerações e constantes, como usamos antes Todos eles têm suas próprias subseções e descrições de como usá-los. De volta ao Editor do GDA, a pesquisa Ajuda abre uma janela no GDA onde você pode ver uma lista de todas as classes Ao selecionar uma turma, podemos ver todas as mesmas informações que estão disponíveis no site do GDA em nosso editor, para que possamos acessá-las offline Voltando ao nosso script, podemos até acessar essas informações mais facilidade mantendo pressionada a tecla de controle ou comando do que clicando no nome de uma classe, levando-nos diretamente às informações de referência dessa classe. O mesmo pode ser feito para funções e variáveis específicas. Clicar neles não apenas abre a página de referência da classe, mas também nos leva à função ou variável em que clicamos Também existem funções globais que podemos usar principalmente para realizar operações matemáticas, como clamp, por exemplo Se usarmos essa função, podemos ver os parâmetros que ela espera e podemos usá-la para fixar nossa variável em 0-1 Segurar a tecla de controle ou comando e clicar no nome da função global nos permitirá acessar a referência dessa função, completa com uma descrição e como usá-la. Todos eles estão contidos na classe de escopo global. Vou adicionar outra variável e outra linha ao meu script. Se executarmos nossa cena, podemos ver a árvore de cenas da simulação em execução por meio do painel de cena clicando no botão remoto Essa não é a mesma árvore de cena na guia local que criamos para definir a cena como uma planta Essa árvore de cena é aquela que foi construída pelo motor para executar a cena. Selecionando qualquer nó, podemos ver suas propriedades no inspetor e podemos ver que a função ready já foi executada, pois as cores têm valores diferentes Também podemos alterar os valores de qualquer uma dessas propriedades. Também podemos usar a impressão para imprimir sempre que quisermos ver o que nossas variáveis contêm a qualquer momento. E ajuda ser o descritivo possível com suas declarações impressas, para que não haja confusão sobre a origem delas Mas se mudarmos as coisas e usarmos a função de processo, mudarei a cor gradualmente ao longo do tempo adicionarei uma declaração impressa aqui. Como essa função de processo é executada 60 vezes por segundo, o valor das instruções de impressão como ferramenta de depuração é bastante reduzido, pois o registro de saída simplesmente repetirá a mesma mensagem mais rápido do que podemos lê-la ou reagir a Podemos pausar a simulação enquanto ela está em execução, usando o botão de pausa ou pressionando F sete Isso nos permite ver a árvore da cena remota como ela está neste momento e revisar o conteúdo do painel de saída com a simulação pausada Mas isso ainda não é muito útil, pois vários quadros serão concluídos entre o momento em que a simulação começa e quando podemos pausá-la Se clicarmos à esquerda de qualquer linha de código, podemos adicionar um ponto de interrupção automático indicado com um círculo vermelho Quando executamos a cena atual, a simulação será pausada quando atingir essa linha antes de executá-la . Isso é muito mais útil se quisermos ver nossa simulação ser executada um quadro por vez. Agora podemos ver como a cor de cada quadro muda gradualmente de um quadro para o outro. Vamos fazer com que nossa função de processo chame outra função para realizar uma tarefa simples. Vou mudar a cor gradualmente reduzindo seu valor de vermelho. Então, agora devemos ver a cor mudar gradualmente a cada quadro, ficando menos vermelho e mais azul. Com o ponto de interrupção ainda na primeira linha da função de processo, vou executar a cena Ele pára aqui e podemos ver que a próxima linha de código a ser executada é indicada com um triângulo amarelo. Enquanto a simulação é pausada dessa forma, podemos pedir que ela execute apenas uma única linha de código por vez, em vez de um quadro inteiro, selecionando passar por cima no menu Depurar ou usando o atalho F ten Isso executará apenas a linha de código apontada pelo triângulo amarelo e, em seguida, fará uma pausa novamente. Assim, podemos ver as alterações feitas apenas por essa única linha de código e podemos ver o triângulo amarelo apontar para a próxima linha esperando para ser executada. Podemos continuar executando nosso script linha por linha se continuarmos avançando até que a função do processo termine e o quadro seja concluído, retornando ao topo da função do processo para ser executado pela segunda vez Agora podemos observar cada alteração individual na cor à medida seu valor de azul aumenta separadamente de quando o valor de vermelho diminui, mesmo que elas ocorram durante o mesmo quadro. No caso de chamadas de função, há outra opção para entrar na função. Se selecionarmos essa opção ou usarmos o atalho F 11, a seta amarela entrará na função que está sendo chamada e executará essa linha por vez até sua conclusão Quando a função estiver concluída, a seta amarela retornará à função original para continuar executando aquela Usando essas ferramentas, temos uma visão muito focada do que nossas aulas estão fazendo e quando, como elas estão se comportando, e podemos observá-las em câmera lenta o quanto precisarmos para descobrir o que está errado em qual momento específico Se você não consegue resolver um problema sozinho, a comunidade GDA é muito prestativa e está sempre disposta a Existem servidores Discord para desenvolvedores do GDA, incluindo meu servidor, onde meus alunos se ajudam mutuamente O link para participar está no meu perfil. Também existem fóruns on-line em sites como o Redit, onde você também pode fazer perguntas. Agora você tem uma compreensão básica da maior parte da sintaxe do GDScript e das ferramentas necessárias para explorar mais esses conceitos Quando estiver pronto, peça um código de desconto para qualquer um dos meus cursos de projetos de jogos e boa sorte. 14. 1 3 Configuração: Oh amigos, bem-vindos ao meu curso. Estou fazendo um jogo de plataforma completo de dois pixels D em Godot. Para começar a usar o motor Cado, primeiro você precisa baixá-lo do site deles, acessar GodoEngine.org e baixar a versão estável mais recente Para este curso, usarei a versão 4.2 do God . Quando o download estiver concluído, basta descompactar a pasta e executar o arquivo EX Certifique-se de realocar esses arquivos descompactados para um local apropriado em seu Eu gostaria de ter o motor preso à minha barra de tarefas para facilitar o acesso Não há instaladores, hubs ou interfaces de armazenamento complicados para usar. Se você já trabalhou com outros motores de jogo, provavelmente ficará surpreso com quão simples e fácil é usar o Good. Em comparação, quando estiver pronto, clique no botão Novo projeto. Dê um nome ao seu projeto. Geralmente é o mesmo que o título do seu jogo, mas geralmente os jogos começam sem ter um título oficial ainda. Os desenvolvedores usarão coisas como Untitled Platform ou Untitled Pirate game até que um título oficial Selecione em seu disco rígido onde você deseja que o projeto seja armazenado. Eu recomendo criar uma subpasta em documentos chamados Godot Projects e dar a cada um de seus projetos sua própria pasta dedicada dentro dessa pasta para mantê-los Como o jogo que criaremos usa arte simples de dois pixels D em duas cenas D, podemos usar o renderizador de compatibilidade que suporta plataformas desktop, móveis e web e é o mais rápido em renderizar cenas simples como Por fim, Deus otimizará compatibilidade com o controle de versão do Github por padrão, o que é muito útil quando você terminar Clique em Create and It para criar o projeto e abri-lo para edição O projeto começa em uma cena vazia de três D, mas estamos fazendo um jogo em dois D. Na guia Cena, que está no canto superior esquerdo. Por padrão, clique em duas cenas D para criar uma nova cena em duas D. Isso mudará automaticamente nossa visualização do editor para dois modos D. Se você descobrir que seu editor está em três modos D, você sempre pode alternar com os botões na parte superior da janela do editor. Cado. Cada cena é definida como uma árvore de nós. A cena em si é definida como um nó dois. É um nó dois D, esse é o nó raiz da cena. Construímos nossas cenas adicionando galhos à árvore da cena. Clique no botão de adição na guia Cena para adicionar um nó à árvore da cena. Como você pode ver, há muitos tipos diferentes de nós. Digite, rotule na barra de pesquisa e adicione um nó de rótulo à sua cena. Selecione seu novo nó As propriedades dos nós A podem ser editadas na guia inspetor, que fica no lado direito da janela do editor Por padrão, digite qualquer mensagem que desejar na área de texto. Quando terminar, salve sua cena selecionando cena na barra de menu e, em seguida, salve a cena. Você também pode usar o controle de carrinho curto do teclado S, ou o comando S, dar um nome à sua cena. A convenção de nomenclatura para Godot é usar letras maiúsculas minúsculas com sublinhados Clique no botão Salvar para salvar sua primeira cena. Quando terminar, clique no botão Executar cena atual no canto superior direito da janela do editor. É aquele com o ícone de jogo em uma claquete. Essa ainda não é uma cena muito empolgante, mas funciona. Clique no ícone de parada para parar a cena. Na guia do sistema de arquivos , localizada no canto inferior esquerdo, por padrão, você pode ver uma lista de todos os arquivos que compõem seu projeto. Cada novo projeto Godot tem apenas um arquivo de recurso fornecido por padrão, o logotipo Godot Clique e arraste o logotipo para sua cena. Isso adicionou um sprite de dois nós D chamado icon à árvore de cena e definiu o ícone como a textura dos sprites Esta é apenas uma imagem sendo desenhada na tela. Vamos nos preparar para a próxima seção do percurso criando um piso sólido para nosso personagem andar e pular. Para isso, precisaremos adicionar colisão. Clique com o botão direito do mouse no nó do ícone e selecione adicionar nó filho. Usando a barra de pesquisa, procure o nó D do corpo estático dois. Isso adiciona o novo nó como filho do sprite, mas está mostrando um aviso Se passarmos o mouse sobre o ícone de aviso, ele nos fornecerá mais informações Esse nó não pode colidir com nada porque não sabe qual é sua forma Para fazer isso, o nó D do corpo estático dois precisa de outro nó filho. Adicionando outro nó, como antes dessa vez, pesquise dois nós D em forma de colisão, o ícone de aviso no corpo estático da nota Tu T desapareceu Mas o recém-adicionado nó Tut em forma de colisão tem outro aviso Ele pede que criemos um recurso de forma para ele. Isso é feito no painel do inspetor usando o menu suspenso Shape Select New Retangle Shape Isso satisfez o aviso. Mas olhando para a cena, podemos ver que a forma da colisão não combina com o ícone Se quisermos que a colisão cubra todo o ícone, precisamos ajustá-la Você pode clicar e arrastar os círculos vermelhos para redimensionar a forma da colisão. Se você quiser um controle mais preciso, pode clicar no recurso D em forma de retângulo dois para expandi-lo, que expõe campos de texto nos quais você pode inserir valores exatos para o tamanho Se a forma da colisão estiver fora do centro, você pode expandir a seção de transformação sob o nó dois D para ajustar sua posição Você também pode ajustar esse valor manualmente clicando e arrastando a Cruz Vermelha no centro da forma de colisão Selecione o nó do ícone e renomeie-o para floor. Como não precisamos mais fazer nenhum ajuste nos nós secundários, podemos contrair esse nó clicando na seta de colapso. Agora vamos transformar isso em um piso real. Ajuste sua visualização dentro da janela de exibição até que você possa ver toda a borda azul Como está sobreposta ao eixo x vermelho, a parte superior da caixa aparece magenta e o lado esquerdo sobreposto Essa caixa azul pode ser o limite da tela? Quando executamos o jogo com o nó do piso selecionado, ajustamos sua posição, tamanho e forma para que cubra a parte inferior da tela. Manter pressionado o botão Alt ou Opções moverá somente o nó selecionado e seus filhos. Acabamos de criar um piso funcional para nosso ambiente de teste de jogos a partir de nada mais do que o ícone de Godot Esse tipo de fluxo de trabalho é comum no desenvolvimento de jogos. Usando recursos de espaço reservado para criar um projeto mínimo, que pode ser usado para criar protótipos e demonstrar a mecânica do jogo Mas para criar um jogo que pareça bom, precisaremos de recursos. Eu criei este curso usando um pacote de ativos gratuito chamado Treasure Hunters, criado pela Pixel Frog A partir disso, esses ativos são liberados sob uma licença Creative Common Zero. Você pode distribuir, remixar, adaptar e desenvolver o material em qualquer meio ou formato, mesmo para fins comerciais. A atribuição não é necessária. Você pode baixar o pacote completo de ativos gratuitamente ou opcionalmente, apoiar o artista pagando qualquer quantia de dinheiro que você escolher Quando o download estiver concluído, descompacte a pasta. Importar os ativos é tão simples quanto clicar e arrastá-los para a janela do projeto Também usarei efeitos sonoros e músicas baixadas do Freesound.org. A biblioteca de loops Victory War and Battle Music foi composta pela Little O pacote de sons Battle foi criado por Luke Sharpals. Esses arquivos de som e música estão sob uma licença de atribuição. Eles ainda podem ser usados gratuitamente para qualquer finalidade, mas você deve dar o crédito apropriado ao criador desses ativos e fornecer um link para a licença. Preste muita atenção aos requisitos de licenciamento e atribuição dos ativos que você inclui em A importação desses ativos funciona da mesma forma que a arte. Basta clicar e arrastá-los para o editor. No entanto, esses arquivos de áudio são muito maiores do que as imagens e não usaremos muitos deles. Eu recomendo importar esses ativos somente quando você decidir implementar cada um Agora temos um piso funcional com colisão e todos os recursos artísticos necessários para iniciar a próxima seção, que implementará um personagem Te vejo na próxima seção. 15. 2 1 personagem: Olá amigos. Na primeira seção, iniciamos o projeto, importamos alguns ativos e criamos um piso funcional com colisão Nesta seção, vamos nos concentrar em criar um personagem para o jogador controlar e jogar. Para começar, primeiro construiremos a estrutura de nós de um personagem típico no painel de cena. Clique no botão de adição para adicionar um novo nó à árvore da cena. Procure o nó corporal de um personagem dois D e crie-o. Vou renomear esse nó para o nome do meu personagem. Assim como no chão, há um aviso. Esse nó não tem forma. Portanto, ele não pode colidir ou interagir com outros objetos. Já sabemos como resolver esse problema. Basta adicionar dois nós D em forma de colisão e definir sua forma O aviso nos lembra que devemos criar um recurso de forma no inspetor A maioria dos personagens dos jogos usa cápsulas como forma de colisão porque elas são facilmente ajustadas para abranger a forma geral de um humanóide e são fáceis de usar para o Por padrão, novos nós são adicionados na origem da cena, no canto superior esquerdo. Vamos ampliar os novos nós. Também precisamos ser capazes de ver a aparência do personagem. Para isso, adicionaremos outro nó secundário ao personagem, Um sprite, dois D. Vimos na lição anterior que há uma propriedade de textura no painel do inspetor para sprites, mas essa está vazia ao navegar pelo pacote de ativos dos caçadores de tesouros Selecione um sprite de personagem para usar. Por padrão, não quero que meu personagem seja equipado com a espada por padrão. Vou selecionar na pasta sem espada e escolher uma inativa Agora podemos ver o personagem como ele será desenhado no jogo, mas ele está embaçado Isso porque as configurações padrão do projeto do Godo não são otimizadas para pixel art Para corrigir isso, selecione projeto na barra de menu e, em seguida, Configurações do projeto. Há muitas configurações de projeto e, dependendo da sua versão de Godot, elas podem não estar organizadas ou nomeadas da mesma forma Se você tiver problemas para encontrar as configurações do projeto, há uma barra de pesquisa na parte superior da janela chamada configurações de filtro Precisamos encontrar as configurações para renderizar duas texturas em D e, em seguida, alterar o filtro de textura padrão de linear para Isso impedirá que o mecanismo gráfico tente suavizar a textura e simplesmente desenhar como está na tela. Com as alterações feitas, podemos fechar a janela e agora o personagem é desenhado em pixels perfeitamente definidos. Ao trabalhar com pixel art, essa geralmente é a estética preferida. Com os eixos X vermelho e Y verde marcando a origem da cena. Devemos supor que a origem do personagem estará aos pés deles. Vamos arrastar o spread para cima até que o eixo X vermelho atue como um piso onde o personagem ficará de pé. Certifique-se de que eles também estejam centralizados em torno do eixo Y verde. Para facilitar o ajuste da forma da colisão, vou reordená-la para que fique abaixo do sprite na árvore da cena, mas ainda seja infância para o Isso também determina a ordem em que os nós são desenhados na tela. Com a forma de colisão na frente do sprite, é mais fácil mover e ajustar seu tamanho para combinar com o personagem Lembre-se de que o ponto inferior da cápsula de colisão deve estar alinhado com os pés do personagem e o eixo X vermelho para que o personagem fique limpo no E também deve ser centralizado em torno do eixo Y verde. Em dois jogos D como esse, geralmente é considerado uma boa prática tornar a forma de colisão menor que a do personagem Isso evitará que o jogador seja atingido por ataques que ele perceba estarem perto da Sra. e permitirá que ele se aproxime do ambiente. Antes da próxima etapa, verifique se o painel do sistema de arquivos está focado na pasta raiz de recursos. Novos recursos serão criados na última pasta com a qual você interagiu No painel do sistema de arquivos, você pode fechar qualquer pasta aberta e clicar no espaço em branco. Se sua seguradora fez isso da maneira certa, clique no seu personagem Podemos pegar qualquer galho em nossa árvore de cenas e salvá-lo como sua própria cena. Vou nomear essa nova cena com o nome do personagem que ela já fez, pois ela usará o nome do nó como o novo nome da cena por padrão. Agora Roger é a própria cena separada da cena em que estamos trabalhando nó de Roger na árvore da cena tem um botão de claquete e os nós secundários foram Clicar na claquete abre a cena de Roger. Isso nos permite editar Roger isoladamente. Todas as alterações que fizermos aqui serão transferidas para todas as cenas que contêm Roger na cena principal Agora podemos mover Roger da origem da cena para o chão, onde eles serão desenhados na tela Se examinarmos a cena atual, podemos ver Roger pairando acima do chão, mas ele provavelmente deveria cair no chão por causa da gravidade Para fazer Roger se comportar como um personagem, precisamos adicionar uma chave de script à cena de Rogers e selecionar o nó raiz Em seguida, clique na rolagem com botão de adição para adicionar um novo script. É uma boa prática escrever comportamentos comuns da forma mais genérica possível Esse script não deveria ser Roger. Em vez disso, vou nomear o personagem do script e escrever o script de uma forma que ele possa ser aplicado a qualquer personagem, não apenas Roger Godot oferece um modelo padrão para scripts anexados a determinados nós Vamos ver o que esse modelo contém. Por padrão, o script herdará os comportamentos do tipo de nó ao qual está anexado, neste caso, um corpo de caractere dois D. Escreveremos todos os nossos scripts no idioma nativo de Goido, o script Godot Clique em Criar para criar o novo script e anexá-lo ao nó. O painel principal mudará automaticamente para a visualização do script e abrirá o script para edição. Como você pode ver, o modelo já tem vários recursos. O personagem tem uma velocidade e uma velocidade de salto. Eles são medidos em pixels por segundo. Há também uma força gravitacional que está sendo definida pelas configurações do projeto Na função do processo físico, podemos ver que a gravidade é aplicada ao personagem se ele não estiver no chão. Um botão de salto foi implementado adicionando velocidade de salto. Ao pressionar a interface do usuário , exceto a barra de espaço, há controle direcional para direções esquerda e direita, permitindo que o personagem se mova Move inside é uma função embutida que medirá a posição, a velocidade e as forças externas do corpo do personagem velocidade e as forças externas Em seguida, determine onde o personagem estará depois de decorrido o tempo delta Com as configurações padrão, esse código será executado 60 vezes por segundo. Se executarmos a cena atual, veremos Roger cair da origem da cena Mas essa é a cena de Rogers, não é para ser interpretada Volte para a cena principal e mude a visão para duas D. Jogando essa cena, podemos ver Roger cair imediatamente no chão Pressionar a barra de espaço faz com que Roger pule. Pressionar as teclas de seta esquerda e direita moverá Roger para a esquerda e para a direita Essa implementação de controles não é muito boa, mas oferece um ponto de partida a partir do qual podemos construir nosso jogo. Agora temos um personagem básico sendo desenhado na tela com controles básicos e física. Na próxima lição, vamos nos concentrar em melhorar nossos controles de jogador. Te vejo na próxima aula. 16. 2 2 Entrada: Olá amigos. Na lição anterior, criamos um personagem básico com física de colisão de spray e informações básicas Nesta lição, configuraremos um melhor tratamento de entrada para controlar nosso personagem. Vamos começar esta lição com algumas tarefas domésticas. Como você pode imaginar, nosso jogo conterá muitos recursos diferentes. E é importante mantê-los organizados para que possamos encontrar com rapidez e facilidade qualquer recurso de que precisamos, certo? Cozinhando na pasta raiz ou em um espaço em branco. Crie uma nova pasta e dê um nome a ela. Scripts e, em seguida, arraste o script do personagem para a pasta. Em seguida, repita o processo com as cenas. Mas temos dois tipos diferentes de cenas. Podemos ainda distingui-los com uma subpasta dentro da pasta de cenas chamada characters e colocar Roger nessa subpasta colocar Roger nessa Quando terminar, alterne para a visualização do script. Examinar novamente o modelo padrão fornecido para o script D body two do personagem realmente não atende às nossas necessidades. Chamamos esse script de Personagem e planejamos aplicá-lo a todos os personagens do nosso jogo, muitos dos quais não serão controlados pelo jogador. É importante isolar e separar a funcionalidade em scripts diferentes para esse script, que estamos usando para descrever os atributos e comportamentos dos personagens Devemos remover qualquer manipulação de entrada. Vou comentar essas linhas pressionando o controle K ou o comando K. Aplicar a entrada de gravidade e movimento durante o processo físico ainda é útil Mas vamos adicionar alguns métodos públicos ao script para descrever exatamente o que um personagem pode fazer. Em nosso jogo, um personagem pode ficar virado para a esquerda ou para a direita. Por enquanto, vamos deixar o corpo desses métodos vazio escrevendo, passando ou retornando. Um personagem pode correr, o que requer uma direção para saber se está se movendo para a esquerda ou para a direita. Podemos representar a direção como um flutuador, que é um número que permite valores decimais Isso não só será útil para saber a direção, mas também permitirá velocidades variáveis. Precisaremos armazenar esse valor em uma variável para que ele possa ser usado durante o próximo processo físico. Vamos definir uma variável local privada em nosso script chamada direção de sublinhado e, em seguida, definir seu valor na função de execução Também podemos editar o processo físico para usar essa variável em vez da que ela estava usando antes. Um personagem também pode pular, mas não precisamos de nenhum parâmetro para isso. Se o personagem estiver no chão, adicione a velocidade de salto à velocidade y do personagem Esses serão nossos métodos públicos que outros scripts podem usar para controlar qualquer personagem em nosso jogo. Adicionaremos mais métodos ao script à medida que adicionarmos comportamentos adicionais aos nossos personagens. Outros métodos, como o processo físico, que não dizem respeito a outros scripts, são marcados com um sublinhado anterior, assim como a variável de direção do sublinhado Eles não devem ser usados por outros scripts, eles são apenas para esse script. Se outro script quiser controlar a direção de um personagem, ele deve chamar o método run em vez disso, porque o método run é público. Isso cria um conjunto universal de comportamentos claramente identificados para descrever como um personagem agirá em nosso benefício. Uma prática conhecida na programação como encapsulamento. O conteúdo desses métodos, variáveis e do processo físico não é importante para outros scripts. Os outros scripts não precisam saber como o personagem pula, eles só precisam saber que se trata de um personagem e que ele pode pular se escondendo Os detalhes de como a funcionalidade é implementada são conhecidos na programação como abstração Essas práticas tornarão seus scripts muito mais organizados, fáceis de entender, usar e adaptar para outros fins. Isso está começando a parecer um roteiro de personagem melhor, mas eliminamos a capacidade do jogador de controlar o personagem, porque queremos que isso seja feito por meio uma mudança de roteiro separada para a cena principal. Se você ainda não estiver lá, clique com o botão direito do mouse no seu personagem e adicione um nó secundário. Esse nó não precisa de nenhum tipo. Pode ser apenas um nó básico e chamá-lo de Player. Estamos usando isso apenas para anexar um script extra ao personagem. Em seguida, no painel do sistema de arquivos, vamos escrever, clique na pasta de scripts para criar um novo script e chamá-lo de player. Em seguida, conecte-o ao novo nó. Clique no ícone do script para abrir o script para edição. O objetivo do script será receber informações e, como resultado, chamar os métodos apropriados no os métodos apropriados no script do personagem. O que significa que precisaremos nos referir ao personagem. Se você se lembra, anexamos esse script a um nó filho do nó do personagem. Podemos facilmente obter uma referência ao nó do personagem declarando uma variável na parte superior do script Nomearemos essa variável como caractere de sublinhado, porque somente esse script deve precisar acessá-la e atribuir seu valor para obter o pai Iniciar a declaração com at on ready nos permitirá atribuir um valor a essa variável depois que o nó for criado, entrar na árvore de cena e estiver pronto para começar a ser executado. O que significa que o nódulo saberá quem é seu pai nesse momento. Para receber e processar a entrada, usaremos dois métodos diferentes, processo de sublinhado e entrada de sublinhado O método de entrada é mais eficiente para lidar com eventos de pressionar e soltar botões. Esse método usa um parâmetro, normalmente chamado event, e seu tipo será evento de entrada. Tudo o que precisamos fazer é verificar o evento para ver se o jogador pressionou o botão de pular. Se o fizeram, diremos ao personagem pule, como no processo físico O Underscore Process usa delta como parâmetro, que é um tipo flutuante que representa a quantidade de tempo decorrido desde o último Normalmente, um 60º de segundo. Mas como não vamos usar o valor de delta aqui, podemos prefixar seu nome com um sublinhado, informando ao Goodot Engine que não precisamos desse valor no método do processo, que executará todos os quadros, independentemente de a entrada ter sido fornecida ou De qualquer forma, podemos verificar o status de nossa entrada de movimento. Isso nos permitirá lidar com o pressionamento de teclas e os eixos analógicos de forma mais fácil Chamaremos o caractere do run aqui passando o argumento da entrada get axis, run para a esquerda como o valor negativo e run para a direita como o valor positivo. Você deve ter notado que as entradas padrão eram UI accept, UI left e UI right Eles são mapeamentos de entrada integrados destinados a controlar as interfaces do usuário Como usamos nomes diferentes para os mapeamentos de entrada, precisaremos adicioná-los às configurações do projeto antes que funcionem Abra as configurações do projeto e alterne a guia para o mapa de entrada. Se você clicar no botão Mostrar ações incorporadas, poderá ver as ações de entrada que foram usadas anteriormente Você pode reocultar esses mapeamentos com o mesmo tipo de alternância. Vá para a esquerda no campo Adicionar nova ação e clique no botão Adicionar. Em seguida, repita para correr para a direita e pular para mapear cada um deles em um botão. Clique no botão de adição à direita. Isso abre uma janela pop-up na qual você pode selecionar qualquer entrada para teclado, mouse ou joypad Você pode usar a barra de pesquisa para filtrar as opções ou usar um campo de escuta para detectá-las automaticamente. Para correr para a esquerda, vou usar a tecla A. Em seguida, repita o processo para adicionar uma tecla para correr para a direita e pular. Você também pode adicionar vários botões a cada mapeamento para que seus jogos funcionem perfeitamente Com um game pad, usarei o manípulo esquerdo para correr e o botão inferior para pular. Quando terminar, tente executar a cena e testar seus novos mapeamentos de entrada para controlar o personagem Tudo deve funcionar da mesma forma que antes, mas agora o tratamento de entrada e os controles de caracteres estão sendo tratados por scripts separados Usando esse método, você pode imaginar como o personagem que o jogador está controlando pode se tornar intercambiável O script de manipulação de entrada também pode ser substituído por um script de IA para controlar outros personagens em seu jogo com bastante facilidade. Agora temos um melhor gerenciamento de entradas para controlar um personagem em seu jogo. Na próxima lição, vamos nos concentrar em melhorar a sensação da locomoção e da mecânica do salto Te vejo na próxima aula. 17. 2 3 Locomoção: Olá, amigos. Na lição anterior, aprimoramos o tratamento de entrada de nosso personagem isolando-o em seu próprio script, separado do nosso personagem Nesta lição, faremos com que os controles de locomoção do personagem pareçam melhores para o jogador Se você comandar a cena principal e prestar atenção na sensação do movimento para a esquerda e para a direita, ela é muito rígida. A velocidade do movimento é instantânea e constante, o que não é como os humanos ou quaisquer outros objetos realmente se movem Abra o script do personagem para simular movimentos mais realistas Na verdade, podemos usar variáveis retiradas da física do mundo real. Na realidade, um objeto acelerará gradualmente até sua velocidade máxima e também acelerará. Aqui na parte superior do script, Godot definiu um valor constante para a velocidade dos personagens Vamos adicionar duas novas variáveis aqui para representar a aceleração e a desaceleração, que estamos medindo em pixels por segundo Eles podem ser privados precedidos por um sublinhado e serão do tipo Por enquanto, daremos a eles os valores iniciais. Vou usar o mesmo valor da velocidade e ajustá-los mais tarde, depois de testar como eles se sentem. Agora, o processo físico precisará usar esses valores para calcular a velocidade do personagem Se olharmos primeiro para o bloco else, é aqui que o personagem desacelerará quando o jogador não estiver fornecendo nenhuma entrada Tudo o que precisamos fazer aqui é mudar a velocidade para a desaceleração. Essa função útil chamada mover em direção começará no valor da velocidade x e se moverá em direção a zero com uma quantidade de desaceleração Isso funciona bem tanto para a esquerda quanto para a direita, pois parar significará mover a velocidade em direção a zero Mas se você olhar acima, o valor da gravidade está sendo multiplicado por delta Lembre-se de que esse código é executado 60 vezes por segundo. E estamos fornecendo nossa taxa de desaceleração em unidades de pixels por segundo Podemos multiplicar o valor da desaceleração por delta para ajustar seu valor de acordo com a quantidade de tempo decorrido desde o último processo físico Então, podemos reescrever o bloco F para usar a mesma função e aplicar aceleração Desta vez, estamos começando na velocidade x, avançando em direção à velocidade vezes a direção uma taxa de aceleração multiplicada por delta Lembre-se de que podemos usar esse script para todos os personagens do nosso jogo, e talvez não queiramos que todos tenham exatamente a mesma velocidade constante. Primeiro, vamos mudar a velocidade de uma variável constante para uma variável privada e editar a fórmula de aceleração para corresponder. Em seguida, podemos adicionar at export à frente dessas declarações de variáveis para torná-las acessíveis a outras partes do motor Godot, ou seja, o Se mudarmos para a cena do personagem e selecionarmos o nó raiz, agora você verá essas variáveis no inspetor e poderá editar seus valores Dessa forma, cada personagem pode definir seus próprios valores de movimento, velocidade, aceleração e desaceleração Nem todos precisam ter os mesmos valores constantes. Volte para a cena principal e tente jogar com esses novos valores. Você pode ver como o personagem acelera gradualmente e também desacelera Como usamos o mesmo valor velocidade dos caracteres para aceleração e desaceleração, sabemos que o tempo necessário para atingir a velocidade máxima é de exatamente Da mesma forma, a quantidade de tempo que o personagem leva para parar completamente também é de 1 segundo. Podemos fazer ajustes nesses valores de forma rápida e fácil com o inspetor mesmo enquanto a cena está sendo reproduzida Isso nos permite testar e sentir rapidamente como valores diferentes de nossas variáveis afetarão o jogo e ver quais valores funcionam melhor. Acho que o personagem deve atingir a velocidade máxima em meio segundo e parar em um quarto de segundo. Aumentaremos os valores de aceleração e desaceleração em um fator de 2,4, portanto, vamos experimentar Isso me parece melhor se você tiver sua taxa de aceleração definida abaixo da taxa de desaceleração No entanto, se você tentar mudar de direção enquanto se move, o redirecionamento parecerá muito pouco natural Isso ocorre porque você espera que o personagem desacelere até zero e, em seguida, acelere na direção Mas o código, conforme escrito, diz que eles devem simplesmente acelerar da direção errada para a direção certa. Para melhorar a sensação, podemos alterar a instrução if para primeiro verificar se a direção é zero. Nesse caso, o caractere deve desacelerar Em seguida, sabendo que a direção não é zero, podemos verificar se a velocidade x é zero, o que significa que o personagem está parado e pedir Também precisamos da condição se o seno de direção é o mesmo que o seno de velocidade x, que significa que eles já estão se movendo e o jogador quer continuar se movendo na Nossa última possibilidade é se nem a direção nem velocidade forem zero e seus senos não coincidirem, o que significa que o jogador quer se mover na direção oposta à do personagem Nesse caso, podemos, em vez disso, avançar em direção à velocidade a uma taxa de desaceleração Isso parecerá muito mais natural quando o jogador tentar se virar enquanto se move. Vamos experimentá-lo muito melhor antes de prosseguirmos. Pessoalmente, não gosto muito de pensar em termos de pixels, especialmente porque eles podem ser apenas recursos reservados E se você decidisse que queria fazer este jogo usando um pacote de ativos diferente que usa blocos de 64 pixels em vez de 32 pixels? Agora, toda a sua mecânica não funcionará da mesma forma, e cada valor precisa ser ajustado para corresponder ao novo tamanho em pixels de seus ativos Em vez disso, prefiro pensar na minha mecânica em unidades de blocos por segundo, pixels por segundo Esse seria um valor constante em todo o projeto, qual muitos scripts diferentes precisarão de acesso rápido e fácil. Para isso, podemos criar uma nova pasta de scripts chamada carregamentos automáticos e, em seguida, criar um novo script dentro dessa pasta chamada global. Esse script não precisa executar nenhum código. Ele só será usado para armazenar variáveis quando elas forem usadas por todo o projeto. Assim como este, podemos declarar nossa variável neste script, PPT ou pixels por bloco É um número inteiro, um número sem pontos decimais, e seu valor será 32 Mas como outros scripts acessam esse valor? Abra as configurações do projeto e mude para a guia de carregamento automático. Esta é uma lista de scripts que serão carregados automaticamente quando o jogo começar e permanecerão lá até que seja fechado. Eles também podem ser acessados por qualquer outro script pelo nome do nó. Clique no ícone da pasta para abrir um navegador e encontrar seu script global. O nome do script será usado para gerar automaticamente o nome do nó. Clique no botão Adicionar e adicione-o à lista de nós carregados automaticamente no script de caracteres. Podemos ajustar os valores de nossas novas variáveis para serem definidas em unidades de blocos em vez de pixels. Na minha opinião, faz mais sentido que o personagem se mova a uma velocidade de oito peças por segundo, em vez de 300 pixels por segundo. Se eu optar por mudar para um pacote de ativos que usa blocos de 64 pixels, toda a minha mecânica ainda funcionará da mesma forma Tudo o que eu precisaria alterar é o único valor no script global de carregamento automático. Se você preferir usar pixels como unidade principal, fique à vontade para continuar fazendo isso. Quando começarmos nosso jogo. O Cado executará automaticamente um método em cada nó quando estiver pronto, apropriadamente chamado de underscore Nesse método, simplesmente multiplicamos cada um desses valores pelo ponto global para convertê-los em unidades de pixels Agora temos nosso personagem acelerando e correndo de forma mais realista Na próxima lição, melhoraremos a mecânica do salto e da gravidade Te vejo na próxima aula. 18. 2 4 Saltar: Olá amigos. Na lição anterior, aprimoramos a mecânica de locomoção do personagem Nesta lição, faremos ajustes semelhantes saltos e na gravidade do personagem Se rodarmos a cena principal e tentarmos pular, você verá que o personagem pula muito alto e flutua no ar por um Realmente não é bom dar uma olhada no roteiro do personagem. A velocidade do salto é outro valor constante arbitrário que realmente não atende às nossas necessidades Em vez disso, vamos definir que nossos personagens pulam em termos de quantas peças de altura eles devem ser capazes de pular. Essa será uma variável privada exportada chamada altura do salto sublinhada com o tipo E usarei um valor padrão de 2,5, embora não seja exatamente realista. Isso permite que o jogador pule em cima de uma plataforma na qual ele também pode escolher andar. Também precisamos multiplicar isso por um bit global. No método pronto, antes do início do jogo, precisaremos calcular a velocidade que o personagem precisará para atingir aquela altura de salto Podemos substituir a constante de velocidade de salto por uma variável privada para manter esse valor Como ele será calculado em tempo de execução, ele não precisa ser exportado Esse cálculo pode ser adicionado ao método pronto. Segundo, a velocidade do salto pode ser calculada usando a raiz quadrada da altura do salto multiplicada pela gravidade multiplicada por Não podemos usar raiz quadrada em um número negativo, tem que ser positivo. Felizmente, em dois jogos D, o eixo y está A gravidade já está expressa como um valor positivo. No entanto, nosso resultado para a velocidade do salto também é um número positivo Como resultado, precisamos multiplicar por menos um para fazer o personagem pular para cima, não para baixo. Agora podemos editar o método jump para usar essa nova variável. Se testarmos, o personagem pulará exatamente 2,5 peças de altura quando pressionarmos o botão de pular, mas o salto ainda é lento e flutuante. Para corrigir isso, podemos abrir as configurações do projeto e alterar o valor da gravidade. Filtrando as configurações ou clicando em física dois D, podemos encontrar a configuração padrão de gravidade Isso é definido para 980 pixels por segundo ao quadrado. Em vez disso, digitarei o cálculo diretamente no campo começando com 9,8, que é a gravidade na Terra, multiplicado pelo tamanho do ladrilho de 32 pixels, depois multiplicarei por oito, obtendo um valor de 2508 0,8 que é aproximadamente 2,5 vezes o que Isso fará com que tudo no jogo pareça mais pesado e caia mais rápido, o que parecerá mais realista para o jogador Agora, o salto parece muito melhor, mas eu gostaria de dar ao jogador a opção de controlar a altura em que o personagem pula Existem várias maneiras diferentes pelas quais os jogos implementam esse recurso, como medir quanto tempo o botão de pular ficou pressionado antes do lançamento Adicionar uma força de salto inicial, uma força extra a cada quadro por um curto período de tempo, etc., se for mal executado, isso pode fazer com que controles frustrantes e sem resposta, ou que os personagens sintam que estão usando Minha solução pessoal favorita para isso é muito simples e parece muito responsiva ao jogador Basta impedir que o jogador se mova para cima quando o botão de pular for solto no script do personagem No método jump, podemos adicionar um método stop jump. Lembre-se de que o eixo y está invertido. Em dois jogos D, o valor zero para Y está na parte superior da tela e os valores positivos se movem para baixo. Se a velocidade y dos caracteres for menor que zero, o que significa que eles estão subindo, podemos defini-la como zero para impedir que subam Então a gravidade começará a se mover para baixo. O jogador perceberá isso como controlar seu Ppe de salto segurando e soltando o botão de pular Só precisamos chamar esse novo método a partir do script do player. Quando o jogador solta o botão de pular, se o evento for uma ação liberada, pule e o personagem pare de pular. Agora vamos experimentar. Podemos controlar facilmente a altura em que o personagem pula soltando botão de pular antes que ele atinja o ápice máximo Isso é fácil de implementar e eficaz para que o jogador sinta que tem controle total. A última coisa que quero abordar nesta lição é que o jogador tem tanto controle sobre o movimento do personagem no ar quanto no solo. Realisticamente, não existiria controle aéreo durante o Mas na maioria dos videogames, controle aéreo existe para manter o jogador no controle do personagem. Pode ser especialmente útil em jogos de plataforma para permitir que o jogador evite armadilhas ou redirecione a ousadia para Um pouco de controle aéreo pode ser bom, mas não deve ser o mesmo que movimento no solo. Para adicionar um controle aéreo mais específico ao nosso personagem, podemos definir outra variável exportada para ela na parte superior do script como um tipo flutuante e atribuir a ela um valor padrão de 0,5. Tudo o que precisamos fazer é multiplicar isso pela aceleração quando o jogador não está tocando o Para simplificar o método do processo físico, vamos dividi-lo em dois métodos separados, física e física terrestre. Ambos podem ser métodos privados no processo físico. Se o personagem estiver no chão, aplique a física do solo, caso contrário, aplique a física do ar. Em seguida, mova e deslize. física do solo não mudará em relação ao que já temos no método da física do ar. Se a direção não for zero, podemos mover a velocidade x em direção à velocidade vezes a direção a uma taxa de aceleração vezes o controle aéreo vezes delta Isso ainda permitirá que o jogador tenha algum controle no ar, mas reduzido pela metade. Vamos manter essas variáveis separadas das acima, exportando também categorias para elas. Essas variáveis serão exportadas para a categoria de salto. As variáveis acima serão exportadas para a categoria de locomoção Vamos experimentá-lo. Como com as outras variáveis, você pode fazer ajustes no valor e ver o que é bom para você. Agora temos nosso personagem pulando e caindo mais realista e com melhor controle para Na próxima lição, vamos animar o personagem de acordo com seu movimento Te vejo na próxima aula. 19. 2 5 Animação: Olá amigos. Na lição anterior, melhoramos a sensação geral da mecânica de salto do personagem e demos ao jogador um melhor controle da altura e da trajetória do salto Nesta lição, adicionaremos animações à cena do personagem, abriremos a cena do personagem e obteremos uma boa visão do personagem Primeiro, vamos fazer com que o personagem fique voltado para a direção em que está se movendo. Se você selecionar o nó D do sprite two e olhar no inspetor, expanda a seção de deslocamento abaixo do sprite two D. A propriedade que queremos alterar é flip H. Ao clicar horizontalmente na caixa de seleção, podemos ver que o podemos ver Passar o mouse sobre o nome nos mostra como acessar essa propriedade Em nosso script, o nome da propriedade é flip underscore H, abrindo o script do caractere Criamos métodos para a face esquerda e para a direita, mas ainda não os usamos. Tudo o que precisamos fazer é modificar o valor da propriedade flip H do nó D do sprite two. Podemos obter uma referência ao nó D do sprite two na parte superior do script usando at on ready var, vamos chamá-lo de underscore Isso será do tipo sprite two D. Em seguida, atribua o valor dessa variável sendo cifrão sprite two D. Qualquer que seja o nó esse script de caractere esteja anexado, ele pesquisará nos nós filhos para encontrar um chamado sprite two D e o atribuirá Lembre-se de que, para que esse script funcione conforme o esperado, cada personagem que criamos deve ter um nó filho chamado sprite two D. Caso contrário, essa variável não conterá um valor Agora, nos métodos face esquerda e face direita, podemos usar essa referência ao sprite two D para alterar a propriedade flip H. Se o caractere estiver voltado para a esquerda , a propriedade flip H deve ser verdadeira Se eles estão voltados para a direita, isso deve ser falso. Mas essas funções não estão sendo chamadas em nenhum lugar. O melhor lugar para ligar para eles seria no início do processo de física. Não importa se o personagem está no chão ou no ar. Afinal, se o seno de direção for negativo, o personagem deve estar voltado para a esquerda Se o seno de direção for um, o personagem deve estar voltado para a direita Não precisamos fazer nada se o seno de direção for zero Agora, quando executarmos a cena principal, o personagem ficará voltado para a direção da entrada do jogador. Esse é um bom começo, mas também vamos começar a trabalhar na animação do personagem Clique com o botão direito do mouse no nó D do sprite two na árvore da cena e adicione um nó filho O nó que precisamos pesquisar é um nó de player de animação. Esse nó nos permitirá alterar aspectos do personagem ao longo do tempo, principalmente a textura do sprite Adicionar esse nó abrirá automaticamente o painel de animação na parte inferior da janela do editor. Clique no botão de animação e, em seguida, clique em Novo nome, o novo ídolo da animação Agora você pode ver uma linha do tempo no painel de animação. Cada aspecto do personagem que está sendo alterado pela animação será listado nesta linha do tempo Clique no botão de adição para adicionar uma nova propriedade à animação. A propriedade que precisamos alterar é textura do sprite two ts. Para marcar as posições na linha do tempo em que o sprite mudará Podemos adicionar um quadro-chave clicando com o botão direito do mouse na faixa da propriedade e selecionando inserir chave Depois que um quadro-chave é adicionado à linha do tempo, podemos movê-lo facilmente Clicando e arrastando, se não estiver no lugar certo. Ao clicar em um quadro-chave, podemos definir seu valor no inspetor O sprite 01 inativo já está preenchido no campo Como esse é seu valor atual, acho que esses ativos têm a melhor aparência. Com uma taxa de quadros de dez quadros por segundo, vou querer alterar a textura do sprite cada décimo de segundo, o que significa que a duração total da animação será de 0,5 Atualmente, a linha do tempo está mostrando 15 segundos, o que dificulta a edição apenas do primeiro segmento de toda a linha do tempo Vamos ampliar usando o controle deslizante no canto inferior direito até que possamos ver facilmente cada 0,1 segundo na linha do tempo Então, vamos adicionar mais quatro quadros-chave e preencher cada um com os sprites restantes Para isso, precisamos reduzir a duração da animação atualmente definida em 1 segundo para 0,5 segundos. Queremos que essa animação seja repetida. Clique no botão Animation Looping à direita. Podemos visualizar essa animação clicando no ícone de reprodução na parte superior do painel de animação. Isso parece muito bom. Em seguida, precisamos executar a animação. Clique no botão de animação e selecione Duplicar. Em seguida, nomeie a nova execução da animação. Expandindo a pasta de ativos que contém a animação de execução, podemos ver que ela contém seis sprites Precisaremos expandir a duração da animação para 0,6 segundos e adicionar outro quadro-chave. Em seguida, preencha cada quadro-chave com os sprites corretos Quando terminar, visualize a animação para garantir que ela tenha uma boa aparência Repita o processo mais três vezes para criar as animações de salto, queda e chão Prestando atenção à duração de cada animação com base no número de sprites fornecidos no pacote de ativos No entanto, essas animações não devem ser repetidas, portanto, certifique-se de desativar o loop para Agora temos as animações de nossos personagens todas configuradas. Na próxima lição, construiremos uma máquina de estados para sincronizar as animações com o que o personagem está fazendo Te vejo na próxima aula. 20. 2 6 máquina de estado: Olá amigos. Na lição anterior, configuramos animações para o movimento de nossos personagens Nesta lição, implementaremos essas animações e as sincronizaremos com o comportamento do personagem Mas antes de fazermos isso, vamos adicionar rapidamente outro nó à cena principal. Uma câmera de dois nós D. Isso nos ajudará a ter uma visão melhor de nosso personagem rapidamente , pois podemos reposicioná-lo e ampliá-lo editando suas propriedades no inspetor Agora, quando testarmos a cena, teremos uma visão melhor dos resultados dessas animações Agora, para implementar as animações, abriremos a cena do personagem e adicionaremos outro nó secundário ao player de animação Esse nó é chamado de árvore de animação. O nó da árvore de animação nos dá um aviso: nenhum nó de animação raiz para o gráfico está definido. Olhando no painel do inspetor, há um campo chamado Anim Clicando onde está escrito um sinal, podemos selecionar o reprodutor de animação que criamos na lição anterior. O objetivo dessa árvore de animação será controlar qual animação está sendo reproduzida em um determinado momento. Usando o menu suspenso denominado raiz da árvore selecione a nova máquina de estado do nó de animação Isso abrirá a máquina de estado recém-criada no painel da árvore de animação na parte inferior da janela do editor. Antes de começarmos a editar a máquina de estado, no entanto, vamos dar uma olhada na pasta de ativos do nosso personagem. As animações são divididas em duas pastas rotuladas com espada e sem espada O conteúdo de cada uma dessas pastas são todas as mesmas animações, com exceção do personagem segurando uma espada Ou, para evitar esforços redundantes, planejarei com antecedência a estrutura dessa árvore de animação para acomodar recursos que não serão implementados até o final do curso Para começar a usar nossa máquina de estado, primeiro clicaremos com o botão direito do mouse em algum espaço vazio no painel da árvore de animação e selecionaremos Adicionar máquina de estado. Em seguida, nomeie essa nova máquina estatal sem espada. Também podemos fazer isso novamente e criar outra máquina de estado chamada With sword. Em seguida, podemos clicar no botão de transição no canto superior esquerdo e adicionar uma transição do início para sem espada. Agora, quando o jogo começar, a árvore de animação usará como padrão a reprodução animações para nosso personagem sem a espada Podemos ignorar a máquina de estado da espada por enquanto, voltar ao modo de seleção e clicar no ícone do lápis para abrir a máquina de estado sem espada para edição. Dentro da máquina de estado, podemos criar outra máquina de estado chamada movimento. Em seguida, adicione a transição do início ao movimento como padrão. Essa camada da árvore será usada posteriormente para outra finalidade. Abra a máquina de estado do movimento para edição mais uma vez. Crie outra máquina de estado, desta vez chamada de locomoção, e crie uma transição do início para a Em seguida, abra a máquina de estado de locomoção para edição. Finalmente, podemos adicionar animações à máquina de estado. o botão direito do mouse para selecionar adicionar animação, depois inativo e repita para adicionar execução Crie uma transição do início para o modo inativo, tornando-a a animação padrão Em seguida, adicione uma transição de inativo para execução e de execução de volta para inativo O objetivo dessa máquina de estado será alterar a animação entre esses dois estados. Podemos definir as condições sob as quais essas transições ocorrerão clicando nelas e editando-as no inspetor com a transição de inativo para execução selecionada, expandir a seção avançada e selecionar a área de texto da expressão A expressão inserida nessa área de texto deve produzir um valor booleano, verdadeiro ou falso A condição sob a qual queremos que o personagem mude de ocioso para executado é se a velocidade não for zero Da mesma forma, a condição para a transição da corrida para a marcha lenta será se a velocidade x for Também precisamos dizer à árvore de animação qual nó está controlando essas expressões avançadas. Selecionando a árvore na árvore da cena. Em seguida, examinando o painel do inspetor, podemos alterar o campo base da expressão avançada para o nó raiz do personagem Agora podemos executar a cena principal e ver a árvore de animação funcionar. Alternar a animação do personagem entre inativa e corrida com base na velocidade x do personagem Para incorporar o resto das animações. Volte ao painel da árvore de animação e navegue até a camada de movimento da máquina de estado. Clique com o botão direito do mouse para adicionar as animações de salto, queda e solo Crie transições de locomoção para salto, salto para queda, queda para chão, chão para locomoção e locomoção para queda chão para locomoção e locomoção para Então, podemos definir as condições para cada uma dessas transições. A animação do personagem deve mudar para pular se sua velocidade y for menor que zero, depois mudar para cair se sua velocidade for maior ou igual a zero, seguida pelo solo se estiver no chão Como esse é um método incorporado do nó dois do corpo do personagem, podemos acessá-lo e ele retorna um valor booleano Não há condição para a transição do solo para a do solo Em vez disso, expanda a seção do switch e selecione no final do menu suspenso Isso permitirá que a animação terrestre seja concluída antes da transição para a locomoção, mas não imporá Por fim, se o jogador sair de uma saliência, queremos que a animação passe da locomoção para a da locomoção Isso será verdade se não estiver no chão. Mas as transições da locomoção para o salto e a queda serão verdadeiras a qualquer momento em que o Podemos dar prioridade ao salto alterando sua prioridade 1 a 0 Voltando para a cena principal e executando a cena atual Agora podemos ver a árvore de animação em funcionamento, pois ela fará a transição automática do personagem entre os vários estados. Agora temos os movimentos básicos do personagem animados. Na próxima lição, adicionaremos poeira e efeitos sonoros a algumas dessas animações. Te vejo na próxima aula. 21. 2 7 efeitos: Olá amigos. Na lição anterior, usamos uma máquina de estado para sincronizar a animação dos personagens com seu comportamento Nesta lição, adicionaremos alguns efeitos sonoros e visuais para aprimorar as animações. Começando na cena do personagem, vamos adicionar um novo nó, um sprite animado em dois D, e renomeá-lo para partículas de poeira Um aviso nos diz que precisamos criar um recurso de sprite frames para que esse nó funcione com o novo nó selecionado Olhando no inspetor, expanda a seção de animação Clicando no menu suspenso denominado molduras de sprite, selecione novas molduras de sprite e, em seguida, clique no recurso de molduras de sprite para abri-lo para edição, que aparecerá na parte inferior da janela do Aqui podemos ver uma animação de quadro de sprite recém-criada chamada Default, com uma taxa de quadros de cinco quadros por segundo No painel do sistema de arquivos, pesquise no pacote de ativos para encontrar o grupo de pastas de partículas de poeira, selecione os sprites do outono e arraste-os para a área dos quadros de animação Pressionando play para visualizar a animação, podemos ver como ela ficará. Não queremos que essa animação seja repetida, desative o loop cozinhando o botão de loop da animação Expanda a seção de deslocamento e ajuste o deslocamento y até que esteja nivelado com o eixo x vermelho, que será nosso solo É importante usar o campo de deslocamento e não a posição de transformação para que as partículas apareçam no solo Também alterarei a taxa de quadros para corresponder às animações dos meus personagens, que tinham uma taxa de quadros de dez quadros por segundo Agora, quando clicarmos em reproduzir, a animação será reproduzida apenas uma vez. E podemos ver como isso ficará no jogo em relação ao personagem. O objetivo dessa animação será jogar uma vez quando o personagem cair no chão e desaparecer quando terminar. Esses tipos de efeitos ficam melhores quando existem independentemente do personagem, como se a poeira fizesse parte do mundo e não devesse acompanhar o personagem. Vamos clicar com o botão direito do mouse no nó de partículas de poeira e salvar esse galho como sua própria cena. Isso realmente não pertence a nenhuma de nossas pastas existentes. Vamos criar uma nova pasta para ela chamada dust. nome a essa cena em particular, poeira de outono cozinhando na claquete, ícone na árvore da cena Podemos abrir a cena da poeira do outono para fazer as partículas desaparecerem. Depois que a animação for concluída, precisaremos anexar um script ao nó raiz, clicando no botão do script de anúncio para nomear o novo script dust. Não precisamos usar nenhum dos modelos padrão. Desmarque a caixa de seleção do modelo e certifique-se de que o script esteja salvo na pasta de scripts Isso iniciará o script com nada mais do que estender duas linhas D do sprite animado na parte superior Mas antes de realmente escrevermos qualquer código com os dois nós D do sprite animado selecionados, veja o painel do inspetor e mude para o painel do nó Os sinais devem ser selecionados por padrão. Essa é uma lista de sinais que o nó pode usar para acionar comportamentos em seu próprio script ou em outros scripts. Podemos usar o sinal de animação finalizada para saber quando a animação está concluída. E execute um método em nosso script. Clique com o botão direito na animação concluída. Conecte-se para abrir uma nova janela. Certifique-se de que as partículas de poeira estejam selecionadas como receptoras do sinal. Em seguida, clique em Conectar. Você notará que Do gerou automaticamente um método no script que será acionado quando a animação for concluída. Há um ícone de conexão verde à esquerda da declaração do método para nos informar que esse método está sendo acionado por um sinal. Também na árvore da cena, o ícone de sinal é exibido ao lado do nó de partículas de poeira para nos informar que esse nó tem uma conexão de sinal A única coisa que precisamos fazer no script quando a animação estiver concluída é dizer ao mecanismo que terminamos com esse nó e ele pode ser removido. Isso é feito usando um método embutido chamado free. Também queremos dizer ao script que reproduza automaticamente a animação quando ela for adicionada à cena. Substituindo o método underscore ready, podemos simplesmente chamar quando esse nó for adicionado à árvore, ele será reproduzido uma vez e se removerá quando terminar Agora podemos duplicar essa cena para criar cenas semelhantes de partículas de poeira para partículas de pular e correr nessas novas cenas. Substituir os sprites na animação pelos sprites corretos do pacote de ativos Agora temos três efeitos diferentes de partículas de poeira que queremos gerar sob condições diferentes para nosso personagem, mas todos eles podem usar um método Voltando à cena do personagem, agora podemos excluir o nó de partículas de poeira , pois ele não deveria fazer parte da cena. Em seguida, mude para a visualização do script e abra o script do personagem. Vamos adicionar uma nova função privada chamada spawn dust, que usará um parâmetro chamado dust O tipo desse parâmetro será uma cena compactada que nos permitirá usar as cenas que acabamos de criar como argumento para o método. Primeiro, precisamos instanciar a cena depois mudar sua posição para que ela fique no mesmo local do personagem Em seguida, adicione-o à árvore da cena obtendo primeiro o nó pai do personagem e, em seguida, adicionando a poeira como nó secundário. Ao fazer do pó um irmão do personagem, ele existirá no mundo independente do personagem e não o seguirá Assim que for adicionado à árvore de cena, o sprite animado reproduzirá sua animação padrão e, em seguida, o próprio Q será removido quando a animação terminar apenas uma fração de segundo depois Para acionar as partículas de poeira de salto, podemos chamar esse método diretamente do método de salto , inserindo poeira de salto como argumento. Em seguida, declare qual é a poeira saltada na parte superior do script como uma variável exportada do tipo cena compactada Selecionar o nó raiz do personagem e voltar para o painel do inspetor Em seguida, podemos preenchê-lo no inspetor clicando e arrastando a cena para o campo exportado As partículas que correm e caem não têm um lugar simples em nosso script onde possam ser geradas No entanto, o que podemos fazer em vez disso é selecionar o reprodutor de animação do nosso personagem, abrir a animação terrestre e adicionar uma nova faixa. Desta vez, uma faixa de método de chamada. Então, podemos acessar o nó raiz do personagem e chamar o método spawn particles no início da animação Ao adicionar um quadro-chave. Selecionar o quadro-chave nos permitirá passar argumentos para o método , que podemos então preencher. Ao clicar e arrastar a poeira do outono. Podemos fazer a mesma coisa com as partículas de poeira de corrida, adicionando-as à animação da corrida. Lembre-se de que a animação de execução será repetida, então novas partículas aparecerão toda vez que a animação for repetida Para as partículas de queda e salto, realmente não importa para que lado o personagem está voltado. Mas para as partículas de corrida, é importante que elas pareçam se mover atrás do personagem. Podemos definir a propriedade animada Steph para corresponder à do personagem no momento de sua criação Vamos experimentá-lo. A corrida cria poeira a cada 0,6 segundos de corrida contínua. Saltar e pousar também criam suas próprias nuvens de poeira exclusivas Para melhorar ainda mais, também podemos adicionar sons às nossas faixas de animação, voltar para a cena do personagem e adicionar um novo nó à árvore da cena, um reprodutor de streaming de áudio, dois nós D. Com esse nó na árvore, agora podemos abrir a animação de salto e adicionar uma nova faixa de reprodução de áudio Selecionar o nó do reprodutor de fluxo de áudio como destino. Colocar um quadro-chave no início da animação. Em seguida, podemos preencher esse quadro-chave com um fluxo de áudio. Navegar pelos sons fornecidos na batalha, sons embalados por Luke Sharps Existem alguns sons apropriados para escolher que se encaixam perfeitamente nesse personagem Importe os sons que você gosta e coloque-os em uma pasta de efeitos sonoros designada para manter seu projeto organizado. Em seguida, preencha seu quadro-chave de animação adequadamente. Para fazer com que a animação da corrida passe por cima dos sons dos sapatos. Certifique-se de modificar o deslocamento inicial e o deslocamento final para selecionar uma amostra menor que a animação Vamos experimentá-lo agora. O personagem emite um ruído grunhido ao pular, um som de impacto ao pousar e ruídos de passos enquanto um som de impacto ao pousar e ruídos de passos Ao longo desta primeira seção do curso, criamos um personagem totalmente animado com efeitos visuais e de áudio e divertida mecânica de plataforma Na próxima seção, começaremos a trabalhar na construção de níveis para o nosso jogo. Nos vemos na próxima seção. 22. 2-1 Tilemap: Olá amigos. Na última seção, criamos um personagem totalmente animado com mecânica de plataforma Se você concluiu a tarefa, agora você deve ter um elenco completo de quatro personagens E descobriremos que você pode duplicar o nó do jogador para controlar mais de um personagem simultaneamente Se você conseguir completar o desafio intermediário, também terá alguns scripts de IA controlando um ou mais personagens. Com o desafio mais avançado, você provavelmente terá todos os nós do personagem, do filho ao nó do jogador, com o personagem sendo controlado, capazes de ser trocados com o pressionamento do botão Nesta seção, criaremos um nível para o nosso jogo. Nossa primeira lição, começaremos com a construção do terreno nivelado Adicione outro nó à cena principal. O nó que estamos procurando desta vez é o mapa de blocos. Um mapa de blocos nos permitirá adicionar e modificar rapidamente sprites em nosso nível, que serão organizados em blocos de um tamanho específico Para que um mapa de blocos funcione, ele precisa de um conjunto de blocos. Como você pode ver no inspetor no menu suspenso, rotule o conjunto de blocos, selecione um novo conjunto de blocos clique no recurso do conjunto de blocos para expandi-lo, expondo alguns campos que precisaremos editar. Nossos blocos são quadrados Mas você pode ver que existem várias outras opções para facilitar o trabalho com outras formas de ladrilho. A primeira coisa que precisamos mudar é o tamanho do ladrilho. O tamanho do bloco do pacote de ativos que estou usando é de 32 pixels em largura e altura. É importante que você defina essa propriedade antes de adicionar qualquer bloco ao conjunto de blocos. Como estamos usando esse mapa de blocos para o terreno, também precisaremos adicionar uma camada física para colisão Um conjunto de terrenos facilitará muito a edição do terreno. O conjunto de terrenos pode conter vários terrenos. Precisamos adicionar um terreno ao conjunto de terrenos. Você pode pensar em cada terreno como um bioma ou material de construção diferente Vamos nomear essa primeira ilha de terreno. Cada tipo de terreno pode ser atribuído a uma cor diferente para diferenciá-los uns dos outros Como vamos usar apenas um tipo de terreno por enquanto, podemos usar apenas a cor padrão Essa cor não será usada no jogo somente enquanto estivermos editando o terreno É apenas para nosso benefício como desenvolvedor. Com essas alterações feitas, podemos voltar nossa atenção para a parte inferior da janela do editor, onde uma nova guia foi aberta para o mapa de blocos. A mensagem nos diz que precisamos configurar um conjunto de blocos primeiro, mudar para a guia de conjunto de blocos na parte inferior. Aqui, podemos adicionar os blocos fornecidos no pacote de ativos a esse conjunto de blocos. Clicando no botão de adição ou clicando e arrastando o arquivo de imagem do sistema de arquivos código da guia oferecerá a criação automática de blocos para nós. Selecione Sim. Se tiver certeza de que definiu o tamanho do bloco corretamente, caso contrário, selecione não. Os ladrilhos agora devem estar mais claros e ter uma borda laranja. Selecionar a ferramenta de borracha permitirá que você remova os blocos do conjunto de blocos clicando neles Da mesma forma, desligar a ferramenta de borracha permitirá que você adicione blocos ao conjunto de blocos clicando neles Voltando para a guia do mapa de blocos, agora podemos selecionar e desenhar qualquer ladrilho do conjunto de blocos na visualização em dois D. Ao clicar em Goode, fornece uma grade laranja correspondente ao tamanho do ladrilho para facilitar O editor de mapas de blocos também fornece todas as ferramentas usuais para selecionar linhas de pintura, retângulos e preenchimento de baldes Você também pode colar os olhos, selecionar, apagar, girar, virar e aleatoriamente os ladrilhos Faça um piso básico, coloque seu personagem sobre ele e posicione a câmera para ver os resultados. Em seguida, reproduza a cena. Você notará que o terreno ainda não colidiu. Volte para a guia do conjunto de blocos. Alterne para o modo de seleção e selecione em grupo todas as peças clicando e arrastando sobre elas. Vamos primeiro adicionar colisão aos nossos blocos expandindo a seção de física Então, camada física zero. Essa ferramenta permitirá que você crie formas de colisão complexas para cada peça, mas precisamos apenas de quadrados básicos Ao clicar no ícone da elipse, selecione Redefinir para a forma padrão do ladrilho ou, alternativamente, pressione a tecla para simplesmente fazer com que a forma da colisão corresponda à forma dos Agora, todos os nossos blocos entrarão em colisão, assim como o ícone do Codell que estávamos usando como piso da cena Isso é ótimo, mas construir níveis preenchendo blocos individuais no mapa de blocos será extremamente entediante Felizmente, o Godel fornece um editor terreno muito fácil de usar Mude para o modo de pintura. Isso nos permite pintar propriedades nos ladrilhos. A propriedade que queremos pintar é a propriedade do terreno. Particularmente em terrenos a zero, o terreno da ilha. Talvez você queira expandir o painel ou ampliar a área do ladrilho. Para esta parte, cada ladrilho é dividido em nove quadrados menores que podemos pintar na cor do terreno clicando ou apagar clicando Cada ladrilho que faz parte desse terreno deve ter seu quadrado central preenchido Para que o editor de terreno funcione conforme o esperado, precisamos pintar as bordas de cada ladrilho que deve ser desenhado ao lado de outro ladrilho Quando terminar, não deve haver duplicatas nesse conjunto de blocos Cada ladrilho deve ter um padrão único. Volte para a guia do mapa de blocos. Mude para a guia de terrenos na parte superior. E o terreno da nossa ilha deve ser listado como uma opção, selecionando que você verá todos os ladrilhos do conjunto de ladrilhos listado, junto com duas opções extras, modo contínuo e modo de caminho Selecione o modo contínuo e, em seguida, desenhe o terreno livremente nas duas visualizações D clicando e apague com o botão direito Cada bloco se conectará automaticamente corretamente aos ladrilhos adjacentes. Você deve ser capaz de desenhar terrenos de qualquer formato que possa imaginar e os ladrilhos adequados serão selecionados automaticamente para cada posição do ladrilho Se houver alguma inconsistência, verifique se há erros na pintura da propriedade do terreno Usando essa ferramenta, podemos gerar de forma rápida e fácil o terreno para cada nível do nosso jogo Agora temos um terreno básico em nosso jogo que podemos usar para construir a base de nossos níveis Na próxima lição, adicionaremos um pouco de vegetação decorativa para tornar o ambiente mais vivo. Te vejo na próxima aula. 23. 2-2 decorações: Olá amigos. Na última lição, configuramos o terreno básico com colisões e edição do terreno Nesta lição, adicionaremos algumas decorações ao nosso terreno para torná-lo mais interessante Como o mapa de blocos, mude para a guia de conjunto de blocos na parte inferior da janela do editor. Há outro gráfico de conjunto de ladrilhos no pacote de ativos que pertence a esse conjunto de ladrilhos chamado frente, palma, fundo e grama. Vamos adicionar isso ao atlas. Esses elementos decorativos realmente não precisam de nenhuma edição física ou de terreno A grama pode simplesmente ser desenhada aleatoriamente em áreas ao redor do seu nível onde você acha que ficará bonita As raízes, no entanto, devem ser desenhadas sobre ladrilhos de terreno Mas se tentarmos fazer isso, ele substituirá o terreno Para fazer isso, precisamos adicionar outra camada ao nosso mapa de blocos para essas raízes. Selecionando o mapa de blocos na árvore da cena, podemos reduzir o recurso do conjunto de blocos e expandir a seção de camadas. Aqui temos uma camada que não tem nome. Vamos nomear essa camada de terreno, depois clicar no botão Adicionar elemento, Adicionar outra camada e nomear essa camada Para fazer com que essa camada seja desenhada na frente do terreno, podemos editar o índice z, aumentando-o para um Como o terreno está na camada zero, as raízes na camada um sempre serão desenhadas por cima O menu suspenso no canto superior direito da guia do mapa de blocos agora contém nossas duas camadas diferentes. Isso nos permite adicionar ladrilhos de raiz à camada raiz, que podemos então pintar sobre os ladrilhos de terreno na camada de terreno Quando cada camada estiver sendo editada, ela aparecerá em cores, enquanto todas as outras camadas ficarão esmaecidas Mas essas raízes também precisam de árvores. Vamos também construir as árvores. Se você quiser que as árvores colidam e sejam um objeto imóvel que age como um terreno, o tipo de nó mais apropriado a ser usado seria um corpo estático dois D, que chamaremos Esse é o mesmo tipo de nó que usamos originalmente para o ícone Godot Esse nó em particular ainda pode ter colisões, mas não será movido por colisões com outros objetos Ele permanecerá estático. Essa árvore terá uma animação. Então, vamos adicionar um sprite animado, dois D como nó filho da palmeira Crie um recurso de molduras de sprite para o sprite animado. Em seguida, abra o recurso para edição. Clique e arraste as imagens da palmeira para a animação. Altere a taxa de quadros e pressione play para visualizar a animação. Isso parece bom. Vamos garantir que essa animação seja reproduzida automaticamente por padrão clicando no botão Reprodução automática na parte superior do painel Vamos salvar o nó da palmeira como sua própria cena e classificá-lo em uma nova pasta de cena para decorações Agora, a palmeira pode ser editada isoladamente, e todas as alterações feitas na cena da palmeira serão aplicadas a todas as cópias da palmeira Com o nó da palmeira selecionado, clique e arraste-o para movê-lo pelo nível e posicioná-lo sobre as raízes. Podemos tornar isso muito mais fácil ativando o ajuste de grade com o botão na parte superior das duas visualizações D. Também podemos configurar as opções de encaixe clicando no ícone da elipse Vamos garantir que os objetos se encaixem em múltiplos de 32 pixels para corresponder ao tamanho do bloco Mas a palmeira não quer se alinhar porque a origem da árvore está no centro. Para que a árvore se alinhe com os blocos, a origem precisa estar no canto selecionando o sprite animado, dois nós D. Ajuste o deslocamento para que o sprite desenhe 16 pixels, ou metade de um ladrilho, à direita da origem Agora, a palmeira pode ser facilmente movida para combinar com os ladrilhos do terreno O corpo estático precisa de uma forma de colisão. Para colidir com qualquer coisa, precisamos adicionar outro nó-filho, uma forma de colisão, dois D. Para tornar essa palmeira mais interessante Também vamos fazer com que funcione como uma plataforma para o jogador pular. Defina a forma de colisão como um segmento em forma dois D, esta é apenas uma linha que podemos editar movendo os dois pontos Faça o segmento de linha se alinhar com o topo da palmeira. Vamos experimentá-lo. Funciona como uma plataforma, mas seria bom poder pular pelo fundo em vez de colidir com ele Eu gostaria que o jogador não passasse mouse tão longe da borda antes de cair Ajustando as configurações de ajuste da grade para oito pixels ou um quarto Vou fazer com que o segmento de linha cubra apenas metade do comprimento total do ladrilho. Se você quiser que o jogador possa passar pela parte inferior da plataforma e pousar em cima dela. Há uma implementação simples incorporada para esse comportamento. Em Godot, basta marcar a caixa de seleção de colisão unidirecional nas duas propriedades D da forma de colisão Isso desenha uma seta no editor mostrando em qual direção a colisão será aplicada Isso é muito melhor. Agora posso pular pela parte inferior da plataforma da palmeira e deslizar pela borda em vez de ficar em uma barreira invisível. Algo que pode ser incômodo para alguns jogadores que gostam do estilo de arte pixelizada em particular é que o jogador não está sendo desenhado exatamente com os mesmos deslocamentos de pixels Se eu posicionar o personagem próximo a um pouco de grama, você pode ver que os pixels do meu personagem nem sempre se alinham com os pixels da grama nas configurações do projeto. Podemos ajustar essas configurações de renderização para forçar todas as imagens desenhadas na tela a serem desenhadas nas coordenadas exatas de pixels, que é o que os fãs de pixel art prefeririam Essas configurações estão ocultas por padrão. Clique na opção de configurações avançadas em Renderização. Uma nova opção para dois D é revelada. Aqui temos opções para transformar transformações e vértices Isso pode fazer com que o jogador passe um pixel acima do chão Se for esse o caso, ajuste o colisor para que fiquem limpos no chão Agora, quando clicamos em play, o personagem e tudo o mais em nosso jogo sempre serão desenhados em coordenadas de pixels Agora temos grama e palmeiras animadas decorando nossa ilha perfeita em pixels. Na próxima lição, adicionaremos um script à nossa câmera, que acompanhará o jogador, permitindo criar níveis maiores que uma tela. Te vejo na próxima aula. 24. Câmera 2-3: Oh, amigos. Na lição anterior, decoramos nossa ilha com vegetação. Nesta lição, faremos com que a câmera acompanhe o jogador ao redor do nível. A maneira mais fácil de fazer isso seria simplesmente direcionar a câmera para o jogador. Mas essa abordagem é muito restritiva e pode causar enjôo movimento da câmera deve ser mais sutil e mostrar ao jogador o que está à frente de seu personagem Tendo o personagem na câmera como irmãos, precisaremos que a câmera reaja às ações do jogador e tenha seu próprio comportamento roteirizado Vamos começar criando um novo script para a câmera. Podemos simplesmente chamá-la de câmera e garantir que ela esteja salva na pasta de scripts. Esta câmera precisará saber o que está seguindo. Vamos exportar uma variável privada que chamaremos de assunto de sublinhado O tipo disso não precisa ser um personagem com corpo dois D. Em vez disso pode ser algo mais genérico, como um nó dois D. Se você olhar na árvore de cenas, notará que os nós têm cores diferentes, a maioria das quais são azuis. Esses nós azuis são todos do nó dois D, mas são tipos mais específicos do nó dois D, incluindo a própria câmera. Existem dois personagens D, dois corpos estáticos em D, dois sprites animados em D, etc Ao selecionar qualquer um deles, você verá no inspetor que eles têm as propriedades rotuladas como nó dois D, bem como a propriedade de transformação que contém sua posição, rotação, escala e inclinação Ao definir o tipo de nosso objeto para o nó dois D, a câmera será capaz de seguir qualquer coisa em nossa cena que se qualifique como um nó dois D. Como só precisamos saber se ele tem uma posição para a câmera segui-lo, clique e arraste o personagem do jogador para o campo exportado do assunto da nossa câmera No método do processo, que será executado 60 vezes por segundo, podemos simplesmente definir a posição da câmera para a posição do objeto. Serão os mesmos comportamentos de quando a câmera era infância para o personagem sem o movimento vertical, reduzindo severamente o enjôo entanto, seria mais útil se o personagem não estivesse centralizado na visão da câmera Mas, em vez disso, ele deve olhar para a frente do personagem e ligeiramente para cima para que o jogador possa ver partes mais relevantes do nível. Assim como acontece com os sprites animados, podemos adicionar um deslocamento ao script da câmera para deslocá-lo de sua posição original Faremos disso uma variável privada exportada, sublinhado deslocado com o tipo de Um vetor dois contém dois flutuadores, um valor x e um y. Ele é usado para definir qualquer coisa em duas dimensões, incluindo as variáveis de posição com as quais estamos trabalhando. Agora, o método de processo pode simplesmente adicionar a parte x do deslocamento à posição X da câmera Se posicionarmos o personagem exatamente na origem da cena, podemos mover a câmera para nos dar uma ideia de onde achamos que ela ficará bem. Em seguida, use a posição atual da câmera como valor de deslocamento Como alternativa, você pode definir o deslocamento em blocos e multiplicá-lo pelo Google Ppt no método pronto blocos e multiplicá-lo pelo Google Ppt no método Agora, a câmera seguirá o movimento horizontal do jogador enquanto olha para a direita. Mas e se não quisermos que nossos níveis sejam tão lineares? E se o jogador quiser ir para a esquerda? A câmera também deve olhar para a esquerda do personagem. A câmera precisará reagir a uma ação realizada pelo personagem. Temos duas funções em nosso script de personagem, que são chamadas sempre que o jogador está voltado para a esquerda ou para a direita, mas elas são chamadas constantemente a cada entrada. Só vamos chamar essas funções quando o personagem realmente mudar de direção. Para fazer isso, podemos exportar uma variável privada para armazenar se o personagem está ou não voltado para a esquerda. Como booleano. Os métodos face esquerda e face direita definirão esse valor como verdadeiro ou falso de acordo. Então, no início do processo físico, podemos adicionar condições para chamar apenas a face esquerda se o personagem ainda não estiver voltado para a esquerda, se estiver voltado para a esquerda. Agora, nossos métodos de face esquerda e face direita só são chamados quando o jogador escolhe mudar de direção Também devemos chamar os métodos apropriados de face esquerda ou face direita durante o método pronto com base no valor da variável exportada Isso também tem a vantagem de fazer essa função funcionar com os personagens cujos sprites estão voltados para a esquerda Por padrão, o script da câmera agora pode reagir à mudança de direção do personagem usando sinais. Na parte superior do script do personagem, podemos criar um sinal personalizado que chamaremos de direção alterada e adicionar um parâmetro informando câmera se o personagem está voltado para a esquerda. Agora, os métodos face esquerda e face direita podem fazer com que esse sinal emita passagem, independentemente de o personagem estar ou não voltado para a esquerda como argumento Com as notas do personagem selecionadas na árvore da cena. Mude para o painel de nós, clique com o botão direito do mouse em nosso novo sinal e selecione Conectar. Em seguida, selecione a Câmera. Nota da lista. A câmera escutará esse sinal. Podemos renomear o método que será chamado como resultado Para colocá-lo em termos mais fáceis de entender dentro do contexto da câmera, vamos nomeá-lo em Subject changed Direction. O método é adicionado automaticamente ao script da câmera. Agora podemos alterar o deslocamento da câmera para olhar para a esquerda ou para a direita Como sabemos para qual direção o personagem está voltado. Para preservar o valor do deslocamento, vamos criar outra variável privada chamada look Ahead distance Que começa como uma cópia do deslocamento de sublinhado X definido durante a fase de preparação com at on ready Em seguida, podemos definir a distância de visualização antecipada como o deslocamento X, mas multiplicada por menos um se o sujeito estiver voltado para esquerda ou positivo se não estiver Em seguida, use a distância de visualização antecipada na função de processo para definir a posição da câmera. Agora, a câmera olhará à frente do personagem, não importa para qual direção ele esteja voltado. Mas e se quisermos que nossos níveis também subam e diminuam? Podemos usar um método semelhante para fazer com que a câmera reaja ao objeto emitindo um sinal Desta vez, movendo a câmera quando o personagem pousa no final do salto, ajustando a câmera para uma nova altura no script do personagem Vamos adicionar outro sinal chamado aterrissado e passar um parâmetro chamado altura do piso, que será um flutuador Como sabemos quando o personagem chega? Bem, temos o método prático no chão. Se armazenarmos esse valor em uma variável privada, vamos chamá-la de was on floor como booleana Vamos gravá-lo aqui. Acima, mova e deslize. Depois de mover o slide, podemos verificar se o personagem não estava no chão e agora está no chão, o que significa que esse é o momento exato em que ele pousou Vamos chamar um novo método privado aqui chamado underscore landed Escrevendo uma definição para esse método, não precisamos realmente fazer mais nada aqui agora, além de emitir o sinal de aterrissagem passando em nossa posição Y como a nova altura do piso Dizendo à câmera que ouça o sinal, a câmera pode então chamar um novo método chamado on subject landed Tudo o que precisamos fazer é ajustar o valor da posição Y da câmera para ser a nova altura do piso mais o deslocamento Y. Agora temos a câmera seguindo o jogador, permitindo criar níveis maiores do que cabem em uma única tela, mas os movimentos são instáveis. Na próxima lição, faremos com que a câmera se mova suavemente entre essas posições usando interpolações. Te vejo na próxima aula. 25. 3 4 Tween: Olá, amigos. Na última lição, movemos a câmera, seguindo o jogador enquanto ele se move para a direita, para a esquerda, para cima e para baixo. Nesta lição, faremos com que a câmera passe suavemente entre essas posições A maneira mais simples de ajustar gradualmente os valores ao longo do tempo é usar uma interpolação Vamos declarar duas novas variáveis privadas. Na parte superior do script da câmera, temos dois sinais diferentes acionando dois comportamentos diferentes no script da câmera Queremos que eles fiquem separados um do outro. A primeira variável será chamada de interpolação look ahead, a interpolação de altura do segundo andar Ambos são do tipo tween. Começando com a interpolação antecipada, quando o assunto muda de direção, podemos definir o valor da interpolação antecipada para criar uma interpolação Esse é um método incorporado que podemos usar para criar nosso comportamento de interpolação com rapidez e facilidade Em seguida, mostramos esse olhar para frente, interpolando uma propriedade começando com a qual nó a propriedade pertence e qual é Em seguida, designamos entre aspas o nome da propriedade Vamos intercalar o valor da distância visual para se tornar esse valor que já calculamos ao longo de um período de tempo Por enquanto, vamos dizer 1 segundo. Isso parece melhor. Mas se o jogador mudar direção enquanto a câmera estiver ofegante, não devemos ter dois pré-adolescentes criados ao mesmo tempo competindo pelo controle da Não parece estar causando nenhum problema. Mas podemos eliminar a possibilidade verificando primeiro se a interpolação já existe e está em execução Se isso for verdade, então devemos matá-lo antes de começar outro. Atualmente, essa interpolação é linear e tem uma duração de 1 segundo Mas podemos personalizá-lo facilmente para criar uma grande variedade de efeitos. Primeiro, vamos exportar uma variável flutuante chamada duração do sublinhado e atribuir a ela o valor padrão de um Em seguida, conecte essa variável na chamada do método de interpolação. Agora podemos ajustar a velocidade de panorâmica da câmera simplesmente alterando o valor dessa variável no inspetor Lembre-se de que você não precisa parar o jogo para ajustar os valores no inspetor Acho que isso deveria ser um pouco mais lento caso o jogador vire as costas para um inimigo, mas não queira que ele seja imediatamente removido de vista Por exemplo, para alterar a forma como a câmera se move ao longo do tempo, podemos adicionar tipos de atenuação e transição à interpolação, fazendo com que ela se mova mais devagar ou mais rápido no início ou no final Até mesmo salte ou se mova além dos limites definidos. Vamos exportar uma nova variável privada chamada tipo trans. O tipo dessa variável será o tipo de transição de interpolação. Então, quando criamos a interpolação, também podemos chamar outro método, definir trans para passar nosso tipo de transição como argumento para esse método Podemos fazer isso porque os métodos create tween e set trans retornam a Como resultado, o método create tween cria a interpolação e a retorna, que é então usada para chamar o conjunto trans e retorna a interpolação novamente, que é então atribuída à nossa variável, que é então atribuída à nossa variável, selecionando a câmera na árvore de cena e olhando para o inspetor, você verá que o tipo de transição padrão é linear, o que significa que o valor progride uniformemente ao longo do cria a interpolação e a retorna, que é então usada para chamar o conjunto trans e retorna a interpolação novamente, que é então atribuída à nossa variável, selecionando a câmera na árvore de cena e olhando para o inspetor, você verá que o tipo de transição padrão é linear, o que significa que o valor progride uniformemente ao longo do duração do menu suspenso. Há várias opções para alterar a forma como o valor mudará com o tempo. Também podemos adicionar outra variável chamada tipo de atenuação, tipo de atenuação de interpolação digitada de forma semelhante Isso alterará a transição para afetar apenas o início do final da interpolação ou ambos Assim como com o tipo de transição, também podemos definir o tipo de atenuação na mesma linha de código Quando criamos a interpolação, experimente diferentes durações, transições e tipos de atenuação para ver como elas se sentem Podemos usar a mesma técnica para ajustar gradualmente a altura atual do piso da câmera ao longo tempo após o objeto pousar. Em vez de usar um corte rígido, primeiro precisamos armazenar a altura atual do piso em uma variável privada. Então, quando o assunto chegar, podemos copiar a maior parte do mesmo código de quando eles mudam de direção, alterando apenas a variável de interpolação de look ahead para floor height e também alterando o nome da propriedade na qual estamos interpolando o Vamos interpolar dois é o mesmo que o parâmetro do método. Em seguida, podemos editar o método do processo para definir a posição y da câmera como sendo a altura do piso mais o deslocamento y. Agora, a câmera se moverá suavemente para cima ou para baixo após o objeto pousar, ajustando-se a uma nova altura do piso Se você quiser que esses dois comportamentos tenham durações, tipos de transição ou tipos de atenuação diferentes , basta exportar mais variáveis Eu gostaria que a pintura horizontal fosse mais lenta e suave, mas a vertical fosse mais rápida e mais Terei uma duração maior na horizontal, mas também terei o tipo de facilidade de entrar e sair. Para a vertical, terei uma duração menor e só relaxarei. A câmera se move mais rápido no início e mais devagar depois de nós Dependendo da versão do que você está usando, pode haver um problema em mover a câmera e o personagem ao mesmo tempo, criando um efeito instável. Para corrigir isso, tente abrir as configurações do projeto. Procure na janela de exibição a sincronização V na parte inferior e desative a configuração. Agora temos nossa câmera, mostrando ao jogador exatamente o que ele precisa ver de forma suave e gentil. Na próxima lição, adicionaremos um plano de fundo animado à nossa cena. Te vejo na próxima aula. 26. Fundo de 2-5: Olá amigos. Na lição anterior, concluímos o script de comportamento da nossa câmera, para que ela siga o personagem do jogador. Nesta lição, adicionaremos um plano de fundo animado ao nosso nível. O plano de fundo nivelado precisa dar a impressão de que está muito distante. Caso contrário, o ambiente parecerá muito plano e bidimensional para o jogador Podemos criar uma ilusão de profundidade adicionando um nó secundário à câmera Um nó dois D, ele terá um valor de posição, bem como um índice Z, um nome de fundo. Em seguida, expanda a seção de pedidos no item de tela e defina o índice Z desse nó como um valor negativo O terreno nivelado está usando o índice Z padrão de zero. Um número negativo será desenhado para trás, dependendo de quantas camadas de profundidade você deseja em seu ambiente. Talvez você queira colocar o índice z de fundo mais atrás do que apenas o negativo Vou colocar o plano de fundo em menos dez, deixando menos um a menos nove disponíveis para qualquer coisa que precise estar entre o plano de fundo e o terreno Mesmo que eu não esteja planejando fazer isso, é melhor deixar essa possibilidade lá. Agora, cada nó secundário que adicionarmos a esse nó seguirá automaticamente a câmera e será desenhado por trás de todo o resto do nível. O pacote de ativos contém vários sprites que podemos usar para montar um ambiente em segundo plano. Podemos simplesmente clicar e arrastar as imagens do plano de fundo para nossa cena. E Godot os transformará automaticamente em um grupo sprite de dois nós D, selecionando todos os novos Faça com que todos sejam filhos do nó de fundo. Ao arrastá-las para dentro dela, vou apenas esticar as imagens do pôr do sol, do céu e da água para que cubram toda a janela de visualização da câmera Vamos fazer do plano de fundo sua própria cena para que ele possa ser editado isoladamente e salvá-lo na pasta de cenas. Em seguida, clique no ícone da claquete para abri-lo. Na mesma pasta, há algumas animações de sprites para fazer a água Vamos adicionar três sprites animados e dois D's em nossa costura. Em seguida, podemos preencher cada um deles com um recurso de sprite frames E preencha os quadros de sprites com cada uma das três animações de sprites Além disso, certifique-se de que eles reproduzam automaticamente suas animações em loop com a taxa de quadros correta e, em seguida, posicione cada uma na água onde elas ficarão bonitas Quando terminar, você pode salvar seu trabalho e ver como ele ficará executando a cena principal. Em seguida, vamos adicionar algumas nuvens ao céu. Eles não são animados, então podemos simplesmente arrastá-los para a visualização em dois D para transformar o sprite em dois nós D. Se você quiser ajustar a forma como os sprites são colocados em camadas, em vez de ajustar o valor do índice Z de cada sprite, também podemos usar a árvore de cena para reordenar os Os nós com o mesmo índice Z serão desenhados da parte superior da árvore da cena até a parte inferior. A simples organização da lista de nuvens pelo tamanho também classificará sua ordem e colocará a menor nuvem na parte de trás e a maior nuvem na frente. Uau, uau. Essa maior nuvem também já é maior do que a janela de visualização da câmera e tem essas bordas rígidas Ele foi projetado dessa forma para ser girado em torno de si mesmo usando uma técnica chamada rolagem paralaxe, duplicando o nó do sprite si mesmo usando uma técnica chamada rolagem paralaxe, . Podemos colocar dois deles em nossa cena e movê-los gradualmente para o lado. Então, quando alguém sai da tela, podemos reposicioná-lo para o outro lado, fazendo com que ele se repita infinitamente em segundo Isso aumentará ainda mais a ilusão de profundidade de que o fundo está distante, mas também criará a ilusão de que há vento Vamos adicionar um script ao nó raiz dessa cena, que criará o efeito de rolagem paralaxe Primeiro, precisaremos obter uma referência aos nós secundários que queremos mover, podemos usar em e prontos para armazená-los em variáveis, certificando-se de colocar os nomes exatos dos nós após o cifrão em suas atribuições Vamos também exportar uma variável para velocidade de rolagem, que é uma flutuação baseada na animação da palmeira Está implícito que o vento estará soprando para a esquerda. Vamos usar um valor padrão de menos 100 no método do processo. Podemos então adicionar uma velocidade de rolagem multiplicada por delta à exposição das nuvens, fazendo com que elas se movam para a esquerda a uma velocidade constante Mas vamos fazer isso com cinco nuvens diferentes. Portanto, seria melhor fazer com que esse método um nó dois D como parâmetro junto com a distância em que ele está sendo rolado como flutuador Então, podemos simplesmente adicionar a distância à sua posição. Agora, o método do processo pode chamar esse método, passando em cada nuvem junto com a velocidade de rolagem multiplicada pelo delta Para calcular a distância por quadro, podemos melhorar ainda mais a ilusão de profundidade fazendo com que as nuvens se movam em velocidades diferentes, com as nuvens maiores mais próximas do jogador se movendo rápido e as nuvens menores mais distantes se movendo mais devagar. Mas evite usar multiplicadores de velocidade que sejam múltiplos um do outro Isso formará um padrão muito óbvio e quebrará a ilusão se a velocidade de uma nuvem for exatamente a metade da outra Por exemplo, o jogador notará que é útil usar números primos para. A última coisa que precisamos fazer é verificar se alguma de nossas nuvens saiu completamente da câmera depois movê-la para o outro lado. Se posicionarmos uma grande nuvem no meio, a outra agora estará onde ela estará quando quisermos que ela se contorne, que também é a largura em pixels da imagem. Vamos fazer com que esse valor de largura seja exportado tipo flutuante variável com um valor padrão de 448 Verificando se a posição x de uma nuvem é menor do que com vezes menos um. Podemos então movê-la para a direita pela largura multiplicada por dois para colocá-la do outro lado da segunda grande nuvem Isso também fará com que as outras nuvens circulem periodicamente sozinhas. Vamos ver como isso fica lindo. No entanto, assim que o jogador redimensiona a janela do jogo, a ilusão é quebrada Abrindo as configurações do projeto na janela de exibição, podemos definir a resolução desejada para o nosso jogo. Mais importante ainda, podemos mudar o modo de alongamento para itens de tela elástica, que é tudo em nossos dois jogos D. Definitivamente, queremos manter nossa proporção a mesma, mesmo que o player redimensione a janela, um novo recurso adicionado recentemente Também podemos restringir o alongamento escalar apenas por valores inteiros Isso pode impedir que nossos pixels sejam desenhados em tamanhos inconsistentes Depois de escolher uma configuração de resolução, verifique se o plano de fundo se encaixa nas novas configurações e deve ser impossível vê-lo fora do plano de fundo. Agora temos um belo pôr do sol nublado no fundo do nosso nível Na próxima lição, adicionaremos água ao primeiro plano. Te vejo na próxima aula. 27. 2-6 água: Olá, amigos. Na lição anterior, adicionamos um plano de fundo animado à nossa cena. Nesta lição, adicionaremos água ao primeiro plano. Para esta lição, eu baixei e modifiquei outro efeito sonoro para respingos de água Esse efeito sonoro foi criado por Yin Yang Jake 007 no Freesound.org Assim como o plano de fundo, podemos começar criando um Desta vez, use um nó D da área dois e chame-o de água. Em seguida, defina um índice para um número positivo, para que ele sempre seja desenhado na frente, deixando espaço para camadas extras no meio. Os ativos para água no pacote de ativos têm uma animação para ondas e um quadrado plano para todo o resto. Vamos adicionar um sprite animado dois nós D para a superfície da água Crie um novo recurso de sprite frames. Adicione o loop de reprodução automática dos quadros de sprites e, em seguida, defina a taxa de quadros, adicione um deslocamento ou mova a transformação animada dos sprites para que a origem da água esteja no canto superior esquerdo Isso facilitará o alinhamento com o mapa de blocos e também fornecerá o valor Y de zero sendo a superfície da água. Em seguida, adicione também o sprite inferior como um nó D do sprite. Embora a parte inferior possa ser facilmente esticada para preencher qualquer área, a superfície precisará ser duplicada e repetida para manter a árvore da cena organizada Devemos criar outro nó dois D, para atuar como uma pasta dobrável contendo esses sprites animados A área dois D precisa uma forma para definir como sua colisão funcionará A física da água precisa de dois comportamentos diferentes. Quando algo está na superfície da água e sob a água, podemos usar um segmento de linha desenhado sobre a superfície da água, pois isso nos dirá se algo está tocando a superfície ou não Para facilitar as coisas, certifique-se de que a origem do objeto aquático esteja alinhada com o colisor de superfície Também vamos duplicar rapidamente uma de nossas cenas de partículas de poeira para criar uma cena de respingo Em seguida, exclua os quadros de sprite nessa cena e substitua-os pelos sprites splash one do pacote de ativos Para que a água reaja às colisões, precisaremos criar um script de água Esse script precisará reagir a dois sinais quando um corpo entra e o outro sai Podemos simplesmente conectar esses sinais ao próprio script usando os nomes padrão. Os parâmetros corporais desses métodos são do tipo nó dois D, como você pode ver na lista de sinais. Mas para definir como nossos personagens se comportarão em relação à água, precisamos saber se esse nodo dois D chamado corpo é um personagem ou se é outra coisa. Teremos que dar ao nosso script de personagem um nome de classe antes que a palavra se estenda. Na primeira linha, adicione nome da classe, caractere. Agora, essa é uma palavra que outros scripts podem usar para se referir a esse script como um tipo geral. De volta ao script da água, quando um corpo entra na água, agora podemos verificar se o corpo é um personagem. Em seguida, chamar um método que ainda não definimos, que chamaremos de entrar na água e passar na posição y da água, que é a superfície da água no corpo. Método encerrado. Podemos realizar a mesma verificação para ver se o corpo é um personagem. Novamente, quando um personagem sai, o que significa que não está mais tocando o segmento de linha que cobre a superfície da água, uma de duas coisas pode estar acontecendo Ou eles estão agora acima da superfície da água ou estão abaixo da superfície. Como sabemos que a posição Y desse nó é a superfície da água, o corpo também tem uma posição Y. Podemos comparar os dois valores para determinar em qual caso esse é. Mas também adicionando PPT global dividido por dois ou dois blocos. Se a posição do corpo for menor ou igual à superfície da água, isso significa que o corpo parou fazer contato com a superfície da água e está totalmente acima da superfície da água. Como os pixels por bloco são definidos como um número inteiro, mas a posição y é definida como um ponto flutuante, Godel nos avisará que os valores decimais Podemos remediar isso convertendo o valor inteiro em um valor flutuante aqui e o caractere está saindo Caso contrário, o personagem está abaixo da superfície da água. E devemos chamar um método diferente, que chamarei de mergulho. Mudando para o script de caracteres, podemos adicionar essas três definições de método aos nossos métodos públicos. Insira água, que assume um valor flutuante representando a superfície da água como parâmetro Além disso, mergulhe e saia da água. O objetivo desses métodos públicos é permitir que o processo físico e os métodos de salto saibam onde o personagem está e como ele deve se comportar. Precisaremos adicionar algumas novas variáveis privadas. A altura da superfície da água como uma bóia e dois booleanos nos dizendo se o personagem está na água e se está abaixo da Agora, cada um dos nossos novos métodos pode definir essas variáveis de forma adequada. Enter water define a altura da superfície da água nos diz que estamos na água, mas não abaixo da saída da superfície. A água se fixará na água até cair. O mergulho simplesmente ficará abaixo da superfície. Para ser verdade na física, precisamos considerar se o personagem flutuará ou afundará, bem como o quanto estar na água restringe seus movimentos Podemos adicionar uma nova categoria de variáveis exportadas ao nosso script chamada Swim Por uma questão de simplicidade, o valor que determina se um caractere flutua ou não, podemos chamar densidade e atribuir a ela um valor padrão de menos 0,1. Esse valor será comparado à densidade da água Um valor zero terá uma flutuabilidade perfeita, menos de zero flutuará, maior que zero afundará para restringir Também podemos definir um valor para o arrasto, que será multiplicado pelas forças para reduzir sua eficácia E use um valor padrão de 0,5 Para começar, quando um objeto atinge pela primeira vez a superfície da água, há uma força de impacto reduzindo sua velocidade no método de entrada de água Se nossa velocidade y for maior que zero, podemos multiplicá-la pelo arrasto. Para simular essa força de impacto, assim como fizemos com o solo na física do ar, podemos primeiro verificar o processo físico, se o personagem está na água, depois aplicar a física da água, depois aplicar a física certificando-se de passar pelo delta, trocando se for outra na próxima linha, verificando se eles estão no O movimento horizontal na água se comportará da mesma forma que no solo, mas com a desaceleração e a aceleração também multiplicadas pelo arrasto para Como copiei essa linha de cima, preciso mudar a desaceleração para a aceleração O movimento vertical dependerá se o personagem está abaixo da superfície da água ou se sua densidade é maior que zero. Em qualquer um desses casos, precisaremos mover sua velocidade Y em direção à flutuabilidade, que é a gravidade multiplicada pela densidade, e também aplicar arrasto A taxa de variação é calculada usando gravidade vezes arrasto vezes delta. Se o personagem estiver tocando a superfície da água , queremos fazê-lo balançar para cima e para baixo. Que pode ser dividida em duas situações com outra declaração if. Se o centro de flutuabilidade do personagem estiver acima ou abaixo da superfície da água, ajuste a velocidade y para se mover para cima ou para Podemos simplificar isso para que a posição y do caractere menos um quarto de um ladrilho seja menor que a altura da superfície da água Para simplificar, podemos simplesmente copiar a fórmula de cima multiplicada por menos um se elas estiverem abaixo da superfície da água para se moverem na direção oposta A última coisa que precisamos fazer é alterar o funcionamento do salto na água Se o personagem estiver na água e abaixo da superfície, velocidade do salto deverá ser afetada pelo arrasto Se o personagem não estiver abaixo da superfície, ele deverá ter toda a força de salto para poder pular facilmente na terra. Também podemos emitir o sinal de aterrissagem aqui para ajustar a câmera Além disso, quando eles entram na água o método stop jump também deve ser desativado enquanto estiverem na água. Enquanto temos o script do personagem aberto, vamos copiar o método spawn dust e usá-lo para criar um método splash No roteiro aquático, precisaremos de uma referência à cena lotada, que contém o respingo Renomeando nossas variáveis e métodos adequadamente. Como a água está criando o respingo e a água não se move, o respingo pode ser resfriado na água, A posição y dos respingos será padronizada para zero, que já é a superfície da água E sua posição global x pode ser definida como o valor passado para o método como argumento. Essa será a posição do corpo que entrou na água para criar o respingo Podemos definir a posição X do splash para corresponder exatamente a isso. A água também precisa de um reprodutor de fluxo de áudio dois D para gerar o efeito sonoro de respingo Preenchido com o arquivo modificado que eu baixei do Freesound.org. O script pode obter uma referência a esse nó filho durante a fase de preparação e, em seguida, fazer com que o efeito sonoro seja reproduzido Podemos gerar um respingo sempre que um corpo entra na água passando pela posição do corpo Além disso, quando o corpo de um personagem escolhe sair da água, posicionando a água onde o jogador possa acessá-la e lembrando de preencher a cena cheia de respingos no inspetor, podemos fazer um teste rápido e fazer os ajustes que desejarmos no arrasto de densidade do personagem ou nos cálculos da flutuabilidade ou do estouro na superfície até arrasto de densidade do personagem ou nos cálculos da flutuabilidade ou do que ele se sinta posicionando a água onde o jogador possa acessá-la e lembrando de preencher a cena cheia de respingos no inspetor, podemos fazer um teste rápido e fazer os ajustes que desejarmos no arrasto de densidade do personagem ou nos cálculos da flutuabilidade ou do estouro na superfície até que ele se sinta bem. Com a água totalmente funcional, vamos fazer com que ela abranja todo o primeiro plano do nível, esticar a parte inferior, duplicar a superfície e editar a forma da colisão para combinar com o piso que criamos na primeira lição também pode estar no Agora temos a água no primeiro plano do nosso nível e os personagens podem nadar nela Na próxima lição, estruturaremos nosso nível e adicionaremos limites. Te vejo na próxima aula. 28. 2-7 limites: Olá amigos. Na lição anterior, adicionamos água ao primeiro plano da nossa cena Nesta lição, configuraremos a estrutura para nossos níveis e nossos limites. Primeiro, o mapa de blocos está atualmente acionando o ruído de respingo. Quando executamos nossa cena, adicionar uma condição ao método inserido no corpo pode retornar se o corpo for um mapa de blocos, impedindo que esse código Também nesse caso, algumas das animações aquáticas podem não ter sido sincronizadas durante a execução da cena, o que é apenas um problema temporário causado pela reprodução das animações no editor Se você estiver vendo uma emenda nas nuvens de rolagem, você também pode reduzir a propriedade de largura em um pixel Também devemos ajustar os colisores de caracteres restantes para que eles possam ficar limpos no chão Nossa árvore de cenas agora está cheia de muitos componentes diferentes. Os nós da etiqueta e do piso não são mais relevantes. Vamos excluí-los. Devemos separar todos os nós que serão usados para construir níveis diferentes em um único galho, transformando todas as nossas decorações em filhos de um nó dois D. Eles se tornam mais fáceis de organizar, faça a mesma coisa com nossos inimigos, tornando-os todos filhos de um nó dois D para mantê-los organizados Como todos esses são componentes do nível do nosso jogo, podemos criar uma nova área dois D para mantê-los e chamá-la de nível. Em seguida, faça as decorações do mapa de blocos, os inimigos e os filhos da água do nó de nível Por uma questão de simplicidade, vamos definir temporariamente a origem do nível o local inicial do jogador e mover o jogador para a origem da cena. Em seguida, ajuste todos os nós secundários do nível para correspondam, salve o nível como sua própria cena, que pertence a uma nova pasta chamada levels. Podemos chamar esse nível de um, um. A câmera e o plano de fundo do personagem do jogador serão usados em todos os níveis, já que o pacote de ativos não contém nenhum outro recurso para planos de fundo Dependendo de como você planeja criar seu jogo, o plano de fundo também pode fazer parte do nível Agora podemos abrir a cena de nível um. Como transformamos o nó raiz do nosso nível em uma área dois D, isso significa que podemos dar uma forma a ele. Vamos definir nosso nível como um retângulo. E ajuste o tamanho e a posição do retângulo para definir limites aos quais o jogador e a câmera ficarão confinados E ajuste a cor do bug D dessa área de colisão para ficar mais transparente Isso não afeta nossa visão de todo o resto. Criando um novo script para o nível, podemos obter uma referência à forma de colisão de dois nós D durante a fase de preparação O objetivo desse retângulo é que o jogador e a câmera saibam onde parar Precisaremos obter os valores mínimo e máximo permitidos dentro dos limites desse retângulo Vamos escrever dois métodos, get min e get max, que serão públicos e retornarão um vetor dois. O valor mínimo será a posição da forma de colisão menos a metade de seu tamanho Mas para acessar o tamanho, precisamos primeiro acessar sua forma, depois o retângulo, depois o tamanho e repetir para obter o valor máximo Para evitar repetir esse código várias vezes, também devemos definir isso como uma variável, nomeá-la com metade do tamanho Voltando à cena principal. O objetivo dessa cena é facilitar a comunicação entre o personagem do jogador, a câmera e o nível atual, permitindo que troquemos facilmente o nível por um novo, conforme necessário Você pode renomear essa cena e seu nó raiz para refletir esse propósito Em um jogo simples como esse, você pode chamar isso de cena principal ou cena do jogo. Se seu ciclo de jogo incluir outra jogabilidade além da plataforma, convém nomear a cena da plataforma para diferenciá-la de outras cenas de jogo Para gerenciar as regras de como essa cena de jogo funcionará, devemos dar a ela um script. O nome do roteiro geralmente será o nome da cena seguido pelo gerenciador de palavras. O trabalho desse gerente é garantir que todas as anotações da criança tenham todas as informações necessárias para realizar cada um de seus trabalhos exclusivos. Para evitar que o personagem do jogador ou a câmera saiam dos limites do nível, eles precisam saber quais são esses limites. Como essa cena será capaz de rodar qualquer nível, ela precisará solicitar as informações sobre os limites do nível no script do nível e passar essas informações para o script do personagem do jogador, bem como para a câmera. Na parte superior do script do gerenciador. Vamos primeiro obter referências ao nível, ao jogador e à câmera dentro do método pronto. Podemos então obter os limites do nível e definir os limites para o jogador e a câmera. Agora, tanto o personagem quanto os roteiros da câmera precisarão de métodos públicos para definir esses limites e, em seguida, impor esses limites a si mesmos Começando com o personagem, podemos simplesmente criar duas novas variáveis do tipo vetor dois e armazenar os valores mínimo e máximo. Escreva um método de conjunto de limites que usa dois vetores dois e define os valores das variáveis privadas Então, na parte inferior do processo físico, podemos restringir a posição do personagem a ser contida dentro desses limites usando o método clamp, fornecendo ao valor atual um mínimo e um máximo Depende de você se deseja impor essas restrições a todos os personagens do seu jogo ou apenas ao personagem do jogador Mas acho que os inimigos deveriam ter a liberdade ultrapassar os limites de nível do meu jogo. Farei com que essa última etapa dependa do fato de esses limites terem sido definidos ou não, adicionando também uma variável booleana chamada is bound Quando o método set bounds é chamado no personagem do jogador, ele também define essa variável como verdadeira, mas outros caracteres permanecerão não vinculados A câmera será um pouco mais complicada pois a própria câmera também tem um formato. Copiar as mesmas variáveis e definir o método no script da câmera. Podemos editar os valores de min e max para acomodar o tamanho da visão da câmera. Podemos recuperar esse valor usando get Viewport wrecked size dividido pelo zoom e reduzido pela metade Em seguida, adicione esse valor ao mínimo e subtraia do máximo Quase sempre é melhor armazenar qualquer valor calculado em uma variável do que calculá-lo mais de uma vez. Então, podemos fixar a posição da câmera da mesma forma que fizemos com os personagens Vamos experimentá-lo. A visão da câmera está contida dentro do limite do nível assim como a origem do personagem, e funciona em todos os lados Podemos manter todo o Roger na tela aplicando a mesma lógica, usando o tamanho do sprite Mas como o sprite não está centrado na origem do personagem, precisamos calcular os valores de x e y Agora, Roger só poderá ficar com o sprite inteiro na tela Ao longo desta seção, desenvolvemos muitos dos recursos que serão usados para gerar níveis para nosso jogo. Na próxima seção, adicionaremos tesouros colecionáveis e uma interface de usuário à nossa cena principal Nos vemos na próxima seção. 29. 3-1 dados: Olá amigos. Na seção anterior, construímos muitos dos componentes estruturais necessários para criar níveis do nosso jogo. Nesta seção, criaremos um tesouro colecionável para o jogador coletar e dispersá-lo em nossos níveis Se você concluiu a tarefa, deverá ter dois níveis básicos construídos com terrenos, decorações e limites diferentes Ao concluir essa tarefa, você provavelmente também fez ajustes para se adequar melhor ao seu jogo. Por exemplo, diminuí a velocidade de rolagem das nuvens para menos 32 pixels por segundo porque não gostei da aparência delas quando a câmera era intermitente Quando a câmera girou, reduzi a gravidade em cerca de metade do que era antes e alterei os valores de todos os personagens, locomoção Também fiz uma pequena correção efeito sonoro do respingo no script aquático Como os dois nós D do reprodutor de áudio reduzem o volume com base na proximidade da câmera, o som ficará mais silencioso quanto mais você estiver do início do nível. Para corrigir isso, defino a exposição global nó do reprodutor de fluxo de áudio para a exposição passada para o método em que o som se originará do mesmo local do splash no volume máximo Embora os tutoriais devam ser sempre a última coisa que você cria para seu jogo, gostaria de aproveitar a oportunidade para examinar alguns princípios de design de níveis para um aprendizado intuitivo Para o primeiro nível da ilha, iniciei o jogador com um obstáculo imediato que ele deve pular, seguido por um obstáculo maior e outro ainda maior Depois disso, isso deve ser suficiente para que o jogador entenda que pode pressionar o botão de pular para alcançar o topo do segundo, mas não o terceiro obstáculo Eu apresentei a árvore como uma plataforma unidirecional em um ambiente seguro e exijo que o jogador aprenda a usá-la antes de chegar à próxima seção do nível. Aqui, as mesmas árvores estão disponíveis, com um pouco mais de risco de serem introduzidas, ter que pular de árvore e potencialmente cair na água. Se falharem, o risco não é real, embora seja percebido apenas pelo jogador. Eu criei três caminhos diferentes nesta parte, sendo o mais fácil o caminho a seguir e os outros dois potencialmente levando a recompensas. Todos estão claramente visíveis, ensinando ao jogador que ele deveria procurar mais caminhos ramificados como esse no futuro. Na próxima vez que eu bater em algo assim, o jogador verá a recompensa primeiro, mas deverá voltar para buscá-la novamente, ensinando ao jogador o que ele deve Foi a primeira vez que usei uma árvore de fundo. Porque eu não queria que o jogador pensasse que poderia pular nessa árvore, falhar e aprender falsamente que nem todas as árvores são plataformas essa altura, o jogador já tem experiência no uso de árvores em primeiro plano como plataformas Esta árvore está posicionada para ser saltada da árvore para a esquerda ou do chão Isso ensina ao jogador que apenas as árvores de fundo não são plataformas para prosseguir, ele deve ignorar a árvore de fundo e pular da borda Em vez disso, caso a primeira árvore não funcionasse, eu a segui com uma segunda árvore destinada a induzir o jogador a tentar pular nela. E em vez disso, seguindo. Aqui está outra caverna secreta. Mas desta vez o jogador não consegue ver. Se eles aprenderam nas partes anteriores do nível que deveriam explorar na água, serão recompensados Todas essas entradas na água estão claramente marcadas com raios de luz, dois, que ajudam a chamar a atenção do jogador e a fazer com que a água pareça convidativa Eu coloquei árvores de primeiro plano e de fundo juntas para testar a habilidade do jogador de pular até a árvore mais alta As árvores se distinguem ainda mais por sua coloração e camadas na frente ou atrás do jogador Usar cores ou iluminação consistentes para atrair a atenção do jogador é chamado de usar linguagem visual ou recursos para dizer ao jogador que ele pode ou deve fazer algo naquele local ou usando aquele objeto Muitos jogos usam essas técnicas para indicar saliências escaláveis, objetos quebráveis e NBCs objetos quebráveis Ou para dizer quando você deve usar uma arma ou habilidade específica. Tirando o primeiro nível do caminho, substituindo-o por um nível de navio e renomeando os nós Em vez disso, posso jogar o outro nível. Quando o jogador atingir esse nível, ele terá uma boa compreensão da mecânica da plataforma e não precisará ser ensinado Em vez disso, concentro-me em criar a aparência geral de um navio pirata, moldando todo o nível para representar um E adicionou ladrilhos extras para esconder o fundo até que o jogador alcance acima do nível da água Decorei salas específicas e becos sem saída com barris e garrafas, e posicionei as escadas forma temática e evitei que o jogador saísse do navio Antes que o jogador possa coletar qualquer tesouro, precisaremos criar um script para saber quanto tesouro ele tem. Podemos colocar esse script na pasta Autolodes e chamá-lo Mas em vez de estender o nó, desta vez precisamos estender Podemos remover o modelo. O objetivo do script será armazenar todas as informações sobre progresso do jogador no jogo. Para começar, vamos adicionar um número inteiro, que será o número de moedas que o jogador coletou, e outro inteiro para representar o número de vidas restantes do jogador A exportação dessas variáveis nos permitirá visualizá-las no inspetor enquanto o jogo está Se necessário, o valor padrão para um número inteiro é zero, que é bom para as moedas de um jogador como valor inicial, mas não é tão bom para suas vidas no início do jogo Devemos definir exatamente o que esse recurso conterá quando for criado pela primeira vez. sublinhado, podemos definir os valores iniciais para cada variável, bem como realizar qualquer outra lógica que desejarmos Como parte da inicialização dos recursos, gostaria que os jogadores começassem meu jogo com zero moedas e três vidas Para referenciar esse recurso por seu tipo, precisamos dar a ele um nome de classe. Vamos chamá-lo de Dados com D maiúsculo À medida que nosso jogo se torna mais complicado, esse recurso de dados conterá muito mais variáveis de diferentes tipos para acompanhar o progresso dos jogadores. Agora temos um local para armazenar essas informações, mas precisamos dos scripts em nosso jogo para poder acessá-las livremente. Como fizemos com o carregamento automático global, podemos criar outro carregamento automático cuja responsabilidade é acessar e gerenciar os dados. Vamos nomear esse arquivo conterá uma variável chamada data com uma letra minúscula do tipo data com uma letra maiúscula D. O objetivo do script será dar ao resto do jogo acesso ao arquivo de dados atual, mas também gerenciar o arquivo de dados Aqui, precisaremos escrever métodos para iniciar um novo jogo, salvando e carregando dois. Na verdade, só estamos interessados em criar um novo recurso de dados. Devemos definir o valor dos dados como dados. Novos dados novos criarão um novo recurso de dados e acionarão automaticamente o método init que acabamos de escrever, definindo as vidas como três em vez de zero Por enquanto, podemos simplesmente chamar o novo método de jogo quando esse nó estiver pronto. Abrindo as configurações do projeto, alterne para a guia de carregamento automático adicione o novo script de arquivo à lista de carregamentos automáticos. O nome do nó padrão funcionará bem se executarmos essa cena. Podemos voltar para Deus enquanto o jogo está rodando. Em seguida, mude de local para remoto na guia de cena. Isso nos mostrará a árvore de cenas do jogo que está sendo executado no momento. Selecionando o nó carregado automaticamente do arquivo e examinando o inspetor, podemos ver que ele tem um recurso de dados O nome do recurso de dados é ID do objeto, seguido por um número longo. Ao clicar no recurso, podemos visualizar e editar seu conteúdo. Qualquer um dos nossos scripts pode acessar essas informações facilmente. Para demonstrar, vamos abrir o script do gerenciador de jogos. E depois de fazer essas coisas usuais com os limites de nível, basta imprimir o valor das vidas arquivadas. Executando a cena, podemos ver o número três impresso no painel de saída. Agora temos um recurso personalizado configurado para armazenar as informações de nossos jogadores que podemos acessar a qualquer momento Na próxima lição, criaremos moedas que o jogador poderá coletar. Te vejo na próxima aula. 30. 3-2 moedas: Olá amigos. Na lição anterior, criamos um recurso personalizado para monitorar o progresso e os dados do jogador. Nesta lição, criaremos moedas colecionáveis. Podemos nos dispersar por nossos níveis para o jogador coletar Para esta lição, importei um conjunto de sons de cliques em moedas do FreeSound.org feito por Val Inspire com uma licença Creative Commons Vamos começar abrindo nosso primeiro nível e criando uma nova pasta D do node two para o tesouro. Moedas são objetos físicos que existem no mundo. Precisaremos detectar colisões. Também podemos querer que eles sejam afetados pela gravidade. O nó que melhor define esses comportamentos será um corpo rígido, dois nós D. Vamos renomeá-la para moeda de prata para poder ver nossa moeda Vamos primeiro adicionar um sprite animado a ele. Crie um novo recurso de sprite frames. Encontre os sprites da moeda de prata no pacote de ativos e preencha a animação padrão Defina essa animação padrão para reprodução automática, repetida e defina os quadros por Também podemos adicionar uma segunda animação a esse sprite animado clicando no nome do botão adicionar animação Esse efeito de animação e, em seguida, preencha-o com os sprites do efeito moeda do pacote de ativos Essa animação não deve ser repetida. Esta é a animação que deve ser reproduzida quando a moeda é coletada antes que ela desapareça. Volte para a animação padrão. Assim, podemos ver o tamanho e a forma da moeda claramente no editor. Agora que podemos ver nossa moeda, como acontece com todos os objetos físicos dessas colisões, precisaremos dar a ela uma forma de colisão, criando um recurso em forma de círculo Podemos redimensioná-lo para caber no tamanho da moeda. Você pode precisar desativar o ajuste de notas. Colisões com moedas também costumam gerar efeitos sonoros Também devemos adicionar um reprodutor de fluxo de áudio ao nó e preenchê-lo com o efeito sonoro coin Cl Vamos salvar o galho da moeda de prata como sua própria cena e colocá-lo em uma nova pasta de cenas chamada tesouro. Como todo o resto, as moedas precisarão de um script para controlar como elas se comportam. Devemos começar a organizar nossos scripts em pastas designadas. Vou criar uma pasta de nudez para roteiros de tesouros. Podemos começar nosso script obtendo referências aos nós do sprite e do reprodutor de áudio durante a fase de preparação. Com o nó raiz da moeda selecionado, conecte o sinal inserido pelo corpo a si mesmo para que a moeda possa reagir a colisões Quando um corpo entra no colisor de moedas, devemos primeiro reproduzir o efeito sonoro Então, queremos verificar se a moeda colidiu com algo além de um personagem e, se não for um personagem, retornar para que seja ignorada Se for realmente um personagem, podemos dizer ao sprite animado reproduza o efeito de animação Em seguida, esse nó deve ser removido da cena. Com uma versão gratuita, todo esse código será executado em um único quadro. Não conseguiremos ver a animação se desenrolar. Podemos usar um novo comando aqui chamado peso para pausar esse código até que algo aconteça O que queremos esperar será quando animação do sprite terminar com o nó raiz das moedas selecionado Precisaremos alterar algumas das configurações padrão do nó de corpo rígido Por padrão, o sinal inserido pelo corpo só acontecerá quando os colisores se sobrepuserem Mas como a física está sendo aplicada tanto ao personagem quanto à moeda, isso não acontecerá. o colisor de personagens empurrará o colisor de moedas Podemos alterar essas configurações para permitir que o sinal aconteça quando os colisores entrarem em contato Ao configurar o monitor de contatos para o máximo real de contatos reportados para qualquer valor maior que zero, mas na verdade só precisaríamos de um próximo. Expanda a seção de desativação. A maioria das pessoas não gostaria que o pixel girasse, então podemos bloquear a rotação das moedas clicando nesta caixa de seleção As moedas colecionáveis na maioria dos jogos se enquadram em uma das duas categorias Aqueles que pairam no ar e aqueles que são jogados ao redor após quebrar uma caixa ou derrotar Podemos fazer a primeira opção definindo a propriedade de congelamento como verdadeira e alterando o modo de congelamento para Cinemático Agora, a moeda não será afetada pela física, incluindo a gravidade, mas ainda assim colidirá com outros objetos Se quisermos ativar a gravidade ou jogar a moeda ao redor, simplesmente definimos o valor de congelamento como falso e aplicamos as forças que quisermos Também queremos garantir que nossas moedas sejam coletadas apenas pelo personagem do jogador, não pelos inimigos ou quaisquer outros personagens. A maneira mais simples de fazer isso é usando camadas de colisão Até agora, tudo em nosso jogo tem usado a camada de colisão padrão, a camada um Usando diferentes camadas de colisão, podemos controlar facilmente quais objetos reagem ou ignoram outros objetos Vamos deixar que a camada padrão, camada um, represente o terreno Como a maioria dos objetos, se não todos, precisarão colidir com isso, por padrão, talvez queiramos ter diferentes tipos de ambientes com diferentes tipos de ambientes com diferentes tipos colisões no futuro, vamos deixar o mundo usar as primeiras oito camadas de colisão abrindo a Podemos mudar sua camada de colisão para a camada nove e deixar o segundo bloco representar as camadas de colisão do nosso jogador Da mesma forma, podemos colocar os personagens inimigos na camada 17. E deixe o terceiro bloco representar nossas camadas de colisão inimigas Finalmente, as moedas podem estar na camada 25, com o quarto bloco representando um tesouro. A seção de máscara das camadas de colisão é com a qual esse objeto colidirá A única coisa com a qual queremos que a moeda colida é com o meio ambiente. E o jogador que definimos para as camadas uma e nove moedas agora ignorará as colisões com inimigos e outros tesouros Farei com que o personagem do jogador colida com os inimigos, os inimigos colidam com o jogador e com outros Também devemos abrir as configurações do projeto e dar nomes a cada uma dessas camadas de colisão para que possamos lembrar facilmente para que as reservamos Os nomes serão exibidos como uma dica de ferramenta ao mouse sobre a camada de colisão no Há um segundo conjunto de sprites de moedas no pacote de ativos para duas moedas de ouro Vamos duplicar nossa cena de moedas de prata e renomeá-la para moeda de ouro E substitua os sprites de moedas de prata por sprites de moedas de ouro se quisermos que moedas diferentes tenham denominações diferentes Também podemos adicionar um valor inteiro exportado ao nosso script e atribuir a ele o valor padrão de um para o meu jogo Vou fazer com que as moedas de ouro tenham o valor de dez moedas de prata. Embora improvável, é possível que depois que o jogador colida com a moeda, colida com a mesma moeda uma segunda vez antes que ela Para evitar isso, devemos definir a máscara de colisão da moeda para zero, eliminando a possibilidade de ela colidir com qualquer coisa depois de ser coletada Colocando uma de cada moeda em nosso nível, o jogador agora pode coletá-las. Também podemos colocar a água em uma camada separada do terreno e fazer com que ela colida com personagens e tesouros, nomear a camada nas configurações do projeto Agora temos moedas colecionáveis de valores variados que o jogador será motivado a coletar ao longo Na próxima lição, criaremos uma interface de usuário com um contador para mostrar ao jogador quantas moedas ele tem. Te vejo na próxima aula. 31. 3-3 Interface de usuário: Olá amigos. Na lição anterior, criamos moedas de valores diferentes para o jogador coletar. Nesta lição, mostraremos quantas moedas o jogador tem na interface do usuário. Na cena máxima da plataforma principal, podemos adicionar uma interface de usuário para exibir todos os tipos de informações importantes de que o jogador precisa. Essas informações devem ser independentes da câmera e sempre exibidas na frente de todo o resto. Você pode ficar tentado a fazer disso um filho da câmera, como fizemos com o plano de fundo Não existe um tipo para criar isso mais fácil, chamado de camada de tela. Cada dois nós em arsene tem uma ordem de sorteio com base em seu índice definido e sua posição na árvore da cena Mas depois que tudo foi processado pela câmera em uma única imagem, tudo isso se torna a camada padrão, camada zero. Por padrão, uma camada de tela desenhará uma imagem totalmente nova na camada um. Além disso, as camadas de tela são preenchidas com um novo tipo de nó Na verdade, usamos um na primeira aula. Eles são chamados de nós de controle e estão marcados em verde. Para exibir números na tela, poderíamos usar um nó de rótulo, que pode exibir qualquer texto que quisermos, mas não se encaixaria realmente em nossa estética de pixel art. E nosso pacote de ativos vem com bons sprites numéricos, então vamos usá-los em vez disso Podemos adicionar nós de controle à camada de tela chamada textura Rets para exibir esses sprites para nós Vamos adicionar uma textura para um dígito, outra para os dez dígitos e preencher os e preencher Por padrão, você precisará definir um limite de quantos dígitos deseja exibir na tela Seguindo as convenções de jogos como Mario e Donkey Kong, limitarei o número de moedas em 99 e darei ao jogador uma recompensa extra para cada 100 Também devemos adicionar uma textura de ícone para dizer ao jogador o que esse número significa e preenchida com a imagem de uma moeda para evitar a reorganização manual dos nós de controle individuais Na camada de tela, também há nós fornecidos por Godot, cujo objetivo é organizar seus nós secundários para nós Vamos adicionar uma caixa horizontal à tela, chamá-la de contador de moedas e definir nossos outros nós como filhos da caixa. Eles são automaticamente reorganizados para caber horizontalmente dentro da caixa Vou posicionar esse contador a 32 pixels do canto. E aumenta na escala dois, é muito mais fácil de perceber e ler Em seguida, podemos editar as configurações dos controles individuais para determinar como eles serão desenhados em relação ao contêiner principal. Eu gostaria que o ícone fosse exibido, ajustando-se proporcionalmente à sua largura E aumente a escala para caber no tamanho do contêiner principal. Os dígitos, eu gostaria de dobrar de tamanho para que sejam mais fáceis de ler Sabendo que há cinco pixels de largura, definirei a largura mínima personalizada para dez pixels. Ajuste-os proporcionalmente à sua altura. E mantenha a proporção ao mesmo tempo, mantenha-os centralizados nos pais Observe como os controles da tela estão sendo desenhados aqui na água. Mas se clicarmos em play, eles serão exibidos no canto superior esquerdo da janela. Se você se lembra da primeira lição, a imagem que está sendo desenhada na tela por padrão é esse retângulo azul Se isso ajudar, você pode ocultar o nível, personagem e a câmera enquanto trabalha na tela clicando nos ícones. Lembre-se de exibi-las quando estiver pronto para testar seu jogo Experimente experimentar como seu contador é exibido na tela e veja como ele fica enquanto joga Para fazer o contador funcionar, precisaremos escrever um script para ele. Vou colocar isso em uma nova pasta de scripts para UI e chamá-la de Counter. Como a natureza de um contador de moedas não tem nada a ver com a organização de uma caixa horizontal, vou fazer com que ele estenda o tipo de controle mais genérico. Em vez disso, precisaremos de referências a cada uma das nossas especificações de textura que desejamos alterar durante a fase de preparação Também precisaremos de uma lista de texturas para trocá-las, representando cada um dos nossos números de 0 a 9. Podemos armazená-las em uma matriz exportada de texturas com representando cada um dos nossos números de 0 a 9. Podemos armazená-las dois dígitos chamados de sublinhado Uma matriz é semelhante a uma lista; nesse caso, uma lista de duas texturas em D ou imagens de números examinados no inspetor Podemos clicar nessa matriz exportada para expandi-la e atribuir um tamanho de dez Os elementos da matriz são convenientemente numerados de zero a nove Esses são os índices que usamos para acessar os elementos individuais da matriz Preencha cada índice de matriz com o dígito correspondente do pacote de ativos Esse script precisa de uma função que possamos chamar para definir o número que está sendo exibido. Vou chamá-lo de valor definido e usar um inteiro como parâmetro Sabendo que esse contador serve apenas para exibir um número 0 a 99, vamos primeiro aplicar essa regra Ao fixar o valor entre esses números. Podemos definir a textura que está sendo exibida por aqueles com textura k, como dígitos em um índice O que é o índice? É o mesmo que o dígito em si. Mas como extraímos um dígito? Podemos usar um operador comum na programação chamado módulo, representado pelo sinal de porcentagem, que retorna o restante de um valor de divisão Dez retornará um dígito, que é o índice da matriz da textura que queremos exibir Em seguida, também podemos definir o dígito das dezenas executando a divisão em vez do módulo Agora precisamos que o jogador colida com nossas moedas para, de alguma forma, atualizar nossa interface de usuário Mas eles existem em cenas diferentes, dificultando um pouco os sinais ou as chamadas de métodos. Para preencher essa lacuna, podemos delegar essa responsabilidade ao gerente do jogo, pois ele é facilmente acessível como nó raiz e tem acesso a todas as crianças Abrindo o script da moeda. Quando a moeda é coletada, podemos obter uma referência à raiz da cena usando a raiz cifrão seguida pelo jogo, que é o nome do nó raiz da cena. Em seguida, chame um método no script do gerenciador de jogos que ainda não escrevemos. Coletaremos a moeda e repassaremos o valor da moeda que está sendo coletada. Mudando para o script do gerenciador de jogos, precisaremos de uma referência ao contador de moedas durante a fase de preparação. O tipo disso não precisa ser uma caixa horizontal. Como não estamos acessando nada específico desse tipo de nó, verdade, só nos importamos que seja alguma forma de nó de controle. Primeiro, podemos definir esse método de coleta de moedas, tomando o valor inteiro da moeda como parâmetro Em seguida, adicionaremos o valor da moeda aos dados do arquivo. Em seguida, atualize o contador na interface do usuário, definindo seu valor para o novo valor da moeda dos dados do arquivo. Além disso, essa atualização do contador também deve ocorrer quando a costura for carregada pela primeira vez. Também vamos testar o contador definindo seu valor para algo aleatório, como 77. Percorrendo a cena, podemos ver que ela estava realmente definida para 77. E quando colidimos com uma moeda de prata, o contador aumenta em um Coletar a moeda de ouro também aumenta em dez. Sinta-se à vontade para testar a configuração do contador para qualquer número aleatório , negativo ou algo maior que 99. Mas lembre-se de excluir essa linha. Quando você terminar, Deus nos avisa que estamos dividindo por um número inteiro Clicar no aviso nos leva ao script da moeda, onde, de fato, estamos dividindo por um número inteiro e os valores decimais estão sendo Como isso é proposital, podemos adicionar uma linha extra aqui na divisão de números inteiros Para ignorar esse aviso, agora temos a interface do usuário exibindo quantas moedas o jogador coletou. Na próxima lição, adicionaremos um item de vida colecionável e o rastrearemos também Te vejo na próxima aula. 32. 3-4 vidas: Olá amigos. Na lição anterior, criamos um contador de moedas para exibir na interface do usuário. Nesta lição, adicionaremos um item de vida colecionável ao nosso jogo Vamos começar com nossa cena de primeiro nível. O ativo que eu gostaria de representar, a vida do jogador no meu jogo, é uma caveira dourada E eu não acho que seria bom tê-lo afetado por forças como a gravidade. Ao contrário das moedas, quero que pareça mais sinistro e misterioso Sempre será algo que flutua até ser coletado Usaremos um nó D de área dois para definir suas propriedades básicas e renomeá-lo para Golden Skull Em seguida, adicione um sprite animado. Dois D, crie um recurso de sprite frames e preencha-o com os ativos do golden skull Reproduza automaticamente o loop e defina os quadros por segundo. Em seguida, como a moeda, adicione uma segunda animação chamada Effect e preencha-a com os sprites do efeito caveira Voltando ao crânio e obtendo uma boa visão dele no editor, podemos adicionar uma forma de colisão a ele, que será um círculo Vou ajustar o sprite um pixel para a esquerda e um pouco para que fique melhor centralizado E ajuste o planador Circle para caber. Adicione um reprodutor de fluxo de áudio com dois nós D. O efeito sonoro que eu selecionei para o crânio será colorido, aberto, feito por uma sopa da nova era Mas eu o reduzi um pouco em um editor de áudio, ainda é mais longo do que a animação, então precisarei adicionar um ou dois quadros vazios no final da animação para que o som possa terminar Em seguida, salve o ramo do crânio como sua própria posição de cena, o crânio onde ele pode ser coletado durante nosso teste, abra a cena do crânio e adicione um script ao Muitos dos comportamentos do crânio serão muito semelhantes aos da escrita de moedas que escrevemos anteriormente Vamos começar copiando e colando a escrita da moeda na escrita da caveira Meu script de caveira não precisa de um valor, já que cada crânio representará uma vida Mas ele ainda terá um sprite e um efeito sonoro quando ocorrer uma colisão. Ainda podemos fazer a mesma lógica, exceto a parte em que dizemos ao gerente do jogo que o jogador coletou uma moeda. Vamos separar isso em um método privado separado chamado underscore collect e chamar o método do mesmo local Mudando para o script de moedas, podemos fazer as mesmas alterações no formato. Agora, tudo nesses dois scripts é quase idêntico, exceto o conteúdo desse método de coleta e eles estendem diferentes tipos de nós. Se selecionarmos a moeda e a caveira, podemos ver que ambas têm propriedades de um objeto de colisão dois D. Não queremos escrever exatamente esse mesmo script Toda vez que criamos um novo tipo de tesouro para adicionar ao nosso jogo, podemos definir um script mais abstrato chamado tesouro e estender o objeto de colisão dois D. Aqui podemos escrever todos os comportamentos comuns do podemos ver que ambas têm propriedades de um objeto de colisão dois D. Não queremos escrever exatamente esse mesmo script Toda vez que criamos um novo tipo de tesouro para adicionar ao nosso jogo, podemos definir um script mais abstrato chamado tesouro e estender o objeto de colisão dois D. Aqui podemos escrever todos os comportamentos comuns do vários tipos de tesouros para o nosso jogo, copiando todo o conteúdo para o novo script do tesouro. O comportamento padrão do método collect pode ser vazio, pois de tesouro é muito abstrato conceito de tesouro é muito abstrato para saber o que devemos fazer com ele quando é coletado. O objetivo desse método é simplesmente dizer a Godot que tudo o que é tesouro pode ser coletado Dê a esse script o nome da classe tesouro. Como as moedas e crânios são tipos diferentes de objetos de colisão, podemos fazer com que eles estendam tesouros e obtenham todos os benefícios úteis que colocamos no script do Agora, em nosso script de moedas, temos coisas específicas sobre moedas, como valor. Podemos ignorar o comportamento de ser coletado em vez de não fazer nada para dizer gerente do jogo que uma moeda foi coletada Um método que está substituindo outro método é indicado com esta seta azul Você deve ter notado que essa seta aparece sempre que substituímos o Da mesma forma, quando o crânio for coletado, ele dirá ao gerente do jogo que um crânio foi Agora, não importa que tipo de tesouro seja coletado, esses mesmos comportamentos acontecerão automaticamente para todos eles. Mas devemos ter cuidado e garantir que todos os tesouros tenham esses nós secundários, e que o sprite animado tenha uma animação de efeito Tratar diferentes tipos de objetos como se todos tivessem um conjunto similar de comportamentos é chamado de polimorfismo Todas as moedas e caveiras podem ser tratadas como tesouros. A única diferença será o que eles fazem quando são coletados. Qualquer novo tipo de tesouro que adicionarmos também pode seguir esse padrão. Mudando para o script do gerenciador de jogos, podemos simplesmente adicionar um método de coleta de caveira, aumentando a vida do jogador em uma Quando isso acontece, duplicando a referência do contador de moedas, podemos adicionar uma contra-referência de vidas e, em seguida, atualizar a interface do usuário quando uma vida é adicionada Como o método pronto está executando duas tarefas diferentes e não relacionadas, devemos separá-las em métodos diferentes para mantê-las organizadas. Vamos escrever limites de nit privados e métodos de interface de usuário de TI que executam cada uma dessas tarefas isoladamente e são chamados pelo método ready Vou seguir as convenções estabelecidas por Mario e Donkey Kong, concedendo ao jogador uma vida extra depois de coletar 100 moedas Quando as moedas arquivadas forem maiores ou iguais a 100, subtraia 100 moedas e adicione uma vida, além de atualizar o contador de vidas Em seguida, podemos duplicar o nó do contador de moedas na camada da tela e renomeá-lo para Lives Para colocar isso no canto superior direito, alterarei a propriedade de direção do layout da direita para a esquerda. Já que meu contador de moedas estava a 32 pixels do lado esquerdo da tela. Posso espelhar isso subtraindo 64 pixels para adicionar o mesmo preenchimento no lado direito A reversão da direção do layout também inverteu a ordem dos nós secundários Gosto que o ícone esteja no lado direito, mas os dígitos de um e dez estão invertidos Vou arrastá-los para a posição correta. Eu editei o cachorro zero um para caber melhor na interface do usuário, removendo as partículas acima da imagem do crânio para criar esse Png de zero ponto zero para usar como textura do ícone Por fim, nos casos em que a moeda não está congelada, quero que ela permaneça parada enquanto está sendo coletada Atualmente, a colisão de Rogers com a moeda adiciona força ao corpo rígido da moeda, fazendo com que ela se mova enquanto a animação do efeito é reproduzida no script da No método collect, queremos acessar as propriedades do modo de congelamento e congelamento do corpo rígido dois D. Mas elas são inacessíveis para este script pois ele está estendendo o objeto de colisão dois D e Godot não gosta que alteremos as configurações de colisão enquanto uma colisão Podemos resolver esses dois problemas usando um método incorporado chamado call deferred O método call deferred dirá a Godot execute isso após o término da colisão O processamento da chamada adiada usa um argumento de string do nome do método que queremos chamar Nesse caso, set free habilitou o valor para o qual queremos defini-lo, o que é verdadeiro. Então, eu também preciso definir o modo de congelamento para um valor definido dentro do corpo rígido Dois modos de congelamento de classe D, estáticos. Um corpo rígido estático não se moverá nem por causa de forças nem de colisões, que é o que eu gostaria Isso impedirá que a moeda se mova depois de ser coletada com o nó raiz do crânio Defina a camada de colisão para a camada do tesouro e a máscara de colisão para a camada do jogador Também conecte o sinal inserido pelo corpo aos crânios no método inserido pelo corpo Agora temos um contador de vidas e o jogador pode ganhar mais vidas coletando caveiras ou moedas Na próxima lição, criaremos um baú de tesouro cheio de espólios de piratas Te vejo na próxima aula. 33. Caixa 3-5: Olá amigos. Na lição anterior, adicionamos um tesouro de caveira colecionável ao nosso jogo Nesta lição, criaremos um baú cheio de tesouros que o jogador poderá abrir. Vou fazer com que um baú do tesouro seja um objeto estacionário que parece estar em segundo plano para que o jogador possa andar na frente dele Quando isso acontecer, o baú se abrirá e lançará uma certa quantidade de moedas no ar. Começando pela cena do nível, vamos adicionar um nó da área dois à pasta do tesouro. Ter comportamentos mais complicados do que outros itens do jogo. Um sprite animado não será suficiente. Como nossos personagens, precisaremos usar um sprite com dois nós D e, em seguida, usar um reprodutor de animação para controlá-lo e uma árvore de animação para controlar o jogador Vamos primeiro definir o sprite padrão para o nó D do sprite two. Estou usando os sprites do baú da pasta do navio mercante, não o da pasta Palm Tree Island Eu quero um em que o baú não esteja trancado, apenas fechado dentro da pasta desbloqueada Vou escolher o sprite número três. Também podemos adicionar uma forma de colisão, que deve ser um retângulo e esticá-la para cobrir todo o peito E um reprodutor de streaming de áudio para adicionar alguns efeitos sonoros. Renomeie o baú do branch node e salve-o como sua própria cena na pasta do tesouro Nosso teste precisará de um script para controlá-lo, que também deve estar na pasta de scripts do tesouro. O baú terá uma variável exportada para saber se está aberto ou não Como o valor padrão para um lingote é falso, o baú não está aberto O baú também precisará saber o que está dentro dele. Vamos adicionar uma variável inteira para especificar o valor total de todas as moedas dentro do baú e atribuir a ela o valor padrão de um Não faria sentido permitir que esse número fosse um número negativo ou um número ridiculamente alto Podemos restringir o intervalo de valores da variável exportada adicionando intervalo de sublinhado e especificando um valor mínimo e máximo Agora, esse número não pode ser definido algo negativo ou muito alto. Também podemos adicionar uma variável chamada underscore booty como uma matriz de tesouros para representar os nós reais da moeda dentro do baú do tesouro Para fazer essas moedas, precisaremos de cenas repletas da prata e da moeda de ouro. Dentro do método pronto, podemos então escrever um algoritmo simples para instanciar as moedas necessárias para somar o valor total Embora o valor total seja maior que dez, podemos reduzir o valor total dez e instanciar uma moeda de ouro Essa moeda recém-instanciada pode ser adicionada à matriz de espólios com um empurrão Isso se repetirá até que o valor total seja menor que dez ou seja totalmente ignorado Se já tiver menos de dez, repita o processo. Desde que o valor total seja maior que zero, podemos reduzi-lo em um e instanciar uma moeda de prata e, em seguida, colocá-la na parte de trás da matriz Ao final desse processo, o valor total será zero e o baú terá um monte de moedas representando essa quantia, prontas para serem geradas Quando o jogador abre o baú, podemos então percorrer a matriz de espólios, um item por vez, usando um loop for, definir a posição global de cada item na mesma posição global do baú, mas também mover uma peça para cima Transformar a propriedade de congelamento falsa física será aplicada à moeda. Podemos aplicar um pouco de força aleatória cada moeda para fazê-las se espalhar no ar quando o baú se abrir Para fazer isso, precisaremos criar uma variável geradora de números aleatórios e inicializá-la com um gerador de números aleatórios novo durante a fase de preparação Em seguida, adicione um impulso ao item. A direção do impulso deve estar acima de um ladrilho multiplicado por um número aleatório Vou definir meu intervalo aleatório para 5-10. Em seguida, adicionarei também o vetor dois, um ladrilho à direita e multiplicarei por um número aleatório entre menos um e um positivo Números negativos farão com que ele vá para a esquerda em vez de para a direita. Isso deve produzir uma fonte de moedas satisfatória. Quando precisamos adicionar o item à árvore da cena, prefiro torná-lo um irmão do baú, não uma criança Vou pegar primeiro o pai do baú e depois adicionar a moeda como filha dele. Quando isso for feito, podemos limpar a matriz, pois o baú agora está vazio. Selecionando o reprodutor de animação, podemos começar fazendo uma animação inativa fechada, que só precisa de uma faixa para o sprite two D, enviando sua textura para o mesmo sprite que ele já tem Em seguida, reduza a duração da animação para 0,1 segundos. Duplique a animação inativa fechada e crie uma animação aberta ideal E mude o sprite para o número oito. Podemos então fazer uma animação fechada alterando o sprite, contando de 8 a 4 para que a duração da animação seja de 0,5 segundos Também podemos adicionar uma faixa de áudio a essas animações e fechar o baú Som Os sons que estou usando para abrir e fechar o baú foram criados pelo frisbee Se um artigo no Freesound.org duplicando Podemos fazer uma animação aberta simplesmente invertendo os sprites e alterando o efeito sonoro Mas na animação aberta, também podemos adicionar uma faixa de chamada de método à animação. Adicionando um quadro-chave durante o quadro quando a tampa está aberta, podemos chamar o método de pilhagem para gerar as moedas, mudar a árvore de animação, definir o nó base da expressão avançada como o nó raiz do baú e a propriedade anim player para o Em seguida, crie uma nova máquina de estado para a árvore de animação. Podemos adicionar todas as nossas quatro animações à máquina de estado e conectá-las a um ciclo de transições A transição de inatividade fechada para aberta será acionada por está aberto e, em seguida, aberta para aberta inativa no final da animação Da mesma forma, abrir inativo para fechar acontece quando nada está aberto, quase fechar inativo no final da animação Essa estrutura nos permite inicializar o baú como aberto ou fechado quando a cena começa com base no valor de também está aberto Ao fazer mais de uma transição desde o início e definir suas condições, selecione o nó raiz e preencha as cenas repletas de moedas arrastando-as do sistema de arquivos para o Também precisamos definir a colisão para colocar o baú na camada do tesouro e fazer com que ele procure colisões na camada do jogador E defina o índice Z do peito para ficar atrás do jogador. Mude para o painel de nós e conecte o sinal inserido pelo corpo ao próprio tórax. Adicionando um método inserido no corpo, se esse corpo for um personagem, devemos definir is open to true, que aciona a animação aberta, que por sua vez aciona o método de pilhagem, por sua vez aciona gerando o tesouro Coloque um baú do tesouro em algum lugar do seu nível. Tente clicar no botão Está aberto para abrir e fechar o baú e editar o valor total das moedas que serão geradas Quando o baú se abrir, toque de quadril e tente abrir o baú e coletar suas moedas ganhas com dificuldade. Agora temos um baú do tesouro que gera uma explosão de moedas para o jogador coletar A próxima lição adicionará um cadeado ao baú do tesouro e uma chave que o jogador poderá usar para desbloqueá-lo. Te vejo na próxima aula. 34. 3-6 Bloqueio e chave: Olá amigos. Na lição anterior, criamos um baú do tesouro que gera uma fonte de moedas quando aberto Nesta lição, trancaremos o baú e esconderemos uma chave em algum lugar do nível que o abre. Vamos começar duplicando a cena da moeda de prata para criar uma cena chave Abra a nova cena principal, selecione o sprite animado e troque os sprites da moeda pelos sprites principais E a chave também tem sua própria animação de efeito. Vou apenas mudar o efeito sonoro das teclas para uma moeda diferente. Som A chave precisará de um novo script herdado do tesouro salvo na pasta de scripts do tesouro Tudo o que precisamos fazer é informar script do gerenciador de jogos quando a chave for coletada. O script do tesouro cuidará de todo o resto. Substituir o script no nó raiz esse novo script de chave é tão simples quanto clicar e arrastá-lo até o nó Como ainda é um script precioso, o comportamento do sinal ainda está relacionado à mudança para a cena do jogo. Eu terei apenas uma chave por nível no meu jogo. Em vez de contar as chaves, como fizemos com as moedas, usarei apenas uma única textura para indicar se o jogador tem ou não a chave. Vou adicionar uma textura destruída à interface do usuário preenchê-la com a chave padrão Espadilha, dobrou de escala para ficar mais visível e posicione-a abaixo da moeda Em seguida, clique no ícone para ocultá-lo, já que o jogador não começa com a chave no script do gerenciador de jogo, podemos definir uma referência para essa textura na fase de preparação quando o jogador coleta a chave Podemos definir uma variável nos dados do arquivo que o player tem como chave verdadeira. Também defina a propriedade visível do ícone da chave como verdadeira. Também devemos criar outro método para quando o jogador usa a chave para definir filet has key como false e ocultar o ícone na interface do usuário Mudando para o script de dados, podemos adicionar a variável has key e definir seu valor padrão no método init Coloque uma chave em algum lugar próximo ao nível e tente pegá-la. Para bloquear o baú, precisaremos adicionar outra variável de bulling para que o baú saiba se está ou não bloqueado no momento Podemos então alterar a lógica no código de colisão. Se o baú estiver trancado e o jogador tiver a chave, defina como falso e informe ao gerente do jogo que o jogador usou a chave. Se o baú não estiver trancado, o conjunto está aberto para verdadeiro. Não estou usando ElSef aqui porque quero que o baú desbloqueado e aberto em um evento de colisão Ao selecionar o reprodutor de animação, precisaremos adicionar mais animações. Vamos começar duplicando a animação inativa fechada para criar uma animação inativa bloqueada E mude o sprite para o sprite ocioso. Em seguida, duplique a animação de fechamento para criar uma animação de bloqueio Alterando o sprite de 3 a 2 para um, reduzindo a duração da animação para 0,3 segundos e reproduzindo um Desta vez, estou usando o key twist in lock feito por Karen Keegan no Freesound.org. Podemos então duplicar essa animação para também criar uma animação desbloqueada invertendo a ordem in lock feito por Karen Keegan no Freesound.org. Podemos então duplicar essa animação para também criar uma animação desbloqueada invertendo a ordem dos sprites. Mudando para a árvore de animação, podemos adicionar essas novas animações à máquina de estado E conecte-os. Com um ciclo de transições semelhante ao que fizemos com abrir e fechar O baú passará de ídolo fechado para cadeado. Quando está bloqueado é definido como verdadeiro e, de bloco para bloqueado, inativo no final da animação Da mesma forma, ele mudará de ídolo bloqueado para desbloqueado quando estiver bloqueado estiver definido como falso e, em seguida, para ídolo fechado no final da animação desbloqueada Em seguida, também podemos iniciar o baú no estado inativo bloqueado, se estiver bloqueado, mas as condições para iniciar o baú como fechado e trancado podem ser verdadeiras Adicionaremos a condição de inatividade fechada, que o baú não deve estar aberto nem trancado na cena do nível Agora podemos alterar o estado bloqueado do baú clicando no botão Lembre-se de que um baú trancado deve ser desbloqueado antes de poder ser aberto Um baú aberto deve ser fechado antes de poder ser trancado. Isso funciona, mas eu não gosto disso. A fechadura simplesmente desaparece. O pacote de ativos tem um cadeado desbloqueado como um ativo separado, então vamos usá-lo Duplique a cena principal Para criar uma cena de cadeado, altere o tipo do nó animado do sprite dois D para um nó D do sprite dois, já que o cadeado não tem animações, já que o cadeado não tem animações, renomeie os nós adequadamente e preencha o sprite com o recurso e preencha Altere a forma da colisão para um retângulo e redimensione-a para se ajustar à forma da Remova sua colisão com o jogador e reduza o índice Z do cadeado para combinar com o Também tornarei a configuração padrão da propriedade da frase falsa, pois sempre quero que o cadeado seja afetado pela física E remova o script clicando no botão do script com um X vermelho nele. O cadeado não é um tesouro e não deve ser recolhido pelo jogador Abrindo o script do baú, podemos adicionar uma cena compactada exportada para o cadeado, assim como fizemos com o método de pilhagem Podemos definir outro método para jogar o cadeado. Como o método de saque pode lidar com muitas moedas, nós as instanciamos durante o Então, quando o jogador abre o baú, as moedas já existem na memória e estão simplesmente sendo adicionadas à árvore da cena. Essa é uma forma mais responsável de instanciar grandes quantidades de nós Mas como o cadeado é apenas uma coisa, não precisamos nos preocupar em instanciá-lo no momento em que for necessário Dentro do método throw padlock, podemos definir uma nova variável para o cadeado instanciado Em seguida, execute a mesma lógica das moedas reposicionando a fechadura de acordo com a localização do baú Aplicando uma força de impulso e adicionando-a à árvore da cena, removerei a randomização da força ascendente Só é jogado um pouco para o lado. Mudando para duas visualizações em D, adicionarei rapidamente a imagem do cadeado à cena para que eu possa reposicioná-la onde eu quero que ela comece e, em seguida, examinar seus valores transformados para obter as posições x e y. Depois de escrever menos quatro e menos sete, posso excluir o nó do sprite, voltar para a visualização do script e definir a posição inicial do cadeado como a posição do peito mais o vetor dois, menos quatro, menos sete. Agora, o cadeado aparecerá na posição exata em que parece coincidir com o sprite bloqueado e será jogado Lembre-se de preencher a cena compactada arrastando o cadeado do painel do sistema de arquivos para o inspetor, selecionar o reprodutor de animação, alternar para a animação desbloqueada e adicionar uma faixa de chamada de método durante o quadro. Quando o cadeado desaparecer, podemos chamar o método de lançamento do cadeado podemos Agora, quando o jogador pega a chave e toca no baú do tesouro, o cadeado é jogado para o lado, o baú se abre e o jogador é Agora temos uma chave que pode abrir nosso baú do tesouro. Na próxima lição, adicionaremos uma meta final aos nossos níveis. Te vejo na próxima aula. 35. Mapa 3-7: Olá, amigos. Na lição anterior, trancamos o baú do tesouro e adicionamos uma chave para desbloqueá-lo. Nesta lição, criaremos uma meta final para nossos níveis. Usarei os mapas pequenos como meta para meus níveis, pois isso facilmente implicará para o jogador que Roger está seguindo cada segmento do mapa para encontrar o próximo para montar um mapa completo do tesouro É um conceito simples o suficiente que eu não precise explicá-lo. E também fornece uma estrutura para a estrutura de níveis. Vamos começar duplicando a cena do crânio para criar um pequeno mapa Uma cena renomeia o nó raiz. Selecione o sprite animado e troque os sprites de caveira Para o mapa pequeno, um sprites. Vou usar os sprites de entrada e saída juntos para criar a animação do efeito Em seguida, altere a forma da colisão para retângulo e redimensione-a para caber Vou usar o som de papel feito por brevceps como efeito sonoro Assim como com todos os outros tesouros, podemos dar a ele um script de tesouro chamado Small Map Inheriting from treasure Tudo o que precisamos fazer é dizer gerente do jogo que o mapa foi coletado. Troque o script no nó raiz do novo script de mapa pequeno. Em seguida, duplique essa cena três vezes para criar um pequeno mapa Dois, três e quatro. Trocando os sprites na animação padrão pelos sprites correspondentes do pacote de ativos pelo pequeno mapa quatro pelo No entanto, vou mudar a animação do efeito pois quando o jogador coleta essa peça, ele completou o mapa inteiro Depois que a entrada em vigor for reproduzida, reproduzirei a animação de desdobramento do mapa grande seguida pela animação ociosa, pela animação dobrável e, em seguida, pelo efeito de saída Isso permitirá ao jogador saber que os mapas pequenos se combinaram para formar um mapa maior e que seu objetivo está próximo. Quando o jogador coleta o pequeno mapa, o nível termina E eu gostaria de recompensar o jogador com uma pequena fanfarra seguida pela tela ficando preta antes de retornar ao menu de seleção de níveis Vamos mudar para a cena do jogo em duas vistas D. Podemos cobrir a tela em preto com um nó chamado Color Wrecked e nomeá-lo, desbotar no inspetor, mudar a mudar a Em seguida, expanda a seção de layout e selecione full wrecked nas âncoras menu suspenso predefinido para garantir que esteja sempre na frente, certifique-se esteja posicionado na parte inferior da ramificação da interface do usuário ou forneça um valor de índice Z mais alto do que Não queremos que isso bloqueie as entradas do mouse nos controles da interface do usuário. Porém, por trás disso, expanda também a seção do mouse e diga ao destruidor de cores que ignore a entrada do mouse Agora, a tela inteira ficará preta, o que é ideal para que cada cena do nosso jogo comece. Está no nosso caminho à medida que desenvolvemos essa cena. Vamos ocultá-lo por padrão para facilitar a cópia em outras cenas. Vamos salvá-lo como sua própria cena abri-lo para que esse retângulo preto desapareça. Ele precisará de um script que pertença à pasta de scripts de interface do usuário Assim como usamos interpolações para mover a câmera, também podemos usar interpolações para ajustar outras propriedades ao longo do tempo, como Primeiro, vamos definir duas cores na parte superior do script, uma para preto e outra para transparente. O preto tem valores de vermelho, verde e azul de zero e um valor alfa de um. Enquanto claro tem um alfa de zero, alfa é uma medida de transparência. Também precisaremos de uma variável privada para a interpolação de cores. Vamos começar desaparecendo já que o retângulo atualmente está preto Assim como com a câmera, é uma boa ideia verificar primeiro se a interpolação já existe e está funcionando e, em caso afirmativo, matá-la Em seguida, crie a interpolação. Não há necessidade de se preocupar com transições ou flexibilizações aqui, linear Em seguida, interpola uma propriedade nesse nó em si, a propriedade de cor, com o valor alvo de clear por uma duração de 1 segundo Queremos saber quando esse comportamento estiver concluído, que possamos retornar um sinal desse método para nos informar quando a interpolação de cores terminar especificação de um tipo de retorno para uma declaração de método no script Gudo é feita após os parâmetros indicados com uma seta Como o desbotamento para preto será idêntico, exceto pela alteração da cor, vamos alterar o nome desse método para esmaecer e usar uma cor como parâmetro e, em seguida, usar essa cor como valor alvo Podemos então escrever fade to clear, simplesmente chamando fade passing in clear como argumento Da mesma forma, escreva fade to black. Chamando fade, passando preto como argumento. Ambos os métodos podem retornar os mesmos sinais retornados pelo fade Mudando para o script do gerenciador de jogos, precisaremos definir uma referência ao fade durante a fase vermelha A primeira coisa que devemos fazer quando a cena é carregada é definir a propriedade visible do fade como true, para que o jogador não veja nada além de preto Então, quando toda a inicialização estiver concluída e o jogo estiver pronto para o jogador começar a jogar, podemos dizer que o fade to fade é fade para desaparecer e aguardar o sinal para que ele seja Nesse ponto, devemos dar ao jogador a capacidade de começar a jogar. Vamos definir uma referência ao nó do jogador durante a fase de preparação e chamar um método que ainda não definimos. Defina como habilitado passando true como argumento. Mudando para o script dos jogadores, podemos adicionar uma variável booleana privada chamada underscore ativada Defina também o método set enabled, usando um parâmetro booleano que define a variável privada Em seguida, verifique esse valor antes de processar qualquer entrada retornada Se o jogador não estiver habilitado novamente no gerenciador de jogo quando o jogador coletar o mapa, podemos então remover o controle do jogador definindo ativado como falso Eu também gostaria de tocar uma fanfarra de vitória aqui. Então, adicionarei um nó reprodutor de streaming de áudio chamado Fanfare e o preencherei com uma pequena faixa de música A fanfarra que eu selecionei é Game Success Fanfare Short de L Boss em Freesound.org Depois que o jogador for desativado, podemos Espere a fanfarra terminar. Espere até que o desbotamento fique preto. Em seguida, troque de cena. Coloque uma meta no final do seu nível. Clique em Play. A cena é carregada com uma tela preta e desaparece O jogador não pode se mover até que o fade in esteja completo. Coletar o tesouro no final do nível remove o controle do jogador, aciona a fanfarra e Agora temos uma maneira de terminar nossos níveis e uma boa transição de tela suave. Na próxima seção, daremos saúde ao jogador e deixaremos que ele sofra danos. Nos vemos na próxima seção. 36. 4-1 de dano: Olá amigos. Na seção anterior, criamos vários tesouros diferentes para o jogador coletar. Nesta seção, o jogador receberá saúde, permitindo que ele sofra danos e morra. Se você completou a tarefa, seus níveis devem ser preenchidos com tesouros para o jogador coletar e colocá-los estrategicamente para manipular seu comportamento se você Você também pode ter exportado uma variedade de cenas compactadas em seu script de baú que adicionam itens de tesouro extras ao conjunto de espólios e geram itens de tesouro extras Ou tenha um valor mínimo e máximo de moeda, com o baú gerando um número inteiro aleatório entre eles. Em seguida, instanciando moedas iguais a esse valor aleatório. Todos vocês podem ter apreendido os diamantes coloridos para criar novo tesouro e dado a eles um propósito único para seu jogo dar saúde aos personagens Vamos começar no script de caracteres, onde podemos adicionar uma nova variável exportada para definir a saúde máxima dos caracteres Isso deve ser restrito a ser apenas um número natural. Algo de 1 a 100 deve estar bem. Provavelmente só vou fazer um acordo fiscal, um dano por vez, 100 será muito, e vou definir o valor padrão para cinco. Em seguida, também podemos declarar uma segunda variável representando sua saúde atual Para simplificar, presumo que, quando os personagens entram em cena, eles estão com a saúde total, definindo sua saúde atual igual à saúde máxima. Durante a fase de preparação, podemos então escrever um método público que cause dano ao personagem, tomando a quantidade de dano como parâmetro. Por enquanto, vamos apenas reduzir a saúde atual pela quantidade de dano depois imprimir a saúde atual para que possamos ver o resultado. A maioria dos jogos como esse inclui um breve período de invencibilidade após sofrer danos A maneira mais simples de fazer isso seria desligar as colisões durante esse período Mas o colisor do personagem não está apenas sofrendo danos, mas também colidindo com o ambiente Podemos separar essas responsabilidades adicionando outro nó filho aos nossos personagens, uma área dois D, chamada de caixa Rt. A única responsabilidade da caixa Rt é ser detectada por fontes de dano e ser ligada ou desligada sem afetar outros aspectos do personagem. Ele também precisará de uma colisão de dois nós secundários D para determinar sua forma Para diferenciá-la das colisões normais do personagem, podemos mudar a cor da caixa Rt para algo mais parecido Não precisa necessariamente ser idêntica à cápsula do personagem, mas é um bom lugar para começar com o nó da caixa do quadril selecionado. Mude a camada de colisão para a camada dez, fazendo com que esta seja a camada lesionada do jogador Qualquer coisa que quisermos machucar, o jogador deve mascarar camada dez para procurar a caixa machucada do jogador. Para testar isso, precisaremos de algo simples em nosso nível que possa machucar o personagem. Criaremos uma nova cena cheia usando o recurso spikes. Este será um corpo estático de dois nodos D, já que não se moverá nem será afetado pela física. Adicione um sprite two D node e preencha-o com um ativo sprite Adicione uma forma de colisão a ela e torne-a um retângulo. Essa será uma superfície sólida que pode ser percorrida e que o colisor de personagens tratará como se fosse parte do terreno Ele deve abranger toda a largura do ladrilho, mas atingir apenas cerca de um quarto da altura do ladrilho. Isso também evitará que o jogador se machuque se tocar nas pontas pela lateral em vez de pela parte superior Isso faz parte do nível, mas não do terreno ou da água. Vamos fazer com que seja a camada três, uma nova camada de perigos Podemos então adicionar outro nó de colisão para causar dano, que será uma área dois D e vamos renomeá-la para hip box Dependendo de quão preciso você gostaria de ser com sua caixa de quadril, você pode usar um formato personalizado aqui. Vamos adicionar um polígono de colisão com dois nós D como filho da caixa do quadril no inspetor Podemos ver que o polígono é uma matriz de dois vetores compactados. Clicando nela para expandi-la, a matriz tem um tamanho zero que está atualmente vazia. Podemos simplesmente clicar em qualquer lugar no editor para adicionar um vértice ao polígono Vou adicionar um em cada ponta da lança e outro próximo à borda direita para dar um pouco de volume Em seguida, clique no vértice inicial para fechar o polígono. Agora, essa é uma forma de colisão personalizada que, se o personagem tocar, ele se machucará Mas observe como ele é dividido em duas formas menores, vermelho e roxo. Isso porque a detecção de colisão em videogames é complexa e requer muita computação, é muito mais fácil detectar colisões dentro de um polígono convexo do que em um polígono côncavos serão divididos em polígonos convexos Ao fazer com que o polígono de colisão corresponda à altura desse terceiro pico, dobramos a quantidade de computação necessária para detectar colisões com esses picos, já que o motor precisa verificar se o personagem está tocando no polígono vermelho ou no polígono tocando Para simplificar isso, vamos remover o vértice do terceiro pico, que em nossa matriz é o elemento número dois O polígono agora é convexo e completamente colorido em vermelho. E podemos simplificar isso ainda mais removendo o último vértice Esta caixa de quadril precisa procurar o jogador ferido camada dez se você quiser que os inimigos sofram danos causados pelos espigões dois, também na camada 18 Salve o galho do espigão como sua própria cena Você pode optar por colocá-lo em sua própria pasta chamada armadilhas ou perigos, mas como não há outros ativos que se enquadrem nessas categorias, vou apenas salvá-lo como decoração No entanto, criarei uma nova pasta de scripts chamada environment e, em seguida, moverei coisas como nível da câmera, paralaxe e água para ela antes adicionar um novo script chamado Em seguida, anexe esse script ao nó raiz dos picos. O objetivo do roteiro será reagir à colisão da caixa ferida de um personagem com os espinhos Clique na caixa, selecione o interruptor da caixa de acerto no painel do nó e conecte o sinal da área inserida conectando-o ao nó raiz do pico Isso mudará o nome do método para esteja na área inserida na caixa de acerto, o que é um pouco mais descritivo do que está acontecendo Obter o pai da área nos dá o personagem, então devemos dizer a esse personagem que sofra danos. Como esse script pode ser usado para qualquer número de perigos ou talvez você queira ajustar o dano rapidamente, vamos transformar a quantidade de dano causado em uma variável exportada e valor padrão de um deve ser suficiente Defina um intervalo para que não possa ser definido como algo negativo ou zero. Abra as configurações do projeto e nomeie as camadas de colisão, perigo, o jogador ferido e o inimigo Coloque pontas em algum lugar seu nível e tente pular sobre elas Você pode ver no painel de saída que Roger agora tem quatro pontos de vida restantes em cada colisão, o número é reduzido Além disso, o jogador e outros personagens podem ser configurados para andar sobre os espigões ou através deles com base em sua máscara de colisão com a camada três Agora temos um risco de pico Na próxima lição, faremos com que o personagem reaja ao sofrer danos. Te vejo na próxima aula. 37. 4-2 reação: Oh amigos. Na lição anterior criamos espinhos que danificam o jogador Nesta lição, o personagem reagirá ao sofrer danos. Você provavelmente percebeu, quando estamos criando personagens, que há animações de sucesso no pacote de ativos Vamos implementá-los agora. Na cena do personagem com o player de animação selecionado, adicione uma nova animação chamada hit. Preencha a animação de sucesso a partir dos picos da pasta sem espada Adicione também um efeito sonoro se quiser selecionar a árvore de animação. Edite a máquina de estado sem espada. Podemos adicionar a animação de sucesso aqui e fazer a transição para ela. Se o personagem for atingido , faça a transição de volta quando não for atingido abrir o script do personagem, será necessário criar a variável is hit do tipo booleano defini-la como verdadeira quando o personagem sofrer dano O valor precisa ser definido novamente como falso para fazer a transição do personagem da animação de sucesso para o movimento. A animação em si pode executar essa função. Mas para que a animação possa acessá-la, a variável deve ser exportada Vamos criar uma nova categoria para isso em saúde chamada Combate. Em seguida, podemos adicionar uma faixa de propriedade à animação de sucesso para definir o valor de é atingido volta como falso no final da animação. Agora, o personagem reproduzirá a animação de sucesso uma vez ao sofrer dano. Isso interromperá qualquer animação de movimento que estivesse acontecendo porque ela está saindo da camada de movimento da máquina de estado Vamos experimentá-lo. Seria bom se o personagem continuar sofrendo danos sem exigir que saia do colisor da caixa de acerto e entre nele novamente. Se permanecerem nos espigões, continuarão sofrendo danos Além disso, deve haver uma breve janela após sofrer danos quando o jogador estiver invencível Podemos resolver esses dois problemas com uma solução. Desligando a caixa machucada do jogador e ligando-a novamente, selecionando o nó da caixa ferida. As propriedades na parte superior do painel do inspetor, denominadas Monitoramento e Monitorável, podem ser usadas para determinar se as colisões Como é uma caixa de ferimento, ela é passiva e não está procurando por nada. O monitoramento pode ser definido como falso. Sua finalidade é ser encontrada por meio de caixas de sucesso. Deve ser monitorável. Transformar o monitorável em falso evitará que as caixas de acerto colidam com essa caixa ferida e transformá-la novamente em verdadeira desencadeará uma nova colisão com os espigões que têm uma caixa no Podemos então fazer o oposto. Configure-o para monitorar as camadas pert, mas não monitorável Existe um tipo de nó simples em Godot para fins de temporização, um cronômetro, que podemos adicionar ao nosso personagem e chamá-lo O tempo padrão é de 1 segundo, o que é bom, e queremos que isso conte apenas uma vez por vez. Marque a caixa de seleção one shot. Durante a fase de preparação, podemos definir uma referência à caixa do personagem e ao cronômetro em que o personagem sofre dano Podemos definir o monitorável como falso, iniciar o cronômetro, aguardar o sinal de tempo limite e definir o monitorável Mas Godot não nos deixará desligar o colisor durante uma colisão Usaremos set deferred para dizer a Godot que defina monitorável como falso após a monitorável como . Usaremos set deferred para dizer a Godot que defina monitorável como falso após a conclusão da colisão. Se você quiser ter outras coisas em seu jogo que tornem o personagem invencível por um tempo determinado, também podemos transformar isso em um método público tomando um tempo de flutuação como parâmetro Em seguida, passe isso para o método de início dos temporizadores. Agora, o método take damage pode chamar o método become invencible, passando 1 segundo como parâmetro Mas eu não quero que os inimigos se tornem invencíveis, só o jogador Vou adicionar uma variável de combate exportada para o tempo em que o personagem fica invencível após sofrer danos restritos a não negativos, com o padrão de zero no método de zero no receber Em seguida, verificarei se esse valor não é zero antes de chamar o método become invencible, usando esse tempo como parâmetro Se os inimigos não usarem esse nó de cronômetro, eles não deveriam tê-lo em sua árvore de cena Em vez de definir a referência para o cronômetro usando ready, usarei o método ready Verifique o valor da duração invencível. E se não for zero, defina a referência para o cronômetro. Agora, apenas o personagem do jogador precisa ter o nó do cronômetro e terá um valor de duração invencível definido acima Mas os personagens inimigos ainda precisam ter caixas Rt adicionadas a eles. Caso contrário, seus scripts tentarão definir referências durante a fase de preparação e causarão um erro porque elas não existem. Suas caixas de rebanho também pertencerão à camada 18 em vez de dez Em seguida, dê a Roger uma duração de invencibilidade maior que 0 segundos Experimentando, o personagem que está sobre os espigões continuará sofrendo um dano a cada segundo, conforme vemos a contagem regressiva no painel de saída Por fim, gostaria que o personagem expulso da fonte do dano Vamos modificar o método de tomada de dano para também aceitar a direção da força como um vetor dois. Em seguida, defina a velocidade do personagem para ser essa direção multiplicada por cinco peças O script de perigo precisará então calcular essa direção e enviá-la ao personagem ao machucá-lo Isso pode ser apenas a posição global do personagem menos a posição global do perigo Para que o perigo saiba sua posição global, ele não deve se estender por dois D. Mas não queremos que a distância seja um fator aqui, apenas a direção Colocando isso entre colchetes, podemos chamar o método normalizado Normalizado, pegaremos o vetor e o tornaremos mais longo ou mais curto para que tenha um comprimento de um Vamos experimentá-lo. O personagem atinge os espinhos é atingido com uma força para trás, tem uma animação de sucesso e se torna invencível por 1 segundo Agora temos personagens reagindo ao serem atingidos. Na próxima lição, adicionaremos a saúde do jogador à interface e daremos a ele um item de poção para recuperar a saúde Te vejo na próxima aula. 38. 4-3 Recovery: Olá, amigos. Na lição anterior, nosso personagem reagiu ao sofrer dano. Nesta lição, adicionaremos saúde do jogador à interface e criaremos poções de saúde Primeiro, vamos fazer um medidor de saúde. Os ativos no pacote de ativos são divididos em três imagens separadas para o medidor e uma cor vermelha plana para o preenchimento O medidor de saúde em si será apenas um nó de controle básico com dois filhos, um para o plano de fundo e outro para o preenchimento O nó de fundo pode ser uma caixa horizontal classifica automaticamente as três imagens de fundo para nós, que são todas destruições de textura Preencha as texturas com os do pacote de ativos Você pode esconder os outros galhos de lá no seu caminho. Selecionando a caixa horizontal de fundo, expanda a seção de substituição do tema no inspetor e defina a separação em zero pixels para que as imagens sejam desenhadas sem lacunas O preenchimento é apenas mais um texto com essa cor vermelha plana que podemos redimensionar manualmente e encaixar no Selecionar o nó raiz dos medidores de saúde. Vamos aumentá-lo quatro vezes para torná-lo mais visível. Acho que ficaria bem no canto inferior esquerdo. Vou definir as predefinições de âncora para o canto inferior E ajuste o deslocamento do pivô y para ficar na parte inferior do medidor, que é de que Em seguida, defina a posição x do medidor para 32 pixels para adicionar o mesmo preenchimento da moeda acima, apenas para fazer o layout e conferir a aparência enquanto joga Ampliando o novo medidor de saúde. Selecione o Efeito de Textura de Preenchimento. Para usar o preenchimento, podemos definir o modo de expansão para ignorar o tamanho, permitindo definir manualmente o tamanho para o que quisermos. Clique e segure o valor do tamanho X e mova o mouse para a esquerda, reduzindo o valor X, que podemos ver, também faz com o medidor pareça estar se esgotando Quando o valor X é zero, o medidor está vazio e quando o valor x é 75, o medidor está cheio Podemos usar isso para exibir qualquer quantidade de saúde que o jogador tenha, transformando-a em uma porcentagem de 75 pixels. Criação de um script para o medidor de saúde. Vamos chamá-lo de Gauge e salvá-lo na pasta de scripts de interface do usuário. Podemos obter uma referência ao preenchimento durante a fase de preparação. Assim como os contadores, um medidor realmente só precisa um método para definir o valor que está sendo exibido Seria melhor considerar esse valor como uma porcentagem com um tipo flutuante Tudo o que precisamos fazer para exibir essa porcentagem é definir o tamanho do preenchimento como 75 multiplicado por porcentagem Uma porcentagem na programação geralmente é representada como um número 0-1, ao contrário matemática, onde é 0-100 Isso simplifica nossos cálculos para serem Se quisermos tornar esse script mais flexível, podemos exportar o valor de 75 pixels como uma variável chamada max pixels e definir 75 como o valor padrão. Mudando para o script do personagem, podemos criar um novo sinal para quando o valor da saúde do personagem mudar e dar a ele um parâmetro que é a porcentagem da saúde restante do personagem. Então, quando o personagem sofre dano, podemos emitir esse sinal Para calcular a porcentagem da saúde restante do personagem, basta dividir a saúde atual pela saúde máxima, mas esses dois valores são definidos como números inteiros, o que significa que o resultado sempre será zero ou um Se mudarmos um de seus tipos para float, o resultado será um float two Em seguida, podemos conectar o sinal de alteração de saúde do personagem do jogador ao medidor de saúde Mas não queremos chamar um novo método. Ao clicar no botão de seleção, apresentaremos uma lista dos métodos de medidores de saúde que queremos chamar de valor definido Para fazer isso, tanto o sinal quanto o método devem ter os mesmos parâmetros. No nosso caso, flutuando, lembre-se de mostrar os outros galhos Quando você estiver pronto para testar, vamos experimentá-lo. O medidor começa cheio, mas pular nos espigões reduz o medidor em um quinto de Lembre-se de posicionar o fade na parte inferior da ramificação da interface do usuário se quiser que ele seja desenhado sobre todo o resto. Agora vamos ajudar o jogador com uma poção de saúde para recuperar a saúde perdida Como fizemos na última seção, podemos simplesmente adicionar um novo item de tesouro usando os ativos da poção vermelha e criar um novo script para herdar do tesouro, copiando um dos outros Renomeie a poção vermelha e abra-a. Renomeie o nó raiz de acordo com a combinação, substitua os sprites de animação pelo potente vermelho e os sprites de efeito pelo efeito Vou centralizar o sprite e transformar o colisor em uma cápsula para melhor ajustar a imagem Estou usando minha gravação Gulp feita por Miley Joe Moss, 1.996 para o efeito sonoro da poção As diferentes cores das poções provavelmente não estarão apenas ajustando uma variável, mas terão uma função completamente diferente E precisaremos de seus próprios scripts exclusivos. Em vez de ter um script de poção genérico, vou nomear essa poção vermelha herdada do tesouro e, em seguida, trocar o script que está anexado ao Podemos exportar uma variável inteira para a quantidade de saúde que a poção recupera como Vou definir o meu para ter um valor de três. Não quero incomodar o gerente do jogo transmitir essas informações da poção para o personagem, já que o personagem colidiu com poção para o personagem, já que o personagem a Em vez disso, farei uma pequena alteração no script do tesouro, armazenando o personagem que colidiu com esse tesouro em uma variável Depois de verificar se o corpo é um personagem, salve o corpo como a variável do caractere Agora, o script da poção pode se comunicar diretamente com o personagem quando ele é coletado Quando coletada, a poção vermelha chamará um método de recuperação de saúde do personagem, passando a quantidade recuperada Passando para o script do personagem, podemos adicionar esse método de recuperação de saúde aos métodos públicos, tomando uma quantidade de saúde para recuperar como parâmetro, adicionando a quantidade de saúde recuperada à saúde atual. Também devemos limitar a saúde atual à saúde máxima usando a função min e, em seguida, emitir o sinal de alteração de saúde para atualizar o medidor de saúde no Y. Podemos combinar essas duas linhas e executá-las em Coloque uma poção de saúde em seu nível, tente receber o dano dos espinhos e, em seguida, colete a poção para recuperar a Agora temos uma maneira de o jogador saber quanta saúde ele ainda tem e um item para ajudá-lo a recuperar a saúde perdida. Na próxima lição, adicionaremos um ponto de verificação ao nível. Te vejo na próxima aula. 39. 4-4 Ponto de verificação: Olá amigos. Na lição anterior, adicionamos um medidor de saúde à interface e uma parte para ajudar o jogador a recuperar a saúde perdida Nesta lição, definiremos locais onde o jogador deve responder após morrer. Vou deletar o outro nível da cena do jogo. Agora, como editaremos a estrutura dos níveis e todos os níveis exigirão que essa nova estrutura funcione corretamente, outros níveis precisarão ser editados. Até agora, usamos a origem da cena como o local em que o jogador começará, esperando que ele chegue até o fim sem morrer Em vez disso, você pode querer que seus níveis sejam mais longos e forneça ao jogador pontos de verificação onde ele possa responder, em vez de começar do início todas as vezes Vamos adicionar outra pasta à hierarquia dos níveis vistos, chamada checkpoints Podemos então adicionar um nó básico vazio de dois D a essa pasta, chamado posição inicial, onde queremos que o jogador inicie o nível. Se você preferir. Você também pode querer que o gatilho de nível esteja nessa pasta e renomeie para algo como end para criar um ponto de verificação Também criaremos um nó D de área dois nessa pasta chamada middle. Dê a esse ponto de verificação um nó de sprite animado. Vou usar os recursos da bandeira no meu posto de controle, pois o ponto de origem do posto de controle é o local onde a origem do personagem será definida e a origem do personagem está aos pés dele A origem dos postos de controle deve estar no chão onde os pés do personagem serão posicionados Com isso em mente, vou posicionar a bandeira forma que a base do mastro fique na origem Adicionando uma forma de colisão, vou usar apenas um segmento de linha cobrindo o mastro da bandeira para que o jogador realmente faça contato com o mastro para acioná-lo Também adicionarei um reprodutor de streaming de áudio ao de node, que reproduzirá Game Reward de a Yen Ba no FreeSound.org Salve a ramificação do checkpoint como Vou colocar a minha na pasta raiz das cenas , pois ela será incluída em todos os níveis do meu jogo. Abrindo a nova cena do posto de controle, vou editar o índice z da minha bandeira para ser desenhado atrás do personagem, embora seja muito semelhante ao comportamento de um item do tesouro Eu não pensaria logicamente nisso como um tesouro e não quero refatorar o script do tesouro para encaixá-lo nele Vou criar um novo script do zero e colocá-lo na pasta de scripts do ambiente. Pegue uma referência aos dois nós D do reprodutor de stream de áudio durante a fase de preparação e conecte o sinal inserido pelo corpo para reagir à colisão do player com a bandeira Reproduza o efeito sonoro e , em seguida, defina a máscara de colisão para zero para impedir que mais colisões aconteçam Em seguida, queremos definir uma variável nos dados do arquivo para saber se o jogador chegou ao ponto de verificação Você pode querer que seja um booleano se quiser ter apenas um posto de controle, como um jogo típico de Mario, ou um número inteiro se quiser ter vários pontos de verificação, mais parecido com um jogo country de Donkey Kong, um número inteiro é mais flexível e também pode ser usado para o sistema de ponto como um jogo típico de Mario, ou um número inteiro se quiser ter vários pontos de verificação, mais parecido com um jogo country de Donkey Kong, um número inteiro é mais flexível e também pode ser usado para mais parecido com um jogo country de Donkey Kong, um número inteiro é mais flexível e também pode ser usado Assim, cada ponto de verificação precisará de um número inteiro exclusivo para identificá-lo, que o gerente do jogo usará para saber onde responder ao Vamos definir uma variável como um número inteiro para conter esse número Em seguida, defina o valor do ponto de verificação arquivado como esse número de identificação Quando o jogador toca no ponto de verificação, podemos exportar a variável para definir cada uma manualmente, mas isso estaria sujeito a erros e a mais trabalho para nós a longo prazo Em vez disso, gostaria de delegar essa responsabilidade ao script de nível Primeiro, precisamos garantir que a máscara de colisão do posto de controle esteja configurada para colidir com E dê a esse script um nome de classe para que ele possa ser identificado pelo script de nível. Mudando para o script de nível, se pudermos assumir com segurança que todos os níveis terão essa pasta de pontos de verificação, poderemos usá-la para definir uma variável não para a pasta do ponto de verificação em si, mas para uma matriz de Podemos definir o valor como pasta de pontos de verificação, fornecendo uma lista de cada nó na pasta de pontos de verificação Então, usando um loop de quatro, podemos contar de zero até o tamanho dessa matriz. Se a nota for um ponto de verificação, defina o ID do ponto de verificação para sua posição nessa O nível agora contém uma lista de todos os pontos de verificação onde o personagem do jogador pode ser gerado e cada ponto de verificação sabe sua posição nessa Será responsabilidade do gerente de jogo carregar o nível e mover o jogador para o ponto de verificação apropriado antes do início do jogo Também vamos adicionar um método ao script de nível para que o gerente do jogo possa solicitar essa informação chamada get checkpoint position Tomando o ID do ponto de verificação como um parâmetro inteiro e retornando uma posição vetorial de duas posições Vou começar com um caso à prova de falhas de apenas retornar o vetor dois zero. Antes de usar um argumento para indexar uma matriz, devemos verificar se é um índice de matriz válido, se é maior ou igual a zero e menor que o tamanho da matriz. Em seguida, simplesmente retornamos o índice da matriz do ponto de verificação no ID do ponto de verificação e obtemos sua posição global Mudando para o script do gerenciador de jogos. Depois que toda a inicialização tiver sido realizada, mas antes de começar, devemos gerar Agora podemos definir a posição global do personagem do jogador perguntando ao nível a localização do ponto de verificação, passando o ponto de verificação arquivado como argumento Por fim, precisamos adicionar a variável de ponto de verificação ao recurso de dados com o valor padrão de zero O jogador começará no nó secundário superior da pasta de pontos de verificação, que é o nó inicial vazio Como não estamos usando o parâmetro body passado para a colisão dos pontos de verificação Godot preferiria que ele fosse sinalizado como opcional, precedendo-o com um sublinhado Coloque o ponto de verificação em algum lugar no meio do seu nível, certificando-se de que o início do nível seja o nó superior na pasta do ponto de verificação Ao clicar em Jogar, nada terá mudado, mas agora podemos mover a localização inicial do jogador com mais facilidade Além disso, se editarmos o valor padrão do ponto de verificação no script de dados, podemos gerar o jogador na bandeira Agora temos um sistema de checkpoint para que o gerente do jogo saiba onde gerar o Na próxima lição, adicionaremos a morte do jogador e faremos com que o jogador reapareça no último checkpoint Te vejo na próxima aula. 40. 4-5 Morte: Olá amigos. Na lição anterior, criamos um sistema de checkpoint para que o gerente do jogo possa gerar o jogador em posições diferentes Nesta lição, adicionaremos morte do personagem e reapareceremos o jogador quando ele Começando no roteiro do personagem. Assim como limitamos a saúde ao máximo usando Min quando o jogador se recupera Também precisamos parar a saúde atual em zero quando eles sofrem danos, definindo a saúde atual para o máximo de saúde atual menos a quantidade de dano ou zero Podemos então emitir o sinal de alteração de saúde e definir a velocidade de retração O resto desse método dependerá do fato de esse dano os ter matado ou não. Precisamos verificar se a saúde atual é zero. Se for chamado de um novo método, morra. Se o personagem não estiver morto, a variável is hit será definida como verdadeira e ele poderá se tornar invencível Antes de escrevermos o método die, devemos declarar uma variável booleana para saber se o caractere está morto ou Também crie um sinal para emitir quando o personagem morrer para que o gerente do jogo possa reagir a ele No método die, podemos definir a nova variável booleana está morta como verdadeira, que podemos usar no animador. Como fizemos com ela, é atingida e emitir um sinal de que o personagem Também seria uma boa ideia desligar a caixa de rebanho do personagem para que ele parasse de sofrer danos Mas isso ainda é algo que provavelmente está acontecendo durante uma colisão. Precisaremos adiar isso até o final do quadro atual Definir a camada de colisão do personagem como zero e a máscara de colisão uma evitará colisões futuras com qualquer coisa que não seja o terreno Um personagem morto não coletará tesouros nem acionará um posto de controle Finalmente, definir a direção como zero cancelará qualquer entrada de movimento fornecida no momento da morte. Para responder ao jogador, também precisamos de um método público para ressuscitá-lo da morte, do cenário estar morto, de volta à falsa saúde atual até a saúde máxima Em seguida, precisamos restaurar a colisão do personagem configurando a propriedade monitorável da caixa Rt Isso não é desencadeado por uma colisão, provavelmente pela lógica do gerente de jogo Não há problema em configurá-lo diretamente. Podemos armazenar os valores da camada de colisão e da máscara de colisão em variáveis durante a fase de preparação e, em seguida, restaurá-los aos valores originais ao reviver Como reviveremos o personagem do jogador depois de reposicioná-lo no posto de controle, também seria uma boa ideia omitir o sinal de aterrissagem aqui, o que posicionará que posicionará Mudamos o do personagem, também devemos omitir o sinal de mudança de saúde para Também não queremos que o personagem seja capaz de fazer nada enquanto estiver morto Começando com o método face left, devemos primeiro verificar se o personagem está morto e, em caso afirmativo, retornar para evitar que isso aconteça. E faça isso com qualquer método que não deva ser executado enquanto o personagem estiver morto, incluindo virar para a direita, correr, pular e parar de pular. Eu também gostaria de fazer uma adição ao script do gerenciador de jogos. Ao gerar o jogador, estamos definindo sua posição provavelmente no chão ou próximo ao solo em um local no nível Você pode imaginar que existe a possibilidade o personagem do jogador morrer e cair de uma grande altura. No momento em que esse método de respawn reposiciona o personagem, o personagem teria uma velocidade muito alta Para evitar que a velocidade persista e potencialmente interrompa a colisão da chuva, devemos definir sua velocidade para zero Mudando para o reprodutor de animação, podemos adicionar as animações dead hit e dead ground Lembre-se de usar os ativos da pasta sem armazenamento. Dead Hit deve causar um grito de dor do personagem, enquanto Dead Ground emite um som de impacto ao cair no chão Com a alta probabilidade de que esses sons se sobreponham, seria uma boa ideia separar sons vocais dos efeitos sonoros gerais Adicionando um segundo reprodutor de fluxo de áudio a dois nós D, podemos nomear uma voz e os outros efeitos sonoros. Podemos então manter os sons vocais restritos a tocar apenas um de cada vez, ao mesmo tempo em que permitimos que os efeitos sonoros reproduzidos simultaneamente sem interrupções Definir a propriedade de polifonia máxima dos efeitos sonoros para um valor maior que um também permitirá que vários efeitos sonoros sejam reproduzidos juntos Esse formato também nos permite ajustar as configurações de volume de vozes e efeitos sonoros, selecionando independentemente a árvore de animação. Adicione essas novas animações à máquina de estado sem espada Primeiro, reproduzindo a animação Dead Hit seguida por Dead Ground. Dead hit é jogado quando o personagem está morto. Então, o terreno morto será jogado após a conclusão do golpe morto, somente se o personagem estiver no chão. Para reanimar o jogador, precisamos que essas animações também voltem ao Quando está morto se torna falso na cena do jogo, selecione o nó do personagem do jogador e conecte o sinal Did ao gerente do jogo. Vamos nomear esse método no player Did. Quando o jogador morre, uma das duas coisas pode acontecer. Ou eles respondem em seu último posto de controle ou ficam sem vidas e entram no jogo pelo estado Primeiro, verifique se a vida útil dos dados do arquivo é igual a zero. Em seguida, chamaremos um método de fim de jogo, dando uma definição de fim de jogo. Por enquanto, podemos simplesmente imprimir o fim do jogo. Se as vidas não forem zero, podemos reduzi-las em uma, atualizar a interface do usuário e chamar um método diferente. Retorne ao último posto de controle. Para retornar ao último posto de controle, devemos esperar, desaparecer, escurecer Crie o personagem no último posto de controle alcançado, reviva-o e espere que Em ambos os casos, eu gostaria de tocar um jingle curto como com a fanfarra da vitória Vamos adicionar três variáveis exportadas ao script do gerenciador de jogos do tipo stream de áudio, que serão denominadas Victory, Death e Game Over Estou usando músicas de encerramento de cena para morte e tristeza, ou mudança de cena assustadora Música para o fim do jogo, ambas feitas por Dominic Trace do Freesound.org Podemos então dizer ao fanfare node que toque o som apropriado para cada situação Jogando o tema da vitória quando o jogador coleta o mapa no final do nível Jogando o tema da morte quando eles morrem e o tema do fim do jogo quando ficam sem vidas. Também seria prudente desativar a entrada do jogador no início do retorno ao último ponto de verificação e habilitar a entrada do jogador no final Eu coloquei o início de vida dos jogadores em um e a saúde de Mac em um. Para esta demonstração, temos agora temos o personagem do jogador capaz de morrer e responder no último posto de controle alcançado Na próxima lição, daremos ataques aos inimigos para machucar o jogador. Te vejo na próxima aula. 41. 4-6 inimigos: Olá amigos. Na lição anterior, demos ao personagem do jogador uma animação de morte e fizemos com que ele reaparecesse após Nesta lição, adicionaremos ataques aos personagens inimigos que podem ferir o jogador. Vou usar Fierce Tooth como exemplo para esta lição. Mas todos os personagens precisarão ter suas estruturas de nós editadas para corresponder antes de executar qualquer teste. Selecionando o nó do player de animação, podemos começar adicionando as mesmas animações de acerto, golpe morto e terreno morto para os inimigos, assim como fizemos com Roger Em seguida, adicione também expectativa e ataque. Na máquina de estado das árvores de animação, podemos recriar as mesmas animações de acerto e morte que fizemos com Estruturação da máquina estatal em camadas. Assim, permite que o inimigo seja ferido ou morto para interromper seus ataques Editando a camada de ataque, podemos então adicionar as animações de antecipação e ataque Aqui, adicione uma transição de movimento para antecipação, antecipação para ataque e ataque para A transição da antecipação para o ataque acontecerá no final, assim como a transição do ataque para o movimento Mas a transição do movimento para a antecipação, que desencadeia a cadeia de animações, acontecerá quando o personagem quiser atacar no roteiro do personagem Vamos adicionar os desejos de atacar bolin às variáveis de combate Em seguida, adicione um método público chamado attack, que define seu valor como verdadeiro. Cada vez que esse método for chamado, o inimigo desejará atacar uma vez, como se a variável is hit precisasse ser retornada para falsa, caso contrário, a animação seria repetida. Também precisamos definir a variável want to attack novamente como falsa durante a animação. A variável want to attack precisará ser exportada para que o reprodutor de animação possa acessá-la Voltando ao reprodutor de animação durante a animação de antecipação, podemos definir o valor de desejos de atacar novamente como falso Isso é suficiente para acionar a sequência de animação para que esse inimigo ataque. Mas, assim como os espinhos, também precisa haver uma caixa de acerto procurando a caixa machucada do jogador Selecione a animação de ataque com o primeiro quadro selecionado. Isso é o que está mostrando no editor com uma boa visão do personagem. Vamos adicionar outra área ao nó D à árvore de cena chamada hit box e dar a ela uma forma de colisão Para distinguir esse colisor do colisor de ambiente azul e da caixa Rt verde, podemos dar à caixa de acerto outra cor, como Selecione a forma que você acha que melhor se ajusta à área alvo do ataque. Vou usar uma cápsula e depois redimensioná-la para caber no tamanho e na forma da área alvo Certifique-se de deixar a caixa do quadril centralizada no personagem e apenas mover a forma de colisão para fora do Também há uma animação de efeitos. Vamos adicionar um sprite toting node animado como filho da caixa do quadril Crie um recurso de sprite frames e preencha-o com os sprites de efeitos de ataque Ao contrário de outras animações de efeitos, não queremos que isso seja reproduzido automaticamente Além da taxa de quadros usual de dez quadros por segundo, ela também não deve ser repetida. Adicione também uma moldura vazia na extremidade, reposicione o nó do sprite para que pareça que o efeito está emanando do ataque Quando terminar, defina o quadro padrão como o último quadro vazio, para que ele seja inicialmente carregado na cena como se não mostrasse nada. Mas quando mandarmos que ele toque, ele reproduzirá a animação mais uma vez e desaparecerá novamente. Podemos definir a camada de colisão das caixas de acerto como camada 19, que será a camada atingida do inimigo, e fazer com que ela mascare a camada dez da camada ferida do jogador Por ser uma entidade ativa, está monitorando as caixas feridas. Nada está procurando por caixas de sucesso. Normalmente, eles não são monitoráveis. No entanto, não queremos que isso seja monitorado até que o inimigo realmente ataque. O valor padrão do monitoramento também será falso. No roteiro do personagem. Seria uma boa ideia pegar uma referência à caixa do quadril durante a fase de preparação. Precisamos adicionar um nó de hit box a cada caractere para satisfazer os requisitos dos scripts de caracteres antes de testar e definir a propriedade de monitoramento como falsa. precaução, na animação do ataque, podemos adicionar a propriedade de monitoramento das caixas de acerto à animação, definindo seu valor como verdadeiro durante o primeiro quadro novamente como falso durante o segundo quadro. Em seguida, adicione também uma faixa de método de chamada para a animação do efeito , solicitando que ela seja reproduzida durante o primeiro quadro do ataque. Embora as animações sejam divididas em antecipação e ataque, na verdade, existem três fases em um ataque, um contato e uma recuperação ao lidar com inimigos A fase de antecipação é como o inimigo telegrafa que vai atacar, dando ao jogador tempo Seguido pelo contato, que é o momento exato o colisor é ligado e o inimigo realmente machuca o jogador. Finalmente, a recuperação, que dá ao jogador tempo para reagir ao ser atingido ou retaliar Conecte o sinal da área inserida da caixa de acerto ao script do personagem. A única área que permitiremos colidir com uma caixa de acerto é uma caixa Rt Graças às camadas de colisão, tudo o que precisamos fazer é perguntar à área da caixa Rt seu pai, que será um personagem, e pedir que esse personagem sofra danos Por enquanto, basta causar um dano na direção da posição global do jogador menos a posição global desse inimigo Em seguida, normalizado, devemos exportar a quantidade de dano como uma variável de combate para que ela possa ser modificada para cada personagem na cena do nível Encontre seu inimigo e conecte um nó de cronômetro a ele. E ajuste o cronômetro para algo um pouco mais longo, como dois ou 3 segundos. E configure para automóveis, comece. Conecte o sinal de tempo limite desse cronômetro ao método de ataque do inimigo Agora, esse inimigo será instruído a atacar uma vez toda vez que o cronômetro chegar a zero, e isso se repetirá Quando estiver pronto, aperte play para ver o personagem atacando automaticamente e tente deixar que ele atinja você Isso funciona desde que o personagem inimigo não se vire. Vamos definir a propriedade flip H do sprite node como true para simular o inimigo voltado para a direita Agora, a animação do ataque estará voltada para a direita, mas a caixa do quadril e a animação do efeito ainda estão voltadas para a esquerda. Ao selecionar a caixa angular na seção de transformação, clique no ícone da cadeia para desvincular os valores x e y para que possam ser editados separadamente Em seguida, clique e arraste a partir da propriedade scale x, movendo o mouse para a esquerda. Quando o valor se aproxima de zero, a caixa do quadril fica tão fina que desaparece Mas, à medida que se torna negativo, é espelhado no eixo y. Podemos usar isso no script do personagem para virar a caixa do quadril Ao mesmo tempo, invertemos o sprite no método face esquerda Defina a escala da caixa do quadril x para um se o sprite estiver naturalmente voltado para a esquerda, l menos um e vice-versa. No método face right, podemos inverter a direção inicial do nosso inimigo com a variável exportada. Para testar isso, agora temos nossos personagens inimigos atacando o jogador Na próxima lição, adicionaremos uma tela de sobretela do jogo. Te vejo na próxima aula. 42. 4-7 Game Over: Olá amigos. Na lição anterior, usamos os ataques do inimigo para ferir o jogador. Nesta lição, adicionaremos um game over screen. Esta será uma nota de controle sobre a tela da interface do usuário, provavelmente desenhada sobre todo o resto, mas ainda abaixo do fade, chamada Game Vou usar uma caixa vertical para organizar tudo facilmente, começando com um rótulo que diz Game Over, para que o jogador entenda rapidamente o que está acontecendo quando o jogador fica sem vidas. Vou apenas apresentar a eles três opções: tente novamente desde o início do nível, volte ao menu de seleção de níveis ou saia do jogo Vou adicionar três botões para cada uma das minhas três opções, Selecionar e sair. Vou ampliar tudo quatro vezes e reposicioná-lo para ficar no centro da tela. Usando âncoras, selecionando cada um dos botões, conecte o sinal pressionado ao script do gerenciador de jogos, criando três novos métodos que serão chamados quando o jogador pressionar os Primeiro, precisaremos de uma referência ao menu de fim de jogo definido durante a fase de preparação. E defina sua propriedade visível como quedas para ocultá-la. Então, quando o estado de fim de jogo for atingido, podemos definir sua propriedade visible como verdadeira. Em seguida, pressionar qualquer um desses botões deve ocultar o menu da tela de fim de jogo, configurando sua propriedade visível de volta para falsa Se o jogador quiser recomeçar do início do nível, precisaremos redefinir várias variáveis, responder a todos os tesouros e postos de controle do inimigo , etc Podemos simplificar isso simplesmente descarregando e recarregando o mesmo nível descarregamento é fácil, pois temos uma referência ao nó de nível Podemos simplesmente chamar o nível de sublinhado gratuitamente. Para recarregar o nível. No entanto, precisaremos saber qual nível foi carregado. Abrindo o script de dados, podemos adicionar duas novas variáveis, uma para o mundo e outra para o nível, ambas com um valor inicial de um. Se você não quiser organizar seus níveis em mundos, você pode ignorar essa variável enquanto estamos aqui. Também precisaremos redefinir esses outros valores quando o jogador recomeçar do início do nível , adicionando um método público de nova tentativa Podemos definir moedas como zero, viver até três, ponto de verificação como zero e ter a chave falsa De volta ao script do gerenciador de jogos, podemos chamar os dados do arquivo para redefinir o progresso do jogador. Em seguida, podemos definir o valor do nível a ser carregado, que usa um argumento de string representando o caminho do arquivo para o recurso que queremos carregar. Pesquisando na guia do sistema de arquivos, encontre seu nível, clique com o botão direito do mouse e selecione o caminho de cópia. Em seguida, cole esse caminho entre aspas. E siga a chamada de carregamento que retorna um recurso com instanciate para transformar esse recurso em um Em seguida, adicione esse nó à árvore de cena com add child, mas isso só carregará o nível um. Podemos substituir as do nome do arquivo pelas variáveis dos dados do nosso arquivo, mas as variáveis são números inteiros E esta é uma string que converte os números inteiros em strings usando o colchete STR Desde que cada nível esteja dentro da pasta de níveis e seja nomeado no mesmo formato, ele será carregado simplesmente definindo as variáveis de mundo e nível nos dados do arquivo. Podemos então gerar o jogador, desligar os controles do jogador e revivê-lo. Mas não queremos que o jogador veja nada disso acontecendo. Devemos começar ficando pretos. Depois, no final, espere que o fade desapareça e ative os controles do player novamente O jogador estará no início do nível que foi completamente recarregado novamente e tentará novamente com três Por enquanto, se o jogador quiser retornar ao menu de seleção de níveis, podemos simplesmente escurecer e redefinir os dados do arquivo, já que ainda não criamos essa cena Mas deixe um comentário ou uma declaração impressa aqui para que saibamos implementar esse recurso no futuro Se eles pressionarem o botão Ex It, podemos esperar, escurecer Em seguida, ligue para get tree quit para fechar o jogo. Como alternativa, você pode querer que isso retorne à tela de título do jogo quando tivermos uma. Para fins de teste, vou apenas deixar a tela do jogo visível Por padrão, o botão Sair funciona. O botão de seleção de nível ainda não faz muita coisa, mas isso é intencional O botão de tentar novamente também funciona. Mas esse menu parece ruim e não se encaixa na estética do jogo. Vamos usar o pacote de ativos para torná-lo melhor. Começarei mudando o rótulo para um nó de controle básico chamado Banner e o preencherei com fragmentos de textura, preenchendo-os com as imagens das letras para terminar o jogo e classificá-los usando Redefinindo o tamanho e alterando a separação para dois pixels entre cada letra Vou adicionar mais cinco Ts de textura e usar as pequenas imagens do banner para montar um banner, reorganizando-as para ficarem centralizadas no ponto de origem do banner e ter as palavras escritas no Em seguida, direi ao banner que se centralize dentro da caixa vertical principal, selecionando o nó do menu Game Over. Expanda a seção do tema e selecione Novo tema no menu suspenso. Em seguida, clique no recurso do tema para abri-lo no painel inferior. Essa tela mostra vários elementos diferentes da interface do usuário e como eles serão exibidos usando esse recurso de tema, que podemos editar. Vamos adicionar um botão ao tema. Na guia da caixa de estilo, há cinco opções para diferentes estados de botão. Adicionando todos eles ao tema. Em seguida, podemos alterar a aparência do botão em cada estado. Começando com o normal, adicione uma nova textura de caixa de estilo, clique na caixa de estilo para abri-la e preencha-a com o botão verde Uma imagem. Os botões na pré-visualização agora estão verdes, assim como os botões do nosso jogo. Mas eles são esticados e feios. Em seguida, expanda a seção da margem da textura, adicionando alguns pixels de espaço na margem. A imagem agora parece melhor. As imagens neste pacote de ativos têm uma margem inferior maior do que os outros lados. Já que o menu de fim de jogo está usando esse recurso temático. Todos os seus filhos também têm o mesmo tema aplicado ao passar o mouse ou focar em um botão Vou trocar sua textura pelo botão amarelo. Podemos ver como isso se comporta passando o mouse e clicando nos botões na pré-visualização Quando desativado, uso a mesma textura do botão verde, mas modulo a cor, multiplicando os valores RGB e alfa pela metade para que fique mais Quando pressionado, usarei a mesma textura de botão amarelo, mas farei a mesma coisa, modulando com valores RGB cinza Mas deixe o alfa em total opacidade, removendo o texto dos botões Em vez disso, vou substituí-los por ícones. Em seguida, coloque cada botão uma caixa horizontal emparelhada com outra caixa horizontal para funcionar como a etiqueta do botão. Cada caixa horizontal de etiqueta terá várias texturas Recs para cada letra da palavra que eu quero soletrar, fazendo com que a caixa horizontal encolha e centralize Para selecionar o nível, usarei apenas um texto vazio direto como espaço. Eu gostaria de mais espaço entre os botões e seus rótulos. Então, vou agrupar as caixas horizontais e editar seus valores de separação em 14 pixels. Em seguida, colocarei os três botões em outra caixa vertical e colocarei dentro de um nó de contêiner de painel chamado madeira. E também adicione um nó de painel ao contêiner do painel chamado papel, reabrindo o tema No painel inferior, podemos fazer mais alterações nos painéis e nos contêineres do painel. Adicionando o contêiner do painel ao tema, também podemos dar a ele uma caixa de estilo, usando o prefabs Three como imagem Quero margens mais largas neste painel para que os botões não pareçam tão cheios perto das Os nós de contêiner são redimensionados automaticamente para caber em seus conteúdos Vamos também adicionar o painel ao tema. Os painéis são semelhantes a uma textura destruída, mas também têm margens de textura, como E vou usar o prefab nine como textura. Isso tem margens bastante amplas de 20 pixels. E, ao contrário das imagens dos botões em que o interior era apenas de uma cor plana, o papel e a madeira têm uma textura que está sendo esticada Expandindo a seção de alongamento do eixo, podemos definir as texturas como ladrilhos em vez de esticar para espaçar mais as coisas Darei ao painel de madeira uma largura mínima de 160 pixels e ao papel um tamanho personalizado de 120 por 100 pixels Posicionando o papel no lado direito da madeira e os botões centralizados verticalmente As palavras parecem estar escritas no papel. E remova a altura mínima personalizada do banner. Agora temos um game over temático na tela. Na próxima seção, daremos ao jogador uma espada para que ele possa revidar. Nos vemos na próxima seção. 43. 5-1 espada: Olá amigos. Na seção anterior, permitimos que o personagem do jogador sofresse danos e morresse. Nesta seção, daremos ao jogador uma espada e seus próprios ataques para que ele possa revidar se você concluir a tarefa. Todos os seus níveis agora terão a pasta de pontos de verificação. E todos os seus inimigos terão animações de morte e ataque Todos os seus inimigos serão capazes de atacar O jogador sofre danos e morre se você completar os desafios. Você também pode fazer com que sua interface de usuário e menu do game over sejam interpolados fora da tela Bem como poções verdes e azuis que afetam o personagem de maneiras únicas Vamos começar com um pouco de limpeza. Eu gostaria de classificar os scripts dos personagens e dos jogadores em uma nova pasta de scripts chamada personagens. Essa cena principal do jogo será usada em todos os níveis, não apenas no primeiro nível. Assim, podemos excluir o nó de nível no script do gerenciador de jogos. Não definiremos o valor do nível usando at on ready. No método pronto. Depois de definir o fade para ficar visível, devemos então carregar o nível atual Escrevendo um novo método privado. nível de carga, podemos usar o mesmo código que escrevemos no método pressionado do botão de nova tentativa para carregar o nível e substituí-lo por uma chamada de método Em seguida, mova também os limites e a interface do usuário para o nível de carga. Eles serão atualizados para corresponder aos novos valores. Adicione também uma linha à interface do usuário do nit para definir a propriedade visível do ícone da chave para determinar se o jogador tem ou não a chave Agora, seja qual for o mundo em que um nível esteja definido nos dados do arquivo, esse nível será carregado quando o jogo começar. Se o nível for recarregado ou alterado, os limites e a interface do usuário serão atualizados para corresponder Até agora, tudo o que fizemos em nosso roteiro de personagem foi aplicável, ou pelo menos flexível o suficiente, para ser aplicado a qualquer personagem. No entanto, o pacote de ativos tem apenas o humano carregando a espada. Para separar esses comportamentos do script do personagem, podemos criar um novo script que herda do personagem, que conterá comportamentos que só podem ser aplicados ao herói do nosso jogo, salvos na nova pasta de scripts de personagens e substituindo o script do personagem na nota raiz de Roger Esse script precisará de uma variável booleana exportada para nos dizer se o herói está ou não segurando uma Também podemos dar a esse script um nome de classe para que outros scripts possam verificar facilmente se algo é um personagem ou um herói. Também terei uma referência particular à espada que está equipada. Em seguida, adicione um novo método público que outros scripts possam usar para instruir Roger a equipar uma Tomando a espada como parâmetro, definindo a variável privada local e ajustando sua espada para outro método público, dizendo ao nosso herói que solte a espada. Se eles não tiverem uma espada para soltar, podemos ignorar e voltar. Caso contrário, a configuração faz com que a espada caia, mandando a espada cair. Passando a posição global do herói como argumento, a espada sabe onde deveria estar. Como o herói não tem mais uma espada, a variável espada será nula, o que significa vazia Quando o herói morrer, ignoraremos o comportamento de morrer do personagem para verificar se o herói tem uma espada e, se sim, soltá-la , ainda queremos que o resto do código do dado também seja executado. Em vez de copiar e colar, podemos usar super die para chamar a definição herdada de Seguindo o mesmo processo que usamos para criar todo o nosso tesouro colecionável Vamos fazer uma espada equívoca para o personagem do jogador. Quero que minha espada tenha física aplicada. Às vezes, faço dela um corpo rígido de dois D, como as moedas, mas minha espada é mais complexa do que itens de tesouro típicos com vários estados e mais coisas a mudar do que apenas o sprite, mais parecida com o baú do tesouro Dando a ele um sprite de dois nós D. Vou definir seu sprite padrão para ser sword, idle, zero one. Adicionando um reprodutor de animação e a árvore de animação, posso criar a animação inativa para que a espada gire. Em seguida, adicione uma forma de colisão ao galho, dando a ele um tamanho de cápsula adequado ao sprite da espada Vou colocar isso na camada 26 para mantê-la separada de outros itens e fazer com que ela colida apenas com o trem ou com o jogador, como as moedas Não conseguirei fazer com que ele gire congelado por padrão, com o modo de congelamento definido como Cinemático para que ele não se mova, mas ainda possa ter colisões E relate colisões ao entrar em contato com até duas pessoas ao mesmo tempo, selecionando o tratamento de animação Definirei a propriedade Anim player como esse reprodutor de animação e criarei esse reprodutor de animação e criarei uma nova máquina de estado por enquanto Isso fará com que a animação inativa seja reproduzida por padrão E também adicionarei um reprodutor de stream de áudio ao node, que preencherei com o efeito sonoro não revestido, salvando essa ramificação como Talvez você queira colocar isso em uma pasta de armas ou equipamentos, mas como não há outros ativos como esse, vou mantê-lo na pasta Scenes. Eu retirei a espada da origem da cena, então vou redefinir sua transferência e propriedade para entrar novamente nela Agora precisamos criar um script para a espada. Embora isso se comporte de forma semelhante ao tesouro, é diferente o suficiente para que eu prefira não refatorar o código e, em vez disso, apenas herdar o corpo rígido dois D, conectar o sinal inserido do corpo ao script Graças às camadas de colisão, é bastante seguro presumir que a única coisa que pode ser usada com a espada é Mas vou verificar apenas para ter certeza se o corpo é um herói e pode equipar a espada Precisaremos definir esse método e fazer com que ele retorne um valor booleano Então, podemos dizer ao herói que equipe essa espada, fazendo-se passar por argumento, e fique invisível para que o jogador não veja mais a espada. Já que o sprite do personagem desenhará para facilitar a física de soltar a espada Também vou descongelar o corpo da crista com conjunto adiado. Obtendo uma referência ao stream de áudio que dois reprodutores fazem durante a fase de preparação Também podemos reproduzir o efeito sonoro. Quando isso acontece no script do herói, precisamos escrever o método da espada equipada retornando um booleano Só precisamos dizer se o herói não tem uma espada e não está morto. Sob essas condições, o herói deve ser capaz de equipar a espada Então, quando o herói solta a espada, eles chamam um método de soltar. Escrevendo essa definição, podemos tomar a posição de onde a espada foi lançada como um parâmetro do tipo vetor dois. Vou precisar de um gerador de números aleatórios iniciado durante a fase de preparação para fornecer uma flutuação aleatória entre menos um e um positivo Vou definir a posição global da espada para ser essa posição mais meio ladrilho acima. Aplique uma força de impulso de até oito peças mais a direita multiplicada por um número aleatório semelhante ao efeito das moedas E, finalmente, defina visível como verdadeiro para que o jogador possa vê-lo. Agora podemos duplicar nossas animações para criar novas em que o herói segura a espada, começando pelo ídolo, depois corre, pula, cai no chão Agora podemos conectar nossos heróis sem a máquina de estado da espada à largura da máquina de estado da espada com base no valor de tem espada abrindo a largura da máquina de estado armazenada. Essa camada superior conterá a máquina de estado de ataque conectada à animação da espada de ataque, pois quando o jogador morrer, ele soltará a espada dentro da máquina de estado de ataque. Por enquanto, basta adicionar a máquina de estado de movimento e conectá-la desde o início, adicionando as animações de salto, queda e solo, bem como a máquina de estado de locomoção, conectando-as da mesma forma que todo o E, finalmente, completando a máquina de estado de locomoção dois, colocando a espada em algum lugar do seu nível O herói agora poderá pegá-la e todas as animações continuarão funcionando da mesma forma, só que com a espada equipada E quando eles morrem, a espada cai. Agora temos um item de espada que o jogador pode pegar e equipar. Na próxima lição, adicionaremos ataques com espada. Te vejo na próxima aula. 44. Ataque 5-2: Olá amigos. Na lição anterior adicionamos uma espada que o jogador pode equipar e soltar Nesta lição, adicionaremos um botão de ataque e as animações de ataque para o jogador Vamos começar abrindo as configurações do projeto , a guia do mapa de entrada e adicionando um botão de ataque. Vou usar o botão esquerdo do mouse, clique no botão J no teclado e o botão esquerdo do mouse no gamepad Acomoda uma variedade de estilos de jogo em dois nomes de camadas físicas Também adicionarei nomes de golpe de jogador, golpe de inimigo e camada de espada. Então, no script do jogador, durante o evento de entrada, se o botão de ataque for pressionado, devemos dizer ao personagem do jogador que ataque. O script do personagem já foi configurado para processar essa configuração de entrada que deseja atacar até que seja verdadeira, mas os jogadores podem e irão apertar os botões mesmo quando a ação desejada for impossível Definir o desejo de atacar como verdadeiro desencadeará um ataque quando for possível, graças à árvore de animação. Mas isso acontecerá mesmo se um tempo significativo passar um tempo significativo desde que o botão foi pressionado. Devemos definir um limite de tempo para o tempo em que a entrada de ataque é considerada válida antes de ignorá-la. Se o personagem não conseguir realizar o ataque durante esse período, vamos adicionar um nó de cronômetro à caixa de acerto chamado buffer de entrada e definir tempo para meio segundo e um tiro Então, no script do herói, podemos pegar uma referência a esse nó durante a fase de preparação. Substituindo a definição de ataque, podemos definir o desejo de atacar como verdadeiro, iniciar o temporizador do buffer de entrada e aguardar o sinal aguardar Em seguida, set quer atacar de volta ao falso. Se nenhum ataque for acionado dentro de meio segundo após pressionar o botão , o pressionamento do botão será ignorado. A duração do tempo pode ser facilmente ajustada nas propriedades dos nós do temporizador Ao atacar, gostaria de evitar que os personagens realizassem outras ações no script do personagem Vou precisar de outra variável de ouro para saber se o personagem está atacando ou Que vou definir durante as animações e definir seu valor como falso quando a cena for carregada pela primeira vez, precaução, como fizemos com o monitoramento da caixa de sucesso Então, da mesma forma que verifico se o personagem está morto antes de realizar outras ações, também adicionarei a condição que ele não esteja atacando No entanto, alterarei a corrida para que, se eles estiverem mortos ou atacando, em vez de apenas retornar, eu defina o valor da direção como zero Caso contrário, comporte-se normalmente. Os personagens terão que terminar seus ataques antes de realizar qualquer outra ação. Também adicionarei a condição à colisão da caixa de sucesso de que esse personagem não esteja morto e esteja atacando para poder causar danos Na visão em dois D de Rogers, eu ainda não dei uma forma ao nó da caixa do quadril de Rogers conectei o sinal ou configurei a camada de colisão e a Podemos conectar facilmente o sinal do nó da área inserida ao método que já definimos no script de caracteres. Em seguida, defina essa caixa de quadril para ser desligada por padrão o jogador atingir a camada de colisão 11 e mascarar a camada T inimiga, camada 18 Selecionando o reprodutor de animação Rogers, podemos adicionar uma animação de ataque preenchida com os sprites apropriados e definir a configuração de duração que deseja atacar como falsa durante o primeiro quadro Precisamos definir o valor de está atacando como verdadeiro enquanto a animação é reproduzida. Então, de volta ao falso. Depois de terminar, o personagem sabe que não deve se mover nem pular. Em seguida, defina a propriedade de monitoramento da caixa do quadril como verdadeira durante o segundo quadro e falsa durante o terceiro. Detectando a colisão que ferirá os inimigos. Usando o segundo quadro da animação como guia visual, crie uma nova forma para a colisão Vou usar uma cápsula e definir sua cor para vermelho para combinar com minhas outras caixas de quadril. Em seguida, defina sua forma, posição e rotação de acordo com a área afetada do ataque. Adicionar faixas à animação da colisão. Forma nós, forma, posição e rotação. Podemos adicionar quadros-chave para cada um durante o primeiro quadro da animação. Adicione um desenho animado à caixa do quadril para criar as animações de efeito E crie uma animação para cada um dos três efeitos de ataque com um quadro vazio no final como valor padrão. Assim como fizemos com os ataques inimigos. Posicione o nó à frente do personagem para que a animação do sprite pareça estar alinhada com o ataque. Na animação de ataque um, podemos adicionar uma faixa que reproduz a animação do efeito, passando o ataque um como o primeiro argumento no método de jogo Chame o inspetor. E também uma faixa de reprodução de áudio para reproduzir um efeito sonoro de deslizar, duplicando a animação de um ataque Podemos criar as animações de ataque dois e três, trocando as texturas do sprite, alterando a passagem do argumento para o sprite animado e preenchendo a reprodução de áudio trocando as texturas do sprite, alterando a passagem do argumento para o sprite animado e preenchendo a reprodução de áudio com um novo efeito sonoro. Em seguida, crie uma nova forma de colisão para as diferentes animações de ataque Reajustando sua rotação posicional e forma para combinar com a área afetada do ataque Dependendo da versão do Godot que você está usando. O editor pode não exibir o colisor corretamente enquanto você faz isso, mas você ainda pode inserir valores manualmente no inspetor e repetir todo o processo para fazer o ataque três Certifique-se de criar um novo recurso em forma de colisão para cada animação Ah, selecionando a árvore de animação. Mergulhando na largura da camada de espada, camada de ataque, queremos adicionar nossas três animações de ataque Eu gostaria de passar por essas três animações de ataque em ordem, desde que o jogador continue pressionando o botão de ataque, mas voltar ao movimento de qualquer uma delas se parar de pressionar o botão de ataque Primeira transição do movimento para atacar um, se o personagem quiser atacar e estiver no chão Em seguida, seguindo as mesmas condições nos outros dois ataques, trocando apenas no final da animação anterior. Os ataques dois e três retornarão ao movimento no final de sua animação. Mas a transição do ataque dois para o ataque três terá prioridade. Se suas condições forem atendidas, ataque 1 voltará ao movimento se o personagem não quiser atacar ou se não estiver mais no chão. Antes do teste, seria útil poder ver a animação do colisor no menu de depuração Selecione Formas de colisão visíveis para renderizar formas de colisão enquanto o jogo está sendo jogado Agora, se pegarmos a espada em nosso jogo, o jogador poderá realizar ataques combinados com ela, cada um com diferentes animações, cada um com diferentes animações, formas de colisão e E os ataques também machucarão e matarão inimigos. Agora temos o personagem do jogador capaz de realizar um ataque combinado de três golpes com uma espada para lutar contra seus inimigos Na próxima lição, adicionaremos dois ataques aéreos. Te vejo na próxima aula. 45. 5-3 Ataque aéreo: Olá amigos. Na lição anterior, adicionamos animações de ataque para o jogador Nesta lição, adicionaremos mais ataques que o jogador pode usar ao pular Começando na cena de Rogers, selecionando o nó de jogador de animação de Roger Podemos duplicar a animação de ataque um para criar um ataque aéreo e trocar os sprites por Trocando o efeito sonoro de deslizar por um diferente. Também precisamos criar uma nova forma de colisão para essa animação Ajustando sua forma, posição e rotação para coincidir com a área afetada Ao ajustar essas formas de colisão com uma animação, é útil criar um novo nó em forma de colisão e ajustá-lo Em seguida, copie os valores nos quadros-chave da animação e exclua o novo nó. Quando terminar, vamos renomear o sprite animado com dois nós para atacar os efeitos Em seguida, duplique-o para criar efeitos de ataque aéreo. Certifique-se de criar um novo recurso de sprite frames para esse novo nó e criar as duas animações com efeitos de ataque aéreo Os efeitos do ataque aéreo não estão posicionados da mesma forma que os efeitos do ataque ao solo Então, precisaremos reposicionar o nó, excluindo a trilha para o efeito de ataque podemos adicionar uma nova faixa para Em vez disso, podemos adicionar uma nova faixa para os efeitos do ataque aéreo e depois duplicar essa animação Para criar o segundo ataque aéreo, podemos repetir o processo, trocando os sprites, mudando o argumento passado para a animação do efeito e trocando o efeito e trocando o Em seguida, ajustando a forma da colisão para coincidir com o ataque. Adicionando essas duas novas animações à árvore de animação, elas se comportarão da mesma forma que os ataques terrestres, apenas com a condição de que o personagem não esteja no chão fazendo a transição do ataque aéreo um para ataque aéreo dois no final da animação, sob as sob as E voltando ao movimento no final do segundo ataque, saindo do primeiro ataque aéreo, voltando ao movimento Se o jogador não quiser mais atacar ou estiver no chão, eu gostaria de criar a sensação de suspender no ar enquanto o jogador está realizando esses ataques aéreos está realizando esses Vamos substituir a definição de física do ar no script do herói Se o herói estiver atacando e sua velocidade y for maior que zero, que significa que ele está caindo, então eu definirei sua velocidade y como zero, em vez de mantê-lo no ar durante o Caso contrário, podemos usar o super air physics delta para realizar os comportamentos herdados do script do personagem Mas como o jogador pode optar por continuar atacando infinitamente, ele também pode optar por ficar no ar Podemos corrigir isso com outra mecânica de jogo, um cronômetro de resfriamento. Adicionando outro nó temporizador à caixa do quadril chamado Cool Down. Vou deixar a configuração de tempo no padrão de 1 segundo, mas definirei uma foto como verdadeira. Obtendo uma referência a esse nó durante a fase de preparação no script do herói para que possamos referenciá-lo na árvore de animação Posteriormente, nas animações de ataque, podemos adicionar uma faixa de chamada de método a cada uma, iniciando o cronômetro de resfriamento no final de cada As chamadas começam no cronômetro de resfriamento. Novamente, com cada ataque , basta redefinir seu valor de tempo para 1 segundo e começar a contagem regressiva novamente. Na árvore de animação, não permitiremos a transição para o primeiro ataque da sequência, a menos que o cronômetro de resfriamento seja interrompido Dessa forma, o jogador será forçado a parar de atacar após no máximo três ataques no solo ou dois ataques no ar A duração do resfriamento pode ser facilmente ajustada nas propriedades dos nós do temporizador Eu também gostaria de atacar um inimigo de cima para fazer o jogador pular Adicionar uma substituição ao script do herói do método inserido na área da caixa de acerto Primeiro, precisarei verificar se esse herói está morto ou não está atacando e depois retornar se ele não estiver no chão E a posição y global da área atingida pelo ataque é maior do que a posição y global do herói, então o inimigo que está sendo atingido está abaixo. Em seguida, definirei sua velocidade y a força de salto dividida por dois, criando um salto que será menor do que um salto completo E, finalmente, chame a definição herdada infligir danos Bem, ao criar as animações de ataque dos jogadores, adicionei a nova variável para está atacando, mas essa variável não foi incluída nas ataque do inimigo. Então, vamos adicionar isso. Enquanto a iluminação da máquina de estados da árvore de animação ajuda a manter as coisas organizadas Também introduz a possibilidade animações serem interrompidas, deixando as variáveis definidas de maneiras que não deveriam Por exemplo, se Roger atacar sua variável de ataque e o monitoramento da caixa do quadril serão definidos como verdadeiros Mas então ele é atingido antes que a animação seja concluída e essas variáveis não voltem a ser falsas Roger agora não consegue se mover e qualquer inimigo que se aproximar dele será danificado por caixas de quadril fantasmas Podemos redefinir essas variáveis quando o personagem sofre dano ou morre. Para evitar que isso aconteça, vamos criar um método de interrupção de ataque Redefina o valor do ataque e do monitoramento da caixa do quadril para falso e chame esse método quando o personagem sofrer dano se estiver Agora temos o personagem do jogador capaz de realizar ataques no ar, suspendendo a gravidade e gerando uma força de salto no impacto Na próxima lição, adicionaremos scripts de IA para que a patrulha do inimigo esteja na área Te vejo na próxima aula. 46. 5-4 Patrulha: Olá, amigos. Na lição anterior, adicionamos ataques aéreos para o jogador Nesta lição, escreveremos um script de IA para fazer com que os inimigos patrulhem uma área Eu movi os outros inimigos e posicionei dente feroz entre dois obstáculos no meu nível E desativou o cronômetro de ataque automático para o comportamento mais básico do inimigo Eu gostaria que eles simplesmente caminhassem para frente até baterem em uma parede e se virarem. Assim como criamos o nó do jogador para controlar o personagem do jogador, podemos criar um nó filho para os inimigos para controlar seu comportamento. Com a IA, esse nó exigirá dois posicionamentos D. Então, vou torná-lo um nó dois D e chamá-lo de Patrulha. Dando a esse nó um nome de script para patrulhar. Vou colocá-lo na pasta de scripts de caracteres e usar o modelo padrão para um nó dois D. Durante a fase de preparação, vou pegar uma referência ao nó pai, que é o personagem que está sendo controlado. Também vamos declarar uma variável para que saibamos em qual direção queremos nos mover como um tipo flutuante No método ready, podemos inicializar o valor da direção com base no fato de direção com base no fato o caractere pai estar voltado para a esquerda ou não Mas a variável está voltada para a esquerda foi marcada como privada. Devemos adicionar um método público que retorne seu valor ao script de caracteres, que possamos acessá-lo indevidamente Em seguida, podemos definir o valor da direção do sublinhado com base no valor de retorno dos caracteres pais Método público está voltado para a esquerda Isso nos permite ler o valor de está voltado para a esquerda , mas não alterá-lo. No método de processo, não precisamos de delta. Devemos colocar um sublinhado na frente dele para que o motor possa ignorá-lo O comportamento padrão será simplesmente dizer ao personagem que corra na direção desejada. Mas antes de fazermos isso, devemos verificar se o personagem bateu em uma parede, que está convenientemente incluída no corpo do personagem two de node para nós Se o personagem estiver em uma parede , devemos mudar o valor da direção. Podemos obter o vetor normal das paredes, que é um vetor perpendicular e apontando para longe da superfície das paredes Só estamos interessados na porção x desse vetor para saber se a parede está voltada para a esquerda ou para a direita. Também podemos aplicar sinais a isso. O retorno será negativo ou positivo. Isso não importará no meu jogo, já que todas as paredes são perfeitamente planas. seus vetores normais estarão qualquer forma, seus vetores normais estarão exatamente à esquerda ou à direita Mas esse código funcionará com paredes angulares. Agora, dois, vamos experimentar. Fierce Tooth agora está andando para frente e para trás entre os dois obstáculos Eles até detectam o jogador como um obstáculo. Segundo, qualquer coisa com a qual o corpo do personagem colida com o nó D que impeça o movimento horizontal será detectada pelo método is on wall E se posicionarmos um dente feroz no topo da plataforma? Eles simplesmente fugirão para o lado e repetirão o mesmo comportamento de antes. Embora eu queira esse comportamento às vezes, provavelmente não quero que isso aconteça o tempo todo e talvez queira que os inimigos se virem se acharem que é alegado. Isso é um pouco mais complicado, pois a detecção de saliências não é fornecida para nós Adicionando um nó filho ao nó de patrulha. Podemos usar dois nós D lançados por raios para detectar a presença ou ausência de terreno na frente de um personagem Vou posicionar o raio para ficar no espaço vazio na frente do personagem e apontando para o chão. Queremos que o comportamento desse inimigo mude com base no fato de a flecha estar atingindo ou não o chão Quando eles se virarem, reposicione a seta para o outro lado De volta ao roteiro de patrulha, podemos pegar uma referência ao elenco durante a fase de preparação e chamá-la de Floor Re definir sua posição para ficar meio ladrilho à frente do personagem no método pronto Como alternativa, você pode exportar uma variável se seus inimigos tiverem tamanhos diferentes e precisarem posicionar o raio de forma diferente. Essa é uma divisão de números inteiros, mas estou fazendo isso de propósito, então vou ignorar o aviso No método do processo. Sempre que o personagem estiver no chão e o raio não estiver colidindo com nada, isso significaria que o personagem está de frente para uma Assim, podemos chamar um método de borda detectada. Se uma borda for detectada, podemos facilmente trocar o valor da direção entre menos um e positivo multiplicando-o por menos um multiplicando-o por Em seguida, redefina a posição do raio para ficar na frente da nova direção do personagem. Em vez de duplicar o código, podemos transformar o código do método pronto em um novo método e chamá-lo sempre que quisermos que ele mude de Agora, o Fierce Tooth andará para frente e para trás sem sair das bordas da plataforma Ativar formas de colisão visíveis no menu de depuração também nos permitirá ver o raio do piso em ação enquanto isso acontece Mas e se eu quiser abrir uma exceção e fazer com que alguns inimigos saiam das saliências Podemos adicionar um novo tipo de variável ao nosso script, uma enumeração geralmente abreviada para enum, que é Dê um nome, ledge behavior e, em seguida, preencha essa lista com todas as opções que queremos ter Vou apenas adicionar duas opções. O valor padrão no topo da lista será virar, mas eu também quero ter a opção de sair das bordas dois Você também pode querer coisas como parar ou pular, etc A convenção para enumerações é usar maiúsculas e minúsculas Você deve se lembrar de usar uma enumeração que já foi definida no corpo rígido de dois nós D, ao definir sua Com a enumeração definida, podemos exportar uma variável usando a enumeração Então, quando uma borda é detectada, podemos combinar o valor dessa variável e fornecer um bloco de código a ser executado para cada Se o comportamento alegado for configurado para reverter, devemos executar o mesmo código de antes. Mas se estiver configurado para sair , podemos simplesmente passar ou voltar. Com esse método, você pode imaginar como esse formato pode ser usado para fornecer vários comportamentos alternativos. Selecionando o nó de patrulha. O inspetor agora contém uma lista suspensa chamada comportamento da borda, a partir da qual podemos selecionar o comportamento que queremos descrever em termos fáceis de entender para qualquer pessoa Também vou mover a posição inicial dos jogadores para ter uma visão melhor. Vamos dizer ao Fierce Tooth que saia das saliências e veja Salve o nó de patrulha como sua própria cena na pasta do personagem Agora podemos aplicar o mesmo script de comportamento a todos os inimigos básicos do nosso jogo. Ajustando a forma como eles reagem a diferentes obstáculos do terreno, usando fundições e Na próxima lição, daremos à detecção de jogadores do inimigo um comportamento agressivo. Te vejo na próxima aula. 47. 5-5 Agressão: Olá amigos. Na lição anterior, criamos um script de IA que pode ser usado para fazer qualquer inimigo em nosso jogo patrulhar área e até mesmo mudar seu comportamento Nesta lição, escreveremos outro roteiro que permitirá que os inimigos percebam o jogador e tentem atacá-lo. Vamos começar com uma cena de dentes ferozes. O primeiro passo será saber se um inimigo pode ou não ver o jogador. Esse será um comportamento único apenas para aqueles personagens que queremos que sejam inimigos. Devemos criar um novo script para inimigos herdados do personagem Podemos então substituir o script do personagem pelo script do inimigo no nó raiz do Fierce Tooth Vamos adicionar uma variável booleana para saber se o inimigo pode ver o jogador ou não Mas como sabemos se o inimigo pode ver o jogador? Assim como fizemos com o ataque, podemos adicionar outra área ao nodo para representar a visão do inimigo E dê a ele uma forma de colisão. A Use uma cor neutra, como branco, para visão. E faça dela uma grande área circular que cubra vários ladrilhos na frente deles e ligeiramente ao redor deles por todos os lados. Isso representa todo o seu campo de visão. Precisamos saber se o personagem do jogador entra nessa área. Vamos ajustar as camadas de colisão. Colocar isso na camada 20, uma nova camada para visão do inimigo e mascarar a camada nove, para que eles possam ver apenas o jogador Esta área será monitorada, mas não monitorável. E sempre ativado por padrão. Mas pode haver obstáculos no caminho bloqueando sua visão. Também podemos usar um nó fundido para verificar sua linha de visão. Não importa onde o alvo esteja agora, vou colocá-lo no meio. Mas o ponto de origem do Raycast deve estar nos olhos do inimigo Podemos distinguir esses dois nós renomeando-os para Clarity A Field Division procurará apenas o jogador. A linha de visão será mascarada pelo terreno e pelo jogador, bem como por qualquer outra coisa que você queira obscurecer a Em seguida, podemos conectar os sinais de entrada e saída do corpo do nó D da área dois ao script inimigo Eles têm um nome bonito para que possamos ver o corpo entrar e sair Vamos armazenar o herói em uma variável à medida que ele entra e sai do campo de visão do inimigo. Graças às camadas de colisão, somente o herói deve acionar Mas é sempre mais seguro verificar primeiro, armazenando uma referência ao herói quando ele entra no campo de visão e definindo essa referência como nula ao sair do campo de visão Para verificar a linha de visão, precisaremos de uma referência aos nós da linha de visão definidos durante a fase de preparação. Então, durante o método do processo, não precisamos de delta. Se o herói estiver dentro do nosso campo de visão, faremos algumas contas, mas se ele não estiver em nossa divisão de campo, não poderemos ver o jogador configurando isso como falso Podemos definir a posição alvo da linha de visão para ser a diferença entre a posição do herói e a posição do inimigo apontando a linha de visão diretamente para o personagem do jogador. Se a linha de visão está atingindo algo e esse algo é o herói, então podemos ver o jogador Caso contrário, deve estar atingindo nada ou alguma outra coisa, como terreno ou obstáculo Não podemos ver o jogador ativando formas de colisão visíveis no menu de depuração e pressionando Depois, voltando ao editor, podemos mudar para a árvore da cena remota e selecionar Fierce Tooth para observar suas variáveis no inspetor em Agora podemos ver que quando o jogador entra no campo de visão, a linha de visão começa a rastrear sua posição. A variável can C player é definida como verdadeira somente quando eles estão dentro do campo de visão e desobstruídos pelo terreno a partir da linha de Também precisamos que o campo de visão mude como tudo quando o inimigo está voltado para a esquerda ou para a direita Capturando uma referência ao nodo de visão durante a fase de preparação e substituindo as definições de face esquerda e face direita Podemos começar chamando seus supermétodos. Em seguida, adicione a configuração da escala X de visão para um quando estiver voltada para a esquerda ou negativa quando estiver voltada para a direita. Já que, por padrão, todos os inimigos estão voltados para a esquerda. Como os lançamentos não usam a propriedade de escala, precisaremos adicionar uma condição extra ao calcular a posição alvo Se o personagem inimigo não estiver voltado para a esquerda, multiplique o X da posição alvo por menos um para espelhá-lo Depois que o inimigo ver o jogador, queremos pausar seu comportamento de patrulha e fazer com que ele persiga o jogador No script de patrulha, podemos adicionar uma variável booleana privada para controlar se esse personagem está patrulhando ou não E defina seu valor como verdadeiro por padrão. Em seguida, forneça métodos públicos para pausar e retomar esse comportamento Definir o valor de é patrulhar em cada caso quando pausado. Também chame o caractere run zero para forçá-lo a parar executado no método do processo Se esse personagem não estiver patrulhando , devemos retornar e não executar nenhum desses códigos No script inimigo, podemos obter uma referência ao nó de patrulha durante a fase de preparação, mesmo que ele possa ou não existir usando um método chamado get node ou null passando o nome do nó que estamos procurando como argumento Em seguida, substitua cada uma dessas três linhas por uma chamada de método, dizendo ao inimigo se ele pode ou não ver o herói escrevendo esse novo herói de método particular. Será necessário um parâmetro booleano saber se agora eles podem ou não ver o herói, se o inimigo não conseguir ver o herói, o que significa que o valor até o momento era falso, mas agora eles podem ver o herói Este é o momento exato em que o jogador entrou no campo de visão e na linha de visão. Então, devemos transformar o herói em realidade. Se a nota de patrulha existir , peça que ela pause seu comportamento Inversamente, se o inimigo pudesse ver o herói, mas agora não , podemos fazer com que o comportamento de patrulhamento retomado caso o herói esteja atrás do Também podemos forçar o inimigo a ficar de frente para a direção do jogador neste momento comparando suas posições globais e o método de processo do inimigo. Se pudermos ver o herói , devemos correr em direção a ele usando a diferença entre a exposição global do herói e a exposição global do inimigo para saber a direção e aplicar sinais nela Portanto, só é menos um, um positivo ou zero se estiverem diretamente acima ou abaixo. De volta à visualização, podemos adicionar mais uma área ao nó para economizar tempo. Vamos fazer dele um filho do nódulo da caixa do quadril e nomear esse alvo. Vou torná-la amarela para indicar perigo e fazer dessa forma o que você achar que faz sentido, mas provavelmente semelhante ou um pouco maior do que a caixa vermelha. Coloque isso em outra nova camada de colisão, a camada 21, a camada de mira e a máscara do inimigo Para a camada dez da caixa Rt do jogador. Isso será monitorado e não monitorável. Podemos conectar o sinal da área inserida ao script do inimigo. Não precisamos da área dois D, então podemos sinalizá-la com um sublinhado Então, quando a caixa T do jogador entrar na área-alvo do inimigo, o inimigo atacará. Vamos experimentá-lo. Quando Fierce Tooth vê Roger, eles E se não conseguirem ver Roger, voltarão aos seus comportamentos normais de patrulha Se eles pegarem Roger, eles atacarão. Nossos inimigos agora podem ver e perseguir e atacar agressivamente o jogador Na próxima lição, criaremos um inimigo capaz de disparar projéteis Te vejo na próxima aula. 48. 5-6 projétil: Olá amigos. Na lição anterior, permitimos que nossos inimigos percebessem o personagem do jogador e o atacassem. Nesta lição, criaremos um novo inimigo com ataques de alcance. Eu já comecei a criar um novo inimigo para esta lição, a concha marinha. Até agora, a estrutura da árvore de nós é a mesma. A raiz é o corpo de um personagem, dois D na camada de colisão inimiga, mascarando a camada do terreno com o sprite two D, reprodutor de animação e árvore de animação Um nó em forma de colisão com um recurso em forma de cápsula, uma caixa Rt, uma caixa de quadril, uma caixa-alvo e uma visão correspondentes quadril, uma caixa-alvo e uma visão Certifique-se de que cada uma esteja configurada para a camada de colisão apropriada, mascarando as camadas corretas e ou monitorável Começarei adicionando um nó dois D chamado de origem do projétil, que marcará o local exato onde os projéteis serão disparados E um cronômetro, que dirá a esse inimigo que atire. Um projétil configurado para iniciar automaticamente e será disparado a cada 3 segundos Todas as animações foram preenchidas com os sprites apropriados Ocioso, atingido, incendiado e destruído. Destruída é apenas uma moldura. Em seguida, o segundo quadro define a propriedade visível do sprite como falls para ocultá-la A máquina de estado da árvore de animação tem as animações atingidas e destruídas na camada superior, fazendo a transição com base nas variáveis atingidas e mortas do script do personagem dentro da dentro da O padrão do Seashell é inativo e, em seguida, muda para disparar quando eles querem voltar a ficar inativos no final da animação e não querem disparar no final da animação e Vamos criar uma nova pasta de scripts de personagens para inimigos e colocar scripts de inimigos e patrulhas dentro dela Assim como criamos o script inimigo herdando do personagem, podemos dar ao script inimigo um nome de classe inimigo e, em seguida, criar um novo script chamado So Inheriting Enemy Agora, esse script tem todos os comportamentos e atributos de um personagem, um inimigo, e tudo o que colocamos no script do atirador para gerar um projétil, assim como fizemos com a geração de moedas, podemos exportar uma variável de cena compactada e, em seguida, também exportar variáveis para descrever o comportamento do projétil, como sua velocidade, que eu gostaria e atributos de um personagem, um inimigo, e tudo o que colocamos no script do atirador para gerar um projétil, assim como fizemos com a geração de moedas, podemos exportar uma variável de cena compactada e, em seguida, também exportar variáveis para descrever o comportamento do projétil, como sua velocidade, que eu gostaria de descrever em telhas por segundo. Vou configurá-lo para dez por padrão. Além disso, o dano que o projétil causará ao atingir o jogador, um número inteiro variando de 1 a 100 com o padrão de um à duração máxima, permitirei que o projétil exista antes de se destruir como flutuador, com o padrão de 10 segundos. Durante a preparação. Depois de executar todos os métodos prontos herdados, multiplicarei minha velocidade medida em blocos por segundo pelo Cobolpt para alterá-la para pixels Também pegue uma referência ao nó de origem do projétil. Usando at on ready, podemos escrever um método para gerar o projétil que será chamado pela animação de fogo do inimigo atirador durante o quadro exato em que o projétil Criação de uma variável temporária para conter o projétil recém-instanciado. Podemos posicioná-lo em seu ponto de origem e adicioná-lo à árvore da cena como irmão do inimigo Se o inimigo puder se mover, o projétil não será afetado pelo movimento do progenitor Ela existirá como uma entidade independente do mundo. Podemos então mandar o projétil disparar, fornecendo as informações necessárias para realizar seu trabalho: direção, velocidade, dano e duração Esse inimigo só disparará projéteis para a esquerda ou para a direita, dependendo da direção em que está voltado para acionar a animação de fogo Assim como nas animações de ataque, teremos uma variável booleana que quer disparar , que é definida como verdadeira por um reprodutor de animação de fogo em conchas marinhas de método público Durante a animação de fogo que podemos configurar, deseja disparar de volta para falsa gerar o projétil durante o quadro, quando ele parecer mais correto Para fazer isso na cena da concha marinha, também criarei o projétil, que será um nó D da área dois. Não quero que a física seja aplicada aos meus projéteis e prefiro calcular seus comportamentos matematicamente Se você quiser que seus projéteis usem física, eles devem usar um corpo rígido dois D como nó raiz O projétil disparado pela concha marinha inimiga é uma pérola e é colocada na camada inimiga atingida, mascarando o terreno e a camada t do jogador Já que essas são as únicas coisas que eu quero que o projétil seja capaz de atingir E precisará de um sprite para desenhar. E uma forma de colisão, que é o círculo. Vou colorir de vermelho. Posicionando o projétil onde ele deveria se originar dentro da concha Talvez você queira reposicionar o nó de origem do projétil com base aparência em relação ao inimigo atirador Também adicionarei um nó temporizador, que será usado principalmente para limitar a duração da existência desse projétil Vou definir que é uma chance verdadeira quando a pérola atingir algo que eu queria quebrar. Vou adicionar um nó de dois D chamados detritos. Vou esconder o sprite da concha em forma de colisão para uma melhor visão. Enquanto faço os detritos da pérola usando os detritos como pasta, posso então adicionar nódulos secundários para cada pedaço de pérola quebrada como corpo rígido, dois nós para cada pedaço de pérola quebrada Desde agora, gostaria de aplicar física. As peças de detritos terão seus próprios sprites e Vou posicionar a metade superior da pérola onde ela combina o sprite original da pérola e dar a ela uma forma de colisão Coloque-os em uma nova camada, camada quatro para detritos e mascare apenas o terreno, impossibilite-o de girar e congelá-lo com o modo de congelamento Em seguida, duplique-o para criar a parte inferior, trocando sprite e reposicionando-a para combinar com a parte inferior da Os detritos superior e inferior ficarão ocultos por padrão. Com a estrutura do nó concluída, podemos salvar a ramificação do projétil como sua própria cena em uma nova pasta Projéteis e abri-la para edição Agora podemos excluir a pérola da cena da concha e redefinir sua posição para ficar centralizada na origem Em seguida, adicione um script ao nó raiz da pérola chamado Projectile, salvo na pasta de scripts do inimigo Durante a fase de preparação, vou pegar referências aos nós secundários. Sei que precisarei acessar, como o sprite, os detritos Já tendo escrito a chamada do método fire no script do shooter, podemos dar uma definição a isso Aceitando uma direção como vetor, duas velocidades como flutuação, dano como número inteiro e duração como Precisaremos armazenar todos esses valores em variáveis locais privadas, exceto a duração. A duração que podemos simplesmente usar para definir o cronômetro. Se a duração dada fosse maior que zero, valor menor ou igual a zero seria considerado duração ilimitada. Também precisarei de uma variável local privada para saber se esse projétil foi destruído ou não. No método do processo, se esse projétil não foi destruído, adicione à sua posição direção vezes velocidade vezes delta Isso fará com que o projétil se mova em linha reta a uma velocidade constante Qual é o comportamento esperado dos projéteis na maioria dos videogames Conectando a área inserida no corpo, os sinais inseridos são inseridos no script. O único corpo com o qual esse projétil deve deslizar é o terreno Se isso acontecer, ele fará com que o projétil se quebre se entrar em uma área que deveria ser a caixa ferida do jogador Primeiro vou tentar pegar o pai da área, que deve ser o personagem do jogador. Depois de verificar se esse é o herói, direi a eles que sofram dano, passando a quantidade e a direção do dano normalizadas como argumentos e , em seguida, quebrem o Adicionando o método de interrupção, vou conectá-lo ao sinal de tempo limite do cronômetro Ele será chamado automaticamente 10 segundos após o disparo do projétil Se não atingisse nada quando o projétil se rompesse, eu gostaria que algumas coisas diferentes acontecessem com o tempo, que poderia ser feito com um reprodutor de animação, mas prefiro fazer isso com um código relativamente simples Primeiro, adicionarei uma variável exportada para a textura dois D, que mostra o projétil sendo E troque o feixe por este D é destruído de variável para verdadeiro O projétil para de se mover e sua máscara de colisão é zero, então não provocará mais Em seguida, quero reutilizar o nó do temporizador, que está sendo usado atualmente para acionar o método de interrupção no sinal de tempo limite Como esse é o método de quebra, o projétil atingiu alguma coisa e esse comportamento não é mais necessário Vou pegar o sinal de tempo limite do cronômetro e desconectá-lo do método de interrupção Em seguida, reinicie o cronômetro com um novo tempo, 0,1 segundo, que é a taxa de quadros que estou usando para todas as minhas animações Esperando que o sinal de tempo limite seja de 0,1 segundo depois, definirei a propriedade visível do sprites como falsa e, em seguida, direi aos detritos que se espalhem Em seguida, espere mais dez segundos antes de dizer ao motor que esse projétil não é mais relevante e pode ser removido da árvore da cena Agora podemos criar um novo script para espalhar os detritos anexando-os ao nó de detritos, que colocarei na que colocarei Esse script só precisa de uma variável, uma matriz de nós que são seus filhos. Quando instruídos a dispersar, podemos iterar por meio dessa matriz com um loop for seguindo o formato de como outras linguagens o escreveriam Para cada laço, podemos nos referir a cada membro da matriz de peças como uma peça, depois fazer com que fique visível, descongele e aplique uma força de impulso a Como os fragmentos já estão distribuídos suas posições originais em relação ao furo ininterrupto, podemos simplesmente usar sua posição como a direção da força de impulso e multiplicá-la por um ladrilho multiplicá-la Obviamente, você pode experimentar diferentes quantidades de força aplicadas para espalhar os detritos Pode estar normalizando a direção, então a distância da origem não é um fator Quando a concha marinha é destruída, podemos fazer o mesmo que com a pérola criando os detritos Nodo dois D, desta vez com quatro filhos. Para cada um dos quatro sprites de shell quebrados copiando e colando os nós, eles já terão as configurações corretas Posicione cada um no local exato em que corresponda ao sprite de concha ininterrupto e também ajuste suas formas de colisão Em seguida, anexe o script de detritos ao nó de detritos. Finalmente, conecte o sinal de tempo limite do cronômetro para fazer com que a concha marinha atire a cada 3 segundos Selecionando o nó raiz da concha marinha, precisamos preencher a cena compactada contendo o projétil e definir o sprite voltado para a esquerda e para a esquerda para ser Sim. Em seguida, adicione uma faixa de chamada de método à animação destruída para que os detritos sejam espalhados No mesmo momento em que o sprite de conchas marinhas se torna invisível, vamos experimentá-lo A concha lança pérolas a cada 3 segundos que colidem com o terreno e quebram gerando detritos, que são removidos automaticamente colidem com o terreno e quebram gerando detritos, que são removidos automaticamente. Após 10 segundos, essas pérolas podem atingir e danificar o jogador E o jogador também pode destruir a concha marinha atacando-a com a espada Agora temos um inimigo que pode atirar projéteis no jogador Na próxima lição, adicionaremos um chefe inimigo ao nosso jogo. Te vejo na próxima aula. 49. 5-7 Chefe: Olá, amigos. Na lição anterior, adicionamos um novo tipo de inimigo que pode disparar projéteis Nesta lição, adicionaremos um encontro entre chefes e inimigos ao nosso jogo. Eu criei um novo nível para o encontro com o chefe, que é um poço no qual, uma vez que o jogador pule, ele não conseguirá sair do nível O posto de controle fica logo antes do chefe e da espada estarem lá, então eles já o fizeram O totem é feito de três inimigos atiradores, que são quase exatamente baldes da concha marinha da lição anterior Exceto que eles mascaram a camada de colisão inimiga para fins de empilhamento O totem azul tem um polígono de colisão personalizado que dificulta que o jogador fique em cima dele, mas ainda seja capaz de mas ainda seja capaz de Em seu projétil está uma haste de madeira que é uma duplicata da pérola, com apenas os sprites e as formas Ao contrário dos sprites das pérolas, o espigão de madeira não é simétrico na Vamos adicionar uma nova variável exportada, virar com direção. Então, ao disparar o projétil, se o giro na direção e direção x for maior que zero, devemos definir a escala x dois menos um para virar o sprite, a forma da colisão e os detritos e definir o valor das pontas de madeira dessa variável como verdadeiro, deixando as pérolas falsas se o giro na direção e a direção x for maior que zero, devemos definir a escala x dois menos um para virar o sprite, a forma da colisão e os detritos e definir o valor das pontas de madeira dessa variável como verdadeiro, deixando as pérolas falsas. Infelizmente, esses sprites totêmicos não estão centralizados. Para que os totens individuais possam ficar voltados para a esquerda ou para a direita enquanto permanecem centralizados no totem, eles precisarão de um Em seguida, substituindo as definições de face esquerda e face direita, definirei o deslocamento dos sprites como esse número multiplicado por um se houver sprites voltados para a esquerda ou menos um e vice-versa para a face direita menos um e vice-versa Em seguida, definirei o valor dessa variável durante a preparação, antes da superpronta. Como o Super Ready fará com que o personagem fique virado para a esquerda ou para a direita, descobri um problema em definir a posição dos projéteis antes de adicioná-los à árvore da cena Portanto, podemos corrigir isso adicionando-o primeiro à árvore. Além disso, não quero que esse inimigo tenha nenhuma velocidade de repulsão adicionada ao sofrer danos. No script do personagem, podemos adicionar outra variável de combate chamada stagger como um flutuador com um valor padrão de cinco Os outros inimigos ainda terão o mesmo comportamento de antes. Então, quando um personagem sofre dano, podemos multiplicar a velocidade de empurrão por essa nova variável e definir seu valor como zero para o chefe, removendo o efeito Como criamos um encontro com o chefe? Vamos começar adicionando um nó de área a esse nível Quando o jogador entrar, iniciaremos o encontro com o chefe o configuraremos para monitorar a camada do jogador Vou dar a ele uma forma retangular e encher toda a arena Eu gostaria que a câmera permanecesse imóvel e centralizada durante a luta contra o chefe. Então, vou adicionar um novo tipo de nó marcador, dois nós D e chamá-lo Câmera A, marcador dois, nó D é quase o mesmo que um nó dois D, exceto que ele desenha um dispositivo em cruz no editor para que possamos Se quisermos que a câmera permaneça trancada no lugar durante o bosphte, precisaremos ser capazes de substituir seu comportamento padrão em uma variável booleana seguindo o assunto com o valor padrão de true no método do true no Se a câmera não estiver seguindo o assunto , podemos retornar para evitar mudar a posição da câmera. Vamos criar uma nova variável de panorâmica para realizar esse comportamento de panorâmica usando uma interpolação Em seguida, um novo método público, pan to marker, que usará um marcador dois D como parâmetro e também a duração do pan com um valor padrão de 1 Se a panela existir e estiver funcionando, devemos matá-la. Em seguida, crie uma nova e peça para ela deslocar a posição da câmera até a posição global dos marcadores Ao chamar esse método, queremos substituir o comportamento padrão a seguir definindo is following subject to false Em seguida, podemos adicionar outro método para continuar seguindo a configuração do assunto, seguindo o sujeito até verdadeiro. Mas se deixarmos assim , a câmera será cortada com força na posição do objeto. Primeiro, devemos verificar se a câmera está girando no momento e eliminar esse comportamento Se for, podemos então reverter os cálculos da posição da câmera a partir do método de processo para, em vez disso, calcular quais os valores da distância de visualização e da altura do piso seriam os valores da distância de visualização e da altura do piso na posição atual da câmera. Em seguida, emita a mudança de direção e os sinais de aterrissagem, que voltarão suavemente a câmera para De volta à cena do nível, também podemos adicionar uma camada de tela ao nível. Ao contrário da camada de tela na cena do jogo, que será desenhada em todos os níveis, essa camada de tela só será desenhada em níveis com o chefe copiando o medidor de saúde do jogador Podemos colá-lo na tela de encontros com o chefe reposicioná-lo para que fique na parte superior central da E substitua o coração pelo crânio, mantendo-o escondido. Por padrão, vou me certificar de mostrá-la apenas durante a batalha. Depois que a batalha terminar, quero que o tesouro final do nível se revele. Eu terei o tesouro posicionado em uma área impossível de alcançar e invisível na escrita do tesouro Vou adicionar um método público simples chamado To Reveal, que assumirá uma nova posição como um parâmetro vetorial dois. Este método moverá o tesouro para a posição desejada, tornando-o visível. Reproduza a animação do efeito ao contrário. Aguarde até que a animação termine. Em seguida, reproduza a animação padrão, selecionando o nó de encontro com o chefe. Vamos criar o script de encontro com o chefe, salvando-o na pasta de scripts do inimigo. Esse script precisará de uma referência aos nós do marcador da câmera e do medidor de saúde definidos durante a fase de preparação Mas também uma referência à própria câmera, que podemos alcançar iniciando nosso caminho a partir do nó raiz. Também vou pegar uma referência ao tesouro do nível acessando primeiro o pai desse nó, que será o nível. Em seguida, obtenha os pontos de verificação dos nós. Como alternativa, você pode exportar isso como uma variável conectando o corpo do sinal inserido ao script. Isso será acionado quando o jogador entrar na área da arena do chefe. É quando devemos começar o encontro com o chefe. Também vamos armazenar uma referência ao herói em uma variável local. Quando isso acontece para facilitar o rastreamento da posição e do comportamento . Para iniciar o encontro, primeiro desloco a câmera até o marcador da câmera e seguida, exibo o indicador de saúde na tela da interface do usuário Inversamente, para encerrar o encontro, devemos dizer à câmera continue seguindo o jogador e esconda o medidor de saúde. O fim do encontro pode acontecer se o jogador morrer ou se o chefe for Se o chefe for derrotado, o encontro deve terminar , mas também revelar a recompensa. Reaproveitando o marcador da câmera como local da recompensa. Podemos acionar o método de encontro final automaticamente conectando o sinal de saída do corpo a ele Como o jogador responderá fora da arena, esse script precisará saber qual é o chefe inimigo. Neste exemplo que estou usando, o encontro com o chefe é na verdade três inimigos. Vou exportar uma variedade de inimigos. Eu só quero que um medidor de saúde monitore a saúde combinada dos três inimigos Vou fazer com que o script de encontro com o chefe cuide da lógica extra, criando duas novas variáveis para a saúde atual e máxima. Então, no método pronto, posso percorrer minha variedade de inimigos chefes, somando seu máximo de saúde para obter um total combinado Em seguida, definindo a corrente para ser igual ao máximo. Também escreverei aqui um novo método que atualiza o indicador de saúde Iniciando a saúde atual em zero e iterando pela matriz Somando a saúde atual de todos os chefes inimigos. Para obter um total combinado, podemos então calcular a porcentagem da saúde total restante lançando corrente em um flutuador e dividindo-a pelo Em seguida, defina o valor dos medidores de saúde usando essa porcentagem combinada Se o total combinado de saúde for zero, o chefe foi derrotado. Podemos usar o sinal de alteração de saúde emitido pelo script de caracteres para chamar esse método Mas o sinal de alteração de integridade passa junto com ele um argumento flutuante, adicionando isso como um parâmetro ao nosso método Podemos ignorá-lo precedendo-o com um sublinhado e conectando os sinais durante o método pronto quando calculamos a saúde máxima. Uma mecânica comum nos jogos é fazer com que o comportamento do chefe mude em determinadas porcentagens de saúde Se o chefe ainda não estiver morto, vamos chamar um método de verificação de fase, passando a porcentagem como argumento. Como esse comportamento varia de chefe para chefe, deixe o corpo em branco junto com outro método vazio. Decida o próximo ataque. Agora temos todas as estruturas genéricas de encontro com chefes instaladas. Vamos dar a esse script um nome de classe para que ele possa ser herdado para fornecer comportamentos específicos de encontro Removendo o script de encontro com o chefe do nó. Em vez disso, podemos substituí-lo por um script herdado, descrevendo especificamente os comportamentos do totem Neste script, podemos definir como ele decide seus próximos ataques, bem como como e quando ele muda entre as fases da batalha. Vou simplificar as coisas apenas anexando uma nota do cronômetro ao encontro com o chefe, à qual vou pegar uma referência quando estiver pronta Comece quando o encontro com o chefe começa e pare quando o encontro com o chefe termina. Em seguida, conecte seu sinal de tempo limite para decidir o próximo ataque. O totem decidirá o que fazer a cada 1 segundo. Adicionar um gerador de números aleatórios e um inteiro para armazenar um inteiro aleatório Primeiro, examinarei cada chefe na matriz do chefe e, em seguida, gerarei um número aleatório de 0 a 2 para poder igualar os resultados Vou ignorar o zero, o que significa que o inimigo não fará nada. Se for um, eles virarão para a esquerda e atirarão. Ou se for dois, eles se virarão para a direita e atirarão. Para aumentar a dificuldade. À medida que a saúde do chefe fica mais lenta, verificarei quando a porcentagem atingir menos de um terço e menos de dois terços quando esses limites Vou definir que o tempo de espera dos cronômetros seja um pouco menor para que os totens ataquem com mais frequência Mas vou garantir que o tempo permaneça maior do que a animação, permitindo que você termine e volte ao modo inativo entre cada ataque Não vou esquecer de preencher a matriz do chefe com os inimigos do chefe. Vamos experimentar. O encontro com o chefe é acionado quando o jogador entra na arena. A câmera gira e trava no lugar, e o medidor de saúde do chefe é exibido, que rastreia a saúde combinada dos três inimigos Se o jogador morrer, ele responderá no posto de controle e o encontro com o chefe será pausado até que o jogador entre novamente na Quando todos os inimigos estão mortos, o medidor de saúde desaparece, a câmera continua seguindo o jogador e a recompensa é revelada Agora temos um chefe inimigo que seria apropriado para encerrar um mundo de níveis em nosso jogo. Na próxima seção, vamos nos concentrar nos menus e na progressão. Nos vemos na próxima seção. 50. 6-1 Pause: Olá amigos. Na seção anterior, adicionamos combate ao nosso jogo. Nesta seção, adicionaremos menus e progressão. Se você concluir a tarefa, todos os seus inimigos agora terão comportamentos únicos Permitindo que eles patrulhem uma área do seu nível, procurando o jogador, depois o perseguindo e atacando. Você também deve ter um canhão capaz de disparar uma bala de canhão que Se você completou os desafios, seus inimigos também podem estar soltando tesouros ao serem derrotados O canhão pode ser operado pelo jogador ou por um inimigo, e a concha também tem um ataque de mordida Nesta lição, o jogador poderá pausar o jogo e abrir um menu de pausa Vamos começar abrindo as configurações do projeto e adicionando um botão de pausa ao mapa de entrada Vou usar a tecla Escape, o botão Iniciar no meu game pad. Todo o nosso tratamento de entrada está sendo processado pelo script do jogador. Mas pausar o jogo não tem nada a ver com controlar um personagem Qualquer nó em nossa árvore de cena pode substituir o método de entrada. Pausar o jogo deve ser responsabilidade do gerente do jogo No script do Game Manager, podemos adicionar um método de entrada que usa um evento de entrada como parâmetro. Se o botão de pausa foi pressionado, devemos pausar o jogo O método de pausa pode usar um parâmetro de bulling, eu o chamarei, e deve ser pausado Ele pode ser usado para pausar se o argumento for verdadeiro ou não pausar se o argumento A pausa vista em Godot é muito simples, só que o valor de get tree paused, ou neste caso dois, deve ser Então, quando o botão de pausa é pressionado, podemos passar o valor de get tree pause com um operador de nó para mudar seu valor como argumento Mas se pausarmos toda a árvore da cena, incluindo o gerente do jogo , o gerente do jogo não poderá fazer nada, incluindo receber informações e retomar o Selecionar o nó raiz da cena. Olhando para o inspetor. Em node, podemos expandir a seção de processo e definir seu modo de processo para sempre, mesmo quando o jogo estiver pausado, o gerenciador de jogos ainda estará em execução Qualquer coisa que você queira pausar em seu jogo, selecione o nó e defina sua propriedade de modo de processo como empilhar O valor padrão de inherit fará com que todos os nós filhos herdem o modo de processo de seus nós pais. Pausar o nó Rogers também pausará o nó do também pausará Pausar os nós de nível pausará todos os tesouros de seus inimigos e tudo o que há neles Os controles da interface do usuário, como botões, ainda funcionarão enquanto o jogo estiver pausado Mas se você estiver usando Tweens para mostrá-los ou ocultá-los , eles precisarão ser configurados para sempre processar dois. Vamos experimentar. Quando o botão de pausa é pressionado, o jogo é pausado. Quando o botão de pausa é pressionado novamente, ele é reiniciado, isso está funcional, mas eu gostaria de apresentar ao player um menu de pausa Podemos começar duplicando o menu de fim de jogo e renomeando-o para Menu de pausa, obtendo uma referência ao menu obtendo uma referência ao Durante a fase de preparação, podemos definir sua propriedade visível ao pausar ou despausar o Vou editar rapidamente o banner na parte superior do menu de pausa para dizer pausa em vez de fim de jogo Em seguida, altere o botão de nova tentativa para continuar. Não quero mais que o botão de retomar chame o método pressionado ao tentar novamente Vou editar a conexão do sinal. Na verdade, podemos fazer com que isso chame o método de pausa diretamente. Mas o método de pausa usa um parâmetro, clique no botão avançado para adicionar argumentos de chamada extras O argumento que precisamos passar para o método de pausa é um booleano Podemos adicioná-lo à lista e seu valor padrão é false, exatamente o que queremos. Clicar em conectar o botão Continuar agora fará com que o jogo pare de pausar Os botões de seleção e saída de nível podem permanecer exatamente iguais do menu de fim de jogo. Mas eu gostaria de adicionar outra opção para reiniciar esse nível desde o início, duplicando o botão retomado. Vou mudar este para Reiniciar e editar o rótulo do botão para que ele se encaixe melhor na tela. Com um botão extra, editarei a caixa de estilo do painel no editor de temas. Essa imagem em papel tem 128 pixels de tamanho, mas tem uma borda vazia em torno dela de cerca de 12 pixels em todos os lados. Posso dizer a Godot que use apenas a sub-região desta imagem, definindo as coordenadas x e y iniciais, a largura e a altura da sub-região a ser Depois, precisarei ajustar os menus individuais para que as palavras apareçam no papel. O botão de nova tentativa do menu de fim de jogo e esse botão de reinicialização têm um comportamento muito semelhante Vamos tentar combiná-los em um único método. A única mudança real que eu quero fazer aqui é não redefinir as vidas e moedas do jogador Podemos renomear isso ao tentar o método pressionado novamente para reiniciar e fazer com que ele use um parâmetro booleano de se isso é ou não um fim de jogo com um valor padrão Em seguida, passe isso para o método de nova tentativa de dados do arquivo, que vou alterar para ser chamado de reset O nível será descarregado, recarregado e o jogador retornará ao início do Tudo da mesma forma que antes. Mas se o jogador pressionou o botão de reinicialização no menu de pausa, também precisamos retomar o Podemos fazer isso ao carregar o nível no script de dados. Podemos editar o método de repetição, renomeá-lo para reset e o jogo no parâmetro booleano Agora, somente se isso estiver sendo chamado de um estado de fim de jogo , as vidas e moedas devem ser reiniciadas. No menu de pausa, o botão de reinicialização pode ser conectado ao método de reinicialização Como o parâmetro tem um valor padrão de false, não precisamos especificar um argumento aqui. Mas no menu de fim de jogo, o botão de nova tentativa pode ser conectado ao mesmo método de reinicialização Desta vez, especificando verdadeiro como argumento. Agora, todos os mesmos comportamentos serão usados por esses dois botões, com a única diferença de redefinir as vidas e moedas dos jogadores se eles ficarem sem vidas. Vamos experimentar. Agora. Quando o jogo é pausado, o menu de pausa é exibido e pressionar Continuar oculta o menu de pausa que está pausando o O botão de reinício retornará o jogador ao início do nível, redefinindo todos os componentes do nível volta aos seus estados originais O botão de seleção de nível ainda não está fazendo nada, já que ainda não temos um menu de seleção de nível e o botão de saída sai do jogo Agora podemos pausar nosso jogo e dar ao jogador um menu de opções enquanto o jogo está pausado Na próxima lição, adicionaremos uma tela de título para iniciar nosso jogo. Te vejo na próxima aula. 51. 6-2 Title: Olá amigos. Na lição anterior, adicionamos um botão de pausa e um menu de pausa ao nosso jogo Nesta lição, adicionaremos uma cena título e um menu principal. Vamos começar criando uma nova cena em D chamada title salva na pasta Scenes. Podemos copiar muitos dos componentes de outras cenas para colocar na cena do título. Como o plano de fundo, definirei a propriedade de escala do nó raiz da cena do título como três, correspondendo ao zoom das cenas do jogo. câmera então reposiciona o fundo, preenche a tela e captura os sprites animados da superfície da água da minha cena nivelada Adicionar um nó dois D para mantê-los como um grupo. Também adicionarei um novo sprite animado com dois nós D contendo o navio mercante. Preenchendo cada um com os sprites do pacote de ativos. Podemos configurar suas animações para serem reproduzidas automaticamente na taxa de quadros desejada Vou colocar o navio atrás da água reordenando seus nós, outro para a vela e outro para Em seguida, adicione também um sprite de dois nós D para a âncora. Em seguida, adicione também um sprite de dois nós D para a âncora Adicionando um nó de camada de tela, podemos adicionar notas de controle à cena do título. Vou usar uma caixa vertical para segurar o título e outra para segurar os botões. A caixa de título conterá duas caixas horizontais, uma para cada palavra, Jolly e Roger, preenchendo cada uma com Vou usar as letras grandes do pacote de ativos para o título que descreve Jolly Roger Quero que as letras sempre mantenham suas proporções. Vou aumentar o tamanho do título oito vezes, para que ele domine a cena Em seguida, duplique e repita para formar a outra palavra. Vou mover o pivô para ficar no centro do título. Em seguida, use âncoras personalizadas para centralizá-la horizontalmente na tela e a um terço da parte superior da Por enquanto, minha tela de título terá apenas dois botões, Novo jogo e Continuar. Eu gostaria que esses botões tivessem a mesma aparência que os da minha outra cena. Usando o mesmo tema, mas o tema que criamos é local para a cena do jogo. Passando para a cena do jogo, selecione qualquer nó que tenha o tema aplicado. Como o menu de fim de jogo. Expandindo o menu suspenso, podemos salvar o tema como um arquivo de recurso, disponibilizando-o para todo o projeto. Vou salvá-lo na pasta raiz, chamando-o de madeira e papel na cena do título, selecionando o nó de controle dos botões O tema de papel de madeira agora está disponível no menu de carregamento rápido e seus filhos herdam o tema Vou aumentar a escala dos botões quatro vezes e reposicioná-los no canto inferior esquerdo Em seguida, preencherei cada botão com caixas horizontais cheias de Recs de textura para soletrar seus rótulos, mantendo a proporção das letras espaçando cada letra E dê aos botões um tamanho mínimo para caber em seu conteúdo. Ao redefinir o tamanho da etiqueta, eu a ancorarei no centro do botão e depois a duplicarei para criar a Redefinindo sua âncora. Vou deixar os botões um pouco maiores e reposicioná-los. Desativarei o botão de continuação por padrão, pois não faria sentido permitir que o jogador o pressionasse. Se ainda não houver um arquivo, também podemos arrastar e soltar o fade, já que o salvamos como sua cena de zona Vamos ver como fica bom no script do arquivo. Vamos adicionar um novo método para verificar se o arquivo seguro existe. Devolvendo um touro. Por enquanto, ele pode simplesmente retornar falso. Assim como as cenas do jogo nó raiz tem um script de gerenciamento de jogos. Essa cena do título também precisará de um script de gerenciador de títulos. Esse script começará tornando o fade visível. Vou pegar uma referência ao botão contínuo usando at on ready. Em seguida, solicite o carregamento automático do arquivo se existe um arquivo digno para carregar. Se existir um arquivo de digitação, devemos definir a propriedade desativada do botão continuado como falsa, permitindo que o player o pressione. Em seguida, diga ao fade to fade para iniciar o jogo. Conectar o botão pressionado sinaliza para o gerenciador de títulos. Podemos adicionar métodos para lidar com os dois botões. Se o jogador pressionar o botão do novo jogo, direi ao carregamento automático do arquivo para criar um novo recurso de dados Depois de esperar fade, fade to black, carregarei a cena do jogo, que carregará o primeiro nível do meu jogo usando get tree change scene to file, que usa um argumento de string representando o caminho do arquivo para a cena que queremos Explorando o sistema de arquivos, podemos encontrar a cena do jogo clicando com o botão direito do mouse e copiando seu caminho. Em seguida, cole-o entre aspas. Se eles pressionarem o botão continuar, eu direi para o arquivo ser carregado. Para carregar o recurso de dados. Em seguida, gostaria de ficar preto e mudar de cena como no novo botão do jogo, mas em vez disso, carregar a cena de seleção de níveis Vamos transformar as cenas em um método separado. Mude a cena, usando um parâmetro de string do caminho do arquivo de cenas. Então, tanto o novo jogo quanto o botão Continuar podem chamar a mudança de cena, mas mudar para cenas diferentes Até agora, você provavelmente já pressionou o botão Executar projeto acidentalmente em vez do botão Executar cena atual pelo menos uma vez e foi solicitado a definir uma cena padrão para o seu projeto Se você ainda não definiu uma cena principal, você pode clicar em selecionar Atual para definir essa cena do título como a cena principal. Como alternativa, você pode abrir as configurações do projeto, consultar a seção do aplicativo e definir a cena principal aqui usando o navegador de arquivos. Se olharmos em Ambiente de renderização, podemos alterar a cor padrão que é exibida quando o Cade não tem mais nada para renderizar, definindo-a como preta para cobrir qualquer lacuna entre o esmaecimento e o esmaecimento Agora, se apertarmos o botão Executar projeto, a cena do título desaparecerá do preto Como não existe nenhum arquivo, o botão Continuar permanece desativado, mas podemos clicar no botão do novo jogo. Isso fica preto e carrega o primeiro nível, permitindo que o jogador comece a jogar um novo jogo Nosso jogo agora tem uma cena de título que acessa a cena padrão do nosso projeto. Na próxima lição, adicionaremos a cena de seleção de níveis. Te vejo na próxima aula. 52. Seleção de nível de 6-3: Olá amigos. Na lição anterior, adicionamos uma tela de título e um menu principal ao nosso jogo. Nesta lição, adicionaremos uma cena de seleção de níveis. Eu criei uma cena básica, muito parecida com a cena do título, com apenas sprites animados de fundo de Roger e o leme do navio, uma camada de tela e Como fizemos com o recurso do tema, podemos abrir qualquer nível, selecionar o nó do mapa de blocos e salvar o conjunto de blocos como um recurso para que ele possa ser compartilhado por todo o projeto. Na cena de seleção de nível, adicionarei um nó do mapa de blocos e o carregarei com o recurso de conjunto de blocos. Em seguida, use o mapa de blocos para desenhar o convés de popa de um navio com Roger no leme Insinuando para o jogador que entre cada nível, Roger está navegando em seu navio Vamos ver como isso parece até agora. É bom exibir os níveis. Vou adicionar um contêiner de painel à tela. Amplie-o para combinar com todo o resto e defina seu tema para madeira e papel. Esse contêiner conterá uma caixa vertical, que conterá uma caixa horizontal para o título. Vou colocar quatro Ts de textura na caixa horizontal para soletrar os mapas de palavras, certificando-me de que eles mantenham suas proporções e permaneçam Também centralizarei o título como um todo e reduzirei a separação entre as letras. Abaixo do título, adicionarei um contêiner de grade. Isso funciona como uma caixa vertical ou horizontal, mas organiza seu conteúdo em uma grade simples Como cada mapa tem um quarto, vou transformá-lo em uma grade de dois por dois, definindo as colunas como duas. Cada célula da grade conterá outra caixa vertical contendo um botão e um painel, cujo tema foi definido para parecer papel. Definirei seu tamanho mínimo para 36 por 32 pixels, para que seja grande o suficiente para conter o nome do nível. Usando outra caixa horizontal para escrever um hífen, um, vou me certificar de que a etiqueta esteja ancorada no centro do papel Sinta-se à vontade para nomear seus níveis como quiser para os botões. Não quero usar o botão verde. Posso removê-lo clicando no botão plano. Em vez de usar esses botões verdes e amarelos, definirei a propriedade do ícone dos botões sendo o mapa pequeno, uma textura. Vou me certificar de que o botão permaneça centralizado em sua célula de grade Sob o tema, substitui a expansão da seção de estilo. Também definirei o estilo de foco uma caixa de estilo vazia para que o botão permaneça invisível. Vou duplicar o nível 113 vezes para criar os outros botões na grade, alterando os rótulos de nome de cada um para coincidir com os níveis Você pode projetar essa interface para ter a aparência que quiser, acomodando quantos mundos quiser ter em seu jogo Mas isso é suficiente, por enquanto configurar o pivô dos contêineres do painel para ficar no centro Vou fixá-lo em dois terços do lado esquerdo da tela e um, dois na parte superior E altere os ícones dos botões para corresponder aos diferentes segmentos do mapa. Para animar esses ícones de botão, podemos selecionar uma nova textura animada no menu suspenso. Como há oito imagens na animação do pequeno mapa, adicionarei oito quadros a essa textura animada e, em seguida, definirei cada quadro adequadamente. Os valores padrão fazem com que essa animação seja reproduzida um quadro por segundo. Podemos alterar os comprimentos individuais dos quadros para 0,1 segundos ou definir a escala geral de velocidade de toda a textura para dez O botão não está renderizando, então vou alterar uma propriedade para forçá-la a ser atualizada Repetindo esse processo, definirei cada um dos quatro segmentos do mapa texturas animadas para os respectivos ícones de botão Vou remover o excesso de espaço na parte inferior do contêiner do painel redefinindo seu tamanho e dando mais espaço ao título com um tamanho mínimo personalizado Criação de um novo script para o gerenciador de seleção de níveis. Primeiro, vou pegar uma referência ao fade usando at on. Pronto. Quando estiver pronto, configurarei o desbotamento para ficar visível e, em seguida, direi que ele desapareça para ficar claro Escreverei um método personalizado para conectar os botões ao nível selecionado, que tomará o mundo e o nível como parâmetros, ambos representados por números inteiros Conecte o sinal de botão pressionado do botão de nível um ao gerenciador de seleção de nível e escolha esse novo método. Em seguida, expandindo o avançado, podemos adicionar dois argumentos inteiros à conexão do sinal, o mundo e o nível, ambos com o valor um Definindo os valores dos dados de pontos do arquivo, do mundo de pontos e do nível como seus novos valores. Podemos então esperar, escurecer e carregar a cena do jogo A cena do jogo manipulará automaticamente o carregamento do nível correto com base nos dados do arquivo. Lembre-se de que, para um nível seja carregado usando esse método, ele deve estar na pasta de cenas do nível e nomeado usando o formato correto para ser detectado. Podemos então conectar o resto dos botões ao mesmo método, alterando os valores dos argumentos para corresponder ao mundo e ao nível que serão carregados, garantindo que o destino esteja acima de todo o resto. Ao posicioná-lo na parte inferior da lista de nós, reduzirei a separação das caixas verticais para que elas ocupem menos espaço. Em seguida, redefina o tamanho e a posição do menu pela última vez. Vamos testá-lo executando a cena atual. Depois que a cena desaparece, clicando no primeiro nível, um botão desaparece novamente e carrega o primeiro Se fizermos isso novamente, clicar em um botão diferente carregará um nível diferente. Nosso jogo agora tem uma cena de seleção de níveis, que permite ao jogador carregar qualquer nível em nosso jogo. Na próxima lição, permitiremos que o jogo salve e carregue os dados do jogador. Te vejo na próxima aula. 53. 6-4 Salvar: Olá amigos. Na lição anterior, adicionamos uma cena de seleção de níveis que pode carregar qualquer nível em nosso jogo. Nesta lição, faremos com que os dados de progressão dos jogadores sejam salvos e carregados no script do arquivo Já configuramos muitos dos métodos que precisaremos concluir nesta lição Em outros motores e ao lidar com a economia de consoles, é difícil aprender a carregar Mas, para os propósitos do nosso jogo, o Godot Engine fornece maneiras simples de realizar exatamente o que precisamos Primeiro, precisamos saber onde armazenar o arquivo. Vamos declarar uma variável chamada path do tipo string. Iniciar o caminho com o cólon do usuário Godot encontrará automaticamente o local apropriado para armazenar nosso arquivo, digamos Na maioria das plataformas, podemos dar um nome ao arquivo. Vamos chamá-lo de salvamento automático. A extensão do nosso recurso de texto é RS. Como esse é um valor que nunca deve ser alterado, declararei a constante em vez de uma variável Essa é uma forma mais eficiente de armazenar valores que você sabe que não mudarão. Ao contrário das variáveis que são projetadas para mudar, o objetivo principal é reutilizar o mesmo valor em vários lugares em todo o script sem reescrevê-lo todas as vezes O T significa texto, o que significa que o arquivo criado pode ser aberto, lido e até editado em qualquer editor de texto que não seja muito seguro. Mas a criptografia é muito ineficaz e geralmente não vale o esforço extra, não importa quantas medidas você tome Se alguém quiser trapacear, eles o farão. Eu recomendaria apenas se preocupar com a segurança de jogos multijogador online Para verificar se esse arquivo existe, tudo o que precisamos fazer é chamar o método exists do carregador de recursos passando o argumento da string path Para salvar o jogo, precisamos apenas chamar o método save do economizador de recursos, passando os dados a serem salvos e o caminho para sua localização Toda vez que chamamos de save, ele sobrescreve os dados salvos existentes Da mesma forma, o carregamento só precisa definir o valor dos dados como carregamento do carregador de recursos, fornecendo o mesmo caminho para o arquivo Essa é uma implementação simples de um único arquivo de salvamento automático Você pode facilmente vincular os comandos de salvamento e carregamento aos botões do menu. E até mesmo crie vários arquivos usando o mesmo processo. O gerenciador de títulos já está configurado para carregar os dados dos jogadores quando o botão continuar é pressionado. A questão é: quando devemos salvá-lo? Podemos começar salvando os dados ao mesmo tempo em que são criados. Lembre-se de que esse sistema de salvamento automático armazena apenas um arquivo, digamos Iniciar um novo jogo substituirá qualquer arquivo seguro existente Então, quando o botão do novo jogo é pressionado, se não houver um arquivo seguro existente, podemos chamar um novo método para iniciar um novo jogo, criar o novo arquivo salvo, salvá-lo e fazer a transição para a cena do jogo Se um arquivo de digitação existir, devemos pedir o consentimento do jogador antes de sobrescrever o arquivo existente Vou montar rapidamente um contêiner básico com a substituição da pergunta, salvar o arquivo e dois botões para sim e não E defina seus padrões de propriedade visíveis por padrão, obtendo uma referência à confirmação usando add on usando Vou torná-lo visível quando o jogador pressionar o botão do novo jogo, mas já existe um arquivo seguro Em seguida, conecte os botões sim e não ao script. Tudo o que N precisa fazer é ocultar essa confirmação, mas sim, começaremos um novo jogo. Por causa do formato do meu jogo, eu realmente não me importo com o que acontece durante um determinado nível. Para acompanhar a progressão dos jogadores no meu jogo, eu só preciso saber quando eles completam ou saem de um nível Para simplificar as coisas, posso salvar automaticamente o jogo sempre que o jogador entrar na cena de seleção de níveis No script do gerenciador de jogos, temos alguns botões no menu de pausa que ainda não estão funcionando Vamos adicionar as transições do menu de pausa do jogo à cena de seleção de níveis Quando eles pressionarem sair, retorne à cena do título. Esses métodos são acessados a partir do menu de pausa. A árvore de cenas é pausada quando essas transições acontecem quando uma nova cena é carregada, a árvore permanece Precisaremos retomar a árvore de cenas quando as outras cenas forem carregadas usando os métodos prontos do gerente Como o menu de pausa agora só retorna à cena do título, a cena do título deve ter um botão de saída para fechar o jogo Vou colocar isso no canto superior direito. Conecte o sinal pressionado ao script do gerenciador e espere que ele fique preto antes de chamar Get copiando o nó do botão de saída Podemos colá-lo na cena de seleção de nível e editar seu sinal para conectá-lo ao script do gerenciador de seleção de nível E espere que fique preto antes de mudar para a cena do título Vamos experimentá-lo. Depois de coletar uma moeda, posso sair do nível Voltando à cena de seleção de níveis, onde o progresso foi salvo automaticamente, fechando o jogo e rodando novamente. O botão Continuar está ativado porque o arquivo salvo existe para ser carregado. Pressionar continuar nos leva à cena de seleção de níveis, carregando qualquer nível. Podemos ver que o contador de moedas foi salvo e carregado entre as sessões, fechando o jogo e rodando-o novamente. Podemos tentar sobrescrever o arquivo salvo e receber uma confirmação antes de iniciar um novo jogo com zero moedas Nosso jogo agora salva e carrega os dados do jogador sempre que o jogador sai ou completa Na próxima lição, bloquearemos o acesso aos níveis e os desbloquearemos quando o jogador completar um nível Te vejo na próxima aula. 54. 6-5 Desbloquear: Olá amigos. Na lição anterior salvamos e carregamos a progressão do jogador Nesta lição, bloquearemos acesso aos níveis até que o jogador conclua o nível anterior para desbloqueá-lo em nosso recurso de dados Queremos rastrear informações sobre cada nível do nosso jogo, que são organizados em mundos Podemos declarar uma variável chamada Progress como uma matriz de mundos contendo uma matriz de níveis, uma matriz bidimensional, uma navalha vazia Por padrão, precisaremos inicializá-lo para ter o tamanho correto para nossas necessidades e preenchê-lo com valores iniciais Precisaremos de uma matriz para cada mundo e um valor para cada nível em cada mundo. Se eu tivesse dois mundos, a matriz ficaria assim, mas eu só tenho um. Vou remover o segundo subarray. Queremos que o primeiro nível do jogo seja desbloqueado. Por padrão, alterarei o valor 0 a 1 dependendo de quantos marcadores de progresso diferentes você deseja acompanhar por nível Lembrar seus códigos numéricos pode ser problemático. Podemos definir uma enumeração para descrever os diferentes marcadores de progresso, começando com o nível sendo bloqueado, depois desbloqueado e depois concluído Em seguida, inicialize o primeiro nível para desbloquear o progresso. Adicionar um método público para definir um marcador de progresso. Podemos usar o marcador de progresso como um parâmetro junto com um ID mundial e um ID de nível Em seguida, defina o valor do progresso indexado em mundo menos um, nível menos Como as matrizes começam em zero , nossos números de mundo e nível começam em um, usando o operador R equals com o marcador de progresso, dando a eles Supondo que a maioria dos marcadores de progresso sejam definidos para o nível que o jogador está jogando atualmente Mas ainda nos permite definir marcadores para outros níveis, se quisermos Como esses números estão sendo usados para indexar matrizes, devemos validá-los para evitar falhas Para que esses números sejam considerados índices de matriz válidos, eles devem ser maiores que zero e menores que iguais ao tamanho da matriz Já que estamos subtraindo um desses números. Se os índices da matriz não forem válidos, devemos retornar. Mas também podemos enviar uma mensagem para informar a nós ou a qualquer outro desenvolvedor sobre esse erro, com um aviso informando que o índice do marcador de progresso era inválido e exibindo o mundo dos IDs de nível que foram usados Essa é uma operação de bits, o que significa que ela não trata esse número como um número inteiro, mas como uma série de bits, uns e zeros. Se considerarmos que cada bit é um marcador de progresso , o primeiro marcador de progresso, o primeiro bit, bloqueia o nível, se for zero, e desbloqueia o nível, se for A próxima parte nos diz se o nível foi concluído, começando com zero, o que significa que ele não foi concluído, mas depois mudando para um para ser concluído. Se o nível começar com um valor de 0000, desbloqueá-lo se tornará 0001 e, em seguida, marcá-lo como concluído o tornará Como ele está desbloqueado e concluído, podemos alterar bits individuais usando operadores de bits, que nos permite codificar uma grande quantidade de informações em uma única variável Esse operador or definirá o valor do bit marcado pelo marcador de progresso como um Da mesma forma, podemos definir o bit como zero usando e igualando o marcador de progresso invertido com o operador adicionando um parâmetro adicional à Podemos ativar ou desativar o marcador de progresso. Eu terei o comportamento padrão definir o bit como um ou ligado, já que não pretendo nunca bloquear nada que tenha sido desbloqueado pelo jogador no meu Como uma única variável contém 32 bits, podemos rastrear até 32 bits diferentes de informações por nível. Dessa forma, adicionando marcadores de progresso à enumeração. Uma enumeração é apenas uma lista numerada. A entrada no topo da lista tem um valor padrão de zero. O próximo, depois 234, etc. Podemos alterar essas atribuições numéricas se quisermos, dando a bloqueado um valor zero, desbloqueado um e Mas também quero rastrear se o jogador abre um baú do tesouro nos meus níveis. O próximo marcador de progresso, em vez de ser três, será quatro Poderíamos ter até 32 valores diferentes nessa enumeração, cada vez dobrando o valor para oito, 16, etc. Se um em binário é 0012, é 0104, é valores diferentes nessa enumeração, cada vez dobrando o valor para oito, 16, etc. Se um em binário é 0012, é 0104, é 100. Cada marcador de progresso terá todos zeros, com apenas um bit tendo o valor um, que é o bit que será definido ou não definido pelo método do marcador de progresso definido Devemos remover bloqueado igual a zero, pois a maneira correta de bloquear um nível seria o marcador de progresso desbloqueado Também precisaremos verificar os valores de nossos marcadores de progresso, aceitando o marcador de progresso, os números identificação mundial e de nível Igual ao método set, mas retornando um booleano, podemos retornar o valor do progresso indexado pelo mundo em números de ID de nível menos Em seguida, aplique o operador final do bit com o marcador de progresso. Também devemos validar se os índices da matriz são válidos antes de usá-los, assim como acima, e esclarecer a mensagem de aviso para ser mais útil Isso retornará verdadeiro se o marcador de progresso estiver ligado ou falso se estiver desligado, ou se os índices não forem válidos na cena de seleção de nível Podemos controlar facilmente a qual nível o jogador tem acesso alternando a visibilidade dos botões de nível. O contêiner da grade classificará automaticamente o conteúdo visível No script Level Select Manager, podemos obter uma matriz dos filhos dos contêineres da grade usando add on ready declarando uma nova variável inteira como índice na matriz de botões de nível Em seguida, percorre os mundos na matriz de progresso. Novamente, através dos níveis em cada mundo. Podemos definir a propriedade visível de cada botão no contêiner da grade para corresponder se esse nível foi desbloqueado ou não Precisaremos adicionar um ao mundo e ao nível para obter os números de identificação adequados de seus índices de matriz e incrementar o índice do botão a cada No script de nível, podemos exportar variáveis para saber qual nível está desbloqueado ao concluir esse nível e definir seus valores padrão como um O comportamento padrão será desbloquear o primeiro nível, essencialmente sem realizar nada, mas sem causar erros Então, no script do gerenciador de jogos, quando o mapa é coletado, podemos definir o marcador de progresso do nível atual como concluído E também defina o marcador de progresso desbloqueado do nível que deve ser desbloqueado ao completar Em seguida, faça a transição para o nível, selecione a cena no primeiro nível. Vou definir seus valores exportados para desbloquear o segundo nível. De volta ao script do nível, podemos rastrear se o jogador abriu o baú, obtendo uma referência à chave e ao baú, se existirem. Usando at on ready get node ou null. Então, quando o nível for carregado pela primeira vez, se eles existirem e o jogador tiver aberto o baú desse nível , podemos remover a chave e dizer ao baú que ele já foi aberto no script do baú. Vamos adicionar um método público que já está aberto, limpando a matriz booty. Em seguida, a configuração é bloqueada como falsa e aberta para verdadeira quando o baú é saqueado Defina o marcador de progresso para esse nível em que o baú Vamos experimentá-lo. Começando um novo jogo, posso sair do primeiro nível para a cena de seleção de níveis, e somente o primeiro nível é desbloqueado Retornando ao primeiro nível, posso terminá-lo e retornarei à cena de seleção de níveis, onde o segundo nível foi desbloqueado Voltando ao primeiro nível novamente. Desta vez, abrirei o baú e retornarei à cena de seleção de níveis. Entrando no primeiro nível pela última vez para ver que a chave não está lá e o baú já está aberto. Agora, a progressão dos jogadores no jogo é monitorada pelo arquivo, digamos, desbloqueando o acesso a novos níveis à medida que Na próxima lição, adicionaremos música de fundo ao nosso jogo. Te vejo na próxima aula. 55. 6-6 música: Olá amigos. Na lição anterior, bloqueamos o acesso aos níveis até que o nível anterior fosse concluído pelo jogador. Nesta lição, adicionaremos música de fundo. Vamos começar na cena do título e adicionar um nó reprodutor de stream de áudio à cena. Poderíamos definir uma faixa de áudio aqui, pedir que ela fosse reproduzida automaticamente e ajustar o volume Em seguida, faça isso para cada cena no nível. Mas as transições de cena dificultariam nossas faixas de música e, como resultado, soariam bastante chocantes Assim como temos a tela ficando preta, a música em transição também deveria ser desbotada para música em transição também deveria ser proporcionar uma melhor experiência geral Vou deixar a reprodução automática ligada por enquanto e o volume no mínimo possível . Basicamente silenciado. A maioria dos desenvolvedores de jogos que também não são engenheiros de som tendem a pensar no volume como um flutuador, 0-1 com zero sendo silenciado e um sendo Mas o volume é, na verdade, medido em decibéis, que não escalam linearmente Duplicar decibéis não dobra o volume. A escala de volume aqui varia de 80 a 24 decibéis negativos Felizmente, não precisamos saber como isso funciona para poder usá-lo de forma eficaz. Vamos anexar um novo script a esse nó musical. Quando o jogo começa, o áudio reproduz automaticamente a faixa com o volume silenciado Podemos começar diminuindo suavemente o volume de zero até o nível desejado, declarando uma variável para armazenar o volume desejado Em termos mais simples e fáceis de entender, um float 0-1 com escala linear, a propriedade de volume dos nós do player de stream de áudio é denominada volume DB denominada volume Assim, podemos declarar outra nova variável, volume L, para linear, para representar o volume atual em uma escala linear e atribuir a ele um valor padrão de zero ou silenciado No método pronto, podemos garantir que o volume permaneça silenciado configurando o volume em decibéis para corresponder ao volume linear Convertendo-o com uma fórmula de conversão conveniente fornecida pelo Gade linear em decibéis, fornecendo o volume linear Definindo um método privado para diminuir o volume. Podemos usar o volume linear alvo como parâmetro. Junto com a duração do efeito destino, com o valor padrão de 1 segundo. Embora o volume linear não seja igual ao volume linear alvo, devemos mover o volume linear em direção ao volume linear alvo em uma pequena quantidade. Para isso, podemos obter o tempo delta do processo e dividir pela duração. Em seguida, defina os indecibéis de volume para corresponder ao volume linear e aguarde o próximo quadro do processo para fazer isso Feito tudo isso, podemos emitir o sinal para que qualquer pessoa que esteja ouvindo saiba que o destino do volume acabou Da forma como esse código é escrito, é óbvio que o valor da duração deve ser um número positivo. Para evitar possíveis erros ou loops infinitos, devemos verificar se o valor da duração é menor ou igual a zero Nesse caso, podemos ajustar o volume, omitir imediatamente o sinal e retornar Como a música provavelmente será incluída em todas as cenas do jogo, seria mais fácil transformá-la em um script de carregamento automático. Movendo o script para a pasta de carregamento automático. Abrindo a guia de carregamento automático das configurações do projeto. Podemos adicionar isso à lista de nós carregados automaticamente. Em seguida, exclua o nó do reprodutor de fluxo de áudio da nossa cena título. Para que qualquer gerenciador de cenas possa controlar a música de fundo com uma única linha de código, tudo o que precisamos fazer é definir dois métodos públicos, um para iniciar uma faixa e outro para pará-la. Começando com stop track, usaremos um tempo de fade como parâmetro, um float, com um valor padrão de 1 segundo Isso pode simplesmente chamar de fade. O volume linear alvo é zero, silenciado. Passar o tempo de atenuação é o argumento para a duração Em seguida, aguarde o sinal de volume Fade finished antes de interromper o fluxo de áudio Modo de jogador Para reproduzir uma faixa, podemos usar a faixa em questão como um parâmetro junto com o tempo de fade Configure o stream que está sendo reproduzido para essa nova faixa, peça para ela tocar e, em seguida, reduza o volume para o volume desejado durante o tempo de fade Mas e se uma faixa já estiver tocando? Podemos adicionar algumas verificações extras. Primeiro, verifique se a música já está tocando e, em seguida, verifique também se a faixa que está sendo reproduzida no momento é a mesma que queremos tocar. Se for esse o caso, não precisamos fazer absolutamente nada e podemos retornar. Também podemos usar essa oportunidade para ignorar faixas nulas. Caso contrário, o nó musical está tocando uma faixa diferente no momento. Devemos desvanecer essa faixa antes de usar a nova Chamando fade com um volume linear alvo de zero e aguardando o sinal de conclusão do volume fade , o restante do método pode funcionar da mesma forma na nova faixa, evitando cortes rígidos em evitando cortes rígidos cada um dos scripts do gerenciador de cena Podemos exportar uma variável para manter a faixa de música de fundo dessa cena. Então, no método pronto, antes de desaparecer, podemos dizer à música que toque a faixa musical Eu preencho essa variável com uma faixa de música da minha cena de seleção de nível de ativos importados Também exportarei uma variável para a música de fundo e tocarei a faixa durante o método de escrita. Vou usar a mesma música de fundo da cena do título para a cena de seleção de nível no script do gerenciador de jogos. Ao carregar um nível, solicitarei a faixa de música do nível. Dessa forma, cada nível pode definir sua própria música de fundo no script do nível, exportando uma variável de música e definindo uma faixa diferente das outras cenas E também adicionarei faixas de música aos meus outros níveis. Por fim, também adicionarei música ao script de encontro com o chefe, mas também declararei uma segunda variável para armazenar a faixa que estava tocando nível em que o encontro com o chefe começa Eu posso armazenar os níveis de música de fundo normal na segunda variável e depois interpretar o chefe. Música Quando o encontro com o chefe terminar, voltarei a jogar o nível normal música Preencher o encontro com o chefe foi algo mais intenso do que o nível normal Música Ao sair do jogo, também podemos atenuar a música de fundo Ao importar música de fundo, é importante que ela seja projetada para ser repetida dependendo de onde você obtém sua O loop pode estar codificado nos próprios arquivos e já ser capaz de fazer um loop para esses Preciso abrir as configurações de importação e definir o modo de loop para avançar. Em seguida, clique em Importar novamente, para que eles se repitam. Vamos experimentá-lo. A tela de título aparece com algumas músicas com tema pirata, pressione A música continua tocando durante a transição da cena pois a faixa musical é a mesma nas duas cenas. Ao entrar no nível de chefe, a música desaparece e desaparece com uma nova faixa entrando na arena do chefe A música de fundo padrão dos níveis é substituída por uma faixa musical mais intensa. Quando o chefe é derrotado, a música volta ao normal. Retornar à cena de seleção de níveis muda a música novamente e, ao sair do jogo a música se apaga antes de fechar a janela Nosso jogo agora reproduz música de fundo exclusiva para cada cena e nível, até mesmo permitindo que as faixas sejam alteradas temporariamente. Na próxima lição, exportaremos o jogo para ser jogado e testado. Te vejo na próxima aula. 56. 6-7 Exportação: Olá amigos. Na lição anterior, adicionamos música de fundo ao nosso jogo. Nesta lição, exportaremos o jogo para ser distribuído e testado. Antes de podermos exportar, Godot precisará baixar os modelos de exportação no menu do editor Selecione Gerenciar modelos de exportação. Selecione um espelho no menu suspenso e clique em Baixar e instalar. Esses modelos permitem que seu projeto Godot seja exportado para uma ampla variedade de formatos para distribuição Quando o processo estiver concluído, você poderá fechar o gerenciador de modelos de exportação. Nas configurações do projeto, já demos um nome ao nosso projeto. Você também pode adicionar uma descrição, um número de versão e um ícone para obter melhores resultados. Tente usar uma imagem de 256 por 256 pixels ou, no mínimo , com dimensões quadradas. Já definimos a primeira cena para ser executada. Se você estiver trabalhando para um estúdio ou editora, você também pode adicionar uma imagem aqui para isso. Talvez você queira fazer ajustes nas configurações de exibição para melhor se adequar ao projeto exportado, como usar como padrão a tela cheia em vez de Se você alterar alguma configuração de exibição, teste o jogo para garantir que seu jogo vendido seja exibido corretamente antes de exportá-lo Para alterar o ícone do jogo ao exportar para Windows, você precisará baixar um executável de edição RC executável Eu recomendo colocar esse arquivo na pasta Gio Projects, pois você provavelmente precisará usá-lo na maioria dos seus projetos, se não em todos. No menu do editor, abra as configurações do Editor em exportar Windows, há uma opção para adicionar o caminho para a configuração do executável de edição RC Agora, o Cado poderá editar ícones para projetos exportados do Windows se você tiver um certificado de assinatura de pacote Esse também é o local para fornecer essas informações Com todas as configurações definidas, agora podemos acessar o menu Projeto e clicar em Exportar. Clique no botão Anúncio e selecione a plataforma para a qual você deseja exportar seu projeto. Segundo, vou escolher o Web First. Não precisamos fazer muito para ajustar as configurações aqui. Explorando o caminho de exportação. Devemos criar uma nova pasta chamada Export, ou builds, se você preferir Em seguida, dentro dessa pasta, crie uma nova pasta para cada plataforma. Nesse caso, Web. O mais importante ao exportar para a Web é que o projeto tenha o nome de índice HTML Esse é o nome do arquivo que as plataformas da web procurarão ao incorporar seu jogo Se não estiver lá, não funcionará. Ao clicar em Exportar projeto, desmarque a caixa de seleção exportar com depuração para remover coisas como Em seguida, clique em Salvar. Quando estiver pronto, podemos fechar a janela. Depois que o projeto for exportado, encontre-o em seu navegador de arquivos Selecione todos os arquivos que foram criados por Godot e comprima-os em um arquivo zip chamado index Este é o arquivo que você enviará para incorporar seu jogo em plataformas de hospedagem na web, como Itch. Nas opções de incorporação dessas plataformas. O suporte ao buffer de matriz compartilhada pode ser necessário para que o Essa é uma das maneiras mais fáceis de distribuir versões iniciais de seus jogos Plataformas como essa também permitem que você venda seus jogos. Mas e se o seu jogo for muito bom e você quiser vendê-lo profissionalmente em plataformas como o Steam De volta à janela de exportação do projeto, podemos adicionar outra plataforma, desta vez, o Windows. Aqui, talvez você queira ajustar algumas das configurações, como definir como o ícone do jogo é redimensionado em um jogo de pixel art. O dimensionamento usando vizinho mais próximo manterá Você também pode adicionar o nome da sua empresa se tiver um nome e uma descrição. Direitos autorais, marcas registradas, etc. Vamos exportar isso para uma pasta separada da exportação para a web, criando uma nova pasta para Windows e renomeando o executável para corresponder ao nome do jogo Se você estiver distribuindo isso internamente para testes alfa, convém exportar uma compilação de depuração para testes beta, acesso antecipado ou Você também deve desativar a depuração nas configurações de depuração, removendo o invólucro do console Em seguida, exporte o projeto e salve. Depois que o processo de exportação estiver concluído, você poderá encontrar os arquivos exportados criados por Godot e seu Explorador de Arquivos, selecionar os arquivos, compactá-los em um arquivo zip e fazer o upload do zip compactado nas plataformas de distribuição para serem baixados O mesmo processo também pode ser usado para criar plataformas Mac, Linux, IOS e Android. Modelos de exportação para outras plataformas, como Nintendo ou Playstation, não são fornecidos por padrão Você deve ser aprovado pela plataforma antes que eles permitam que você use o SDK para criar jogos Nosso jogo agora é exportado e enviado para sites de distribuição como It ou Steam para ser jogado por qualquer pessoa Agora você tem todas as habilidades necessárias para criar uma plataforma e um jogo de pixels completos. Você pode criar mais níveis, ajustar e ajustar as coisas ao seu gosto e implementar mais ativos desse pacote de ativos Você também pode baixar outros pacotes de ativos ou criar seus próprios ativos para continuar adicionando novos conteúdos Tudo neste projeto é estruturado de forma a ser editado isoladamente. Você pode modificar suas cenas e scripts individuais se quiser. Cada implementação é apenas um modelo básico que você pode criar ou recriar seu próprio do zero e integrar ao jogo Alterar qualquer coisa, desde o comportamento da câmera até o gerenciamento dos arquivos salvos, deve ser fácil Graças à estrutura que construímos, vá em frente e crie seu jogo do jeito que você quiser. Em seguida, compartilhe-o com a turma fazendo o upload do projeto ou compartilhando um link para sua página Ch Reproduza os projetos enviados seus colegas e deixe feedback construtivo sobre o trabalho deles Obrigado por concluir o curso e não deixe de conferir meus outros cursos para aprendizado contínuo.