install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/TerminalSkills/skills/godot" ~/.claude/skills/comeonoliver-skillshub-godot && rm -rf "$T"
manifest:
skills/TerminalSkills/skills/godot/SKILL.mdsource content
Godot Engine — Open-Source Game Engine
You are an expert in Godot Engine, the free and open-source game engine for 2D and 3D games. You help developers build games using GDScript (Python-like language), Godot's scene/node architecture, physics, animation, UI, shaders, and export to desktop, mobile, web, and consoles — with a lightweight editor that runs on any machine and a permissive MIT license with no royalties.
Core Capabilities
Scene and Node System
# Godot's architecture: everything is a node in a tree # Scenes = reusable node trees (like prefabs) # Player.gd — attached to a CharacterBody2D node extends CharacterBody2D @export var speed: float = 200.0 # Editable in Inspector @export var jump_force: float = -400.0 @export var gravity: float = 980.0 @onready var sprite: AnimatedSprite2D = $AnimatedSprite2D @onready var coyote_timer: Timer = $CoyoteTimer var was_on_floor: bool = false func _physics_process(delta: float) -> void: # Gravity if not is_on_floor(): velocity.y += gravity * delta # Coyote time (jump briefly after leaving edge) if was_on_floor and not is_on_floor(): coyote_timer.start() was_on_floor = is_on_floor() # Jump var can_jump = is_on_floor() or not coyote_timer.is_stopped() if Input.is_action_just_pressed("jump") and can_jump: velocity.y = jump_force coyote_timer.stop() # Horizontal movement var direction = Input.get_axis("move_left", "move_right") if direction: velocity.x = direction * speed sprite.play("run") sprite.flip_h = direction < 0 else: velocity.x = move_toward(velocity.x, 0, speed * 0.2) sprite.play("idle") move_and_slide()
Signals (Event System)
# Signals are Godot's observer pattern — decoupled communication # Coin.gd extends Area2D signal collected(value: int) # Custom signal with typed parameter @export var value: int = 10 func _on_body_entered(body: Node2D) -> void: if body.is_in_group("player"): collected.emit(value) # Emit signal # Juice: scale up then disappear var tween = create_tween() tween.tween_property(self, "scale", Vector2(1.5, 1.5), 0.1) tween.tween_property(self, "modulate:a", 0.0, 0.2) tween.tween_callback(queue_free) # GameManager.gd — connects to signal func _ready() -> void: for coin in get_tree().get_nodes_in_group("coins"): coin.collected.connect(_on_coin_collected) func _on_coin_collected(value: int) -> void: score += value score_label.text = "Score: %d" % score
State Machine
# StateMachine.gd — Generic reusable state machine extends Node class_name StateMachine @export var initial_state: State var current_state: State func _ready() -> void: for child in get_children(): if child is State: child.state_machine = self current_state = initial_state current_state.enter() func _physics_process(delta: float) -> void: current_state.physics_update(delta) func _unhandled_input(event: InputEvent) -> void: current_state.handle_input(event) func transition_to(target_state_name: String) -> void: var target = get_node(target_state_name) if target and target is State: current_state.exit() current_state = target current_state.enter() # State.gd — Base state class extends Node class_name State var state_machine: StateMachine func enter() -> void: pass func exit() -> void: pass func handle_input(_event: InputEvent) -> void: pass func physics_update(_delta: float) -> void: pass # IdleState.gd extends State func enter() -> void: owner.animated_sprite.play("idle") func physics_update(delta: float) -> void: if Input.get_axis("move_left", "move_right") != 0: state_machine.transition_to("Run") if Input.is_action_just_pressed("jump") and owner.is_on_floor(): state_machine.transition_to("Jump")
Shaders
// water_shader.gdshader — Visual shader as code shader_type canvas_item; uniform float wave_speed: hint_range(0.5, 5.0) = 2.0; uniform float wave_amplitude: hint_range(0.001, 0.1) = 0.02; uniform float wave_frequency: hint_range(1.0, 20.0) = 10.0; uniform vec4 water_tint: source_color = vec4(0.2, 0.4, 0.8, 0.6); void fragment() { vec2 uv = UV; // Animate UV for wave effect uv.x += sin(uv.y * wave_frequency + TIME * wave_speed) * wave_amplitude; uv.y += cos(uv.x * wave_frequency + TIME * wave_speed * 0.7) * wave_amplitude; vec4 tex = texture(TEXTURE, uv); COLOR = mix(tex, water_tint, water_tint.a); }
Export and Deployment
## Export Targets - Windows, macOS, Linux (desktop) - Android, iOS (mobile) - Web (HTML5/WebAssembly) - Consoles: Switch, PlayStation, Xbox (via third-party porting) ## Command Line godot --export-release "Windows Desktop" game.exe godot --export-release "Web" index.html godot --headless --script tools/build.gd # Headless for CI
Installation
# Download from https://godotengine.org/download/ # Single executable, no installer, ~40MB # Godot 4.x: Vulkan renderer (Forward+ and Mobile) # Godot 3.x: OpenGL (better for low-end/web)
Best Practices
- Scene composition — Build small reusable scenes (Player, Enemy, Coin); instance them in level scenes
- Signals over direct calls — Use signals for node communication; keeps scenes decoupled and reusable
- Groups for queries — Add nodes to groups ("enemies", "interactable"); query with
get_tree().get_nodes_in_group() - State machines — Use a state machine pattern for player, enemy, and UI states; cleaner than massive if/else chains
- @export for tuning — Expose parameters with
; designers tune values in the Inspector without touching code@export - Autoloads for globals — Use autoload singletons for GameManager, AudioManager, SaveSystem — accessible everywhere
- AnimationPlayer — Use AnimationPlayer for everything: sprite frames, position, modulate, function calls, particles
- GDScript for gameplay — GDScript is fast enough for 99% of game logic; use C++ via GDExtension only for performance-critical systems