ziva-sh/godot-4-api-pitfalls

Corrige APIs do Godot 3 e sintaxe GDScript que assistentes de IA escrevem em projetos Godot 4, como KinematicBody2D, move_and_slide(velocity), export, onready, setget, yield, string connect(), instance(), rand_range, o nó Tween, File, change_scene, Spatial, propriedades rect_*, Pool*Array, funções de tempo do OS e a antiga API TileMap. Use ao escrever, revisar ou portar GDScript para Godot 4.x, quando um script falhar com "not declared", "not found in base", "was removed in Godot 4" ou "is not present".

O que é godot-4-api-pitfalls?

Esta skill é um guia de referência abrangente para desenvolvedores que precisam migrar código GDScript do Godot 3 para o Godot 4, ou que estão escrevendo código novo para Godot 4 e querem evitar usar APIs obsoletas. Ela fornece uma tabela de substituição direta que mapeia classes, métodos, propriedades e palavras-chave de sintaxe renomeadas, como `KinematicBody2D` para `CharacterBody2D`, `yield` para `await`, `export` para `@export`, e muitas outras. A skill também inclui exemplos de código "antes e depois" para padrões comuns (controladores de personagem, propriedades/sinais/tweens, arquivos/tempo/aleatoriedade/cenas), explica o que o analisador sintático do Godot (`--check-only`) não detecta e como configurar avisos mais rigorosos para pegar esses erros, e fornece um comando de autoverificação com `grep` para encontrar nomes do Godot 3 nos scripts. É útil para qualquer fluxo de trabalho que envolva Godot 4, seja escrevendo novo código, revisando código gerado por IA ou portando projetos legados.

Funciona com~Claude Code~Codex CLI~Cursor
Part ofMobile
npx skills add https://github.com/ziva-sh/godot-skills/tree/HEAD/skills/godot-4-api-pitfalls

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Godot 4 API pitfalls

A maior parte do GDScript em tutoriais, respostas de fóruns e dados de treinamento de modelos é do Godot 3. O Godot 4 renomeou classes, métodos e propriedades e alterou a sintaxe do GDScript. Algum código do Godot 3 falha ao ser analisado, e algum é analisado mas quebra apenas em tempo de execução. Antes de escrever código, confirme a versão: project.godot tem uma linha como config/features=PackedStringArray("4.7", ...).

Tabela de substituição

