Godot с поддержкой ОС Аврора для Windows и для Linux
Шаблон проекта. Это архив, его необходимо распаковать
Рекомендуется открыть в соседней вкладке страницу с соответствующей лекцией. Фрагменты кода можно брать оттуда
Не копируйте код блоками! Работайте по строчкам, пытайтесь разобраться
scenes/main.tscn — игровое поле с MovableObject (Sprite2D с текстурой circle.svg)scenes/draggable_piece.tscn — объект для перетаскивания (Sprite2D с текстурой star.svg)scripts/ — скелеты с TODO-комментариямиsprites/ — SVG-спрайты (circle.svg, square.svg, star.svg)Примечание: Текстуры уже назначены на Sprite2D в сценах. Godot автоматически импортирует SVG-файлы как текстуры.
Как запускать и проверять (пригодится в каждом задании):
main.tscnprint() и текст ошибок появляются в панели Output внизу редактораЦель: научиться обрабатывать ввод и перемещать узлы.
scripts/movable_object.gdextends Sprite2D
@export var speed: float = 200.0
func _process(delta: float) -> void:
# TODO 1: Создайте переменную direction типа Vector2, равную Vector2.ZERO
# TODO 2: Если нажата "ui_right", увеличьте direction.x на 1
# TODO 3: Если нажата "ui_left", уменьшите direction.x на 1
# TODO 4: Если нажата "ui_up", уменьшите direction.y на 1 (ось Y перевёрнута!)
# TODO 5: Если нажата "ui_down", увеличьте direction.y на 1
# TODO 6: Нормализуйте direction и прибавьте к position (с учётом speed и delta)
pass
scenes/main.tscn и запустите её клавишей F5. Подвигайте объект стрелками.Объект перемещается стрелками клавиатуры с одинаковой скоростью в любом направлении.
Цель: реализовать перетаскивание объекта — ключевая механика для головоломок.
scripts/draggable_piece.gdsignal piece_placed(piece_position: Vector2) — это для бонусного задания, пока его можно игнорировать.extends Sprite2D
signal piece_placed(piece_position: Vector2)
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:
# TODO 1: Проверить, находится ли мышь над спрайтом
# Подсказка: используйте функцию _is_mouse_over()
# Если да — установите dragging = true
# и вычислите drag_offset = global_position - get_global_mouse_position()
pass
else:
# TODO 2: Отпустили кнопку — прекратить перетаскивание
# Установите dragging = false
# Бонус: отправьте сигнал piece_placed.emit(global_position)
pass
# TODO 3: Если event — это InputEventMouseMotion И dragging == true,
# обновите global_position = get_global_mouse_position() + drag_offset
pass
# Проверяет, находится ли мышь над текстурой спрайта
func _is_mouse_over() -> bool:
var mouse_pos := get_global_mouse_position()
if texture == null:
return false
var size := texture.get_size() * scale
var rect := Rect2(global_position - size / 2, size)
return rect.has_point(mouse_pos)
Зачем
drag_offset? Это разница между центром объекта и точкой, за которую его схватили:drag_offset = global_position - get_global_mouse_position(). Без неё объект при первом же движении мыши прыгнет центром под курсор.
Почему везде
get_global_mouse_position(), а неevent.position? Оба варианта в этом проекте дадут одно и то же, ноevent.position— это координаты окна, аget_global_mouse_position()— координаты игрового мира. Как только в проекте появится камера (Camera2D), первый вариант начнёт врать. Привыкайте сразу к правильному.
Как это проверить. В сцене main.tscn перетаскиваемых объектов пока нет — их будет создавать код из задания 3. Чтобы проверить перетаскивание уже сейчас, добавьте один объект вручную:
scenes/main.tscnscenes/draggable_piece.tscn из «Файловой системы» на середину вьюпортаЭтот объект можно оставить в сцене — заданию 3 он не помешает.
Объект можно схватить мышью и перетащить в любое место.
Цель: связать узлы через сигналы — кнопка запускает действие.
Откройте сцену scenes/main.tscn
В сцене уже есть:
SpawnButton (Button) — кнопка «Создать объект»ResetButton (Button) — кнопка «Сброс»SpawnArea (Node2D) — область, где появляются объектыCounter (Label) — счётчик созданных объектовОткройте скрипт scripts/main.gd и реализуйте:
extends Node2D
## Сцена объекта, который будем создавать.
## Уже назначена в инспекторе узла Main: scenes/draggable_piece.tscn
@export var piece_scene: PackedScene
var spawn_count: int = 0
func _ready() -> void:
# TODO 1: Подключите сигнал pressed кнопки $SpawnButton к функции _on_spawn_pressed
# Пример: $SpawnButton.pressed.connect(_on_spawn_pressed)
# TODO 2: Подключите сигнал pressed кнопки $ResetButton к функции _on_reset_pressed
# TODO 9 (задание 4): Подключите таймер автоспауна
# $AutoSpawnTimer.timeout.connect(_on_auto_spawn_timer)
# $AutoSpawnTimer.start()
pass
func _on_spawn_pressed() -> void:
if piece_scene == null:
push_warning("Поле Piece Scene не заполнено в инспекторе узла Main")
return
# TODO 3: Создайте экземпляр piece_scene
# var piece = piece_scene.instantiate()
# TODO 4: Установите его позицию (случайная внутри игрового поля).
# Начинаем с Y = 120, чтобы объекты не появлялись под кнопками.
# piece.position = Vector2(randf_range(100, 1000), randf_range(120, 560))
# TODO 5: Добавьте экземпляр как дочерний узел к $SpawnArea
# $SpawnArea.add_child(piece)
# TODO 6: Увеличьте spawn_count и обновите текст $Counter
# spawn_count += 1
# $Counter.text = "Объектов: " + str(spawn_count)
pass
func _on_reset_pressed() -> void:
# TODO 7: Удалите все дочерние узлы из $SpawnArea
# for child in $SpawnArea.get_children():
# child.queue_free()
# TODO 8: Обнулите spawn_count и обновите $Counter
# spawn_count = 0
# $Counter.text = "Объектов: 0"
pass
func _on_auto_spawn_timer() -> void:
# TODO 10 (задание 4): Вызвать _on_spawn_pressed() для автоматического создания
# _on_spawn_pressed()
pass
Main: поле Piece Scene уже заполнено сценой draggable_piece.tscn. Если оно почему-то пустое — перетащите туда scenes/draggable_piece.tscn из «Файловой системы».Так работает
@export: переменная из скрипта появляется в инспекторе, и её можно задать без правки кода. Имяpiece_sceneредактор показывает как «Piece Scene».
Цель: использовать Timer для периодических действий.
В сцене main.tscn уже есть узел AutoSpawnTimer (Timer). Проверьте его настройки в инспекторе:
3.0 (каждые 3 секунды)false (повторять)falseВ main.gd раскомментируйте TODO 9 — там две строки: одна подключает сигнал timeout, вторая запускает таймер. Без start() таймер так и будет стоять, потому что Autostart у него выключен.
Раскомментируйте TODO 10 — то, что должно происходить по сигналу таймера.
Сохраните и запустите (F5). Ничего не нажимая, подождите — объекты начнут появляться сами.
(Бонус) Добавьте кнопку-переключатель автоспауна:
ToggleAutoButton в сценуpressed к функции, которая вызывает $AutoSpawnTimer.start() или $AutoSpawnTimer.stop()$AutoSpawnTimer.is_stopped()Объекты появляются автоматически каждые 3 секунды (когда таймер запущен).
В draggable_piece.gd сигнал уже объявлен в самом начале файла — найдите эту строку:
signal piece_placed(piece_position: Vector2)
Отправляйте его при отпускании мыши (это часть TODO 2):
piece_placed.emit(global_position)
В main.gd при создании объекта подключитесь к этому сигналу:
var piece = piece_scene.instantiate()
piece.piece_placed.connect(_on_piece_placed)
Напишите обработчик, который выводит позицию:
func _on_piece_placed(pos: Vector2) -> void:
print("Объект размещён в: ", pos)
Запустите (F5), создайте объект кнопкой, перетащите его и отпустите. В панели Output появится строка с координатами.