GDScript

Личный сайт Go-разработчика из Казани

GDScript is a dynamically and statically typed scripting language for the free and open source game engine Godot. Its syntax is vaguely similar to Python’s. Its main advantages are ease of use and tight integration with the engine. It’s a perfect fit for game development.

Basics

1# Single-line comments are written using hash symbol. 2""" 3 Multi-line 4 comments 5 are 6 written 7 using 8 triple 9 quoted 10 strings 11""" 12 13# Doc Comments can add a description to classes and fields 14# which can be viewed in the in-engine docs. 15 16## This class is a demonstration of GDScript 17 18# Script file is a class in itself and you can optionally define a name for it. 19class_name MyClass 20 21# Inheritance 22extends Node2D 23 24# Member variables 25var x = 8 # int 26var y = 1.2 # float 27var b = true # bool 28var s = "Hello World!" # String 29var a = [1, false, "brown fox"] # Array - similar to list in Python, 30 # it can hold different types 31 # of variables at once. 32var d = { 33 "key" : "value", 34 42 : true 35} # Dictionary holds key-value pairs. 36var p_arr = PackedStringArray(["Hi", "there", "!"]) # Packed Arrays can 37 # only hold a certain type. 38 39# Doc comments can apply to properties 40 41## How many times this object has jumped 42var jump_count = 0 43 44# Built-in vector types: 45var v2 = Vector2(1, 2) 46var v3 = Vector3(1, 2, 3) 47 48# Constants 49const ANSWER_TO_EVERYTHING = 42 50const BREAKFAST = "Spam and eggs!" 51 52# Enums 53enum { ZERO, ONE , TWO, THREE } 54enum NamedEnum { ONE = 1, TWO, THREE } 55 56# Exported variables are visible in the inspector. 57# 58# Either a type hint (explained later) or a default value are needed in order 59# for the editor to know what options to give 60@export var age: int 61@export var height: float 62@export var person_name = "Bob" 63# But both is also acceptable 64@export var favorite_color: String = "Green" 65@export var favorite_food := "Pizza" 66 67# Functions 68func foo(): 69 pass # pass keyword is a placeholder for future code 70 71func add(first, second): 72 return first + second 73 74# Doc Comments on functions 75 76## Increases the Jump Count 77func jump(): 78 jump_count += 1 79 80# Printing values 81func printing(): 82 print("GDScript ", "is ", " awesome.") 83 prints("These", "words", "are", "divided", "by", "spaces.") 84 printt("These", "words", "are", "divided", "by", "tabs.") 85 printraw("This gets printed to system console.") 86 87 # Lambdas 88 var my_lambda = func(): print("hello from lambda!") 89 90 my_lambda.call() 91 92# Math 93func doing_math(): 94 var first = 8 95 var second = 4 96 print(first + second) # 12 97 print(first - second) # 4 98 print(first * second) # 32 99 print(first / second) # 2 100 print(first % second) # 0 101 # There are also +=, -=, *=, /=, %= etc., 102 # however no ++ or -- operators. 103 print(pow(first, 2)) # 64 104 print(sqrt(second)) # 2 105 printt(PI, TAU, INF, NAN) # built-in constants 106 107# Control flow 108func control_flow(): 109 x = 8 110 y = 2 # y was originally a float, 111 # but we can change its type to int 112 # using the power of dynamic typing! 113 114 if x < y: 115 print("x is smaller than y") 116 elif x > y: 117 print("x is bigger than y") 118 else: 119 print("x and y are equal") 120 121 var a = true 122 var b = false 123 var c = false 124 if a and b or not c: # alternatively you can use &&, || and ! 125 print("This is true!") 126 127 for i in range(20): # GDScript's range is similar to Python's 128 print(i) # so this will print numbers from 0 to 19 129 130 for i in 20: # unlike Python, you can loop over an int directly 131 print(i) # so this will also print numbers from 0 to 19 132 133 for i in ["two", 3, 1.0]: # iterating over an array 134 print(i) 135 136 while x > y: 137 printt(x, y) 138 y += 1 139 140 x = 2 141 y = 10 142 while x < y: 143 x += 1 144 if x == 6: 145 continue # 6 won't get printed because of continue statement 146 prints("x is equal to:", x) 147 if x == 7: 148 break # loop will break on 7, so 8, 9 and 10 won't get printed 149 150 match x: 151 1: 152 print("Match is similar to switch.") 153 2: 154 print("However you don't need to put cases before each value.") 155 3: 156 print("Furthermore each case breaks on default.") 157 break # ERROR! Break statement is unnecessary! 158 4: 159 print("If you need fallthrough use continue.") 160 continue 161 _: 162 print("Underscore is a default case.") 163 164 # ternary operator (one line if-else statement) 165 prints("x is", "positive" if x >= 0 else "negative") 166 167# Casting 168func casting_examples(): 169 var i = 42 170 var f = float(42) # cast using variables constructor 171 var b = i as bool # or using "as" keyword 172 173# Override functions 174# By a convention built-in overridable functions start with an underscore, 175# but in practice you can override virtually any function. 176 177# _init is called when object gets initialized 178# This is the object's constructor. 179func _init(): 180 # Initialize object's internal stuff here. 181 pass 182 183# _ready gets called when script's node and 184# its children have entered the scene tree. 185func _ready(): 186 pass 187 188# _process gets called on every frame. 189func _process(delta): 190 # The delta argument passed to this function is a number of seconds, 191 # which passed between the last frame and the current one. 192 print("Delta time equals: ", delta) 193 194# _physics_process gets called on every physics frame. 195# That means delta should be constant. 196func _physics_process(delta): 197 # Simple movement using vector addition and multiplication. 198 var direction = Vector2(1, 0) # or Vector2.RIGHT 199 var speed = 100.0 200 self.global_position += direction * speed * delta 201 # self refers to current class instance 202 203# When overriding you can call parent's function using the dot operator 204# like here: 205func get_children(): 206 # Do some additional things here. 207 var r = super() # call parent's implementation 208 return r 209 210# Inner class 211class InnerClass: 212 extends Object 213 214 func hello(): 215 print("Hello from inner class!") 216 217func use_inner_class(): 218 var ic = InnerClass.new() 219 ic.hello() 220 ic.free() # use free for memory cleanup

