Godot — первая 2D-игра за вечер
Godot — бесплатный игровой движок с открытым исходным кодом. В нём вы собираете игру из сцен (файлов с деревом узлов), пишете логику на GDScript (язык, похожий на Python) и экспортируете результат на ПК, веб или мобильные платформы. Эта статья ведёт от установки до полноценного прототипа 2D-платформера с прыжком, монетами, счётом, интерфейсом, звуковыми заготовками и экраном поражения.
Сравнение Godot с Unity, Unreal и Roblox — в Видах игровых движков. Общий маршрут геймдева и игровой цикл на Pygame помогут, если вы уже пробовали код без редактора. Для школьников есть короткая версия — Godot и Construct 3.
Расширенный словарь
Перед установкой полезно пройтись по терминам. Каждый пункт объяснён так, чтобы его понял человек без опыта в геймдеве.
Основные понятия
- Игровой движок — программа, которая рисует кадры на экране, обрабатывает нажатия клавиш и мыши, считает физику и запускает ваш код. Подробнее — Игровой движок.
- Godot Engine — конкретный движок версии 4.x. Скачивается с godotengine.org. Редактор и "игровой рантайм" (программа, которая запускает игру) идут в одном пакете.
- Проект — папка на диске с настройками, сценами, скриптами и ресурсами (картинки, звуки). Godot хранит главный файл настроек
project.godot. - Сцена (scene) — файл с расширением
.tscn(текстовый) или.scn(бинарный). Внутри — дерево узлов. Сцена может быть персонажем, уровнем, меню или монетой. - Узел (node) — один элемент дерева сцены. У узла есть тип (например, спрайт, коллайдер, камера), имя и дочерние узлы. Аналогия — элемент DOM в HTML или GameObject в Unity.
- Дерево сцены — иерархия узлов слева в редакторе. Родитель задаёт систему координат и наследование поведения для детей.
- Ресурс (resource) — данные, которые переиспользуют: текстура, звук, шрифт, тайлсет. Файлы
.tresили встроенные в.tscn. - Инстанс (instance) — вставленная копия другой сцены. Уровень "инстансит"
player.tscn, чтобы не дублировать персонажа вручную. - Main Scene — сцена, с которой игра начинается при запуске. Назначается в настройках проекта.
Языки и скрипты
- GDScript — встроенный язык Godot. Синтаксис близок к Python: отступы,
func,var, без фигурных скобок для блоков. Документация — GDScript reference. - Скрипт — файл
.gd, прикреплённый к узлу. Один узел — один основной скрипт (хотя можно подключать и другие черезpreload). extends— строка в начале скрипта, указывающая тип узла, к которому он привязан. Скрипт наследует методы и свойства этого типа.- Сигнал (signal) — механизм событий Godot. Узел "излучает" сигнал, другие узлы подписываются и реагируют. Похоже на события в GUI.
- Autoload (синглтон) — скрипт, который Godot загружает один раз при старте игры и делает доступным глобально по имени. Удобен для счёта, музыки, сохранений.
2D-узлы и физика
- Node2D — базовый 2D-узел с позицией, поворотом и масштабом. Корень уровня часто именно он.
- Sprite2D — показывает картинку (текстуру) на экране.
- CharacterBody2D — тело персонажа для платформеров. Вы сами задаёте скорость, движок помогает скользить вдоль полов через
move_and_slide(). - StaticBody2D — неподвижное тело (пол, стена, платформа). Не двигается от столкновений.
- RigidBody2D — тело с полной физикой (падает, отскакивает). Для ящиков и снарядов.
- Area2D — зона-триггер без твёрдого отражения. Монета, дверь, зона урона — типичные примеры.
- CollisionShape2D — невидимая форма (прямоугольник, круг, капсула), по которой движок понимает столкновения. Без неё физика "не видит" объект.
- TileMap — слой из плиток (тайлов) по сетке. Стандартный способ строить уровни платформера.
- TileSet — набор плиток с коллизией и текстурами для
TileMap. - Camera2D — камера, задающая, какая часть 2D-мира видна на экране.
- ParallaxBackground — фон из нескольких слоёв, которые двигаются с разной скоростью и создают глубину.
Ввод, UI и звук
- Input Map — таблица в настройках проекта: логические действия ("move_left", "jump") и привязанные к ним клавиши, кнопки геймпада.
- CanvasLayer — слой интерфейса, рисуется поверх игрового мира и не двигается вместе с камерой (если не настроено иначе).
- Label — текстовый элемент UI (счёт, заголовок).
- Control — базовый узел для UI (кнопки, панели).
- AudioStreamPlayer — проигрывает звук или музыку один раз или в цикле.
- AudioStreamPlayer2D — звук в 2D-пространстве с затуханием по расстоянию.
Рендер и экспорт
- Forward+ — рендерер по умолчанию в Godot 4 для desktop. Для простого 2D подходит и он, и Mobile.
- Export preset — профиль сборки под Windows, Linux, Web, Android и другие платформы.
- Export templates — бинарные шаблоны, которые Godot подставляет при сборке. При первом экспорте редактор предложит их скачать.
- PCK — архив с ресурсами игры. Может идти рядом с
.exeили внутри него.
Отладка
- Remote debugger — отладчик, когда игра запущена отдельным окном, а редактор остаётся открытым.
- Breakpoint (точка останова) — строка скрипта, на которой выполнение останавливается для просмотра переменных.
print()— вывод текста в консоль редактора. Самый простой способ понять, что происходит в коде.
Что понадобится
| Требование | Зачем |
|---|---|
| Godot 4.3+ | Редактор и рантайм в одном установщике |
| 2–4 часа спокойной работы | На полный проход по статье с платформером |
| Базовое знакомство с Python или другим скриптовым языком | GDScript читается с первого раза |
| Мышь и клавиатура | Редактор рассчитан на desktop |
Официальная документация — docs.godotengine.org. Официальные туториалы дублируют многие шаги; здесь акцент на связке с энциклопедией и на одном сквозном примере.
Установка Godot 4
Godot распространяется как portable-архив (распаковал и запустил) или через менеджеры пакетов. Регистрация не нужна. Лицензия MIT — движок бесплатен для любых проектов.
Windows
- Откройте godotengine.org/download.
- В блоке Godot Engine выберите Standard version (не .NET, если вы только начинаете — GDScript достаточно).
- Скачайте 64-bit архив
.zip. - Распакуйте в папку без кириллицы и пробелов в пути, например
C:\Tools\Godot\. - Запустите
Godot_v4.x-stable_win64.exe. - При первом запуске Windows может показать предупреждение SmartScreen — нажмите "Подробнее" → "Выполнить в любом случае" (файл с официального сайта).
- По желанию создайте ярлык на рабочем столе.
Системные требования (ориентир)
- Windows 10/11 64-bit
- 4 GB RAM (8 GB комфортнее)
- Видеокарта с поддержкой Vulkan или Direct3D 12 для Forward+
Linux
Вариант A — архив с сайта
- Скачайте Linux x86_64 с godotengine.org/download.
- Распакуйте:
unzip Godot_v4.x-stable_linux.x86_64.zip. - Сделайте файл исполняемым:
chmod +x Godot_v4.x-stable_linux.x86_64. - Запустите из терминала:
./Godot_v4.x-stable_linux.x86_64.
Вариант B — Flatpak
flatpak install flathub org.godotengine.Godot
flatpak run org.godotengine.Godot
Вариант C — дистрибутивный пакет
- Ubuntu/Debian: проверьте
apt, но версия в репозитории часто отстаёт — надёжнее официальный архив. - Fedora: аналогично через
dnf, либо Flatpak.
На Wayland и X11 Godot 4 работает; при глюках окна попробуйте запуск с переменной GODOT_DISABLE_WAYLAND=1 (см. документацию по Linux).
macOS
- Скачайте macOS.universal (Apple Silicon + Intel) с официального сайта.
- Распакуйте и перетащите
Godot.appв Applications. - При первом запуске macOS может заблокировать приложение от неизвестного разработчика: System Settings → Privacy & Security → Open Anyway.
- Для экспорта на iOS позже понадобится Xcode — в этой статье мы его не затрагиваем.
Проверка установки
- Запустите Godot.
- В Project Manager нажмите New Project.
- Если открылось окно выбора рендерера и папки — установка прошла успешно.
Создание проекта FirstPlatformer
- Project Manager → New Project.
- Project Name —
FirstPlatformer. - Project Path — пустая папка, например
Documents/Godot/FirstPlatformer. - Renderer — Forward+ (desktop) или Mobile (если целите слабые устройства). Для чистого 2D разница минимальна.
- Нажмите Create & Edit.
Откроется редактор с пустой сценой. Основные панели:
- Scene (слева вверху) — дерево узлов.
- FileSystem (слева внизу) — файлы проекта.
- Inspector (справа) — свойства выбранного узла.
- Viewport (центр) — вид сцены.
Сохраняйте работу часто: Ctrl+S (Windows/Linux) или Cmd+S (macOS). Подробнее о среде разработки — Разработка и отладка.
Настройка Input Map
Вместо жёсткой привязки к стрелкам удобнее завести свои имена действий. Тогда сменить управление (WASD вместо стрелок) можно без правки скрипта.
- Project → Project Settings.
- Вкладка Input Map.
- В поле Add New Action введите
move_left→ Add. - Разверните
move_left→ + → Key → нажмите A или Left Arrow → OK. - Аналогично создайте действия:
| Действие | Клавиши (пример) |
|---|---|
move_left | A, Left |
move_right | D, Right |
jump | Space, W, Up |
ui_pause | Escape |
- Для геймпада: + → Joy Button или Joy Axis на том же действии.
Как читать действия в коде
Input.is_action_pressed("move_left")— клавиша удерживается.Input.is_action_just_pressed("jump")— нажата один раз за кадр (идеально для прыжка).Input.get_axis("move_left", "move_right")— число от -1 до 1 (влево/вправо/нейтраль).
Встроенные ui_left, ui_right, ui_accept тоже работают, но для учебного проекта лучше явные имена — код читается понятнее.
Сцена игрока Player
Структура узлов
- Scene → New Scene.
- Корневой узел — CharacterBody2D, имя
Player. - Дочерние узлы:
| Узел | Назначение |
|---|---|
| Sprite2D | Картинка героя |
| CollisionShape2D | Форма для физики |
| Camera2D | Камера следует за игроком (добавим позже) |
- Выберите CollisionShape2D → в Inspector у Shape нажмите
<empty>→ New RectangleShape2D → задайте размер под спрайт (например 32×48). - Если нет текстуры — временно добавьте ColorRect (как ребёнок Sprite2D) или используйте встроенную иконку: Sprite2D → Texture → Load → любой PNG из папки
icon.svgпроекта. - Scene → Save Scene As →
player.tscn.
Полный скрипт движения
Выберите корень Player → Attach Script → язык GDScript → Create.
extends CharacterBody2D
## Скорость бега по горизонтали (пикселей в секунду)
const SPEED = 300.0
## Импульс прыжка (отрицательный Y — вверх в Godot)
const JUMP_VELOCITY = -420.0
func _physics_process(delta: float) -> void:
# Гравитация, если не стоим на полу
if not is_on_floor():
velocity += get_gravity() * delta
# Прыжок — только один раз при нажатии и только на земле
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Горизонтальное движение
var direction := Input.get_axis("move_left", "move_right")
if direction != 0.0:
velocity.x = direction * SPEED
else:
# Плавное торможение без нажатой клавиши
velocity.x = move_toward(velocity.x, 0.0, SPEED)
move_and_slide()
Построчное объяснение
| Строка | Что делает |
|---|---|
extends CharacterBody2D | Скрипт привязан к телу персонажа и получает его методы |
const SPEED = 300.0 | Константа скорости; const не меняется во время игры |
const JUMP_VELOCITY = -420.0 | В Godot ось Y направлена вниз, поэтому прыжок — отрицательное число |
func _physics_process(delta) | Вызывается каждый физический кадр (~60 раз/с). delta — секунды с прошлого кадра |
is_on_floor() | Встроенная проверка после move_and_slide() — стоим ли на поверхности |
get_gravity() | Вектор гравитации из настроек проекта (Project Settings → Physics → 2D) |
velocity += get_gravity() * delta | Накапливаем падение: чем дольше в воздухе, тем выше скорость вниз |
Input.is_action_just_pressed("jump") | True только на кадре нажатия — нельзя "зажать" бесконечный прыжок |
Input.get_axis("move_left", "move_right") | -1 влево, +1 вправо, 0 если ничего не нажато |
move_toward(velocity.x, 0.0, SPEED) | Плавно уменьшает горизонтальную скорость к нулю |
move_and_slide() | Двигает тело, учитывает коллизии и скольжение вдоль стен |
Аналог этого цикла в коде без редактора — игровой цикл на Pygame.
Улучшение — coyote time (необязательно)
Короткое "прощение" после схода с платформы — игрок успевает нажать прыжок:
var coyote_timer := 0.0
const COYOTE_TIME = 0.12
func _physics_process(delta: float) -> void:
if is_on_floor():
coyote_timer = COYOTE_TIME
else:
coyote_timer = max(coyote_timer - delta, 0.0)
if Input.is_action_just_pressed("jump") and coyote_timer > 0.0:
velocity.y = JUMP_VELOCITY
coyote_timer = 0.0
# ... остальной код гравитации и move_and_slide
Слои коллизии и маски
Godot различает слой (layer) — "я на слое N" и маску (mask) — "я сталкиваюсь со слоями, где бит N включён". Это битовые флаги в Inspector у тел и зон.
Зачем нужны слои
Без слоёв все объекты сталкиваются со всеми. С слоями вы разделяете:
- игрок
- земля и платформы
- монеты (триггеры)
- враги
- проектили
Рекомендуемая схема для платформера
Project → Project Settings → Layer Names → 2D Physics
| Номер слоя | Имя | Кто использует |
|---|---|---|
| 1 | world | Пол, стены, TileMap |
| 2 | player | CharacterBody2D игрока |
| 3 | pickups | Монеты Area2D |
| 4 | hazards | Шипы, ямы |
Настройка Player (CharacterBody2D)
- Collision Layer — включить бит 2 (
player). - Collision Mask — включить бит 1 (
world) и при необходимости 4 (hazards).
Настройка пола (StaticBody2D)
- Collision Layer — бит 1 (
world). - Collision Mask — можно оставить пустым (пол не "ищет" столкновения сам).
Настройка монеты (Area2D)
- Collision Layer — бит 3 (
pickups). - Collision Mask — бит 2 (
player) — зона реагирует только на игрока.
Монета не должна физически блокировать игрока — для этого подходит Area2D вместо StaticBody2D.
Сцена монеты Coin
- New Scene → корень Area2D → имя
Coin. - Дети: Sprite2D, CollisionShape2D (круг или прямоугольник поменьше спрайта).
- Attach Script:
extends Area2D
signal collected
func _ready() -> void:
# Подписываемся на вход тела в зону
body_entered.connect(_on_body_entered)
func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("player"):
collected.emit()
queue_free()
- Scene → Save Scene As →
coin.tscn.
Построчно
signal collected— объявление собственного сигнала; другие скрипты могут на него подписаться._ready()— вызывается один раз, когда узел попал в дерево сцены.body_entered.connect(...)— при входе CharacterBody2D/RigidBody2D вызовется_on_body_entered.body.is_in_group("player")— проверка группы вместо сравненияbody.name == "Player".queue_free()— безопасное удаление узла в конце кадра.
На узле Player в Inspector вкладка Node → Groups → добавьте группу player.
Autoload для глобального счёта
Счёт монет удобно хранить в одном месте, доступном из любой сцены.
Создание GameState
- Создайте файл
game_state.gdв корне проекта (ПКМ в FileSystem → Create New → Script). - Содержимое:
extends Node
var coins := 0
var lives := 3
signal coins_changed(new_total: int)
signal lives_changed(new_total: int)
signal game_over
func add_coin() -> void:
coins += 1
coins_changed.emit(coins)
func lose_life() -> void:
lives -= 1
lives_changed.emit(lives)
if lives <= 0:
game_over.emit()
func reset_run() -> void:
coins = 0
lives = 3
coins_changed.emit(coins)
lives_changed.emit(lives)
- Project → Project Settings → Autoload.
- Path — выберите
game_state.gd. - Node Name —
GameState(именно так к нему обращаются в коде). - Enable → Add.
Теперь из любого скрипта: GameState.add_coin(), GameState.coins.
Это тот же паттерн "глобального сервиса", что и синглтоны в приложениях — см. Проект и фреймворки.
Связь монеты с GameState
Вариант A — в скрипте уровня инстансить монеты и подписываться на сигнал.
Вариант B — прямо в coin.gd:
func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("player"):
GameState.add_coin()
queue_free()
Уровень Level с TileMap
Ручные платформы из StaticBody2D подходят для пробы; для реального уровня используйте TileMap.
TileSet из одной текстуры
- New Scene → Node2D → имя
Level. - Добавьте дочерний TileMap.
- В Inspector у TileMap → Tile Set → New TileSet.
- Откройте TileSet (клик по ресурсу) → + → Atlas → укажите текстуру тайлов (16×16 или 32×32 сетка).
- Выделите тайлы в редакторе TileSet → Paint → Physics → нарисуйте коллизию на тайлах "земли".
Рисование уровня
- Выберите TileMap → инструмент Paint на панели сверху.
- Рисуйте платформы в viewport.
- Instance Child Scene (кнопка цепочки на панели Scene) →
player.tscn— поместите игрока над полом. - Разместите несколько инстансов
coin.tscn.
Пол без TileMap (быстрый старт)
Если текстур ещё нет:
- StaticBody2D → имя
Ground. - CollisionShape2D — широкий RectangleShape2D (например 2000×40).
- ColorRect или Sprite2D для отображения.
- Позиция Y — низ экрана (например y = 500 при высоте viewport 648).
Интерфейс — счёт и жизни
- В сцене
Levelдобавьте CanvasLayer → имяUI. - Внутри MarginContainer → VBoxContainer → два Label:
CoinsLabel— текст "Монеты: 0"LivesLabel— текст "Жизни: 3"
- На корень
LevelAttach Script:
extends Node2D
@onready var coins_label: Label = $UI/MarginContainer/VBoxContainer/CoinsLabel
@onready var lives_label: Label = $UI/MarginContainer/VBoxContainer/LivesLabel
func _ready() -> void:
GameState.coins_changed.connect(_on_coins_changed)
GameState.lives_changed.connect(_on_lives_changed)
GameState.game_over.connect(_on_game_over)
_on_coins_changed(GameState.coins)
_on_lives_changed(GameState.lives)
func _on_coins_changed(total: int) -> void:
coins_label.text = "Монеты: %d" % total
func _on_lives_changed(total: int) -> void:
lives_label.text = "Жизни: %d" % total
func _on_game_over() -> void:
get_tree().change_scene_to_file("res://game_over.tscn")
Построчно
@onready var ... = $UI/...— ссылка на узел по пути; заполняется после входа в дерево.GameState.coins_changed.connect(...)— UI обновляется при изменении счёта, а не каждый кадр.get_tree().change_scene_to_file(...)— загрузка другой сцены (экран Game Over).
Основы UI — Интерфейс. Стилизация Label через Theme — следующий шаг после прототипа.
Звуковые заготовки
Godot не требует отдельного "аудиодвижка" — достаточно узлов AudioStreamPlayer.
Звук подбора монеты
- Импортируйте
.wavили.oggв проект (перетащите в FileSystem). - В
coin.gdдобавьте:
@onready var pickup_sound: AudioStreamPlayer = $PickupSound
func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("player"):
GameState.add_coin()
if pickup_sound:
pickup_sound.play()
await pickup_sound.finished
queue_free()
- В сцене
Coinдобавьте дочерний AudioStreamPlayer → имяPickupSound→ Stream — ваш файл.
await pickup_sound.finished — скрипт ждёт конца звука перед удалением (опционально; можно удалять сразу).
Фоновая музыка
- В
Levelдобавьте AudioStreamPlayer → имяMusic. - Autoplay — включено, Stream — музыка
.ogg, Bus — Master или отдельная шина Music.
Шины (Audio → Bus Layout) позволяют регулировать громкость SFX и музыки отдельно в настройках игры.
Экран Game Over и перезапуск
- New Scene → Control (корень) → имя
GameOver. - Label — "Игра окончена", Button — "Заново".
- Скрипт на корне:
extends Control
func _ready() -> void:
$RetryButton.pressed.connect(_on_retry_pressed)
func _on_retry_pressed() -> void:
GameState.reset_run()
get_tree().change_scene_to_file("res://level.tscn")
- Сохраните
game_over.tscn. - Project → Project Settings → Application → Run → Main Scene — укажите
level.tscn.
Потеря жизни при падении
На Player добавьте:
@export var fall_limit_y := 800.0
func _physics_process(delta: float) -> void:
# ... движение ...
if global_position.y > fall_limit_y:
GameState.lose_life()
global_position = Vector2(100, 400) # точка респавна — подстройте под уровень
velocity = Vector2.ZERO
При lives <= 0 сработает сигнал game_over из GameState.
Camera2D
- Откройте
player.tscn. - Добавьте Camera2D как ребёнка
Player. - В Inspector:
- Enabled — включено
- Position Smoothing → Enabled — плавное следование
- Limit — границы уровня (left, top, right, bottom), чтобы камера не показывала пустоту за картой
# Опционально в скрипте Level — передать лимиты камере при старте
func _ready() -> void:
var cam = $Player/Camera2D
cam.limit_left = 0
cam.limit_right = 4000
cam.limit_bottom = 648
cam.limit_top = 0
Если камера одна на сцену и не привязана к игроку — используйте RemoteTransform2D или скрипт, копирующий позицию игрока каждый кадр.
Параллакс-фон
- В
Levelдобавьте ParallaxBackground. - Внутри — один или несколько ParallaxLayer.
- На каждый слой — Sprite2D или TextureRect с картинкой неба, гор, облаков.
- У ParallaxLayer свойство Motion Scale —
(0.2, 0)для дальнего фона,(0.5, 0)для среднего. Чем меньше число, тем медленнее слой двигается относительно камеры.
Scroll Base Offset смещает начальную позицию. Mirroring повторяет текстуру для бесконечного горизонта.
Без готовых ассетов временно используйте ColorRect на заднем плане (Z-index ниже TileMap) — CSS-аналогия: слои рисования.
Главная сцена и первый запуск
- Project → Project Settings → Application → Run.
- Main Scene —
level.tscn(или ваш путь). - Display → Window — Viewport Width/Height (например 1152×648), Stretch Mode —
canvas_items, Aspect —keep. - F5 или кнопка Play — запуск с отладчиком.
Если экран чёрный — почти всегда не назначена Main Scene или игрок spawned под землёй.
Отладка
Консоль и print
func _physics_process(delta: float) -> void:
print("velocity=", velocity, " on_floor=", is_on_floor())
Вывод виден во вкладке Output внизу редактора. Для частых сообщений используйте print_rich() или условный флаг DEBUG.
Точки останова
- Откройте скрипт
.gd. - Кликните слева от номера строки — появится красная точка.
- F5 — при достижении строки игра остановится.
- Панель Debugger → Stack & Variables — текущие локальные переменные.
Remote debugger
Когда игра запущена отдельным окном, редактор остаётся подключённым:
- вкладка Remote в Scene tree — живое дерево узлов;
- Remote Inspector — свойства в рантайме;
- ошибки GDScript дублируются в Output.
Типичные сообщения об ошибках
| Текст | Смысл |
|---|---|
Invalid get index 'x' on base 'Nil' | Обращение к узлу, которого нет (опечатка в $Path) |
Attempt to call function in null instance | Метод вызван у освобождённого объекта |
Collision shape not set | У CollisionShape2D пустой Shape |
Подробнее о процессе разработки — Разработка и отладка.
Экспорт на платформы
Project → Export → Add… — выберите пресет.
При первом экспорте Godot предложит скачать export templates — согласитесь (Editor → Manage Export Templates → Download and Install).
Windows Desktop
- Пресет Windows Desktop.
- Runnable — включено.
- Export Path —
builds/FirstPlatformer.exe. - Export Project.
Результат — .exe и рядом .pck (или один embedded, если включено Embed PCK). Распространяйте оба файла в одной папке.
Linux
- Пресет Linux/X11 (или Wayland при необходимости).
- Экспорт даст бинарник без расширения и
.pck. - На целевой машине:
chmod +x FirstPlatformer.
Web (HTML5)
- Пресет Web.
- Export Path — папка
builds/web/index.html. - После экспорта нужен локальный HTTP-сервер — браузер блокирует WASM при открытии файла напрямую через
file://.
# Python 3
python -m http.server 8060 --directory builds/web
Откройте http://localhost:8060.
Ограничения Web-экспорта — нет многопоточности как на desktop, размер загрузки больше. Документация — Exporting for the Web.
Android (обзор)
- Установите Android SDK и JDK 17.
- Editor → Editor Settings → Export → Android — пути к SDK и debug keystore.
- Пресет Android → package name, версии, иконки.
- Подключите устройство с USB-отладкой → Export Project или One-Click Deploy.
Для первой игры достаточно desktop; мобильный экспорт — отдельная неделя настройки.
Таблица пресетов
| Платформа | Формат | Примечание |
|---|---|---|
| Windows | .exe + .pck | Запуск на Win 10+ |
| Linux | бинарник + .pck | Проверьте libc на старых дистрибутивах |
| Web | .html + .wasm + .pck | Только через HTTP |
| Android | .apk / .aab | Нужен SDK и подпись |
| macOS | .app | Codesign для распространения вне Mac |
Публикация в Steam или itch.io — шаг после стабильного билда. См. Маркетинг и распространение.
Производительность 2D
Godot 4 быстр для 2D, но на слабых машинах и Web полезны привычки:
- Один TileMap на слой вместо сотен StaticBody2D — меньше объектов физики.
- Отключайте процесс у объектов вне экрана:
visibility_notifier.visible = false→set_process(false). - Object pooling — переиспользуйте пули и монеты вместо
queue_free+ новый инстанс каждый раз (актуально при сотнях объектов). - Текстуры — степени двойки (256, 512), атласы вместо тысяч мелких PNG.
- Particles2D — ограничивайте amount; на mobile снижайте.
- Profiler — Debugger → Monitors при запуске игры: FPS, объектов, draw calls.
- VisibleOnScreenNotifier2D — не рисовать анимации вне камеры.
Для pixel art включите Project Settings → Rendering → Textures → Canvas Textures → Default Texture Filter → Nearest.
Сравнение движков для 2D-новичка
| Критерий | Godot 4 | Unity | Unreal Engine |
|---|---|---|---|
| Лицензия | MIT, бесплатно | Бесплатно до порога выручки | Бесплатно с роялти после порога |
| Язык по умолчанию | GDScript | C# | C++ / Blueprints |
| 2D из коробки | Сильный TileMap, 2D-узлы | 2D есть, экосистема больше 3D | 2D возможен, фокус на 3D |
| Размер установки | ~100 MB portable | Крупный Hub + модули | Очень крупный |
| Открытый код | Да | Нет | Исходники доступны, не OSI |
| Веб-экспорт | WASM, настраивается | WebGL (ограничения) | Pixel Streaming, тяжело |
| Кривая обучения для платформера | Низкая–средняя | Средняя | Высокая для чистого 2D |
| Сообщество и ассеты | Растёт, Asset Library | Огромное | Огромное, 3D-уклон |
Подробнее — Виды игровых движков. Альтернатива без кода — Roblox Studio — первая игра.
Частые вопросы (FAQ)
Godot 3 или Godot 4? Для новых проектов берите Godot 4. Тutorials и Asset Library постепенно переехали; API 3.x устаревает.
Нужен ли .NET / C#? Нет. GDScript покрывает учебный платформер и большинство indie-2D. C# в Godot 4 на части платформ ограничен — см. официальную таблицу поддержки.
Где взять бесплатные спрайты и тайлы? Kenney.nl, OpenGameArt.org, itch.io asset packs. Укажите авторов в credits.
Почему персонаж дёргается на склонах?
Проверьте форму CollisionShape2D, floor_max_angle у CharacterBody2D, используйте move_and_slide() один раз за _physics_process.
Как сделать двойной прыжок?
Счётчик прыжков: при jump уменьшайте jumps_left; на полу сбрасывайте в 2.
Как сохранить прогресс?
FileAccess.open("user://save.json", FileAccess.WRITE) и JSON — см. Конфигурации и данные.
Можно ли писать на Python? Напрямую нет. GDScript похож; логику из Pygame-практикума переносят почти строка в строку.
Как повернуть спрайт в сторону бега?
sprite_2d.flip_h = direction < 0 или смена animation в AnimatedSprite2D.
Игра тормозит в редакторе, но не в экспорте Редактор тяжелее; сравнивайте F5 и Export. Закройте лишние панели профайлера.
Как поставить игру на itch.io?
Zip с .exe + .pck или Web-папку; в настройках проекта itch укажите главный html или exe.
Area2D не срабатывает Проверьте Monitoring, collision mask/layer, что игрок — CharacterBody2D, а не только Sprite2D.
Ошибка "Main scene not found" Main Scene в Project Settings указывает на удалённый файл — переназначьте.
Как сделать паузу?
get_tree().paused = true и Process Mode у UI — When Paused.
Есть ли мультиплеер? Есть High-level multiplayer API; для первой игры не обязателен.
Как версионировать проект в Git?
Коммитьте project.godot, сцены, скрипты; в .gitignore добавьте .godot/ (кэш импорта). См. Основы Git.
Где учиться дальше официально? Your first 2D game — пошаговый дубликат с официальными ассетами.
Расширенная таблица неполадок
| Симптом | Вероятная причина | Что сделать |
|---|---|---|
| Персонаж проваливается сквозь пол | Нет CollisionShape2D у пола | Добавьте форму, включите слой world |
| Проваливание на краях тайлов | Щели между тайлами | Включите snap в TileMap; проверьте collision polygon |
| Прыжок не работает | is_on_floor() false | Утолщите пол; проверьте collision mask игрока |
| Прыжок срабатывает в воздухе | Используете is_action_pressed вместо just_pressed | Замените на is_action_just_pressed |
| Игрок застревает в стене | CollisionShape больше спрайта | Уменьшите форму или включите separation в move_and_slide |
| Монета не исчезает | Неверная mask у Area2D | Mask должен включать слой игрока |
| Счёт не обновляется | Autoload не подключён | Project Settings → Autoload → GameState |
| UI не видно | Label за пределами экрана | Anchor/margin у Control; CanvasLayer |
| Чёрный экран | Нет Main Scene / камеры | Назначьте Main Scene; Camera2D enabled |
| Розовые текстуры | Файл не импортирован | Подождите импорт; проверьте путь res:// |
| Ошибка при экспорте Web | Нет templates | Editor → Manage Export Templates |
.exe не запускается на другом ПК | Антивirus / отсутствует .pck | Копируйте всю папку builds; подпишите exe позже |
| Звук не слышно | Bus muted / Stream пустой | Audio bus; проверьте @onready путь |
| Игра ускоряется на 144 Hz мониторе | Логика в _process без delta | Физику держите в _physics_process |
| Сцена не сохраняется | Нет прав на папку | Перенесите проект из Program Files |
| Скрипт "не меняется" | Не сохранён .gd | Ctrl+S на скрипте и сцене |
| Параллакс дёргается | Motion Scale слишком большой | Уменьшите до 0.1–0.5 |
| TileMap коллизия только сверху | One Way Collision | Настройте в TileSet physics layers |
Полный чеклист платформера
- Godot 4 установлен, проект
FirstPlatformerсоздан - Input Map:
move_left,move_right,jump -
player.tscn— CharacterBody2D, коллизия, скрипт движения - Группа
playerна узле Player - Слои физики названы и назначены
-
coin.tscn— Area2D, GameState.add_coin() -
game_state.gdв Autoload как GameState -
level.tscn— пол или TileMap, игрок, монеты, UI - Camera2D у игрока с limit
-
game_over.tscnи lose_life при падении - Main Scene назначена
- F5 — игра playable
- Export Windows или Web проверен
Дизайн уровней и playtest — Гейм-дизайн и прототип с playtest.
Куда дальше — маршрут обучения
Неделя 1 — основы (вы здесь)
- Пройти эту статью до чеклиста
- Официальный Your first 2D game
- Виды игровых движков — контекст выбора инструмента
Неделя 2 — контент и полировка
- AnimatedSprite2D — анимации бега и прыжка
- TileMap с автотайлами (terrain)
- Theme и Button — главное меню
- Гейм-дизайн — баланс прыжка и длины уровня
Неделя 3 — системы
- Сохранения через
user://и JSON - SceneTree.change_scene — несколько уровней
- Простой враг на CharacterBody2D или патруль по Path2D
- Практикум на Python — те же идеи без редактора для понимания "под капотом"
Месяц 2 — углубление
- Каталог open-source клонов — разбор чужих Godot-проектов
- Shaders 2D (CanvasItem)
- NavigationAgent2D для врагов
- Экспорт на Android или Steam — игровая индустрия
Параллельные треки
- Roblox Studio — первая игра — онлайн-платформа с готовой аудиторией
- Godot и Construct 3 — упрощённый вход для детей
- Unity — если нужна 3D или C#-экосистема
- Разработка игр — intro — общая карта раздела
Полезные ссылки
- godotengine.org — загрузки и новости
- docs.godotengine.org — справочник API
- Godot Asset Library — плагины и демо
- Форум Godot — вопросы сообщества
Структура папок проекта
Упорядоченная структура упрощает поиск файлов, когда сцен больше десяти.
FirstPlatformer/
├── project.godot
├── game_state.gd # Autoload
├── scenes/
│ ├── player.tscn
│ ├── coin.tscn
│ ├── level.tscn
│ ├── game_over.tscn
│ └── main_menu.tscn # позже
├── scripts/ # общие скрипты без сцены
├── assets/
│ ├── sprites/
│ ├── audio/
│ └── fonts/
└── builds/ # экспорт (в .gitignore)
Пути в коде всегда начинаются с res:// — корень проекта Godot. Пользовательские сохранения пишут в user:// (отдельная папка ОС, не в репозитории).
Переименование файлов в FileSystem безопаснее, чем в проводнике — Godot обновит ссылки в .tscn.
AnimatedSprite2D — анимации бега
Когда появится spritesheet (несколько кадров на одной картинке):
- Замените Sprite2D на AnimatedSprite2D у
Player. - Sprite Frames → New SpriteFrames.
- Откройте редактор SpriteFrames внизу → Add Animation →
run,idle,jump. - Перетащите кадры из FileSystem в timeline анимации.
- В скрипте:
@onready var anim: AnimatedSprite2D = $AnimatedSprite2D
func _physics_process(delta: float) -> void:
# ... гравитация и move_and_slide ...
if not is_on_floor():
anim.play("jump")
elif abs(velocity.x) > 10.0:
anim.play("run")
else:
anim.play("idle")
anim.flip_h = velocity.x < 0
FPS анимации настраивается в SpriteFrames (обычно 8–12 для pixel art). Loop для run и idle включён; для jump — однократное проигрывание.
Главное меню (заготовка)
- New Scene → Control → имя
MainMenu, anchors — full rect. - VBoxContainer по центру → Label "First Platformer" → Button "Играть" → Button "Выход".
- Скрипт:
extends Control
func _ready() -> void:
$VBoxContainer/PlayButton.pressed.connect(_on_play)
$VBoxContainer/QuitButton.pressed.connect(_on_quit)
func _on_play() -> void:
GameState.reset_run()
get_tree().change_scene_to_file("res://scenes/level.tscn")
func _on_quit() -> void:
get_tree().quit()
- Main Scene в Project Settings →
main_menu.tscn.
Кнопка "Выход" на Web не закрывает вкладку — там скрывают её или показывают "В меню".
Git и .gitignore для Godot
Версионирование через Git сохраняет историю сцен и скриптов.
Пример .gitignore в корне проекта:
# Godot 4+ specific
.godot/
*.translation
# Imported assets (регенерируются при импорте)
*.import
# Export
builds/
export_presets.cfg
# OS
.DS_Store
Thumbs.db
Коммитьте:
project.godot.gd,.tscn,.tres- исходные PNG, WAV, OGG
Не коммитьте .godot/ — это кэш импорта; он создаётся заново при открытии проекта.
Первый коммит
git init
git add project.godot scenes/ scripts/ assets/ game_state.gd .gitignore
git commit -m "Initial Godot platformer prototype"
При конфликте в .tscn (текстовый формат) Godot иногда мёржит автоматически; при сложном конфликте проще пересобрать сцену в редакторе.
Сигналы как альтернатива прямому вызову GameState
В coin.gd можно излучать только сигнал без прямого вызова GameState — уровень решает, что делать:
# coin.gd
signal picked_up
func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("player"):
picked_up.emit()
queue_free()
# level.gd — в _ready после инстанса монет
for coin in $Coins.get_children():
if coin.has_signal("picked_up"):
coin.picked_up.connect(_on_coin_picked_up)
func _on_coin_picked_up() -> void:
GameState.add_coin()
$UI/MarginContainer/VBoxContainer/CoinsLabel.text = "Монеты: %d" % GameState.coins
Плюс — монета не знает о глобальном состоянии; минус — больше проводки на уровне. Для учебного проекта оба подхода допустимы.
Настройки физики 2D
Project → Project Settings → Physics → 2D
| Параметр | Значение по умолчанию | Когда менять |
|---|---|---|
| Default Gravity | 980 px/s² | Меньше — "лунная" гравитация; больше — тяжёлый прыжок |
| Default Linear Damp | 0 | Сопротивление воздуха для RigidBody2D |
| Sleep Threshold | 0.1 | Оптимизация тел в покое |
Для платформера часто ставят gravity 980–1200 и подбирают JUMP_VELOCITY экспериментально. Меняйте одну константу за раз и проверяйте F5.
Project Settings → Layer Names → 2D Physics — именуйте все 32 слоя сразу, даже если используете четыре. Через месяц вы забудете, какой бит за что отвечает.
Режимы Process Mode
У каждого узла свойство Process Mode (Inspector → Node):
- Inherit — как у родителя
- Pausable — останавливается при
get_tree().paused = true - When Paused — работает только на паузе (UI меню паузы)
- Always — игнорирует паузу (музыка, Autoload-таймеры)
- Disabled — код
_process/_physics_processне вызывается
UI паузы вешайте на CanvasLayer с When Paused; игровой мир — Pausable.
Итог
За один вечер можно пройти путь от установки Godot 4 до playable 2D-платформера с монетами, счётом через Autoload, UI, камерой, заготовками под звук и экраном поражения. GDScript переносит привычки из Python; сцены и сигналы — навыки, которые масштабируются на большие проекты. Следующий шаг — официальный туториал, TileMap-арт и маршрут геймдева по вашему жанру.