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.