Godot Engine: Meu Primeiro Jogo

De Aulas

Afluentes: Jogos Digitais, Usabilidade, desenvolvimento web, mobile e jogos

Visão Geral

Este tutorial é um guia passo a passo para você fazer um primeiro projeto de jogo no Godot. Você irá aprender como o editor da ferramenta trabalha, como estruturar um projeto e como construir um jogo 2D. Assume-se aqui que você já possui conhecimentos de programação.

O jogo que é visto nesse tutorial se chama "Dodge the Creeps!". Seu personagem se move para desviar dos inimigos enquanto for possível. Abaixo é mostrado uma prévia do resultado final:

Godot dodge preview.gif


Tpl note.png

Porque 2D? Jogos em 3D são muito mais complexos que jogos 2D. É interessante que você tenha uma boa compreensão de jogos em 2D antes que você possa se aventurar no desenvolvimento de jogos em 3D.

Configuração do Projeto

Execute seu programa Godot e crie um novo projeto. Depois baixe o arquivo dodge_assets.zip que contém as imagens e sons que você irá usar para criar o jogo. Descompacte este arquivo na pasta do seu projeto.

Este jogo usa o modo portrait, então é necessário ajustar o tamanho da janela do jogo. Para isso, vá em

Projet -> Project Settings -> Display -> Window

e altere para "Width" 480 e "Height" 720.

Organização do Projeto

Neste projeto, iremos criar três scenes independentes, Player, Mob e HUD, que irão ser combinadas na scene do jogo chamada Main. Em um projeto maior, pode ser aconselhável criar pastas para guardar as várias scenes e seus scripts, mas não há problemas colocar todos os seus arquivos na pasta principal do projeto em um jogo relativamente pequeno. A pasta principal do projeto é referenciada no Godot como res://, tal como visto na figura abaixo:

Godot filesystem dock.png

Player

Vamos iniciar criando um objeto para o jogador, chamado Player. Uma das vantagens de se criar o Player em sua própria scene é que podemos testá-lo separadamente, mesmo antes de criar outras partes do jogo. Podemos fazer isso também para outros elementos ou personagens do jogo.

Node Structure

Para começar, clique No botão +, conforme imagem abaixo, para criar um novo Node e adicione um node Area2D na scene, conforme imagem abaixo:

Godot add node.png

Com uma Area2D é possível detectar colisão com outros objetos. Altere o nome para Player clicando no nome do node. Este é o node raiz da scene. Podemos adicionar outros nodes à este para dar outras funcionalidades.

Antes de adicionarmos qualquer node filho de Player, precisamos ter certeza de que não iremos mover ou alterar o tamanho acidentalmente clicando no objeto. Para isso, selecione o node e clique no ícone a direita para travar o objeto, conforme figura abaixo.

Godot lock children.png


Tpl note.png

Para salvar a scene basta clicar em Scene -> Save ou pressionar Ctrl+S no windows/linux ou Command+S no Mac.

Animação de Sprite

Clique no node Player e adicione um node AnimatedSprite como filho. O AnimatedSprite irá cuidar da aparência e animação do nosso personagem.

Veja que há um símbolo de atenção próximo do node. Isso porque um AnimatedSprite requer um recurso de SpriteFrames, que é uma lista de animações que podem ser apresentadas.

Para criar uma animação:

  1. procure pela propriedade Frames no Inspector;
  2. clique <null> -> New SpriteFrames;
  3. no mesmo local, clique em <SpriteFrames> para abrir o painel para configuração dos SpriteFrames, conforme imagem abaixo.
Godot spriteframes panel.png

Na esquerda está localizada a lista das animações. Siga os procedimentos:

  1. clique na default e mude o seu nome para right;
  2. clique no botão adicionar para criar uma segunda animação chamada up;
  3. araste as duas imagens, conforme visto abaixo, para cada animação, nomeadas de playerGrey_up[1/2] e playergrey_walk[1/2] no painel Animation Frames.
Godot spriteframes panel2.png

