Skip to content

Godot:Migration:4.0

CanvasItem Update

  • this.Update() -> this.QueueRedraw()

Instance function

  • instance() -> instantiate()

C# 씬의 클래스 스크립트 연결

partial class를 사용해야 한다.

class Foo : Node2D
{ ... }
partial class Foo : Node2D
{ ... }

Window Position/Size

DisplayServer를 사용하면 된다.

  • OS.window_position -> DisplayServer.WindowGetPosition()
  • OS.window_size -> DisplayServer.WindowGetSize()

Migration Guide

This document represents the beginning of an upgrade or migration document for GDScript 4.0 and Godot 4.0. I'm focusing on 2D
at the moment as I'm upgrading a 2D game, but will hopefully have more to add for 3D afterward.

If you want more content like this, please help fund my cat's medical bills at https://ko-fi.com/kyleszklenski - thank you very much! On to the migration guide.

Godot 4.0 Upgrade/Migration Guide

GDScript:
    Renames - the following classes have been renamed:
    Node.raise() -> CanvasItem.move_to_front()
    SceneTree.change_scene -> SceneTree.change_scene_to_file
    SceneTree.change_scene_to -> SceneTree.change_scene_to_packed
    ssl -> tls in properties and methods across the board
    in range properties: or_lesser -> or_less
    Curve/Curve2D/Curve3D/Gradient interpolate -> sample
    caret_blink_speed -> caret_blink_interval
    CanvasItem update -> queue_redraw
    AABB/Rect2/Rect2i has_no_* methods -> has_* methods
    TileMap/GridMap world_to_map -> local_to_map
    TileMap/GridMap map_to_world -> map_to_local
    uniform -> parameter in various places across the engine
    ProgressBar percent_visible -> show_percentage
    Object constant CONNECT_ONESHOT -> CONNECT_ONE_SHOT
    JavaScript singleton -> JavaScriptBridge
    range_lerp -> remap
    PopupMenu get_current_index -> get_focused_item
    StreamPeerSSL -> StreamPeerTLS
    EditorInterface get_editor_main_control -> get_editor_main_screen
    str2var -> str_to_var
    deg2rad -> deg_to_rad
    rad2deg -> rad_to_deg
    ParticlesMaterial -> ParticlesProcessMaterial
    Position2D -> Marker2D
    Position3D -> Marker3D
    Label & RichTextLabel percent_visible -> visible_ratio
    PathFollow's offsets -> progress & progress_ratio
    hint_tooltip -> tooltip_text
    Rename JavaScript platform to Web
    PoolByteArray -> PackedByteArray
    PoolColorArray -> PackedColorArray
    PoolFloat32Array -> PackedFloat32Array
    PoolFloat64Array -> PackedFloat64Array
    PoolInt32Array -> PackedInt32Array
    PoolInt64Array -> PackedInt64Array
    PoolStringArray -> PackedStringArray
    PoolVector2Array -> PackedVector2Array
    PoolVector3Array -> PackedVector3Array


    Multiplayer:
    The arguments that can be used with @rpc must be one of: 
      mode: call_local, call_remote
      sync: any_peer, authority
      transfer_mode: reliable, unreliable, or unreliable_ordered
      channel: this is just an integer, not a string, and represents what channel you may want to send data on, so you aren't cluttering up the main channel with text for chat (for instance)

      With the above values for mode, sync, and transfer_mode, you can just write the exact value as a string in your @rpc annotation; it does not have to be quoted like most strings in GDScript.


    Variables:

    `instance()` has been renamed to `instantiate()`.

    Exports:

        Switch to @export; if you have a type hint in parentheses and no default value, add the hint at the end after a colon, like so:
            @export var Speed: float

        You *must* provide a minimum amount of type information at the current time, by including a : hint value, or a default value representing the type.

        If you have a range to limit your floats, switch to use @export_range(float, float);

        If exporting a string or integer as an enum, switch to @export_enum(VALUE1, VALUE2, VALUE3) var Name

        If exporting a named enum, switch to @export with hint at the end, e.g.:
            enum weapon_type { Sword, Gun, SwordGun, Knife, KnifeGun}
            @export var WeaponType: weapon_type

        If exporting strings, you can force the editor to show a large textbox for your string with @export_multiline

        You may use @export and @onready at the same time, just like before:
            @export @onready var MaxHitPoints = 10 # See onready below for more

        Other useful hints:
            https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/gdscript_exports.html


    Onready:
        Switch to @onready


    Properties:
        Properties now follow the form:
            var hp_value: int:
                set(value):
                    hp_value = value
                    hpvalue_changed.emit(hp_value)
                get:
                    return hp_value


