All migration paths
Unity → Godot 4

Unity to Godot.
Build what you know.

Bring your C# habits. Rebuild a player, a pickup, and a HUD with Godot scenes and signals.

00

The Godot way, side by side.

Look up a Unity term, then see how Godot puts each idea together. Every row and card links to the code.

What is it called in Godot?

Core Objects

UnityGodot
GameObjectNode A Godot scene is a tree of typed Nodes; there is no empty container you bolt components onto.
PrefabPackedScene (.tscn) A saved scene is Godot's prefab: instance it at runtime or drop it into another scene.
Component (MonoBehaviour)Child Node Composition happens by adding typed child nodes to the tree, not by attaching components to a container object.
TransformNode2D / Node3D position, rotation, scale Node2D and Node3D each carry position, rotation, and scale directly — there is no separate Transform component to fetch first.
Empty GameObjectNode / Marker2D / Marker3D Use a bare Node for a non-visual container, or Marker2D/Marker3D when you also want the editor gizmo for a reference point.

Lifecycle

UnityGodot
Update()_process(delta) Per-frame logic; use _physics_process for physics-step logic.
Awake()_init() _init() runs when the object is constructed, before it enters the scene tree — child nodes and @onready vars aren't ready yet.
Start()_ready() _ready() fires once a node and all its children have entered the scene tree — the right place for @onready-dependent setup.
FixedUpdate()_physics_process(delta) Runs on the fixed physics tick — put movement, collision, and RigidBody-adjacent code here instead of _process.
OnDestroy()_exit_tree() Fires when the node is removed from the scene tree — the place to disconnect signals or release external resources.
OnEnable() / OnDisable()tree_entered / tree_exiting / visibility_changed There's no direct enable/disable callback pair; hook tree_entered/tree_exiting for lifecycle, or visibility_changed for show/hide-driven logic.

Scripting

UnityGodot
GetComponent<T>()get_node() / typed @onready Reference named child nodes directly instead of searching by type at runtime.
Coroutine / yield WaitForSecondsawait / SceneTreeTimer await a signal or a scene-tree timer instead of an IEnumerator coroutine.
UnityEvent / C# eventsignal Declare a signal, emit it, and connect listeners — no manual unsubscribe needed.
MonoBehaviourA script attached to a typed Node There's no universal base behavior class — any GDScript file that extends a Node subclass becomes that node's behavior.
Instantiate()PackedScene.instantiate() Load or @export a PackedScene, call instantiate(), then add_child() it into the tree.
Destroy()queue_free() queue_free() frees the node at the end of the current frame; use free() only when you need it gone immediately and know it's safe.
SendMessage()signal.emit() or a direct method call SendMessage's stringly-typed broadcast has no direct match — prefer a declared signal, or call a method directly if you hold a reference.
Invoke() / InvokeRepeating()SceneTreeTimer / Timer node One-shot delayed calls use get_tree().create_timer(...).timeout; recurring calls use a Timer node with autostart and wait_time.
[SerializeField]@export @export exposes a typed variable to the Inspector and to scene/resource serialization.
static class (Singleton pattern)Autoload singleton Register a script as an Autoload (Project Settings) and it becomes a globally-accessible node singleton — no static-field workaround needed.

Physics

UnityGodot
Rigidbody / Rigidbody2DRigidBody2D / RigidBody3D Full physics-simulated bodies; apply forces/impulses instead of setting position directly.
CharacterControllerCharacterBody2D / CharacterBody3D + move_and_slide() Set the velocity property, then call move_and_slide() — it reads and writes the velocity property itself.
OnCollisionEnter()body_entered signal Connect the body_entered signal on the physics body instead of overriding a collision callback.
OnTriggerEnter()area_entered / body_entered on Area2D/3D Areas are Godot's trigger volumes — connect body_entered or area_entered instead of flagging a collider IsTrigger.
LayerMaskcollision_layer / collision_mask collision_layer declares what a body IS; collision_mask declares what it SCANS for — both are 32-bit flag sets.
Physics.Raycast()RayCast2D/3D node or PhysicsDirectSpaceState.intersect_ray() Use a RayCast node for continuous checks, or build a PhysicsRayQueryParameters and call intersect_ray() for one-off queries.
Physics.OverlapSphere() / CheckSphere()ShapeCast2D/3D or PhysicsDirectSpaceState.intersect_shape() ShapeCast nodes sweep a shape continuously; intersect_shape() does a one-off query with a PhysicsShapeQueryParameters.