As imagens do personagem do jogador são um pouco grandes para a janela do jogo, então precisamos diminuir o tamanho delas. Podemos fazer isso nas propriedades, clicando no node AnimatedSprite, Transform, e configurando a Scale para (0.5, 0.5). Você pode encontrar isso no Inspector, abaixo do cabeçalho Node2D.

Godot player scale.png

Por fim, adicione um CollisionShape2D como filho de Player. Isso irá determinar as colisões do personagem do jogador, ou a área para colisão. Para este personagem, um node CapsuleShape2D se ajusta melhor. Então próximo ao Shape no Inspector, clique em <null> -> New CapsuleShape2D. Redimensione o desenho para cobrir o sprite:

Godot player coll shape.png


Tpl note.png

Não redimensione a figura para muito fora da imagem. Tente deixar o mais próximo do tamanho do sprite.

Quando você tiver terminado esses passos, sua scene Player irá parecer da seguinte forma:

Godot player scene nodes.png

Movimentando o Player

Agora podemos adicionar algumas funcionalidades por meio de scripts. Clique no node Player e no botão adicionar script à direita:

Godot add script button.png

Na janela de configuração do script, você pode deixar tudo no padrão e apenas clicar em Create:

Godot attach node window.png

Para começar, vamos declarar as variáveis necessárias para o nosso objeto:

extends Area2D

export (int) var SPEED  # how fast the player will move (pixels/sec)
var screensize  # size of the game window

A palavra-chave export na primeira variável SPEED nos permite setar seu valor no Inspector (figura abaixo). Esse recurso pode ser bastante útil para valores que você quer ajustar usando a ferramenta gráfica das propriedades. Lá, clique no node Player e configure a propriedade speed para 400.

Godot export variable.png

A função _ready() é chamadad quando o node entra na scene tree, que é uma boa hora para saber o tamanho da janela do jogo:

func _ready():
    screensize = get_viewport_rect().size

Agora usamos a função _process() para definir o que o personagem faz. A função _process() é chamada em cada frame. Dessa forma, podemos utilizá-la para atualizar os elementos do nosso jogo. Para este jogo, iremos fazer o seguinte:

  • Verificar as entradas;
  • Mover o personagem conforme a direção dada;
  • Rodar a animação correspondente.

Primeiro precisamos verificar as entradas, que nesse caso são as teclas que o jogador irá clicar. Para esse jogo teremos 4 direções, ou entradas para verificar. As ações de entrada são definidas no Project Settings no Input Map. Você pode definir eventos customizados e atribuir teclas diferentes, eventos de mouse ou outro tipos de entradas. Para este jogo vamos usar os eventos padrões que já estão configurados para as teclas de setas no teclado.

Você pode detectar uma tecla pressionada usando Input.is_action_pressed(), que retorna true se alguma tecla foi pressionada ou false em caso contrário.

func _process(delta):
    var velocity = Vector2() # the player's movement vector
    if Input.is_action_pressed("ui_right"):
        velocity.x += 1
    if Input.is_action_pressed("ui_left"):
        velocity.x -= 1
    if Input.is_action_pressed("ui_down"):
        velocity.y += 1
    if Input.is_action_pressed("ui_up"):
        velocity.y -= 1
    if velocity.length() > 0:
        velocity = velocity.normalized() * SPEED
        $AnimatedSprite.play()
    else:
        $AnimatedSprite.stop()

Na função acima verificamos cada entrada e adicionamos ou subtraímos da variável velocity para obter a direção total. Por exemplo, se você segurar a seta direita e a seta para baixo ao mesmo tempo, o resultado em velocity será um vetor (1, 1). Nesse caso, quando fazemos um movimento horizontal e um vertical ao mesmo tempo, o personagem ira se mover mais rápido do que se apenas se movesse horizontalmente ou só verticalmente.

Podemos prevenir isso usando a normalização da velocidade, ou seja, configurar o comprimento do nosso vetor para 1 e multiplicar pela velocidade desejada. Isso significa que o movimento diagonal não será mais rápido do que deveria ser.


Tplnote Bulbgraph.png

