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
Поддержать проект