Godot 3 (incorreto no Godot 4)Godot 4
KinematicBody2D, KinematicBodyCharacterBody2D, CharacterBody3D
velocity = move_and_slide(velocity, Vector2.UP)Defina a propriedade velocity, então chame move_and_slide() sem argumentos. up_direction e floor_snap_length são propriedades
export var x = 1, export(int, 0, 10) var x@export var x := 1, @export_range(0, 10) var x: int
export(String, FILE, "*.json") var path@export_file("*.json") var path: String
export(Array, int) var a@export var a: Array[int]
onready var, tool@onready var, @tool
var hp setget set_hp, get_hpvar hp: int: set = set_hp, get = get_hp, ou um bloco inline set(value):
yield(obj, "signal_name")await obj.signal_name
yield(get_tree().create_timer(1.0), "timeout")await get_tree().create_timer(1.0).timeout
yield(get_tree(), "idle_frame")await get_tree().process_frame
connect("pressed", self, "_on_pressed", [arg])pressed.connect(_on_pressed.bind(arg))
emit_signal("died")died.emit() (a forma com string ainda funciona, mas erros de digitação só são encontrados em tempo de execução)
scene.instance()scene.instantiate()
get_tree().change_scene(path), change_scene_to(packed)change_scene_to_file(path), change_scene_to_packed(packed)
rand_range(a, b)randf_range(a, b) ou randi_range(a, b)
stepify, deg2rad, rad2deg, range_lerp, str2varsnapped, deg_to_rad, rad_to_deg, remap, str_to_var
Nó Tween: $Tween.interpolate_property(...), start()var tween := create_tween(), então tween.tween_property(node, "property", final_value, duration)
File.new(), file.open(path, File.READ)FileAccess.open(path, FileAccess.READ) (retorna null em caso de falha, veja FileAccess.get_open_error())
Directory.new()DirAccess.open(path)
to_json(v), parse_json(s)JSON.stringify(v), JSON.parse_string(s)
OS.get_ticks_msec(), OS.get_unix_time(), OS.get_datetime()Time.get_ticks_msec(), Time.get_unix_time_from_system(), Time.get_datetime_dict_from_system()
OS.window_fullscreen = true, OS.get_screen_size()DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN), DisplayServer.screen_get_size()
OS.set_window_title("Game")get_window().title = "Game"
Spatial, translationNode3D, position
extends Reference, Transform, Quatextends RefCounted, Transform3D, Quaternion
pause_mode = PAUSE_MODE_PROCESSprocess_mode = PROCESS_MODE_ALWAYS
Sprite, AnimatedSprite, Position2D, Particles2D, TextureProgressSprite2D, AnimatedSprite2D, Marker2D, GPUParticles2D, TextureProgressBar
rect_position, rect_size, rect_min_sizeposition, size, custom_minimum_size
margin_left (Control)offset_left
Label.align = Label.ALIGN_CENTERhorizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
add_color_override, add_font_override, add_stylebox_override, add_constant_overrideadd_theme_color_override, add_theme_font_override, add_theme_stylebox_override, add_theme_constant_override
Color.red, Color.whiteColor.RED, Color.WHITE
PoolStringArray, PoolVector2Array, PoolIntArray, PoolRealArrayPackedStringArray, PackedVector2Array, PackedInt32Array, PackedFloat32Array
update() (redesenha um CanvasItem)queue_redraw()
TileMap.set_cellv(pos, id), world_to_mapTileMapLayer.set_cell(coords, source_id, atlas_coords), local_to_map (veja a skill godot-tilemaplayer)
BUTTON_LEFT, BUTTON_WHEEL_UPMOUSE_BUTTON_LEFT, MOUSE_BUTTON_WHEEL_UP
event.scancode, event.controlevent.keycode (ou physical_keycode), event.ctrl_pressed
array.empty(), array.remove(i), array.invert()is_empty(), remove_at(i), reverse()
set_collision_layer_bit(0, true) (bit baseado em 0)set_collision_layer_value(1, true) (número de camada baseado em 1)
space_state.intersect_ray(from, to)space_state.intersect_ray(PhysicsRayQueryParameters2D.create(from, to))
RayCast2D.cast_totarget_position
get_tree().set_input_as_handled()get_viewport().set_input_as_handled()
remote func, remotesync func, puppet func, is_network_master()@rpc("any_peer") func, @rpc("any_peer", "call_local") func, @rpc func (apenas a autoridade pode chamá-la), is_multiplayer_authority(). master func não tem equivalente direto: use @rpc("any_peer") e verifique multiplayer.get_remote_sender_id()
Engine.editor_hint, filenameEngine.is_editor_hint(), scene_file_path
RectangleShape2D.extents (metade do tamanho)size (tamanho total, então dobre o valor antigo)
ResourceSaver.save(path, resource)ResourceSaver.save(resource, path)

Renomeios menos comuns (3D, XR, navegação, shaders, threads) estão em references/renames.md.

Antes e depois

Controlador de personagem:

extends KinematicBody2D

export var speed = 200
var velocity = Vector2()

func _physics_process(delta):
	velocity.x = Input.get_axis("ui_left", "ui_right") * speed
	velocity = move_and_slide(velocity, Vector2.UP)
extends CharacterBody2D

@export var speed := 200.0
@export var jump_velocity := -400.0


func _physics_process(delta: float) -> void:
	if not is_on_floor():
		velocity += get_gravity() * delta
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = jump_velocity
	velocity.x = Input.get_axis("ui_left", "ui_right") * speed
	move_and_slide()

Propriedades, sinais, timers e tweens:

tool
extends Node2D

export(int, 0, 100) var health = 100 setget set_health
onready var button = $Button

func _ready():
	button.connect("pressed", self, "_on_button_pressed")

func set_health(value):
	health = clamp(value, 0, 100)
	update()