Se você nunca usou vetores matemáticos antes, ou precisa refrescar sua memória, você pode ver uma explicação sobre o uso de vetores no Godot em Vector math. É sempre bom ter um certo conhecimento sobre isso, mas não é necessário para o resto desse tutorial.

Também verificamos se o jogador está se movendo ou não para que possamos iniciar ou interromper a animação do AnimatedSprite.


Tplnote Bulbgraph.png

O sinal $ retorna o node do caminho relativo desse node, ou retorna null se o node não foi encontrado. Sendo que o node AnimatedSprite é filho do corrente node, nos podemos usar apenas $AnimatedSprite.

Na verdade, o sinal $ é um atalho para get_node(). Então, o código $AnimatedSprite.play() é o mesmo que get_node("AnimatedSprite").play().

Agora que temos o movimento direcional do personagem do jogador, podemos atualizar a posição do Player e usar a função clamp() para prevenir do personagem sair da tela:

position += velocity * delta
position.x = clamp(position.x, 0, screensize.x)
position.y = clamp(position.y, 0, screensize.y)


Tplnote Bulbgraph.png

Fazer um clamping em um valor, significa restringi-lo à um dado alcance (range).

Depois disso, clique em Play Scene) ou pressione a tecla F6 e verifique que você consegue mover o personagem na tela para todas as direções.

Tpl warning.png

Se você encontrar algum erro no painel Debugger que se refere à uma null instance, isso pode significar que você chamou errado o nome do node. O nome do node é case-sensitive e $NodeName ou get_node("NodeName") precisa fechar com o nome que você vê na scene tree.

Escolhendo as Animações

Agora que nosso personagem pode se movimentar, precisamos mudar a animação no AnimatedSprite para corresponder à direção. Veja que temos a animação right que pode ser espelhada horizontalmente usando a propriedade flip_h para o movimento para a esquerda e a animação up pode ser espelhada verticalmente usando o flip_v para o movimento para baixo. Vamos adicionar o seguinte código na função _process():

if velocity.x != 0:
    $AnimatedSprite.animation = "right"
    $AnimatedSprite.flip_v = false
    $AnimatedSprite.flip_h = velocity.x < 0
if velocity.y != 0:
    $AnimatedSprite.animation = "up"
    $AnimatedSprite.flip_v = velocity.y > 0

Ao rodar a cena novamente, verificamos que a animação está correspondente com cada direção. Depois de conferido que os movimentos estão funcionando corretamente, adicione a seguinte linha abaixo função _ready(). Isso vai garantir que o personagem vai estar invisível quando o jogo começar.

hide()

Preparando para as Colisões

Queremos que o nosso personagem detecte quando ele se choca com os inimigos, mas não temos inimigos ainda! Isso não importa porque iremos utilizar a funcionalidade de signal do Godot para fazer isso funcionar.

Adicione a linha abaixo no início do nosso script, depois de extends Area2d:

signal hit

Isso define um sinal customizado chamado hit que nosso personagem vai emitir quando colidir algum inimigo. Iremos usar o Area2D para detectar a colisão.

Selecione o node Player e clique na aba Node, ao lado da aba Inspector, para ver a lista de sinais que o nosso personagem pode emitir:

Godot player signals.png

Observe ali que o nosso sinal customizado hit está aparecendo também! Como nossos inimigos serão nodes do tipo RigidBody2D, usaremos a função body_entered(Object body) que será chamado quando o corpo colidir com o nosso personagem.

Clique em Connect.. e então Connect novamente na janela Connecting Signal. Não precisamos alterar qualquer configuração, o Godot irá criar automaticamente a função chamada _on_Player_body_entered no script do nosso personagem.


Tplnote Bulbgraph.png

Ao conectar um sinal, em vez de fazer com que o Godot crie uma função pra você, você pode fornecer também o nome de uma função já existente, da qual deseja vincular o sinal

Adicione o seguinte código na função criada:

func _on_Player_body_entered( body ):
    hide() # Player disappears after being hit
    emit_signal("hit")
    $CollisionShape2D.disabled = true


Tpl note.png

