LEARN X · ЗА 15 МИН
GDScript (Godot)
Изучи GDScript за 15 минут: язык движка Godot 4 — переменные, типы, сигналы, узлы, @export и движение персонажа на примерах кода.
GDScript — встроенный язык движка Godot 4. Синтаксис напоминает Python: значимые отступы, динамическая типизация с опциональными аннотациями. Весь язык — ниже, прямо в комментариях кода.
Вывод и комментарии
# Однострочный комментарий начинается с #
# Вывод в консоль (панель «Output» в редакторе):
print("Привет, Godot!") # Привет, Godot!
print("a =", 1, " b =", 2) # элементы через запятую печатаются подряд
printt("таб", "раздел") # значения через табуляцию
print_rich("[b]жирный[/b]") # с BBCode-разметкой
push_warning("это предупреждение") # жёлтое предупреждение
push_error("это ошибка") # красная ошибка
# Блоки задаются ОТСТУПАМИ (как в Python), а не фигурными скобками.
# Принято использовать табы. Двоеточие открывает блок:
if true:
print("вложенная строка")
Переменные и типы
Переменные объявляются через var, константы — через const.
var health = 100 # динамический тип (выводится автоматически)
var name: String = "Игрок" # явная статическая типизация через :
var speed := 5.0 # := — вывод типа (здесь float), тип закреплён
const MAX_HP = 100 # константа, нельзя переприсвоить
const GRAVITY := 9.8
health = 80 # переменную менять можно
# MAX_HP = 50 # ОШИБКА: константу нельзя
var enabled # без значения -> null
var count: int # типизированная без значения -> 0
# enum — именованные целочисленные константы:
enum State { IDLE, RUN, JUMP } # IDLE=0, RUN=1, JUMP=2
var st := State.RUN # 1
Базовые типы
var i: int = 42 # целое
var f: float = 3.14 # дробное
var b: bool = true # true / false
var s: String = "текст" # строка
# Строки:
var greeting := "Привет, " + name # конкатенация
var templated := "HP: %d/%d" % [health, MAX_HP] # форматирование
print(s.length(), s.to_upper(), s.substr(0, 3))
# Векторы — основа 2D/3D-математики в Godot:
var pos2 := Vector2(10, 20) # 2D: x, y
var pos3 := Vector3(1, 2, 3) # 3D: x, y, z
print(pos2.x, pos2.length()) # доступ к компонентам и длина вектора
var dir := Vector2.RIGHT # константы-направления: UP/DOWN/LEFT/RIGHT
# Цвет (RGBA, компоненты 0..1):
var red := Color(1, 0, 0)
var semi := Color(0, 0, 1, 0.5) # синий, полупрозрачный
var named := Color.GOLD # именованные цвета
Операторы и условия
# Арифметика: + - * / % и ** (степень)
print(7 / 2) # 3 (целочисленное деление, оба int)
print(7.0 / 2) # 3.5
print(2 ** 10) # 1024
# Сравнение: == != < > <= >=
# Логика словами: and or not
if health > 50 and not b:
print("много здоровья")
elif health > 0:
print("ещё держимся")
else:
print("конец")
# Тернарный оператор:
var status := "жив" if health > 0 else "мёртв"
# match — аналог switch, но мощнее:
match st:
State.IDLE:
print("стоим")
State.RUN, State.JUMP: # несколько значений
print("в движении")
_: # _ — значение по умолчанию
print("неизвестно")
Циклы
# for по диапазону:
for n in range(3): # 0, 1, 2
print(n)
for n in range(2, 10, 2): # старт, стоп(не вкл.), шаг -> 2,4,6,8
print(n)
# for по коллекции:
for item in ["меч", "щит", "зелье"]:
print(item)
# while:
var k := 3
while k > 0:
print(k)
k -= 1
# break прерывает цикл, continue — пропускает итерацию:
for n in range(10):
if n == 5:
break
if n % 2 == 0:
continue
print(n) # 1, 3
Массивы и словари
# Array — упорядоченный список:
var items := ["меч", "щит", "зелье"]
items.append("лук") # добавить в конец
items.insert(0, "шлем") # вставить по индексу
items.erase("щит") # удалить по значению
print(items[0]) # доступ по индексу
print(items[-1]) # с конца
print(items.size()) # длина
print("меч" in items) # проверка вхождения -> true
items.sort() # сортировка на месте
# Типизированный массив:
var scores: Array[int] = [10, 20, 30]
# Dictionary — пары ключ:значение:
var player := {
"name": "Герой",
"hp": 100,
"level": 5
}
print(player["name"]) # доступ по ключу
player["hp"] = 90 # изменение
player["mana"] = 50 # добавление нового ключа
print(player.has("level")) # есть ли ключ -> true
player.erase("mana") # удалить ключ
for key in player: # перебор ключей
print(key, "=", player[key])
Функции
# Функция объявляется через func:
func greet(who):
print("Привет, ", who)
# С типами аргументов и типом возврата (->):
func add(a: int, b: int) -> int:
return a + b
# Аргументы по умолчанию:
func damage(amount: int, crit: bool = false) -> int:
return amount * 2 if crit else amount
# Функция без возврата -> void:
func log_msg(text: String) -> void:
print("[LOG] ", text)
print(add(2, 3)) # 5
print(damage(10, true)) # 20
# Лямбда (анонимная функция):
var square := func(x): return x * x
print(square.call(4)) # 16
Классы и наследование
Каждый скрипт .gd — это класс. extends задаёт родителя, class_name регистрирует тип в движке.
# Файл enemy.gd — скрипт-класс:
extends Node # наследуем от встроенного узла Node
class_name Enemy # теперь Enemy доступен глобально как тип
var hp: int = 100 # поле класса
var enemy_name := "Гоблин"
# _ready вызывается, когда узел готов (см. жизненный цикл ниже):
func _ready() -> void:
print(enemy_name, " появился")
# Метод класса:
func take_damage(amount: int) -> void:
hp -= amount
if hp <= 0:
die()
func die() -> void:
print(enemy_name, " повержен")
queue_free() # удалить узел из сцены
# Вложенный класс:
class Item:
var title: String
func _init(t: String) -> void: # _init — конструктор
title = t
Сигналы
Сигналы — главный механизм событий Godot. Узел «излучает» сигнал, другие подписываются и реагируют.
extends Node
# Объявление сигнала (можно с параметрами):
signal died
signal health_changed(new_hp: int)
var hp := 100
func _ready() -> void:
# Подписка на сигнал -> вызовется _on_died при излучении:
died.connect(_on_died)
health_changed.connect(_on_health_changed)
func take_damage(amount: int) -> void:
hp -= amount
health_changed.emit(hp) # излучить сигнал с аргументом
if hp <= 0:
died.emit() # излучить сигнал без аргументов
# Обработчики (по соглашению называются _on_имя):
func _on_died() -> void:
print("Персонаж умер")
func _on_health_changed(new_hp: int) -> void:
print("Здоровье теперь: ", new_hp)
Экспорт переменных в редактор
Аннотация @export делает переменную видимой и редактируемой в инспекторе Godot.
extends Node
@export var speed: float = 200.0 # ползунок/поле в инспекторе
@export var title: String = "Враг"
@export var is_boss: bool = false
@export_range(0, 100) var hp: int = 50 # ограниченный диапазон
@export_enum("Лёгкий", "Средний", "Сложный") var difficulty: int
@export var color: Color = Color.RED # выбор цвета
@export var target: NodePath # ссылка на узел из дерева
# Группировка полей в инспекторе:
@export_group("Боевые параметры")
@export var damage: int = 10
@export var attack_range: float = 64.0
Узлы и дерево сцены
Сцена — это дерево узлов. Из скрипта к ним обращаются по пути.
extends Node2D
func _ready() -> void:
# get_node("Path") — получить дочерний узел по пути:
var sprite = get_node("Sprite2D")
# $ — краткая запись get_node:
var label = $UI/ScoreLabel # вложенный путь через /
# Узлом можно управлять:
sprite.position = Vector2(100, 50)
sprite.visible = true
label.text = "Очки: 0"
# Поиск и навигация по дереву:
var parent = get_parent() # родитель
add_child(Node2D.new()) # добавить дочерний узел
var found = get_tree().get_first_node_in_group("enemies")
# Загрузить и создать сцену во время игры:
var bullet_scene := preload("res://bullet.tscn")
var bullet = bullet_scene.instantiate()
add_child(bullet)
Коллбэки жизненного цикла
Движок сам вызывает методы с именами на _ в нужные моменты.
extends Node
# Вызывается один раз, когда узел вошёл в дерево сцены и готов:
func _ready() -> void:
print("Готов")
# Вызывается каждый кадр; delta — время с прошлого кадра (сек):
func _process(delta: float) -> void:
pass # игровая логика, анимация
# Кадр физики (фиксированный шаг) — для движения и физики:
func _physics_process(delta: float) -> void:
pass
# Любое событие ввода (клавиши, мышь, тач):
func _input(event: InputEvent) -> void:
if event.is_action_pressed("ui_accept"):
print("Нажат Enter/пробел")
# Узел покидает дерево (удаление, смена сцены):
func _exit_tree() -> void:
print("Удаляюсь")
Типичный игровой скрипт: движение персонажа
Соберём всё вместе — скрипт управления 2D-персонажем (узел CharacterBody2D).
extends CharacterBody2D
# Скрипт вешается на узел CharacterBody2D — тело с физикой.
@export var speed: float = 300.0 # скорость, настраивается в инспекторе
@export var jump_force: float = 600.0
const GRAVITY := 1200.0 # сила гравитации
signal jumped # сигнал прыжка для других систем
func _physics_process(delta: float) -> void:
# Гравитация: тянем вниз, пока в воздухе
if not is_on_floor():
velocity.y += GRAVITY * delta
# Горизонтальный ввод: -1 (влево), 0, +1 (вправо)
var direction := Input.get_axis("ui_left", "ui_right")
velocity.x = direction * speed
# Прыжок только с земли
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = -jump_force # вверх — это отрицательный Y
jumped.emit() # сообщаем о прыжке
# Двигаем тело с учётом столкновений
move_and_slide() # velocity применяется автоматически
# Поворот спрайта по направлению движения
if direction != 0:
$Sprite2D.flip_h = direction < 0