Input

UnityGodot
Input.GetAxis() / GetAxisRaw()Input.get_vector() get_vector() combines two axes into a single deadzone-normalized Vector2 in one call.
Input.GetButtonDown()Input.is_action_just_pressed() True for exactly one frame — the frame the mapped action was pressed.
Input System package (Action Maps)Input Map (Project Settings) + InputMap/InputEvent Define named actions in Project Settings -> Input Map, then read them with the Input singleton — no separate asset/context system needed.

Animation

UnityGodot
Animator / Animator ControllerAnimationTree + AnimationNodeStateMachine An AnimationTree with a state-machine root replaces the Animator Controller's states and transitions.
Blend TreeAnimationNodeBlendSpace1D / 2D BlendSpace1D blends along one parameter (e.g. speed); BlendSpace2D blends across two (e.g. move direction).
Animation ClipAnimationPlayer track (Animation resource) An AnimationPlayer holds named Animation resources with keyed tracks — play them by name.

Assets & Resources

UnityGodot
ScriptableObjectResource (.tres) Subclass Resource with @export vars for data-driven, savable assets.
AddressablesResourceLoader.load_threaded_request() Background-load a resource by path, then poll status and fetch it once ready — no addressable asset groups to configure.
Resources.Load()preload() / load() preload() resolves at parse time (path must be a literal); load() resolves at runtime, like a dynamic Resources.Load call.
Material (Standard Shader)StandardMaterial3D StandardMaterial3D exposes the built-in PBR shader's parameters without writing shader code.

Scenes & Loading

UnityGodot
SceneManager.LoadScene()get_tree().change_scene_to_file() Swaps the entire current scene tree for a new one loaded from a .tscn path.
Additive Scene LoadingInstance a PackedScene and add_child() it There's no separate additive-load API — instancing a scene and parenting it into the running tree is inherently additive.
DontDestroyOnLoad()Autoload singleton Autoload nodes live outside the current scene and survive scene changes automatically — nothing to mark persistent.

Audio

UnityGodot
AudioSourceAudioStreamPlayer / 2D / 3D Pick the flavor by dimensionality: plain AudioStreamPlayer for UI/music, 2D or 3D for positional sound.
AudioListenerAudioListener2D/3D (falls back to the current Camera) If no AudioListener2D/3D is made current, the active Camera acts as the listener; add one explicitly to decouple hearing position from the camera.

Networking

UnityGodot
[ServerRpc]/[ClientRpc] (Netcode) / Command/ClientRpc (Mirror)@rpc annotation Annotate a method with @rpc(...) and call it directly — the annotation configures authority, reliability, and call mode.
NetworkVariable<T> / SyncVarMultiplayerSynchronizer List properties in a MultiplayerSynchronizer's replication config instead of wrapping each field in a NetworkVariable type.
NetworkObject.Spawn()MultiplayerSpawner A MultiplayerSpawner watches a parent node and auto-replicates scenes instanced under it to peers.

UI

UnityGodot
uGUI CanvasControl node + Containers Build UI from Control nodes; a reusable widget is just a saved Control scene, styled with a Theme.

Misc

UnityGodot
Time.timeScaleget_tree().paused + Node.process_mode Pausing stops _process/_physics_process on pausable nodes; set a node's process_mode to PROCESS_MODE_ALWAYS to keep it running while paused.
Time.deltaTimethe delta parameter _process and _physics_process each receive delta as an argument instead of a global property.
Camera.mainget_viewport().get_camera_2d() / get_camera_3d() There's no global 'main camera' singleton — ask the viewport for its current camera, and it can return null.
Debug.Log()print() print() writes to the Output panel/stdout; print_debug() additionally appends the calling function and line.
PlayerPrefsConfigFile ConfigFile reads/writes simple section/key/value data to disk — a lightweight PlayerPrefs-style store for small settings and save data.
Tag / CompareTag()Groups (add_to_group / is_in_group) Groups are Godot's tag system — a node can belong to many groups at once, unlike Unity's single-tag-per-object default.