Desabilitar a área de colisão significa que as colisões não serão mais detectadas. Assim, garantimos que o gatilho do signa hit não será acionado.

Agora vamos adicionar uma função que será chamada para reinicializar o personagem quando um novo jogo inicia.

func start(pos):
    position = pos
    show()
    $CollisionShape2D.disabled = false

Inimigo (Mob)

Para criar a scene' do nosso inimigo, clique em Scene -> New Scene e renomeie para Mob.

A scene Mob irá usar os seguintes nodes:

Não se esqueça de configurar o Mob para não poder ser selecionado, assim como fizemos na scene Player.

Nas propriedades do RigidBody2D, configure a Gravity Scale para 0. Assim o mob não vai ficar caindo. Também, abaixo da sessão PhysicsBody2D, clique na propriedade Mask e retire a seleção da primeira caixa. Isso irá garantir que os mobs não irão colidir uns com os outros.

Godot set collision mask.png

Configure o AnimatedSprite tal como foi feito no Player. Veja que agora temos três animações: fly, swim e walk. Configure a propriedade Playing no Inspector para On e ajuste a Speed (FPS) tal como é visto na imagem abaixo. Iremos selecionar uma dessas animações randomicamente para que nossos mobs tenham uma certa variedade.

Godot mob animations.gif

O fly' deve ser setado para 3 FPS, e os outros dois para 4 FPS.

Assim como as imagens do Player, as imagens dos mobs precisam ser diminuídas. Para isso, configure a propriedade Scale do AnimatedSprite para (0.75, 0.75).

Em tempo, tal como na scene Player', adicione uma CapsuleShape2D para as colisões. Para alinhar a figura com a imagem, será necessário alterar a propriedade Rotation Degrees para 90 sob o Node2D.

Script do Inimigo

Para começar, adicione um script para o Mob e coloque nele as seguintes variáveis:

extends RigidBody2D

export (int) var MIN_SPEED # minimum speed range
export (int) var MAX_SPEED # maximum speed range
var mob_types = ["walk", "swim", "fly"]

Iremos colocar um valor aleatório entre MIN_SPEED e MAX_SPEED para a velocidade que o mob se movimenta. Seria chato se todos eles se movimentassem com a mesma velocidade. No Inspector, altere essas variáveis para 150 e 250. Também teremos um vetor contendo os nomes das 3 animações que serão selecionadas aleatoriamente para cada mob.

Vamos arrumar nosso script _ready() para escolher aleatoriamente uma das 3 animações.

func _ready():
    $AnimatedSprite.animation = mob_types[randi() % mob_types.size()]


Tpl note.png

você precisa usar a função randomize() se quiser que a sequência de números aleatórios seja diferente a cada vez que a scene for executada. Iremos colocar o randomize() na nossa scene Main. Para retornar um número inteiro aleatório entre 0 e n-1, usaremos randi() %n.

Agora iremos fazer com que os mobs deletem a si mesmos quando eles saem da janela. Para isso, conecte o signal screen_exited() do node VisibilityNotifier2D e adicione o seguinte código:

func _on_Visibility_screen_exited():
    queue_free()

Com isso completamos a scene Mob.

Principal (Main)

Agora chegou o momento de juntar tudo. Vamos criar uma nova scene ea dicionar um Node chamado Main.

Clique no botão Instance e selecione sua scene já salva chamada Player.tscn.

Godot instance scene.png


Tpl note.png

Para aprender um pouco mais sobre instanciação, veja Instancing

Agora adicione os seguintes nodes como filhos de Main, e altere o nome deles em conformidade com o que é mostrado abaixo:

  • Timer (MobTimer): para controlar a criação de mobs;
  • Timer (ScoreTime): para incrementar a pontuação a cada segundo;
  • Timer (StartTimer): para dar um tempinho depois do início;
  • Position2D (StartPosition): para indicar a posição inicial do personagem do jogador.

Depois configure a propriedade Wait Time de cada um dos nodes Timer conforme as especificações a seguir:

  • MobTimer: 0.5;
  • ScoreTimer: 1;
  • StartTimer: 2.