Tweens:
    Tweens are not nodes anymore! These are references, similar to timers you create with the scene tree.
        var sprite = $Sprite
        var tween := get_tree().create_tween() # can omit get_tree() if you wish; this will bind the tween to the node, see below for more
        tween.tween_property(sprite, "position", sprite.position + Vector2(16.0, 16.0), 1.0)
        # Object to tween, nodepath to property to tween, end goal for the value, amount of time to take in seconds

    There is also tween_interval, which waits for a given amount of time before tweening (similar to a timer), tween_callback, which does
    the same thing as interpolate_callback, and tween_method, which calls a method on an object with an argument that goes from the initial
    value to the final value, or in other words the same as interpolate_method.

    You can chain tweening methods together - call one after the other, like so:
        # above

        tween.tween_property(sprite, "position", sprite.position + Vector2(16.0, 16.0), 1.0)
        tween.tween_property(sprite, "rotation", sprite.rotation + deg2rad(180.0), 1.0)

    Tween binding:
        A tween can be bound to a node so that if the node is either not in the tree or paused, it will affect the tween as well.

    Tween looping:
        Tweens can have any number of loops by using the set_loops(loops) method; 0 will cause infinite loops.

    You can stop/reset, pause, resume, or destroy a tween

    Tweens can run in parallel with tween.parallel()

    Similarly, tweens can have all subsequent tween calls be parallel after calling Tween.set_parallel(true)

    You can use tween.set_ease() and tween.set_trans() to set the easing function and transition type respectively

    You can use as_relative() to make the final value be relative:
        # Equivalent to above

        tween.tween_property(sprite, "position", Vector2(16.0, 16.0), 1.0).as_relative()

    To consistently move the same amount from one spot to the next, such as grid-based movement, you can do the above and set the number of loops.


Yield/await:

    No more yields, only awaits! Ultimately, this comes down to:
        yield(get_tree(), "idle_frame")

        becomes:

        await get_tree().process_frame

    Similarly, to await a common signal, you might do something like:
        await $AnimationPlayer.animation_finished


Signals:
    For yielding/awaiting signals, see yield/await above.

    Note that signals are now first-class language features, meaning you no longer rely on strings for them. That means you can swap any connect calls like this:

        button.connect("pressed", self, "_on_button_pressed")

    to:

        button.pressed.connect(_on_button_pressed) # Feel the power!

    Further:
        button.connect("pressed", self, "_on_button_pressed", [button], CONNECT_DEFERRED) 

    becomes:
        button.pressed.connect(_on_button_pressed.bind(button)), CONNECT_DEFERRED)


    This also changes how you have to call to emit signals. It is now:

        signal_name.emit(arg1, arg2, etc_arg)

Functions:

    Functions are now also first-class language features. That means you can use lambda expressions, which are concise bits of code representing a function, like so:
        var _current_value = 0
        @onready var _button = $Button
        @onready var _text = $LineEdit

        func _ready():
            _button.pressed.connect(func(): _current_value += float(_text.text)) # Convert to a float and add to the current value to place a bet


    It's important to note that just because you *can* add a lambda expression, you probably shouldn't always do it. It is often much cleaner to make a separate method,
    like in 3.x, and attach it instead of a lambda.


Resources:
    If you need to load a resource in a script, when you draw the resource into the script in order to get the exact path, you can hold down ctrl while doing so and have it automatically place the preload.


Nodes:

YSort node removed, functionality moved to Node2D

Renamed nodes:
Spatial → Node3D
GIProbe → VoxelGI
BakedLightmap → LightmapGI
Light2D -> PointLight2D
VisibilityNotifier2D -> VisibleOnScreenNotifier2D
VisibilityNotifier3D -> VisibleOnScreenNotifier3D
VisibilityEnabler2D -> VisibleOnScreenEnabler2D
VisibilityEnabler3D -> VisibleOnScreenEnabler3D


The Pool*Array nodes have been renamed to Packed*Array, and instead of being passed by value, they are now passed by reference.

Physics changes:

Physics2DDirectSpaceState
is renamed to:
PhysicsDirectSpaceState2D

The physics queries now have to have parameters created and passed to the various ray functions, like so:

var params = PhysicsRayQueryParameters3D.new()
params.from = first_pos
params.to = second_pos
params.exclude = obstacles

var result = space_state.intersect_ray(params)

File dropping functionality is now moved from SceneTree (3.x) to Viewport (4.x).
Also it doesn't emit the screen argument anymore.

# 3.x

func _ready() -> void:
  get_tree().connect("files_dropped", self, "_on_files_dropped")

func _on_files_dropped(files: PoolStringArray, screen: int) -> void:
  ...
# 4.x

func _ready() -> void:
    get_viewport().files_dropped.connect(on_files_dropped)

func on_files_dropped(files: PackedStringArray) -> void:
   ...

File is now FileAccess and open() is now a static method that returns such object. To then check for errors, call file_access.get_error()

KinematicBody2D:
    KinematicBody2D has been renamed to CharacterBody2D, and a bunch of features have been added to it, such as:
    - A new template script, that already implements basic movement and jumping for a 2d-platform style game
    - Moving is now built-in to the class, which contains lots of properties to define how the movement works
    - move_and_slide now no longer takes any parameters, and uses built-in velocity to control where it is going.
        Before:
            var velocity = Vector2.ZERO
            func _process(delta):
                velocity = velocity.move_towards(direction*200)
                velocity = move_and_slide(velocity)
        Now:
            func _process(delta)
                velocity = velocity.move_towards(direction*200)
    - It has built-in collision including slopes and moving platforms

Change log:
1/27 - initial add
1/27 - Bitron adds yield/await, signals
1/27 - Kyle adds functions
1/29 - Kyle adds instanciate(), preload trick
1/29 - Kobewi adds new example for connecting in a deferred fashion to signals
1/30 - Kyle adds YSort and other node info, add property syntax
2/1 - Dardan adds Pool* vs Packed* array info
2/20 - Deanut adds Physics-related changes
3/27 - Deanut adds further examples for await changes
9/13 - Kyle adds renames
9/28 - Bitbrain adds File changes, and Fenix adds file dropping changes.
9/29 - Kyle adds some multiplayer love with the @rpc annotation information
9/29 - Zemeio adds KinematicBody2D to CharacterBody2D updates

See also