module Lapis::Docs::C_GAMEPLAY_AND_DECLARATIVE_DSL::J_GDSCRIPT_TO_CRYSTAL_CHEATSHEET

Overview

GDScript to Crystal Migration Cheatsheet

Comprehensive conversion guide and syntax cheatsheet for migrating GDScript game logic into idiomatic, high-performance Crystal for Lapis.

Executive Summary & Key Topics

Topic Method / Anchor Description
Cheatsheet Core Topics .topic_00_cheatsheet_features Class declarations, node resolution via ~, exports, signals, and lifecycle.
Complete Syntax Comparison Matrix .topic_01_syntax_matrix Side-by-side mapping of GDScript patterns to Lapis Crystal.
Class Declaration DSL Variants .topic_02_class_declarations node, node2d, node3d, gdclass, and gmodule.
Node Resolution with Unary ~ .topic_03_unary_tilde_node_resolution Matching GDScript's $ and % shorthands using Crystal's unary ~ operator.
Memory Safety & Dead-Pointer Defense .topic_04_memory_safety queue_free vs .destroy and #alive? defensive checks.

Related Guides & Source References

Defined in:

libgodot/docs/c_gameplay_and_declarative_dsl/j_gdscript_to_crystal_cheatsheet.cr

Class Method Summary

Class Method Detail

def self.topic_00_cheatsheet_features : Nil #

Cheatsheet Core Topics: Class declarations, node resolution via ~, exports, signals, and lifecycle.

Key Topics & Information

  • Class declarations: node, node2d, node3d, gdclass, gmodule
  • Node path & unique lookup: ~Sprite2D, ~"path", ~"%unique", ~.as(T)
  • Exported properties: @[Export], ranges, enums, file pickers
  • Signals: typed declarations and synthesized emit_ methods
  • Non-blocking awaiting: await(signal), await(duration), await(timer)

def self.topic_01_syntax_matrix : Nil #

Complete Syntax Comparison Matrix: Side-by-side mapping of GDScript patterns to Lapis Crystal.

GDScript Pattern Crystal Equivalent Architectural Notes
class_name Player extends CharacterBody2D node Player < CharacterBody2D do Explicit parent class. Registers in Godot ClassDB.
class_name GameManager extends Node node GameManager do Defaults automatically to Godot::Node.
class_name Player2D extends Node2D node2d Player2D do Convenience DSL macro defaulting to Godot::Node2D.
class_name Player3D extends Node3D node3d Player3D do Convenience DSL macro defaulting to Godot::Node3D.
class_name ItemData extends Resource gdclass ItemData < Godot::Resource do Registers custom Resource/RefCounted in ClassDB.
$Sprite2D ~Sprite2D Typed lookup of first child matching class in NodeContext.
$"Sprite2D" ~"Sprite2D" String relative path child resolution.
$"../Player" ~"../Player" Parent or sibling tree navigation.
%"HealthBar" ~"%HealthBar" Scene unique node resolution (% prefix).
$SomeName as Player ~"SomeName".as(Player) Explicit casting to custom Crystal node class.
get_node_or_null("Sprite2D") ~Sprite2D? Nilable lookup returning typed Sprite2D? or nil.
@export var speed: float = 300.0 @[Export]
property speed : Float32 = 300.0_f32
Exposes typed property to editor Inspector.
@onready var sprite = $Sprite2D getter(sprite) { ~Sprite2D } Lazy memoized getter resolving child on first access.
signal health_changed(curr, max) signal health_changed(current : Int32, max : Int32) Synthesizes type-safe emit_health_changed method.
await get_tree().create_timer(1.0).timeout await(1.0) Non-blocking signal awaiting without stopping engine loop.
await enemy.died await(enemy.died) First-class bound signal awaiting with optional timeout.
queue_free() queue_free Deferred deletion by engine at frame end.

def self.topic_02_class_declarations : Nil #

Class Declaration DSL Variants: node, node2d, node3d, gdclass, and gmodule.

Lapis supports 5 declarative class and module macros:

# 1. Explicit inheritance from any Godot engine node
node Player < CharacterBody2D do
  @[Export]
  property speed : Float32 = 250.0_f32
end

# 2. Shorthand defaulting to Godot::Node
node GameManager do
  property score : Int32 = 0
end

# 3. Shorthand for 2D nodes (defaults to Godot::Node2D)
node2d Bullet do
  property velocity : Vector2 = Vector2.new(10.0_f32, 0.0_f32)
end

# 4. Shorthand for 3D spatial nodes (defaults to Godot::Node3D)
node3d Turret do
  property range : Float32 = 15.0_f32
end

# 5. Non-Node ClassDB classes (Resources, RefCounted)
gdclass SkillData < Godot::Resource do
  @[Export]
  property cooldown : Float32 = 2.5_f32
end

# 6. Reusable mixin modules with exported properties and signals
gmodule DamageableMixin do
  @[Export]
  property armor : Int32 = 5
  signal damaged(amount : Int32)
end

def self.topic_03_unary_tilde_node_resolution : Nil #

Node Resolution with Unary ~: Matching GDScript's $ and % shorthands using Crystal's unary ~ operator.

In GDScript, nodes are retrieved using $ and %. In Lapis, use the unary ~ operator:

def _ready : Void
  # Typed lookup of child node
  sprite = ~AnimatedSprite2D

  # Path lookup
  hitbox = ~"HitboxArea/CollisionShape2D"

  # Tree navigation
  parent_mgr = ~"../GameManager"

  # Scene unique node
  health = ~"%HealthBar"

  # Explicit downcasting to custom user class
  player = ~"../Player".as(Player)
  bar = ~"%HealthBar".as(ProgressBar)

  # Nilable lookup (returns nil if child absent)
  optional_light = ~PointLight2D?
end

def self.topic_04_memory_safety : Nil #

Memory Safety & Dead-Pointer Defense: queue_free vs .destroy and #alive? defensive checks.

GDScript uses reference counting and garbage-collected variants, while Godot nodes are C++ instances.

  1. Nodes in SceneTree: Call node.queue_free to let Godot deallocate them cleanly at frame end.
  2. Unparented Nodes: Standalone nodes created via Godot.create(Node2D) MUST be cleaned up via node.destroy if they are never added to the SceneTree.
  3. Defensive Checks: When retaining references to enemies or bullets, check #alive? before accessing them to avoid segmentation faults.