Módulo 06 – Orientação a Objetos

Introdução a POO

Neste módulo vamos mergulhar no mundo da programação orientada a objetos na Godot. Estes conceitos nos permitem criar jogos de forma mais organizada, reutilizável e eficiente. A Godot aplica estes conceitos de maneira bastante intuitiva através do uso de cenas e nós.

O que é Orientação a Objetos?

Orientação a objetos é um paradigma de programação que organiza o software em “objetos”, que são instâncias de “classes”. Cada objeto pode conter dados (atributos) e comportamentos (métodos). OO nos ajuda a estruturar o código de forma modular e a reutilizar componentes.

Classes: As classes são como plantas (projetos) de uma casa. Elas definem a estrutura e o comportamento dos objetos, especificando atributos (dados) e métodos (funções).

Objetos: São instâncias de classes. Quando você cria um objeto, está basicamente construindo algo a partir da planta fornecida pela classe.

Nós e Cenas na Godot

Na Godot, a ideia de classes e objetos é implementada através de nós e cenas:

Nós (Nodes): São os blocos de construção fundamentais na Godot. Cada nó representa um objeto no jogo, podendo ser um personagem, uma câmera, um som, etc. Nós podem ser organizados hierarquicamente, formando uma árvore de nós.

Cenas (Scenes): Uma cena é uma coleção de nós organizados de uma maneira específica. Pode representar um personagem, um item, um nível inteiro, um menu, etc. Cenas são reutilizáveis e podem ser instanciadas várias vezes.

Estrutura Básica de um Jogo na Godot

Imagine que você está criando um jogo de plataforma. Você pode ter cenas para o jogador, inimigos, plataformas e a interface do usuário.

Cada uma dessas cenas pode conter vários nós:

Cena do Jogador: Pode incluir nós para o sprite, colisões, animações e scripts de movimento.

Cena do Inimigo: Pode ter nós para o sprite, colisões, comportamento e scripts específicos.

Cena da Plataforma: Pode conter nós para a parte visual e colisões.

Cena da UI: Pode incluir nós para botões, labels e outros elementos de interface.

Herança e Reutilização

Um dos principais benefícios da OO é a herança. Na Godot, você pode criar uma cena base e herdar dela para criar variações. Por exemplo, uma cena base de inimigo pode ser herdada para criar diferentes tipos de inimigos com comportamentos específicos.

Scripts em GDScript

Os scripts da Godot também abraçam a ideia de orientação a objetos. Cada nó pode ter um script anexado que define seu comportamento.

Comunicação entre Nós

A comunicação entre nós na Godot é realizada através de sinais e chamadas de métodos. Sinais permitem que um nó emita um evento que outros nós podem ouvir e responder, facilitando a interação entre diferentes partes do jogo de forma desacoplada.

Criando Objetos em GDSCript

Como mencionado antes, o conceito de programação orientada a objetos na Godot passa essencialmente pelo uso de nós e cenas. Os nós são como as classes de objetos. A Godot oferece uma grande variedade de nós para que possamos montar a estrutura dos nosssos jogos.

Quando criamos objetos na Godot, obrigatoriamente estamos herdando as características de um desses nós previamente defindos e, através dos scripts, podemos adicionar novas funcionalidades para os nós que criamos.

Para criar um novo objeto na Godot, primeiro precisamos de uma cena onde possamos posicioná-lo. Uma cena pode ser composto por um único nó ou por vários nós agrupados.

Criando uma Cena

No canto superior esquerdo da tela da Godot temos a janela Scene.

Nesta janela podemos escolher que tipo de cena desejamos criar. Podemos escolher entre opções pré-definidas como as cenas 2D, 3D e interface ou escolher outro tipo de nó.

No nosso exemplo, criamos uma cena 2D e renomeamos para Main. A cena 2D é uma implementação de um dos Nós básicos da Godot: o Node2D.

O Node2D é um objeto de jogo 2D, que possui propriedades de transformação (posição, rotação e escala). Todos os nós 2D, incluindo objetos físicos e sprites, herdam do Node2D.

O Node2D pode ser utilizado como um nó pai para mover, dimensionar e girar filhos em um projeto 2D.

Adicionando Nós Filhos

Vamos continuar o projeto adicionando um novo nó. Imagine que queremos criar um jogo de plataforma. Então a nossa cena precisa de um personagem que o jogador possa controlar.

Para criar o personagem precisamos adicionar um nó filho. Não se preocupe com os detalhes do tipo de nó que vamos ver agora. Nos próximos módulos veremos os nós com mais detalhes.

Para adicionar um novo nó acessamos o submenu através de um clique com o botão direito do mouse sobre a cena Main e selecionando a opção Add Child Node…

A tela de criação de nodes exibe uma lista de nós nativos da Godot para escolhermos.

O tipo de nó escolhido para o personagem é o CharacterBody2D. . Este nó nativo da Godot possui várias características que nos permitem manipular um objeto facilmente pela tela. Vamos renomeá-lo para Player, por enquanto.

