Нажми — и увидишь, что делает команда
- ⏱ Сколько займёт
- 30–50 минут, 5 шагов. Каждый шаг заканчивается результатом на экране.
- 💻 Что нужно
- Компьютер с Windows или macOS. Понадобится Godot — бесплатный, поставим на первом шаге. С телефона этот квест не проходится.
- ⏸ Если прервёшься
- Ничего не потеряется: прогресс сохраняется на этом устройстве. Вернёшься — продолжишь с того же шага.
- 🎓 Чему научишься
- заготовки сцен · создание объектов в игре · ограниченный ресурс
Сцена внутри сцены
Тео снимает со стены гарпун: «Крабов больше, чем твоей смелости. Пора отвечать».
Гарпунов в колчане десять, и больше в кузне нет. Выстрелил — стало девять.
«Запомни закон кузни: оружие делают заранее, а достают в бою. Сделай заготовку гарпуна — и в бою просто доставай копии».
Это записано в самом Godot — движок посчитал физику и нарисовал каждый кадр. К концу квеста такая же игра будет запускаться у тебя.
Читать текстом
Сегодня главное слово — инстанс: копия заготовки, рождённая прямо во время игры.
В Godot заготовка — это отдельный файл сцены. Сохранил один раз, а дальше делай сколько угодно копий из кода.
Собери это в новой сцене: Сцена → Новая сцена → «Другой узел» → в поиске набери RigidBody2D → Ctrl+S и сохрани как res://prefabs/bullet.tscn (папку prefabs Godot создаст сам, если написать её в пути). У корня в Инспекторе: Gravity Scale = 0 (гарпун не должен падать) и Linear → Velocity → x = 600 (летит вправо сам). Сигнал body_entered у HitZone подключим в третьем шаге.
Игра создаёт гарпун
# вверху скрипта героя, рядом с переменными: var bullet_scene: PackedScene = preload("res://prefabs/bullet.tscn") # внутри _physics_process, после кода движения: if Input.is_action_just_pressed("fire") and GameManager.bullets > 0: GameManager.bullets -= 1 var b = bullet_scene.instantiate() b.position = position + Vector2(60, 0) get_parent().add_child(b)
preload загружает файл сцены один раз при старте. instantiate() делает из него живую копию. add_child кладёт её в уровень — только после этого гарпун появится.Сначала две подготовки — без них игра упадёт на первом же F5.
Раз: открой копилку из третьего квеста scripts/game_manager.gd и допиши в неё строку var bullets: int = 10 — иначе Godot скажет «Invalid get index "bullets"». Полностью копилку разберём в четвёртом шаге.
Два: Проект → Настройки проекта → «Карта действий» (в русской локали — «Список действий», по-английски Input Map) → создай действие fire и назначь ему левую кнопку мыши или клавишу F. Не создашь — Godot напишет «The InputMap action "fire" doesn't exist».
Три строки — три разных действия: взять заготовку, сделать копию, положить в мир. Пропустишь последнюю — гарпун создастся, но его никто не увидит.
Зачем Vector2(60, 0)? Чтобы гарпун появлялся перед героем, а не внутри него — иначе он сразу попадёт в своего или оттолкнёт героя. Число подбирай под свою картинку: примерно половина ширины героя. Толкается — увеличивай.