How Godot works, next to Unity

Objects are node trees

Each component becomes its own child node, and the root node’s type (here CharacterBody2D) decides what the object is.

Unity GameObject + components
  • Player (GameObject)
  • Transform
  • SpriteRenderer
  • BoxCollider2D
  • PlayerController script
Godot A tree of typed nodes
  • Player · CharacterBody2D + player.gd
  • Sprite2D
  • CollisionShape2D

Code side by side: GameObject → NodeComponent (MonoBehaviour) → Child NodeTransform → Node2D / Node3D position, rotation, scale

One script per node

A node carries one script and the script extends that node’s type; split behaviour into child nodes instead of stacking scripts.

Unity Many MonoBehaviours
  • Player (GameObject)
  • Movement : MonoBehaviour
  • Health : MonoBehaviour
  • Shooter : MonoBehaviour
Godot A script extends its node
  • Player · CharacterBody2D + player.gd
  • Health · Node + health.gd
  • Gun · Node2D + gun.gd

Code side by side: MonoBehaviour → A script attached to a typed Node[SerializeField] → @exportGetComponent<T>() → get_node() / typed @onready

The frame loop

_ready() runs once the node and its children are in the tree, and delta arrives as a parameter instead of a global.

Unity Event functions
  1. Awake()
  2. Start()
  3. Update() / FixedUpdate()
  4. OnDestroy()
Godot Virtual methods
  1. _init()
  2. _ready()
  3. _process(delta) / _physics_process(delta)
  4. _exit_tree()

Code side by side: Awake() → _init()Start() → _ready()Update() → _process(delta)FixedUpdate() → _physics_process(delta)OnDestroy() → _exit_tree()

Resources hold data

A custom Resource is the ScriptableObject: give it @export fields, save .tres files and load them like any other asset.

Unity ScriptableObject
  • ItemData : ScriptableObject
  • Saved as an .asset
  • Edited in the Inspector
Godot Custom Resource
  • class_name ItemData extends Resource
  • Saved as a .tres
  • Edited in the Inspector

Code side by side: ScriptableObject → Resource (.tres)

Input is named actions

Name actions once in the Input Map and bind keys and buttons there; code asks for actions, never for keys.

Unity Input System
  1. Input Actions asset
  2. Action Map: Move, Jump
  3. Read the action in code
Godot Input Map
  1. Project Settings → Input Map
  2. Actions: move_left, jump
  3. Input.is_action_pressed("jump")

Code side by side: Input System package (Action Maps) → Input Map (Project Settings) + InputMap/InputEventInput.GetAxis() / GetAxisRaw() → Input.get_vector()Input.GetButtonDown() → Input.is_action_just_pressed()

Pick the body by who moves it

RigidBody for physics, CharacterBody for your own movement code, StaticBody for walls and Area for triggers, filtered by collision layers.

Unity Rigidbody, CharacterController
  • Rigidbody: physics moves it
  • CharacterController: your code moves it
  • Collider with Is Trigger
Godot Physics bodies
  • RigidBody2D/3D: physics moves it
  • CharacterBody2D/3D + move_and_slide()
  • Area2D/3D for triggers

Code side by side: Rigidbody / Rigidbody2D → RigidBody2D / RigidBody3DCharacterController → CharacterBody2D / CharacterBody3D + move_and_slide()OnTriggerEnter() → area_entered / body_entered on Area2D/3DLayerMask → collision_layer / collision_mask

Practice

Now build it in Godot.

Four short exercises: rebuild a scene, translate the code, look up the everyday tasks, and make one small thing work.

01

Change the structure, keep the idea.

Choose a gameplay object. Map its responsibilities, then build its Godot scene tree.

Your missionBuild a visible, script-controlled 3D character that can collide with the level.

player.tscn
What you know

Unity structure

Prefab
Player prefabGameObject + components

A GameObject holds components. In Godot, typed nodes carry responsibilities and child nodes compose the object. A reusable scene is the whole saved tree.

How Godot scenes work

Keep the behavior.
Rebuild who owns it.

Your Godot sceneStructure exercise
player.tscn
PlayerChoose a root below