Até agora já vimos como a Godot implementa a orientação a objetos de forma fácil e intuitiva. Podemos considerar a coleção de nós nativos da Godot como as classes e as cenas e nós que colocamos em nossos projetos como os objetos.

Mas é claro que ainda podemos utilizar outro conceito importante da orientação a objetos aqui: a Herança.

Estendendo Nós

A Herança em classes significa que podemos criar nossas próprias classes utilizando classes existentes e adicionando novas funcionalidades.

No exemplo acima nós temos o objeto player que é uma instância do nó CharacterBody2D. Mas imagine que queremos criar nossa própria classe para o objeto player. Ela será a classe Jogador. Para isso precisamos do poder dos scripts.

Vamos adicionar um script ao nosso objeto clicando sobre ele com o botão direito e selecionando a opção Attach Script…

Quando criamos uma script, já estamos utilizando a característica de herança das classes uma vez que todo script da Godot receberá essa definição logo na primeira linha de código.

Podemos ver a herança do script logo na janela de criação como aparece em destaque na imagem a seguir.

No código gerado automaticamente pela Godot quando estendemos o nó CharacterBody2D também podemos ver esse detalhe.

GDScript
extends CharacterBody2D

const SPEED = 300.0
const JUMP_VELOCITY = -400.0

# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")


func _physics_process(delta):
	# Add the gravity.
	if not is_on_floor():
		velocity.y += gravity * delta

	# Handle jump.
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = JUMP_VELOCITY

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	var direction = Input.get_axis("ui_left", "ui_right")
	if direction:
		velocity.x = direction * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)

	move_and_slide()

Criar nossas próprias classes no GDScript é muito simples. Basta utilizarmos a palavra chave conjugada class_name seguida do nome da classe.

O código fica desta forma:

GDScript
class_name Jogador extends CharacterBody2D

const SPEED = 300.0
const JUMP_VELOCITY = -400.0

# Restante do código...

Agora nossa classe é um novo nó listado juntamente com os nós nativos da Godot.

Resumindo: agora que temos a classe jogador registrada, podemos criar vários objetos do tipo jogador como podemos ver na tela scenes da Godot na imagem a seguir.

Manipulando Objetos

Atributos e Métodos

Os métodos e propriedades desempenham um papel fundamental na manipulação de objetos.

Métodos são funções definidas dentro de uma classe que permitem realizar operações específicas nos objetos, enquanto os atributos são variáveis associadas a um objeto que podem ter lógica adicional para leitura e escrita.

Estrutura Básica de uma Classe

Podemos ver a sintaxe básica de uma classe no código a seguir:

GDScript
# Definição do nome e  herança
class_name Jogador extends CharacterBody2D

# Constantes
const GRAVIDADE = 980
const VELOCIDADE_PULO = 500
const VELOCIDADE_MOVIMENTO = 200

# Atributos
var vida : int = 100
var velocidade : Vector2 = Vector2()

# Métodos

func pular():
    velocidade.y = -VELOCIDADE_PULO
    print("Jogador pulou!")

Métodos Virtuais

Ao estender os nós nativos da Godot, nossas classes podem sobrescrever métodos especiais definidos para realizar ações específicas em determinados eventos, como inicialização, finalização, comparação, etc. Esses métodos, chamados métodos virtuais, têm os nomes precedidos por um sublinhado.

O Node é um dos principais tipos de nós nativos da Godot. Grande parte dos objetos de uma cena é uma herança direta ou indireta de Node.

Vamos dar uma rápida olhada nos principais métodos fornecidos pelo nó nativo da Godot:

_enter_tree(): Método chamado quando o nó entra no SceneTree (por exemplo, ao instanciar, alterar a cena ou após chamar add_child em um script). Se o nó tiver filhos, seu retorno de chamada _enter_tree será chamado primeiro e depois o dos filhos.

_exit_tree(): Método chamado quando o nó está prestes a sair do SceneTree (por exemplo, ao liberar, mudar de cena ou após chamar remove_child em um script). Se o nó tiver filhos, seu retorno de chamada _exit_tree será chamado por último, depois que todos os seus filhos tiverem saído da árvore.

_ready(): Método chamado quando o nó está “pronto”, ou seja, quando o nó e seus filhos entraram na árvore de cena. Se o nó tiver filhos, seus retornos de chamada _ready serão acionados primeiro e o nó pai receberá a notificação de prontidão posteriormente.

_process(delta): Método chamado durante a etapa de processamento do loop principal. O processamento acontece em cada quadro e o mais rápido possível, portanto o tempo delta desde o quadro anterior não é constante. delta está em segundos. Ele só é chamado se o processamento estiver habilitado, o que é feito automaticamente se este método for substituído e pode ser alternado com set_process.

_physics_process(delta): Método chamado durante a etapa de processamento físico do loop principal. O processamento físico significa que a taxa de quadros está sincronizada com a física, ou seja, a variável delta deve ser constante; delta está em segundos. Ele só é chamado se o processamento do simulador de física nativo estiver habilitado, o que é feito automaticamente se este método for sobrescrito e pode ser alternado com set_physics_process.


Revisado em

em

,

por