func _on_button_pressed():
	$Tween.interpolate_property(self, "modulate:a", 1.0, 0.0, 0.5)
	$Tween.start()
	yield($Tween, "tween_all_completed")
	queue_free()
@tool
extends Node2D

@export_range(0, 100) var health: int = 100:
	set(value):
		health = clampi(value, 0, 100)
		queue_redraw()

@onready var button: Button = $Button


func _ready() -> void:
	button.pressed.connect(_on_button_pressed)


func _on_button_pressed() -> void:
	var tween := create_tween()
	tween.tween_property(self, "modulate:a", 0.0, 0.5)
	await tween.finished
	queue_free()

Arquivos, tempo, aleatoriedade e cenas:

extends Node

func save_score(score):
	var file = File.new()
	file.open("user://save.json", File.WRITE)
	file.store_string(to_json({"score": score, "time": OS.get_unix_time()}))
	file.close()

func spawn(scene):
	var enemy = scene.instance()
	enemy.position = Vector2(rand_range(0, 100), 0)
	add_child(enemy)
extends Node

@export var enemy_scene: PackedScene


func save_score(score: int) -> void:
	var file := FileAccess.open("user://save.json", FileAccess.WRITE)
	if file == null:
		push_error("Cannot open save file: %s" % error_string(FileAccess.get_open_error()))
		return
	file.store_string(JSON.stringify({"score": score, "time": Time.get_unix_time_from_system()}))


func spawn() -> void:
	var enemy := enemy_scene.instantiate() as Node2D
	enemy.position = Vector2(randf_range(0.0, 100.0), 0.0)
	add_child(enemy)


func go_to_menu() -> void:
	get_tree().change_scene_to_file("res://menu.tscn")

O que o analisador sintático não detecta

godot --check-only relata um membro desconhecido como erro apenas quando o receptor é self, um tipo embutido (Array, Vector2, Color) ou um nome de classe chamado estaticamente (OS.get_unix_time()); contagens e tipos de argumentos incorretos também são erros. Um membro que está faltando em um objeto, mesmo um tipado como var shape := RectangleShape2D.new(), é tratado como "pode existir em um subtipo" e é analisado com as configurações padrão. Estas linhas do Godot 3 passam --check-only no Godot 4.7.2 e falham apenas quando executadas:

  • scene.instance() em um PackedScene, get_tree().change_scene(path), get_tree().set_input_as_handled()
  • shape.extents em um RectangleShape2D, $Panel.rect_size
  • event.scancode ou event.control em um InputEvent

Para fazer o analisador rejeitá-las durante uma verificação, coloque estas linhas em um override.cfg temporário ao lado de project.godot (Godot o lê além de project.godot, incluindo --check-only) e delete-o depois; se o projeto já tiver um override.cfg, anexe e restaure-o. 2 significa Erro:

[debug]
gdscript/warnings/unsafe_method_access=2
gdscript/warnings/unsafe_property_access=2

Não deixe estas configurações no project.godot do usuário a menos que solicitado: com Erro, toda chamada não tipada como body.take_damage(1) ou $Sprite.play() é um erro de análise, e o jogo ainda inicia com código de saída 0, imprimindo apenas Failed to load script. Código tipado passa, então prefira referências tipadas: @onready var panel: Panel = $Panel, e var key := event as InputEventKey antes de ler key.keycode.

Mudanças de comportamento que nenhum analisador sintático detecta:

  • Métodos de ciclo de vida como _ready() não chamam mais a implementação da classe pai implicitamente. Chame super() quando um script herdado precisar.
  • Array.slice(begin, end) exclui end.
  • Camera2D.zoom está invertido: valores maiores aproximam.
  • String.right(n) retorna os últimos n caracteres.
  • randomize() é executado automaticamente na inicialização. Defina seed() para aleatoriedade reproduzível.
  • call_group() é imediato. Use call_group_flags(SceneTree.GROUP_CALL_DEFERRED, ...) para o comportamento antigo adiado.
  • AnimatedSprite2D.playing foi removido. Chame play().
  • TileMap ainda existe, mas está obsoleto. Código novo usa um nó TileMapLayer por camada.