Add the pieces
this object needs.

Scene illustrationNo root selected
Y
Visible meshCollision shapeUpdates with your choices
1Choose what the root does
2Add its responsibilities

Choose a root and add children. The diagram shows your choices.

Checks the node structure.
No Godot runtime here.

Build it in Godot

Take this structure into a real project.

  1. Create a CharacterBody3D named Player and save it as player.tscn.
  2. Add MeshInstance3D with a CapsuleMesh, and CollisionShape3D with a CapsuleShape3D. Align their sizes.
  3. Attach player.gd to Player. Instance it in a level with a StaticBody3D floor, a collision shape, and a current Camera3D.

Working in 2D? Use CharacterBody2D / Area2D, Sprite2D, and CollisionShape2D. The same composition idea applies. Explore the editor →

02

Same behavior. Different code.

Compare a familiar pattern, inspect the changes, and test the idea before opening Godot.

Keep C# if it suits your project. UnityEngine APIs still need replacing with Godot APIs; these examples use GDScript to make the changes easy to read.

1 of 3 · Move a player

Set velocity, then move the body.

Read named actions each physics tick. Godot’s move_and_slide() uses the body’s velocity, in meters per second.

Unity · C# excerptFamiliar pattern
// Inside a configured MonoBehaviour.
// moveAction: enabled InputAction (Vector2)
// controller: CharacterController
Vector2 input = moveAction.ReadValue<Vector2>();
Vector3 direction = new(input.x, 0, input.y);
controller.Move(direction * speed * Time.deltaTime);
Godot · player.gd
extends CharacterBody3D
 
@export var speed: float = 5.0
 
func _physics_process(delta):
    var input = Input.get_vector(
        "move_left", "move_right",
        "move_forward", "move_back")
    velocity.x = input.x * speed
    velocity.z = input.y * speed
    if not is_on_floor():
        velocity.y -= 9.8 * delta
    move_and_slide()
  1. Create four actions in Project → Project Settings → Input Map. Forward is negative Z in this world-aligned Godot example.

  2. The CharacterBody3D script sets velocity on a physics tick. Unlike Unreal’s Character Movement, gravity and movement policy are yours to write.

  3. Gravity changes velocity over time, so it uses delta. Do not multiply velocity by delta when calling move_and_slide(); the method handles the physics timestep.

Try the ideaBrowser model · run the code in Godot

Start at 0 m. The strip represents 10 meters of unobstructed movement.

Try the code in Godot

Official API guide

Use the Player scene above. Map A/D/W/S to move_left / move_right / move_forward / move_back. This is world-aligned movement without jumping or camera rotation.

Check it worked: Run Main. Hold D for one second on a flat floor: at speed 5, unobstructed motion is about 5 meters along +X.

2 of 3 · Spawn a scene

Create an instance. Then give it a parent.

A PackedScene is the saved resource. instantiate() creates nodes in memory; add_child() puts them into the scene tree.

Unity · C# excerptFamiliar pattern
// coinPrefab is assigned in the Inspector.
// coinParent is a Transform in the scene.
GameObject coin = Instantiate(
    coinPrefab, coinParent);
coin.transform.localPosition = new Vector3(2, 1, 0);
Godot · main.gd
extends Node3D
 
const COIN = preload("res://coin.tscn")
 
func _ready():
    var coin = COIN.instantiate()
    add_child(coin)
    coin.position = Vector3(2, 1, 0)
  1. Save coin.tscn first. preload() loads its PackedScene resource; it does not create a live coin.

  2. instantiate() and add_child() are separate steps. A detached instance is not drawn or processed by the scene tree.

  3. position is relative to Main here. To set a world-space location, use global_position after adding the node to a parent.

Try the ideaBrowser model · run the code in Godot
Main

No coins in the scene tree yet.

Try the code in Godot

Official API guide

Save the Pickup scene as res://coin.tscn. Attach this script to a Node3D named Main. This standalone example creates one coin on startup.

Check it worked: Run Main. In the Remote scene tree, one Coin appears under Main at local position (2, 1, 0).

3 of 3 · Update the HUD

Let the coin announce what happened.

The coin emits an event. Main listens and updates the HUD. The coin does not need to find or own the score label.

Unity · C# excerptFamiliar pattern
// Coin component
public event System.Action Collected;
void Collect() {
    Collected?.Invoke();
    Destroy(gameObject);
}

// Subscribe before collection; unsubscribe
// when the listener is disabled/destroyed.
coin.Collected += OnCoinCollected;
Godot · coin.gd + main.gd
# coin.gd · attached to Coin (Area3D)
extends Area3D
signal collected
var taken := false
 
func _ready():
    body_entered.connect(_on_body_entered)
 
func _on_body_entered(body):
    if body is CharacterBody3D and not taken:
        taken = true
        collected.emit()
        queue_free()
 
# main.gd · separate file, on Main (Node3D)
extends Node3D
var score := 0
 
func _ready():
    $Coin.collected.connect(_on_coin_collected)
 
func _on_coin_collected():
    score += 1
    $HUD/ScoreLabel.text = str(score)
  1. A signal is a named event. The guard prevents a coin being counted twice before queue_free() removes it at the end of the frame.

  2. Connect before the event can happen. Signals do not replay past events for listeners that connect later.

  3. Main owns the score and the HUD reference. Keeping UI access out of the coin makes the pickup scene reusable.

Try the ideaBrowser model · run the code in Godot
CoinNo listenerHUD 0

Connect the listener, then collect the coin. Or try it without the connection.

Try the code in Godot

Official API guide

Use two separate scripts. Place Coin and HUD directly under Main, with ScoreLabel under HUD. Connect in code as shown; do not also connect the same handler in the editor. Player must enter the Area3D.

Check it worked: Run Main and walk into Coin. Coin disappears and ScoreLabel changes from 0 to 1 once.

Prefer C#? See the Godot .NET setup and API changes →

03

“How do I do that in Godot?”

Open a task for the exact place to start, what changes, and how to check the result.

Set up input

Input Actions / PlayerInput → Input Map + Input
  1. Open Project → Project Settings → Input Map.
  2. Add move_left, move_right, move_forward, move_back. Assign A, D, W, S respectively.
  3. Use Input.get_vector() in player.gd. Add gamepad events to the same actions when needed.

Input Map stores named bindings. It does not automatically recreate PlayerInput components or Enhanced Input context priorities.

Check it worked: Change move_right from D to Right Arrow. The same player script should still move right.

Build UI

Canvas / RectTransform / uGUI → Control + Containers
  1. Create a Control scene and use the Full Rect layout preset.
  2. Add a MarginContainer, then a VBoxContainer with two Buttons inside.
  3. Resize the running window. Set Container sizing and anchors rather than hardcoding every position.

Containers arrange their children. A manually positioned child can be repositioned by its parent Container.

Check it worked: Both buttons remain arranged vertically after resizing the window.

Share item data

ScriptableObject → Custom Resource
  1. Create item_data.gd: extends Resource, class_name ItemData, and @export var value: int = 1 (each on its own line).
  2. Create a new ItemData resource in the Inspector or FileSystem and save it as coin_data.tres.
  3. Export an ItemData property on a scene script and assign coin_data.tres in the Inspector.

Loaded Resources can be shared. Duplicate a resource or use Local To Scene when instances need independent mutable values.

Check it worked: Assign the same resource to two coins. Changing its saved value updates both references.

Move art & audio

Project assets and prefabs → Source assets + Godot import settings
  1. Export one model as glTF/GLB from its source tool; keep textures beside it. Use source PNG textures and WAV/OGG audio.
  2. Copy the files into the Godot project and inspect them in the Import dock.
  3. Instance the model in a test scene. Check scale, materials, animation and collision before importing the rest.

Engine-specific materials, shaders, prefab logic and .uasset files are not portable source assets. Rebuild those systems and check each asset’s usage rights.

Check it worked: One imported model has the intended size and materials in a running Godot scene.

04

Make one small thing work.

Use a fresh test project. Tick these off after checking them in Godot.

0 of 4 checks done

Your checklist stays in this browser.

Build the scene
Translate movement
Connect a signal
Follow the export steps

Go deeper when you need it.

All articles

Turn prefab thinking into scenes

Read the guide

Keep C# when moving to Godot

Read the guide

Plan your Unity project migration

Read the guide