Ainda, altere a propriedade One Shot do StartTimer para On e altere a Position do node StartPosition para (240, 450).

Criação de Mobs (spawning)

O node Main irá criar novos mobs que queremos que apareça em uma posição aleatória fora da tela. Adicione um node Path2D chamado MobPath como filho de Main. Quando você selecionar o Path2D, verá que aparecem alguns novos botões em cima do editor:

Godot path2d buttons.png

Selecione o botão do meio (Add Point e desenhe o caminho clicando nos cantos da cena. Certifique-se de que o Snap to Grid está selecionado. Essa opção pode ser encontrada sob o botão Snapping options à esquerda do botão Lock, aparecendo como uma série de três pontos verticais.

Godot draw path2d.gif


Tpl note.png

Desenhe o caminho no sentido horário, ou seus mobs irão aparecer indo para fora e não para dentro!

Depois de colocar o ponto 4 na imagem, clique no botão Close Curve e as linhas irão se completar.

Agora que o path está definido, adicione um node PathFollow2D como filho de MobPath e o renomeie para MobSpawnLocation. Este node irá rotoacionar automaticamente e seguir o caminho conforme ele se move. Isso serve para que possamos usá-lo para selecionar uma posição e direção aleatórias ao longo do caminho.

Main Script

Adicione um script para a scene Main. No início do script vamos usar um export (PackedScene) para nos permitir escolher a scene Mob que queremos instanciar.

extends Node

export (PackedScene) var Mob
var score

func _ready():
    randomize()

Arraste o Mob.tscn do painel FileSystem para a propriedade Mob sobre o Script Variables do node Main.

Depois, ainda no node Main, clique em Player e conecte o signal hit e dê o nome da função de game_over. Adicione o código abaixo nessa nova função:

Next, click on the Player and connect the hit signal. We want to make a new function named game_over, which will handle what needs to happen when a game ends. Type “game_over” in the “Method In Node” box at the bottom of the “Connecting Signal” window. Add the following code, as well as a new_game function to set everything up for a new game:

func game_over():
    $ScoreTimer.stop()
    $MobTimer.stop()

Adicione também uma função chamada new_game:

func new_game():
    score = 0
    $Player.start($StartPosition.position)
    $StartTimer.start()

Agora conecte o signal timeout() de cada um dos nodes Timer. O StartTimer irá iniciar os outros dois timers. ScoreTimer irá incrementar a pontuação em 1.

func _on_StartTimer_timeout():
    $MobTimer.start()
    $ScoreTimer.start()

func _on_ScoreTimer_timeout():
    score += 1

Na função _on_MobTimer_timeout() iremos criar uma instancia mob colocando ela em uma posição inicial aleatória por meio do Path2D e configurando a movimentação do mob.

O node PathFollow2D irá automaticamente rotacionar o mob para seguir um caminho específico.

Veja que a nova instância precisa ser adicionada à scene usando um add_child().

func _on_MobTimer_timeout():
    # choose a random location on Path2D
    $MobPath/MobSpawnLocation.set_offset(randi())
    # create a Mob instance and add it to the scene
    var mob = Mob.instance()
    add_child(mob)
    # set the mob's direction perpendicular to the path direction
    var direction = $MobPath/MobSpawnLocation.rotation + PI/2
    # set the mob's position to a random location
    mob.position = $MobPath/MobSpawnLocation.position
    # add some randomness to the direction
    direction += rand_range(-PI/4, PI/4)
    mob.rotation = direction
    # choose the velocity
    var rand_x = rand_range(mob.MIN_SPEED, mob.MAX_SPEED)
    mob.set_linear_velocity(Vector2(rand_x, 0).rotated(direction))


Tpl note.png

Nas funções que trabalham com ângulo, o GDScript usa radianos e não graus. Se você se sentir mais confortável para trabalhar com graus, será necessário utilizar as funções deg2rad() e ra2deg() para fazer a conversão entre os dois.

HUD

A HUD (do inglês: heads-up display - tela de alerta) é a sigla para representação dos objetos do jogo, tais como: vida, magia, pontos de experiência (XP), etc.

Como parte final para nosso jogo, vamos criar uma HUD. Nela teremos informações como pontuação, mensagem Game Over e um botão para reinicializar o jogo. A HUD será nossa interface do usuário (UI - User Interface).

Para isso, crie uma nova scene e adicione um node CanvasLayer chamado HUD.

O node CanvasLayer vai nos permitir desenhar nosso elementos da interface do usuário em cima do resto do jogo, ou seja, as informações irão aparecer na frente de todos os outros objetos do jogo.

A HUD terá as seguintes informações:

  • Pontuação, que será alterada pelo ScoreTimer;
  • Uma mensagem, tal como Game Over ou Get Ready!;
  • Um botão Start para iniciar o jogo.

O node básico para os elementos da nossa UI é o Control. Para criar nossa UI, usaremos dois tipos de nodes Control: Label e Button.

Crie os seguintes nodes filhos do node HUD:

  • Label chamado ScoreLabel;
  • Label chamado MessageLabel;
  • Button chamado StartButton;
  • Timer chamado MessageTimer.


Tpl note.png

Âncoras e Margens: Os nodes de Control têm uma posição e tamanho, mas também possuem âncoras e margens. As âncoras definem a origem - ponto de referência para as bordas do node. As margens são atualizadas automaticamente quando você move ou redimensiona um node Control. Eles representam a distância das bordas do node de Control até sua âncora. Veja Design interfaces with the Control nodes para saber mais detalhes.

Organize os nodes tal como mostrado na figura abaixo. Clique no botão Anchor (âncora) para configurar a âncora do node do Control.

Godot ui anchor.png

Você pode arrastar os nodes para os lugares manualmente ou pode, mais precisamente, usar as seguintes configurações:

ScoreLabel
  • Layout: “Center Top”
  • Margin:
    • Left: -25
    • Top: 0
    • Right: 25
    • Bottom: 100
  • Text: 0
MessageLabel
  • Layout: “Center Bottom”
  • Margin:
    • Left: -100
    • Top: -200
    • Right: 100
    • Bottom: -100
  • Text: Dodge the Creeps!
  • Selecionar Autowarp
StartButton
  • Layout: “Center”
  • Margin:
    • Left: -60
    • Top: 70
    • Right: 60
    • Bottom: 150
  • Text: Start

A fonte padrão para os nodes Control são muito pequenas e não ficam muito bem quando redimensionadas. Há uma fonte inclusa nos assets do jogo chamada Xolonium-Regular.ttf. Para usar essa fonte, faça o seguinte procedimento para cada elemento da árvore do node Control:

1. Sob o Custom Fonts, escolha New DynamicFont

Godot custom font1.png

2. Clique no DynamicFont adicionado, em Font Data escolha Load e selecione o arquivo Xolonium-Regular.ttf. Você precisa também alterar o tamanho da fonte em Size para o valor 64.

Godot custom font2.png

Agora adicione o script abaixo para o HUD:

extends CanvasLayer

signal start_game

O signal start_game irão informar ao node Main que o botão foi pressionado.

func show_message(text):
    $MessageLabel.text = text
    $MessageLabel.show()
    $MessageTimer.start()

Essa função é chamada quando queremos mostrar uma mensagem temporariamente, tal como a Get Ready. Em MessageTimer, altere o Wait Time para 2 e altere a propriedade One Shot para On.

func show_game_over():
    show_message("Game Over")
    yield($MessageTimer, "timeout")
    $StartButton.show()
    $MessageLabel.text = "Dodge the\nCreeps!"
    $MessageLabel.show()

Essa função é chamada quando o jogador perde. Isso irá mostrar a mensagem Game Over por 2 segundos e retornar para a tela de título, que irá mostrar o botão Start.

func update_score(score):
    $ScoreLabel.text = str(score)

Essa função é chamada no Main sempre que a pontuação for alterada.

Conecte o signal timeout() da MessageTimer e o signal pressed() do StartButton.

func _on_StartButton_pressed():
    $StartButton.hide()
    emit_signal("start_game")

func _on_MessageTimer_timeout():
    $MessageLabel.hide()

Conectando o HUD ao Main

Com nossa scene HUD criada, salve-a e volte para Main'. Instancie a scene HUD em Main tal como foi feito com Player e coloque-o bem abaixo na árvore. A árvore completa deve se parecer com a apresentada abaixo. Verifique se não está faltando nada:

Godot completed main scene.png

Depois precisaremos conectar as funcionalidades da HUD ao nosso script do Main. Isso requer algumas adições na scene Main.

Na aba Node, conecte o signal start_game do HUD à função new_game() do script da scene Main.

Em new_game(), atualize a pontuação para mostrar a mensagem Get Ready:

$HUD.update_score(score)
$HUD.show_message("Get Ready")

Em game_over() precisaremos chamar a função correspondente do HUD:

$HUD.update_score(score)
$HUD.show_game_over()
$HUD.show_message("Get Ready")

Finalmente, adicione em _on_ScoreTimer_timeout() as linhas abaixo. Elas servirão para manter em sincronia a pontuação com a informação da pontuação na tela.

$HUD.update_score(score)

Agora você está pronto para jogar! Clique no botão Play the Project. Você deverá informar a scene principal, então escolha a Main.tscn.

Finalizando

Temos agora um jogo completamente funcional, mas ainda estão sobrando alguns elementos para dar uma refinada na experiência do jogo. Sinta-se livre para alterar o gameplay com suas próprias ideias.

Fundo

Se você não achar fundo cinza padrão muito atraente, você pode alterar a cor. Uma forma de fazer isso é usar um node ColorRect. Crie-o como primeiro node filho de Main, para que ele seja o primeiro node de Main a ser desenhado. Caso contrário, ele será desenhado em cima dos outros nodes. O node ColorRect possui apenas uma propriedade, a Color. Escolha a cor que te agradar melhor e redimencione o tamanho do ColorRect para que ele cubra a tela.

Efeitos Sonoros

Sons e música podem ser adicionados para dar mais efeitos e melhorar a experiência do jogo. No seu game, na pasta assets, você vai encontrar dois arquivos de som: "House In a Forest Loop.ogg" para a música de fundo e "gameover.wav" para quando o jogador perder.

Adicione dois nodes AudioStreamPlayer como filhos de Main. Renomeie-os para Music e DeathSound. Em cada um deles, clique na propriedade Stream, selecione Load e escolha o arquivo de áudio correspondente.

Para tocar a música, adicione $Music.play() na função new_game() e $Music.stop() na função game_over().

Finalmente, adicione $DeathSound.play() na função game_over().

Partículas

Como um último toque visual, vamos adicionar um efeito que deixa um rastro que segue o movimento do personagem do jogador. Escolha seu scene Player e adicione um node Particules2D chamado Trail.

Existem várias propriedades que você pode trabalhar para configurar partículas. Sinta-se livre para experimentar e criar diferentes efeitos. Para esse jogo de exemplo, usaremos a seguinte configuração:

Godot particle trail settings.png

Você também precisa criar um Material clicando em <null> e então New ParticlesMaterial. As configurações para ele serão as seguintes:

Godot particle trail settings2.png

Para criar um gradiente para as configurações da Color Ramp, iremos usar um gradiente que usa o alpha (transparência) do sprite de 0.5 (semitransparente) até 0.0 (totalmente transparente).

Clique em New GradientTexture e, abaixo de Gradient, clique em New Gradient. Você irá ver a janela abaixo:

Godot color gradient ui.png

As caixinhas a esquerda e a direita representam a cor inicial e final. Clique em cada uma delas e no quadro maior na direita para escolher a cor. Para a primeira cor, defina o valor de A (alpha) para mais ou menos na metade. Para o segundo, defina o todo para 0.


Tpl note.png

Veja também Particles2D para maiores detalhes sobre o uso de efeitos de partículas.


Arquivos do Projeto

Você pode encontrar uma versão completa desse projeto aqui: https://github.com/kidscancode/Godot3_dodge/releases


Tpl note.png

Esse tutorial é uma tradução livre de um trecho da documentação do Godot Engine.