Autoverificação

  1. Pesquise nos scripts que você escreveu ou alterou por nomes do Godot 3 (GNU grep; adicione -P ou adapte para outros greps):

    grep -rnE --include='*.gd' \
      -e '\b(KinematicBody2D|KinematicBody|Spatial|Position2D|Particles2D|TextureProgress)\b' \
      -e '\b(yield|setget|rand_range|stepify|deg2rad|rad2deg|range_lerp|to_json|parse_json|funcref)\b' \
      -e '\b(idle_frame|pause_mode|Reference|Quat)\b|\bPAUSE_MODE_' \
      -e '^(export|onready|tool)\b|^(remote|master|puppet)(sync)? func' \
      -e '\.instance\(|change_scene(_to)?\(|\b(File|Directory)\.new\(|OS\.(get_ticks|get_unix_time|get_datetime|window_)' \
      -e '\brect_[a-z_]+\b|(^|[^"])\bmargin_(left|right|top|bottom)\b|add_(color|font|stylebox|constant|icon)_override' \
      -e '\bPool[A-Za-z0-9]+Array\b|\bBUTTON_(LEFT|RIGHT|MIDDLE|WHEEL)|\.scancode\b|set_cellv|world_to_map|map_to_world' \
      -e 'connect\("[^"]+", *self|interpolate_property|\bextends +Sprite *$' .
    

    Reescreva cada correspondência com a tabela acima. As constantes de tema "margin_left" entre aspas do MarginContainer são nomes do Godot 4 e não são correspondidos. Nenhuma correspondência não prova que o código é Godot 4: a lista é o subconjunto comum.

  2. Analise cada script alterado a partir da raiz do projeto: godot --headless --path . --check-only --script res://path/to/script.gd. Leia a saída, não apenas o código de saída. Com o override.cfg temporário acima, membros renomeados em objetos tipados também falham aqui.

  3. Execute a cena que usa o script e leia sua saída, porque erros em tempo de execução não alteram o código de saída. A skill godot-verify tem os comandos.

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

ziva-sh/godot-control-layout

Builds Godot 4 Control UIs that resize instead of clipping or overlapping - containers versus anchors, anchor presets from code, size flags, custom_minimum_size, MarginContainer margins, Label wrapping, mouse_filter, CanvasLayer HUDs, Godot 4 theme override names (add_theme_color_override and friends) and the display/window/stretch settings for multiple resolutions. Use when creating or fixing menus, HUDs, dialogs and inventory screens, when UI elements are cut off, zero-sized, overlapping, igno

ziva-sh/godot-scene-organization

Structures Godot 4 projects so scenes stay reusable and references do not break - when to make a scene, a script or a Resource, instancing with @export PackedScene, preload and load, @onready and %UniqueName node access, _ready order, groups, autoloads, class_name, and resource UIDs with the .uid files added in Godot 4.4, including how to move or rename files safely. Use when creating new scenes or scripts, deciding how nodes find each other, adding global state or an event bus, moving or renami

ziva-sh/godot-signals

Godot 4 signal patterns and their failure modes - declaring typed signals, emit(), connect() and disconnect() with Callables, bind() and unbind(), lambdas, CONNECT_ONE_SHOT and CONNECT_DEFERRED, await on signals and timers, editor-made connections stored in .tscn files, and the call down, signal up rule. Use when wiring UI buttons, timers, Area2D or body events and custom game events, when replacing Godot 3 connect("signal", self, "method") or yield code, or when debugging "already connected", "

ziva-sh/godot-tilemaplayer

Correct Godot 4.3+ TileMapLayer code - set_cell(coords, source_id, atlas_coords), reading cells and custom data, erasing, coordinate conversion, terrains, tile collision through TileSet physics layers, finding the tile a body hit, and migrating from the deprecated TileMap node and its layer-index API. Use when placing, reading or erasing tiles from GDScript, building a TileSet in code, generating levels procedurally, handling tile collisions, or porting TileMap code from Godot 3 or Godot 4.0 to

Habilidades Relacionadas