Accessing other nodes in the scene tree

1extends Node2D 2 3var sprite # This variable will hold the reference. 4 5# You can get references to other nodes in _ready. 6func _ready() -> void: 7 # NodePath is useful for accessing nodes. 8 # Create NodePath by passing String to its constructor: 9 var path1 = NodePath("path/to/something") 10 # Or by using NodePath literal: 11 var path2 = ^"path/to/something" 12 # NodePath examples: 13 var path3 = ^"Sprite" # relative path, immediate child of the current node 14 var path4 = ^"Timers/Firerate" # relative path, child of the child 15 var path5 = ^".." # current node's parent 16 var path6 = ^"../Enemy" # current node's sibling 17 var path7 = ^"/root" # absolute path, equivalent to get_tree().get_root() 18 var path8 = ^"/root/Main/Player/Sprite" # absolute path to Player's Sprite 19 var path9 = ^"Timers/Firerate:wait_time" # accessing properties 20 var path10 = ^"Player:position:x" # accessing subproperties 21 22 # Finally, to get a reference use one of these: 23 sprite = get_node(^"Sprite") as Sprite # always cast to the type you expect 24 sprite = get_node("Sprite") as Sprite # here String gets 25 # implicitly casted to NodePath 26 sprite = get_node(path3) as Sprite 27 sprite = get_node_or_null("Sprite") as Sprite 28 sprite = $Sprite as Sprite 29 30func _process(delta): 31 # Now we can reuse the reference in other places. 32 prints("Sprite has global_position of", sprite.global_position) 33 34# Use @onready annotation to assign a value to 35# a variable just before _ready executes. 36# This is a commonly used syntax sugar. 37@onready var other_sprite = $Sprite as Sprite 38 39# You can export NodePath, so you can assign it within the inspector. 40@export var nodepath = ^"" 41@onready var reference = get_node(nodepath) as Node 42 43# Or export Node directly 44@export var other_reference: Node

Signals

Signal system is Godot’s implementation of the observer programming pattern. Here’s an example:

1class_name Player extends Node2D 2 3var hp = 10 4 5# Doc comments can go on signals too 6 7## Emitted when the player dies 8signal died() # define signal 9signal hurt(hp_old, hp_new) # signals can take arguments 10 11func apply_damage(dmg): 12 var hp_old = hp 13 hp -= dmg 14 hurt.emit(hp_old, hp) # emit signal and pass arguments 15 if hp <= 0: 16 died.emit() 17 18func _ready(): 19 # connect signal "died" to function "_on_death" defined in self 20 died.connect(_on_death) 21 # Alternate way 22 # needed if the target object is not self 23 # died.connect(Callable(self, &"_on_death")) 24 25func _on_death(): 26 queue_free() # destroy Player on death

Type hints

GDScript can optionally use static typing, for both code clarity and performance benefits.

1extends Node 2 3var x: int # define typed variable 4var y: float = 4.2 5var z := 1.0 # infer type based on default value using := operator 6 7var a: Array[int] = [1, 2, 3] # Array can also have its type content specified 8 9enum NamedEnum { ONE = 1, TWO, THREE } 10var n: NamedEnum = NamedEnum.ONE # Enums can be used as types as well 11 12@onready var node_ref_typed := $Child as Node 13 14@export var speed := 50.0 15 16const CONSTANT := "Typed constant." 17 18signal example(arg: int) 19 20func _ready() -> void: 21 # function returns nothing 22 x = "string" # ERROR! Type can't be changed! 23 a.append("q") # ERROR! Array[int] can't hold strings! 24 return 25 26func join(arg1: String, arg2: String) -> String: 27 # function takes two Strings and returns a String 28 return arg1 + arg2 29 30func get_child_at(index: int) -> Node: 31 # function takes an int and returns a Node 32 return get_children()[index]

Further Reading