Сейчас я восстановлю структуру программы Годот Dooge the Creeps

Сегодня мы проведём эксперимент с проектом годот Dodge the Creeps. Для этого создадим новый проект и назовём его Dodge the Creeps Experiment.

Создадим объект Area2D. Внутрь него добавим AnimatedSprite2D, CollisionShape2D и GPUParticles2D.

Теперь подготовим набор спрайтов.

Сохраним сцену как player.tscn.

Теперь добавим область для обработки столкновений. Выберем круглую форму.

Скопируем папку art из исходного проекта «Dodge the Creeps» и перенесём её в папку нового экспериментального проекта. Я также скопировал папку font. Теперь в узле GPUParticles2D в качестве текстуры можно использовать изображение игрока, например playerGrey_up1.png.

После выбора текстуры назначим в Process Material объект ParticleProcessMaterial» — это создаст шлейф за игроком. Чтобы ограничить разлёт частиц, откроем ParticleProcessMaterial, затем раздел Accelerations, подраздел Gravity» и заменим значение 98 на 0.

Сохраняем сцену.

Теперь займёмся прототипированием: сделаем несколько новых сцен, пока без кода, просто для настройки структуры.

Создаём новую сцену. Берём узел RigidBody2D», внутрь кладём AnimatedSprite2D, CollisionShape2DиVisibleOnScreenNotifier2D. Это будет наш враг (моб). Последний узел (VisibleOnScreenNotifier2D`) пригодится, чтобы удалять врага, когда он уходит за край экрана.

Повторяем процесс: создаём ещё одну сцену.

Добавим узел RigidBody2D.

Внутрь RigidBody2D добавим узлы AnimatedSprite2D, CollisionShape2D и VisibleOnScreenNotifier2D.

Сохраним сцену под именем mob.tscn. Теперь настроим каждый из добавленных элементов внутри RigidBody2D.

Со сценой mob.tscn разобрались. Переходим к следующей.

Создадим новую сцену.

Создадим объект CanvasLayer.

Создадим две метки (Label).

Добавим кнопку (Button).

Добавим таймер (Timer).

Сохраним сцену как hud.tscn.

Настроим все метки, кнопку и таймер.

Метка Label должна располагаться в верхней части экрана на всю ширину (Layout).

Метка Label2 — по центру на всю ширину.

Кнопка Button — внизу по центру.

Для таймера Timer установим One Shot в положение «вкл», а интервал — 1 секунда.

Теперь объединим все сцены. Сцены player.tscn и hud.tscn встроим в новую основную сцену, а mob.tscn будем создавать динамически из кода.

Для этого создадим новую сцену.

Добавим к сцене узел Node2D.

Сохраним сцену как main.tscn.
Затем добавим в неё дочерние сцены: player.tscn и hud.tscn.

Создадим узел Path2D и поместим внутрь него узел PathFollow2D.

Теперь настроим кривую для Path2D». Для этого выберите Curve2D» и нажмите «Добавить точку».

Создадим маркер, который будет задавать начальную позицию главного героя (персонажа, которым управляет игрок).

Добавим три таймера, узел ColorRect и два узла AudioStreamPlayer.

Добавим узел ColorRect.

Настроим ColorRect: выберем цвет, растянем его на весь экран через Layout, а в разделе Transform зададим размер (1154×650).

Добавим два узла AudioStreamPlayer.

Переходим к написанию кода. Изначально игрок должен быть скрыт. Прикрепим к нему скрипт player.gd и напишем следующий код.

extends Area2D

func _ready() -> void:
hide()

Таким образом, мы скроем игрока. Отобразить его можно будет после нажатия на кнопку — тогда запустится таймер, который, в свою очередь, активирует два других: один будет вести отсчёт времени, а второй — создавать мобов.

Тем временем добавим игроку сигнал hit — он будет испускаться при касании моба. Для этого реализуем в узле игрока функцию, которая вызывается при столкновении с врагом и излучает этот сигнал.

Теперь добавим управление персонажем. Он должен реагировать на нажатие клавиш вверх, вниз, влево и вправо.

extends Area2D

signal hit
var speed=400


func _ready() -> void:
#hide()
pass



func _process(delta: float) -> void:
var move=Vector2(0,0)
if(Input.is_action_pressed("ui_down")):
move+=Vector2(0,1)
elif(Input.is_action_pressed("ui_up")):
move+=Vector2(0,-1)
elif(Input.is_action_pressed("ui_right")):
move+=Vector2(1,0)
elif(Input.is_action_pressed("ui_left")):
move+=Vector2(-1,0)
position+=move*speed*delta


func _on_body_shape_entered(body_rid: RID, body: Node2D, body_shape_index: int, local_shape_index: int) -> void:
emit_signal("hit")

 

Функцию hide() мы пока закомментировали, однако заметим, что игрок появляется в верхнем левом углу. Нам нужно расположить его в центре экрана. Для этого пригодится узел `Marker2D».

Создадим скрипт main.gd и прикрепим его к сцене main. Внутри main.gd напишем следующий код.

extends Node2D

func _ready() -> void:
$Area2D.set_pos($Marker2D.position)

В дальнейшем этот код будет вызываться не из _ready(), а по таймеру — после того, как игрок столкнётся с врагом. При этом игроку будут передаваться координаты узла `Marker2D» (конечно, после того как мы его зададим).

Добавим в main.gd переменную для Mob2D. Используем аннотацию @export — она нужна, чтобы переменная отображалась в инспекторе.

extends Node2D

@export var Mob2D:PackedScene

Перетащим сцену mob.tscn в инспектор главной игровой сцены

Добавим код, который создаёт одного бота в игровой среде. Временно разместим вызов создания в функции _ready(). Однако в финальной версии мобы должны появляться раз в секунду — для этого будем использовать таймер.

extends Node2D

@export var Mob2D:PackedScene

func _ready() -> void:
$Area2D.set_pos($Marker2D.position)
mob_created()

func mob_created() -> void:
var mob = Mob2D.instantiate()
$Path2D/PathFollow2D.progress = randi()
mob.position=$Path2D/PathFollow2D.position
mob.rotation=$Path2D/PathFollow2D.rotation+PI/2
add_child(mob)

 

Пусть таймер вызывает создание мобов каждую секунду.

Перенесём вызов mob_created из функции _ready() в функцию _on_timer_timeout().

func _on_timer_timeout() -> void:
mob_created()

В функцию _ready() добавим запуск таймера.

func _ready() -> void:
$Timer.start()
$Area2D.set_pos($Marker2D.position)

Если запустить проект, мы увидим, что мобы просто падают сверху вниз.

Выделим игрока (Area2D). В соответствующем узле найдём сигнал hit — он испускается при столкновении игрока с врагом. Добавим связь сигнала с методом, а именно, привяжем сигнал hit от игрока к скрипту main.gd.

В скрипте player.gd при столкновении с мобом реализуем следующую логику:

отключаем обработку физики;

прячем игрока.

При старте игры (или при возрождении) нужно будет:

снова отобразить игрока;

включить физику.

func _on_body_shape_entered(body_rid: RID, body: Node2D, body_shape_index: int, local_shape_index: int) -> void:
emit_signal("hit")
hide()
$CollisionShape2D.disabled=true

func set_pos(pos:Vector2)->void:
position=pos
show()
$CollisionShape2D.disabled=false

 

Теперь добавим немного кода в hud.tscn. Для этого прикрепим к узлу CanvasLayer одноимённый скрипт.

Выделим кнопку (Button). При её нажатии кнопка должна скрываться и запускать таймер. После того, как время таймера истечёт, он испустит сигнал начала игры.

extends CanvasLayer

signal begin

func _ready() -> void:
    pass 


func _process(delta: float) -> void:
pass


func _on_button_button_down() -> void:
hide()
$Timer.start()
$Label2.text="Ready?"


func _on_timer_timeout() -> void:
$Label2.hide()
emit_signal("begin")

 

Перейдём в сцену main.tscn, выделим узел CanvasLayer и свяжем сигнал begin с функцией begin_game. В саму функцию begin_game перенесём весь код, который ранее был в _ready() скрипта main.gd. Также в player.gd раскомментируем вызов hide().

Кроме того, у мобов необходимо отключить гравитацию — иначе они будут просто падать вниз.

Добавим код, который удаляет всех ботов после смерти персонажа, а также останавливает таймер. Отсоединим от сигнала hit все ранее подключенные методы и заново подключим его к методу game_over в скрипте main.gd.

func end_game()->void:
$Timer.stop()
get_tree().call_group("mob","queue_free");
$CanvasLayer/Label2.show()
$CanvasLayer/Button.show()

Важный момент: в коде для CanvasLayer нужно использовать $Button.hide(), а не просто hide(). В противном случае скроется вся сцена целиком. То есть при нажатии на кнопку должен выполняться именно такой код.

func _on_button_button_down() -> void:
$Button.hide()
$Timer.start()
$Label2.text="Ready?"

На этом всё. Спасибо за внимание и за то, что прошли вместе пересоздание туториала Godot «Dodge the Creeps».

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх