Game development: Godot

Sefism.

Chapter 02

Programming for games

How game code is structured in your engine: the script lifecycle, components, exposed variables, events and the language itself.

Script lifecycle

Also called Awake, _ready, _process, BeginPlay, lifecycle method

What
The functions the engine calls on your code at set moments: once when the object is created or enters play, then every frame, then at a fixed physics rate, and finally when it is destroyed.
Why
Putting code in the right callback avoids most beginner bugs: setup in the start callback, per-frame logic in update, physics in the fixed-rate callback.
Python
extends CharacterBody2D

func _ready() -> void:
    pass  # node and children are in the tree

func _process(delta: float) -> void:
    pass  # every frame

func _physics_process(delta: float) -> void:
    pass  # fixed physics tick

Watch out

Reading another object in the earliest callback before it has initialised itself, which gives null references.

Components and composition

Also called ECS, composition over inheritance

What
Building game objects from small parts: a health component, a mover, a sprite, a collider. Unity uses components on GameObjects, Godot uses child nodes, Unreal uses Actor Components.
Why
Small reusable parts let you make a new enemy by combining existing pieces, instead of a deep class tree where every change breaks something.

Watch out

One giant player script of 2,000 lines that handles input, health, animation, sound and UI.

Exposed variables

Also called SerializeField, @export, UPROPERTY EditAnywhere

What
Variables marked so they appear in the editor, where you or a designer can tune them without touching code.
Why
Game feel is found by tweaking numbers such as speed, jump height and cooldowns while the game runs. Exposing them makes tuning fast.
Python
@export var move_speed: float = 300.0
@export var max_health: int = 3
@export var bullet_scene: PackedScene

Watch out

Changing values in the editor while in play mode and losing them all when you stop.

Events, signals and dispatchers

Also called observer pattern, delegates

What
A way for an object to announce that something happened, such as "health changed", so that any number of listeners can react without the sender knowing about them.
Why
It keeps code decoupled: the health bar, the sound and the achievement system all listen to the player instead of the player calling each one.
Python
signal health_changed(new_health: int)

func take_damage(amount: int) -> void:
    health -= amount
    health_changed.emit(health)

# elsewhere
player.health_changed.connect(_on_health_changed)

Watch out

Forgetting to disconnect or unsubscribe when a listener is destroyed, which causes errors or leaks.

Nodes, scenes and the scene tree

What
In Godot everything is a node, nodes form a tree, and a saved branch of nodes is a scene. A scene can be a player, a bullet or a whole level, and scenes nest inside scenes.
Why
Scenes are Godot's unit of reuse: you instance a bullet scene to spawn bullets, and a level scene contains instanced player and enemy scenes.

Watch out

Hard-coding long node paths such as get_node("../../UI/Health") that break as soon as the tree changes; prefer exported references or %UniqueName.

GDScript and static typing

What
Godot's built-in language, with Python-like indentation, tight editor integration and optional static types written as var speed: float.
Why
Typed GDScript gives better autocompletion, catches mistakes in the editor and runs faster. It is the default choice for Godot; C# is available but cannot export to the web in Godot 4.
Python
var speed: float = 200.0
var enemies: Array[Node2D] = []

func heal(amount: int) -> void:
    health = mini(health + amount, max_health)

Watch out

Leaving everything untyped, which hides typos until the line runs in the middle of a playtest.

State machine

Also called FSM, finite state machine

What
Modelling an object as one state at a time, such as idle, running, jumping or attacking, with clear rules for moving between states.
Why
It replaces a tangle of booleans (isJumping, isAttacking, isHurt) with one variable, so impossible combinations cannot happen. Enemy AI and animation both use it.
Example
An enemy patrols until it sees the player, chases while in range, attacks when close, and returns to patrol if the player escapes for three seconds.

Watch out

Adding a new boolean for every behaviour until the player can attack while dead.

Debugging games

Also called logging, breakpoints, debug draw

What
Printing values to the console, pausing on breakpoints in your IDE, and drawing debug lines, shapes and text in the game view to see what the code thinks is happening.
Why
Game bugs are often visual or timing related, so seeing a ray or a hitbox on screen finds them faster than reading code.
Python
print("velocity: ", velocity)
push_warning("Enemy spawned outside the arena")
# Debug > Visible Collision Shapes in the editor

Watch out

Leaving hundreds of log lines running every frame, which slows the game and hides the message you need.

02 · Programming for games2 / 10