L1.1 — Your First Script & Running It¶
What you'll learn
- Recognize that every GDScript file is a class, and that
extendsnames the class it builds on. - Attach a script to a node, write
_ready, andprintto the Output dock. - Run a single scene with F6 versus the whole project with F5, and know which to reach for.
- Diagnose the "I changed it but nothing changed" trap (an unsaved script runs the old bytecode).
How it applies
- The base class is the API you get.
extendsdecides which methods and properties exist on your script. Extend the wrong type and the first method you call that the base lacks is an error — at parse time for an unknown identifier, at runtime for a bad call. Choosing the base is choosing the surface you can use; it is not decoration. printis your cheapest instrument. The Output dock is the first observability surface you have. A developer who cannot see what a script did at runtime is debugging blind;printis the one-line probe that ends most "is this code even running?" questions.- Run the right target or waste the iteration. Pressing F5 launches the project's main scene; F6 launches the scene you are editing. Running the whole game to test one scene buries the thing you changed under everything else that loads first.
- Stale artifacts masquerade as logic bugs. Godot runs the saved version of a script. Edit, forget to save, run, and you are testing the old code — the "I fixed it and it still fails" phantom. It is the same defect class as shipping a build from a stale cache.
Concepts¶
A script is a class¶
In many languages you open a class with a keyword: class Player { … }. GDScript does not. Every
.gd file is already a class — the file is the class body. You do not name it or wrap it; you
just start writing members. The first meaningful line is almost always extends, which names the
class your script builds on:
This says: my class is a Node, plus whatever I add below. Everything a Node can do, your script
can now do, and _ready, print, and the rest are available because Node (and its bases) provide
them. Omit extends and your script silently extends RefCounted, the minimal base — fine for a
plain data class, wrong for anything you attach to a node.
Example
Two scripts, same three lines of behavior, different bases:
The choice is not cosmetic: only the second has a position. Extend Node and write
position = Vector2(10, 0) and you get an error, because plain Node has no position. You meet
the full node hierarchy in G1.2; for now, the rule is extend the type whose abilities you
need.
The node-attached model¶
A script usually does not run on its own. You attach it to a node, and the script's class becomes that node's behavior — which is why it must extend the node's type (or a compatible one). The node provides the data and the place in the tree; the script provides the logic. You will build this out properly in Part B. For now you need exactly one entry point.
_ready — the entry point for a first run¶
When a node enters the running scene, Godot calls its _ready function once, if it has one. That is
where your first code goes:
func declares a function; _ready is the name Godot looks for; -> void states that it returns
nothing (you meet return types in L1.4). The leading underscore marks it as one of Godot's
virtual callbacks — a function the engine calls for you at the right moment, rather than one you
call yourself. The full set and exact ordering of these callbacks is G2.1; _ready is the only
one you need to run a line of code.
print and the Output dock¶
print(...) writes its arguments to the Output dock at the bottom of the editor. It accepts any
number of values of any type and converts them to text:
There is no setup and no cost worth worrying about during development. When a script "isn't working,"
a print at the top of the function answers the first question — did it even run? — before you
theorize about anything subtler.
Running: F6 for this scene, F5 for the project¶
- F5 — Run Project. Launches the main scene set in Project Settings. This is the whole game starting from its entry point. Early on, you may not have set a main scene yet.
- F6 — Run Current Scene. Launches the scene open in the editor, by itself. This is what you use to test one piece in isolation.
Both open a separate game window. Closing it returns you to the editor. For everything in Part A, F6 on a throwaway scene is the right tool.
Walkthrough¶
Perform these in a new, empty Godot 4.6 project.
- In the Scene dock (top-left), click Other Node, choose Node (the plainest type), and confirm. You now have a one-node scene.
- Right-click that node → Attach Script. Accept the defaults (it will offer
res://node.gdand pre-fillextends Node). Click Create. The script editor opens. - Below the
extends Nodeline, write a_readyfunction that prints a line of your choosing. Type it; do not paste — the worked example above shows the shape of the two lines, not the text to copy. - Save the script (Ctrl+S). Save the scene as well when prompted (Ctrl+S again, name it anything).
- Press F6 to run the current scene. A game window opens (empty — there is nothing to draw) and the Output dock shows your printed line.
- Change the printed text. Run again without saving first, and notice the old text still appears. Now save, run, and see the new text. That is the stale-artifact trap, demonstrated on purpose.
Optional sanity check
Temporarily change extends Node to extends Node2D, then add position = Vector2(50, 0) inside
_ready, save, and run — it works. Change the base back to extends Node and run again: you get
an error on the position line, because plain Node has no position. Revert when done. This is
the "the base class is the API you get" point, felt rather than told.
Self-check quiz¶
Q1 — What does the line extends Node actually do?
A. Imports the Node module so its functions can be called.
B. Declares that this script's class inherits from Node, gaining its members.
C. Renames the script file to Node.
D. Registers the script as an autoload named Node.
Reveal answer
B. A .gd file is a class; extends names its base class, so the script inherits that
type's properties and methods and may override its virtual callbacks. A invents a "module
import" GDScript does not have (there is no import). C confuses inheritance with the
filename. D describes the autoload mechanism (G1.5), unrelated to extends.
Q2 — You are editing enemy.tscn and want to test just it. Which key launches that scene alone?
A. F5, because it always runs whatever scene is open. B. F6, which runs the current scene by itself. C. F5, then pick the scene from a dialog every time. D. Either key; they do the same thing.
Reveal answer
B. F6 runs the current scene. F5 runs the main scene set in Project Settings, regardless of what you have open — so A is wrong about what F5 does, and D is wrong that they are equivalent. C describes the one-time prompt you get when no main scene is set yet, not normal F5 behavior.
Q3 — You edit a print line, run with F6, and the old text still appears. Most likely cause?
A. Godot caches scripts for an hour; you must wait.
B. You did not save the script, so the run used the previous saved version.
C. print only updates once per editor session.
D. The Output dock needs to be manually refreshed.
Reveal answer
B. Godot runs the saved bytecode; an unsaved edit is not part of the run. A, C, and D invent behaviors that do not exist — there is no time-based cache, no once-per-session limit, and no manual Output refresh. Save (Ctrl+S), then run.
Integration question¶
Q4 — open
You attach a script to a Node2D and write func _ready(): position = Vector2(10, 0). It works.
You attach a script with the same body to a plain Node, and the position line errors. Explain,
using the three ideas this chapter introduced — a script is a class, extends chooses the base,
and _ready is called by the engine — why the same code is valid on one and invalid on the other.
Reveal expected answer
The script is a class whose base is whatever extends names. Node2D extends Node and
adds a 2D transform, so position is a real member of the Node2D class — your script inherits
it. Plain Node has no transform, so position is not a member of that class, and assigning it
is an error. _ready runs in both cases (both are nodes, both get the callback), so the
difference is not whether the code runs but whether the member exists on the base you chose.
Choosing the base class is choosing the set of members your script is allowed to use — the
chapter's central point.