- 1Вкладка «Список действий»Сюда попадают так: Проект → Настройки проекта → «Список действий». Самого меню «Проект» на кадре нет — на маке оно живёт в верхней строке экрана, над окном Godot, а окно настроек открывается поверх редактора, как здесь. Действие — это имя для клавиши: код знает слово, а не кнопку.
- 2Поле «Добавить новое действие»Печатай fire — маленькими латинскими буквами, ровно так же, как в коде: Input.is_action_just_pressed("fire"). Fire и fire для Godot — два разных действия, и никто тебе на это не укажет: игра просто не выстрелит, а ты будешь искать ошибку в коде, которой там нет.
- 3Кнопка «+ Добавить»Пока не нажал — действия нет. После нажатия fire встанет в список третьим, но пустым: без клавиши оно не сработает. Здесь же, кстати, сделаны jump, move_left и move_right из прошлых квестов.
- 4Плюс справа — назначить клавишуПлюс открывает окошко «нажми клавишу»: жми X — и она встанет под словом fire, как Space стоит под jump. Одному действию можно дать сразу несколько клавиш: X и левую кнопку мыши. Корзина рядом удаляет лишнее, а «Мёртвая зона» 0,5 — это про стик геймпада, клавиатуре она безразлична.
- 5Кнопка «Закрыть» — и назад к сцене гарпунаНастройки сохраняются сами. За окном виден край редактора: слева дерево «Сцена» и «Файловая система» — там ты и соберёшь bullet.tscn из RigidBody2D, Sprite2D, CollisionShape2D и зоны HitZone. Пока действия fire нет, при выстреле Godot напишет красным, что такого действия не существует.
Это настоящее окно «Настройки проекта» в Godot, вкладка «Список действий»: здесь игре объясняют, какая клавиша что значит. Два действия уже сделаны — jump слушает Space, fire слушает X. Нажимай на кружки по порядку: метка покажет место, строка ниже объяснит, зачем оно.
Попадание
extends Area2D func _on_body_entered(body: Node2D) -> void: if body.is_in_group("enemies"): body.queue_free() # враг исчезает get_parent().queue_free() # и сам гарпун тоже
HitZone внутри гарпуна — и там же, во вкладке «Узел», подключи сигнал body_entered, как у монеты в третьем квесте. Без подключения функция не вызовется ни разу. is_in_group("enemies") — проверка по группе: выдели врага → вкладка Узел → Группы → добавь группу enemies.Группы удобнее, чем проверка по имени: врагов может быть десять с разными именами, а группа одна.
И убери за собой. Гарпун, который ни в кого не попал, летит вечно. Добавь в тот же скрипт функцию func _ready(): await get_tree().create_timer(3.0).timeout; get_parent().queue_free() — через три секунды промах исчезнет сам.
HitZone, а исчезнуть должен весь гарпун целиком — вместе с картинкой и физикой. Поэтому команда идёт родителю. Напишешь просто queue_free() — исчезнет только невидимая зона, а картинка гарпуна полетит дальше сквозь всех.
Откуда берутся тысячи пуль
В игре, где стреляют, за минуту рождаются сотни объектов. Никто не рисует их заранее — есть одна заготовка, а движок штампует копии.
В Unity такую заготовку зовут префабом, в Godot — упакованной сценой, в Roblox — шаблоном в ServerStorage. Слова разные, смысл один.
Профессионалы идут дальше: не удаляют гарпун после попадания, а прячут и используют снова. Приём называется «пул объектов» — так игры держат шестьдесят кадров в секунду на телефоне.
Патроны кончаются
extends Node # автозагрузка: живёт над всеми сценами var coins: int = 0 # монеты var bullets: int = 10 # запас патронов var health: int = 100 # здоровье героя
bullets ты уже дописал во втором шаге — здесь она на своём месте, рядом с монетами и здоровьем. Всё, что должно пережить переход между уровнями, живёт тут.Добавь на экран второй Label с патронами — по образцу счётчика монет из третьего квеста.
Стрелять в обе стороны
# у героя запоминаем направление взгляда var facing: int = 1 # 1 — вправо, -1 — влево # в коде движения: if x_input != 0.0: facing = sign(x_input) $Sprite2D.flip_h = facing < 0 # при выстреле: b.position = position + Vector2(60 * facing, 0) b.linear_velocity.x = 600 * facing
sign() выдаёт −1, 0 или 1 — знак числа. flip_h зеркалит картинку. Значок $ — короткая запись «найди у меня ребёнка с таким именем».До сих пор гарпун всегда летел вправо. Теперь герой стреляет туда, куда смотрит.
Читать текстом
Задание Гильдии: сделай двойной выстрел — два гарпуна, один чуть выше другого. Подсказка: скопируй три строки создания и прибавь к Y разное число.
Поднимай флаг.