Mudanças entre as edições de "Godot Engine: SkyFire"
Linha 1: | Linha 1: | ||
+ | |||
Linha 16: | Linha 17: | ||
Veja que: | Veja que: | ||
− | * todas as | + | * todas as Cenas que possuem ''scripts'' coloquei uma tag [''script''] no nó que ele deve ser criado. |
− | |||
* Depois de criado os ''scripts'', em alguns nós da cena devemos criar sinais. | * Depois de criado os ''scripts'', em alguns nós da cena devemos criar sinais. | ||
* Crie os sinais só depois da estrutura e do ''script'' criados. | * Crie os sinais só depois da estrutura e do ''script'' criados. | ||
+ | * A Cena <code>Sky</code> vou explicar um pouco melhor porque vamos precisar fazer um ''scrolling'' na imagem de fundo e vamos usar um recurso bem legal do Godot. | ||
Abaixo temos a estrutura de Cenas e nós. | Abaixo temos a estrutura de Cenas e nós. | ||
− | * | + | * Sky (Node2D) |
− | ** | + | ** TextureRect |
− | |||
* Ship (CharacterBody2D) [''script''] | * Ship (CharacterBody2D) [''script''] | ||
** Sprite2D | ** Sprite2D | ||
Linha 49: | Linha 49: | ||
** Label (Label) | ** Label (Label) | ||
** Score (Label) | ** Score (Label) | ||
+ | |||
+ | == Cena Sky == | ||
+ | Vamos iniciar criando uma cena com um nó raiz do tipo <code>Node2D</code>. Renomeie esse nó para Sky e crie um nó filho do tipo <code>TextureRect</code>. | ||
+ | [[Arquivo:Godot skyfire cena sky.png|centro|commoldura|Cena Sky.]] | ||
+ | Clique no nó <code>TextureRect</code> e arraste a imagem <code>background.png</code> (dos nossos recursos do game) para a aba Inspector... RextureRect... Texture... | ||
+ | [[Arquivo:Godot skyfire arrastar textura.png|centro|miniaturadaimagem|279x279px|Arrastando a textura.]] | ||
+ | Ainda na aba Inspector, vamos em CamvasItem e então clique em Material, expandindo ele. Dentro tem um item chamado '''Material''' (também), clique do lado onde está '''[vazio]''' e adicione um Novo '''Shader Material'''. | ||
+ | [[Arquivo:Godot skyfire material.png|centro|commoldura|Adicionando Material.]] | ||
+ | Vai aparecer uma esfera cinza. Clique nela e vai expandir. Em baixo vai aparecer um elemento chamado '''Shader''' que está como '''[vazio]''', clique ali e adicione um '''Novo Shader'''. | ||
+ | [[Arquivo:Godot skyfire material shader.png|centro|commoldura|Novo Shader]] | ||
+ | Veja que ele vai pedir pra criar um ''script'' especial para esse shader. Como já renomeamos nosso nó raiz como '''Sky''', ele vai salvar como <code>sky.gdshader</code>. Salve esse ''script'' e clique no shader criado (em baixo da esfera). | ||
+ | [[Arquivo:Godot skyfire novo shader.png|centro|miniaturadaimagem|347x347px|Novo Shader.]] | ||
+ | Ele vai abrir uma ferramenta (imagem abaixo) para editar o ''script'' do shader. Vamos alterar o ''script''. | ||
+ | [[Arquivo:Godot skyfire shader editor.png|centro|miniaturadaimagem|623x623px|Editor de script do shader.]] | ||
+ | Não vamos precisar das funções ''<code>fragment</code>'' e ''<code>ligth</code>''. Então vamos excluí-las.<syntaxhighlight lang="python"> | ||
+ | shader_type canvas_item; | ||
+ | |||
+ | void vertex() { | ||
+ | UV.y -= TIME * 0.1; | ||
+ | } | ||
+ | </syntaxhighlight>Veja que na função ''<code>vertex</code>'', usamos o atributo UV.y e diminuímos ele conforme o TIME. Só que como fica muito rápido, multiplicamos por 0.1. | ||
+ | |||
+ | Por fim, para que a textura fique se repetindo, precisamos ir, ainda em CanvaItem, em Texture, selecionar Repeat e colocar '''Enabled'''. | ||
+ | [[Arquivo:Godot skyfire texture repeat.png|centro|commoldura|Deixando a textura em loop.]] | ||
+ | E pronto! Temos nosso fundo que fica se em modo ''scrolling''. | ||
= Scripts = | = Scripts = |
Edição das 09h31min de 21 de maio de 2024
Afluentes : Jogos Digitais, Usabilidade, desenvolvimento web, mobile e jogos
Screenshot
Já vimos alguns games passo a passo, agora vamos tentar um desafio. A partir dos assets, da estrutura do projeto, os scripts e algumas dicas, vamos tentar criar o game SkyFire. Abaixo temos um screenshot.
Assets
Estrutura
Veja que:
- todas as Cenas que possuem scripts coloquei uma tag [script] no nó que ele deve ser criado.
- Depois de criado os scripts, em alguns nós da cena devemos criar sinais.
- Crie os sinais só depois da estrutura e do script criados.
- A Cena
Sky
vou explicar um pouco melhor porque vamos precisar fazer um scrolling na imagem de fundo e vamos usar um recurso bem legal do Godot.
Abaixo temos a estrutura de Cenas e nós.
- Sky (Node2D)
- TextureRect
- Ship (CharacterBody2D) [script]
- Sprite2D
- CollisionShape2D
- Enemy (CharacterBody2D) [script]
- Sprite2D
- CollisionShape2D
- Bomb (CharacterBody2D) [script]
- Sprite2D
- CollisionShape2D
- SoundBomb (AudioStreamPlayer2D)
- Explosion (StaticBody2D) [script]
- AnimatedSprite2D
- Nó (sinal) - _on_animated_sprite_2d_animation_finished()
- CollisionShape2D
- SoundExplosion (AudioStreamPlayer2D)
- AnimatedSprite2D
- World (Node2D) [script]
- Background (instancia)
- Ship (instancia)
- EnemiTimer (Timer)
- Nó (sinal) - _on_enemy_timer_timeout()
- Music (AudioStreamPlayer2D)
- GameOver (TextureRect)
- Label (Label)
- Score (Label)
Cena Sky
Vamos iniciar criando uma cena com um nó raiz do tipo Node2D
. Renomeie esse nó para Sky e crie um nó filho do tipo TextureRect
.
Clique no nó TextureRect
e arraste a imagem background.png
(dos nossos recursos do game) para a aba Inspector... RextureRect... Texture...
Ainda na aba Inspector, vamos em CamvasItem e então clique em Material, expandindo ele. Dentro tem um item chamado Material (também), clique do lado onde está [vazio] e adicione um Novo Shader Material.
Vai aparecer uma esfera cinza. Clique nela e vai expandir. Em baixo vai aparecer um elemento chamado Shader que está como [vazio], clique ali e adicione um Novo Shader.
Veja que ele vai pedir pra criar um script especial para esse shader. Como já renomeamos nosso nó raiz como Sky, ele vai salvar como sky.gdshader
. Salve esse script e clique no shader criado (em baixo da esfera).
Ele vai abrir uma ferramenta (imagem abaixo) para editar o script do shader. Vamos alterar o script.
Não vamos precisar das funções fragment
e ligth
. Então vamos excluí-las.
shader_type canvas_item;
void vertex() {
UV.y -= TIME * 0.1;
}
Veja que na função vertex
, usamos o atributo UV.y e diminuímos ele conforme o TIME. Só que como fica muito rápido, multiplicamos por 0.1.
Por fim, para que a textura fique se repetindo, precisamos ir, ainda em CanvaItem, em Texture, selecionar Repeat e colocar Enabled.
E pronto! Temos nosso fundo que fica se em modo scrolling.
Scripts
Background
extends Node2D
var speed = 100
var screensize
var h
var half_h
func _ready():
screensize = get_viewport_rect().size
h = $A.texture.get_height()
half_h = h / 2
func _process(delta):
$A.position.y += speed * delta
$B.position.y += speed * delta
if $A.position.y - half_h > screensize.y:
$A.position.y -= h * 2
if $B.position.y - half_h > screensize.y:
$B.position.y -= h * 2
Ship
extends CharacterBody2D
const type = 'ship'
var speed = 500
var screensize
var h
var half_w
var half_h
func _ready():
screensize = get_viewport_rect().size
h = $Sprite2D.texture.get_height()
half_w = $Sprite2D.texture.get_width() / 2
half_h = h / 2
func _process(delta):
var vec = Vector2()
if Input.is_action_pressed("ui_left"):
vec.x -= speed
elif Input.is_action_pressed("ui_right"):
vec.x += speed
if Input.is_action_just_pressed("ui_select"):
get_parent().new_bomb(Vector2(position.x, position.y - half_h - 20))
var _info = move_and_collide(vec * delta)
position.x = clamp(position.x, half_w, screensize.x - half_w)
if get_parent().score < 0:
kill()
func kill():
queue_free()
get_parent().new_explosion(position)
get_parent().game_over()
Enemy
extends CharacterBody2D
const type = 'enemy'
const LEFT = 0
const RIGHT = 1
var screensize
var direction
var w
var h
var half_w
var half_h
var speed_y = 200
var speed_x = 300
func _ready():
randomize()
screensize = get_viewport_rect().size
w = $Sprite2D.texture.get_width()
h = $Sprite2D .texture.get_height()
half_w = w / 2
half_h = h / 2
position.x = (randi() % int(screensize.x - w)) + half_w
position.y = -100
direction = randi() % 2
func _process(delta):
var vec = Vector2()
vec.y += speed_y
if direction == RIGHT:
vec.x += speed_x
if position.x + half_w > screensize.x:
direction = LEFT
elif direction == LEFT:
vec.x -= speed_x
if position.x - half_w < 0:
direction = RIGHT
var collision = move_and_collide(vec * delta)
if collision:
var entity = collision.get_collider()
if 'ship' in entity.type:
kill()
entity.kill()
if position.y - half_h > screensize.y:
get_parent().change_score(-1)
queue_free()
if get_parent().is_game_over:
queue_free()
func kill():
get_parent().new_explosion(position)
queue_free()
Bomb
extends CharacterBody2D
const type = 'bomb'
var speed = 200
func _ready():
$SoundBomb.play()
func _process(delta):
var collision = move_and_collide(Vector2(0, -speed) * delta)
if collision:
var entity = collision.get_collider()
if 'enemy' in entity.type:
entity.kill()
queue_free()
get_parent().change_score(1)
if position.y < 0:
queue_free()
Explosion
extends StaticBody2D
const type = 'explosion'
func _ready():
$AnimatedSprite2D.play()
$SoundExplosion.play()
func _on_animated_sprite_2d_animation_finished():
queue_free()
World
extends Node2D
const Ship = preload("res://ship.tscn")
const Bomb = preload("res://bomb.tscn")
const Enemy = preload("res://enemy.tscn")
const Explosion = preload("res://explosion.tscn")
var score = 0
var is_game_over = false
var screensize
func _ready():
screensize = get_viewport_rect().size
func _process(_delta):
if is_game_over:
if Input.is_action_just_pressed("ui_accept"):
_reset()
func _reset():
is_game_over = false
score = 0
$Score.text = str(score)
var ship = Ship.instantiate()
ship.position = Vector2(screensize.y - 10, screensize.x / 2)
add_child(ship)
$GameOver.visible = false
$Music.play()
$EnemyTimer.start()
func change_score(pts):
score += pts
$Score.text = str(score)
func game_over():
is_game_over = true
$GameOver.visible = true
$Music.stop()
$EnemyTimer.stop()
func new_explosion(pos):
var explosion = Explosion.instantiate()
explosion.position = pos
add_child(explosion)
func new_bomb(pos):
var bomb = Bomb.instantiate()
bomb.position = pos
add_child(bomb)
func _on_enemy_timer_timeout():
if is_game_over:
return
var enemy = Enemy.instantiate()
add_child(enemy)
$EnemyTimer.wait_time = (randi() % 2) + 1
$EnemyTimer.start()