GDScript — встроенный язык программирования Godot. Основные черты:
# Без указания типа (тип определяется автоматически)
var score = 0
var player_name = "Игрок"
var speed = 150.5
# С указанием типа (рекомендуется)
var score: int = 0
var player_name: String = "Игрок"
var speed: float = 150.5
var start_pos: Vector2 = Vector2(100, 200)
# Константы — значения, которые не меняются
const MAX_LEVELS: int = 10
const GRAVITY: float = 980.0
| Тип | Описание | Пример |
|---|---|---|
int |
Целое число | 42, -7, 0 |
float |
Дробное число | 3.14, -0.5 |
bool |
Логическое значение | true, false |
String |
Строка | "Привет" |
Vector2 |
2D-вектор (x, y) | Vector2(100, 200) |
Color |
Цвет (r, g, b, a) | Color.RED, Color(1, 0, 0) |
Array |
Массив | [1, 2, 3], ["a", "b"] |
Dictionary |
Словарь (ключ-значение) | {"hp": 100, "name": "Boss"} |
var pos := Vector2(100, 200)
var direction := Vector2.RIGHT # Vector2(1, 0)
# Операции
pos += direction * 5.0 # Сдвинуть вправо на 5
var length := pos.length() # Длина вектора
var velocity := Vector2(3, 4)
var norm := velocity.normalized() # → Vector2(0.6, 0.8), длина = 1
# Расстояние между двумя точками
var dist := pos.distance_to(Vector2(300, 400))
# Массив — упорядоченная коллекция
var inventory: Array = ["ключ", "фонарь", "карта"]
inventory.append("компас") # Добавить в конец
var first = inventory[0] # "ключ"
var count = inventory.size() # 4
# Словарь — набор пар ключ:значение
var stats: Dictionary = {
"level": 1,
"hp": 100,
"items": ["меч", "щит"]
}
stats["hp"] -= 10 # Уменьшить hp
@export делает переменную видимой и редактируемой в инспекторе Godot:
@export var speed: float = 200.0
@export var max_health: int = 100
@export var color: Color = Color.WHITE
@export var object_scene: PackedScene # Ссылка на другую сцену
Это позволяет настраивать параметры объекта без изменения кода — прямо в редакторе. Например, разные экземпляры одного и того же объекта могут иметь разную скорость.
# Простая функция
func say_hello() -> void:
print("Привет!")
# Функция с параметрами и возвратом значения
func add(a: int, b: int) -> int:
return a + b
# Функция с параметром по умолчанию
func damage(amount: int, critical: bool = false) -> int:
if critical:
return amount * 2
return amount
Godot автоматически вызывает определённые функции:
# Вызывается ОДИН РАЗ при добавлении узла в сцену
func _ready() -> void:
print("Узел готов!")
# Вызывается КАЖДЫЙ КАДР (~60 раз в секунду)
# delta — время между кадрами (обычно ~0.016 сек)
func _process(delta: float) -> void:
position.x += speed * delta # Движение, не зависящее от FPS
# Вызывается при каждом событии ввода
func _input(event: InputEvent) -> void:
if event is InputEventMouseButton:
print("Клик мыши!")
# Вызывается с фиксированной частотой (для физики)
func _physics_process(delta: float) -> void:
pass
Важно: delta — время в секундах между кадрами. Умножая на delta, вы делаете движение плавным и одинаковым на любом компьютере, вне зависимости от FPS.
var health: int = 75
if health <= 0:
print("Игра окончена")
elif health < 30:
print("Мало здоровья!")
else:
print("Всё в порядке")
# Цикл for — перебор элементов
for item in ["ключ", "меч", "щит"]:
print(item)
# Цикл for — диапазон чисел
for i in range(5): # 0, 1, 2, 3, 4
print("Уровень ", i)
# Цикл while
var count := 0
while count < 10:
count += 1
var state: String = "idle"
match state:
"idle":
print("Ожидание")
"moving":
print("Движение")
"attacking":
print("Атака")
_:
print("Неизвестное состояние")
func _process(delta: float) -> void:
var direction := Vector2.ZERO
# Проверяем, зажата ли клавиша
if Input.is_action_pressed("ui_right"):
direction.x += 1
if Input.is_action_pressed("ui_left"):
direction.x -= 1
if Input.is_action_pressed("ui_up"):
direction.y -= 1 # В Godot ось Y направлена вниз!
if Input.is_action_pressed("ui_down"):
direction.y += 1
# Нормализуем, чтобы по диагонали скорость не увеличивалась
direction = direction.normalized()
position += direction * speed * delta
Действия ui_right, ui_left и т.д. — предустановленные в Godot (стрелки клавиатуры).
func _input(event: InputEvent) -> void:
# Клик мыши
if event is InputEventMouseButton:
if event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
print("Клик в точке: ", event.position)
# Нажатие клавиши (один раз, не удержание)
if event is InputEventKey:
if event.pressed and event.keycode == KEY_SPACE:
print("Пробел нажат!")
extends Sprite2D
var dragging: bool = false
var drag_offset: Vector2 = Vector2.ZERO
func _input(event: InputEvent) -> void:
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
if event.pressed:
# Проверяем, попали ли мы в этот спрайт
if _is_mouse_over():
dragging = true
drag_offset = global_position - event.position
else:
dragging = false
if event is InputEventMouseMotion and dragging:
global_position = event.position + drag_offset
func _is_mouse_over() -> bool:
var mouse_pos := get_global_mouse_position()
var tex := texture
if tex == null:
return false
var size := tex.get_size() * scale # Учитываем масштаб спрайта
var rect := Rect2(global_position - size / 2, size)
return rect.has_point(mouse_pos)
Сигналы — это механизм коммуникации между узлами. Один узел отправляет сигнал, другие — реагируют.
У многих узлов уже есть сигналы:
Button → pressed (кнопка нажата)Timer → timeout (таймер сработал)Area2D → body_entered (тело попало в зону)Area2D → body_exited (тело покинуло зону)Button)pressedfunc _ready() -> void:
# Подключаем сигнал "pressed" кнопки к нашей функции
var button := $StartButton as Button
button.pressed.connect(_on_start_button_pressed)
# Подключаем сигнал таймера
var timer := $SpawnTimer as Timer
timer.timeout.connect(_on_spawn_timer_timeout)
func _on_start_button_pressed() -> void:
print("Кнопка нажата!")
func _on_spawn_timer_timeout() -> void:
print("Таймер сработал!")
Оператор $ — это сокращение для get_node(). $StartButton означает «дочерний узел с именем StartButton».
Можно создавать свои сигналы:
# Объявляем сигнал
signal health_changed(new_value: int)
signal died
var health: int = 100
func take_damage(amount: int) -> void:
health -= amount
health_changed.emit(health) # Отправляем сигнал с параметром
if health <= 0:
died.emit() # Отправляем сигнал без параметров
В другом скрипте:
func _ready() -> void:
var player := $Player
player.health_changed.connect(_on_player_health_changed)
player.died.connect(_on_player_died)
func _on_player_health_changed(new_value: int) -> void:
$HealthLabel.text = "HP: " + str(new_value)
func _on_player_died() -> void:
print("Игрок погиб!")
# Получить дочерний узел по имени
var sprite := $Sprite2D # Прямой потомок
var label := $Objects/Piece1/Label # Вложенный путь
# Получить родительский узел
var parent := get_parent()
# Получить все дочерние узлы
for child in get_children():
print(child.name)
# Проверить, существует ли узел
if has_node("Sprite2D"):
print("Узел найден")
# Безопасное получение (вернёт null, если нет)
var node := get_node_or_null("MaybeExists")
if node != null:
print("Узел существует")
Часто нужно создавать объекты во время игры — например, снаряды, предметы или эффекты.
# Загружаем сцену (лучше через @export)
@export var piece_scene: PackedScene
func spawn_piece() -> void:
var piece := piece_scene.instantiate() # Создать экземпляр
piece.position = Vector2(400, 300) # Задать позицию
add_child(piece) # Добавить в дерево сцены
instantiate() — создаёт копию сцены. Пока узел не добавлен через add_child(), он не виден и не обрабатывается.
# Удалить узел из дерева (безопасно, в конце кадра)
piece.queue_free()
# Удалить всех потомков
for child in get_children():
child.queue_free()
queue_free() — безопасное удаление. Узел будет удалён в конце текущего кадра, что предотвращает ошибки при обращении к нему.
# Получить количество объектов в контейнере
var count := $SpawnArea.get_child_count()
$Counter.text = "Объектов: " + str(count)
Timer — полезный узел для периодических действий:
# Создание таймера через код
func _ready() -> void:
var timer := Timer.new()
timer.wait_time = 2.0 # Каждые 2 секунды
timer.one_shot = false # Повторять (true = один раз)
timer.timeout.connect(_on_timer)
add_child(timer) # Добавить в дерево
timer.start() # Запустить
func _on_timer() -> void:
print("Тик!")
Или добавьте Timer как узел в редакторе — это проще и нагляднее.
| Тема | Ключевое |
|---|---|
| Переменные | var, const, типизация через : |
| @export | Переменная видна в инспекторе |
| Колбэки | _ready(), _process(delta), _input(event) |
| Ввод | Input.is_action_pressed(), InputEventMouseButton |
| Drag-and-drop | InputEventMouseMotion + отслеживание состояния |
| Сигналы | signal, .emit(), .connect() |
| Доступ к узлам | $NodeName, get_node(), get_parent() |
| Динамические узлы | instantiate(), add_child(), queue_free() |