Создание игр: платформер
Создание игр: платформер
Автоматически переведённая страница
К сожалению, на полный ручной перевод у нас не хватает ресурсов.
Если вы увидели ошибку — отправьте пул-риквест с исправлениями (ссылка для редактирования в конце страницы).
В этом туториале мы создадим небольшой платформер с алмазами, контрольными точками, движущимися платформами и ловушками! Мы научимся обнаруживать столкновения, использовать их для создания бокового движения, а также манипулировать спрайтами и перемещать игрока между уровнями.
Вот что мы сделаем:
Создание проекта
Откройте файл ct.js и введите в нижнем поле стартового окна название вашего проекта – например, «Платформер». Затем нажмите кнопку «Создать» и выберите папку, в которой ct.js будет хранить проект, например, в папке «Документы».
Импорт текстур
Нам понадобятся некоторые ресурсы из пакета упрощенного платформера от Кенни. Эти ресурсы уже включены в ct.js и имеют соответствующие имена; вы можете найти их в встроенной галерее.
Перейдите на вкладку "Assets", нажмите на "New Asset", затем нажмите кнопку "Built-in asset gallery". Найдите пакет "Simplified Platformer" от Кенни и импортируйте необходимые текстуры. Затем закройте галерею; текстуры появятся в списке текстур.
После готовности нажмите на актив "PlatformChar_Walk1".
На изображении представлена маленькая горизонтальная полоска. Она состоит из одной строки и двух столбцов. Мы можем сказать ct.js, чтобы разделить изображение таким образом, установив поля "Columns" и "Rows", а затем настроив поле "Width", которое должно быть уже настроено для нас.
Полное изображение имеет ширину 172 пикселя, поэтому один кадр будет составлять 172 : 2 = 86 пикселей в ширину. Кадры робота теперь должны быть выровнены двумя прямоугольниками.
Теперь давайте отредактируем его маску столкновения. Маски столкновения определяют, какие области изображения считаются прочными, а какие нет, и отображаются как желтый прямоугольник поверх спрайта.
Сначала смещаем его ось, чтобы расположить его в нижней средней точке.
Объяснение
Поскольку у нас есть изображение размером 86x80 пикселей, нам нужно 43 пикселя по горизонтали и 80 по вертикали. Пиксели измеряются с верхнего левого угла, а первая значение точки обычно является ее горизонтальным компонентом, или ее X-компонентом, а второе — Y-компонентом.
У робота есть красивое прямоугольное тело, поэтому мы будем мудре использовать его в качестве прямоугольника. Убедитесь, что вы выбрали прямоугольную форму, нажмите кнопку "Fill" и настройте смещения, чтобы тело робота было покрыто желтым прямоугольником.
Вы можете покрыть как тело, так и руки или выбрать только тело.
Нажмите кнопку "Save" в правом нижнем углу.
Теперь нам нужно настроить маски столкновения для "PlatformChar_Jump" и "PlatformChar_Idle" тоже. Мы можем быстро сделать это, скопировав маску столкновения для "PlatformChar_Walk1" и вставив ее в "PlatformChar_Jump" и "PlatformChar_Idle"! Убедитесь, что вы также смещаете ось на 43x80 для каждого из них.
Также хорошо установить одинаковые смещения для всех трех спрайтов, чтобы робот не врезался в поверхность при переключении анимаций и внезапно не увеличивался в размере как форма столкновения.
Теперь давайте настроим формы столкновения наших кристаллов и бонусов сердца. Они могут быть определены как круги. Откройте актив "PlatformPack_Item09" (Зеленый кристалл), установите его форму столкновения как "Круг", затем нажмите кнопку "Центр изображения", чтобы ось автоматически настроилась на нужные значения, и настройте радиус формы столкновения.
Сделайте то же для актива "PlatformPack_Item17" (Сердце).
Последний актив, который нам нужно изменить, это "PlatformPack_Tile43" (Шпильки). Мы не должны смещать его ось, потому что он будет неправильно выровнен на карте в этом виде, но мы все еще должны настроить его форму столкновения. Установите верхний смещение отрицательным значением, чтобы верхняя часть изображения не заполнялась желтым цветом.
Сохраните свой актив. Если вы взглянете на другие текстуры, вы увидите, что они все имеют прямоугольную форму, заполняющую весь образ; поэтому мы оставим их без изменений.
Создание робот-персонажа и платформы
Откройте вкладку "Ассеты" и нажмите кнопку "Новый ассет". В меню выберите "Шаблон". Назовите шаблон "Робот", установите спрайт PlatformChar_Idle
и сохраните.
Совет
Шаблоны используются для создания идентичных копий. Мы заполняем уровни (также называемые комнатами) копиями, и именно они взаимодействуют друг с другом на экране, но каждая копия была создана на основе определенного шаблона.
Создайте дополнительные шаблоны аналогичным образом (все текстуры скал):
PlatformPack_Tile16
, названный "Rocks"PlatformPack_Tile13
, названный "Rocks_Platform"PlatformPack_Tile31
, названный "Rocks_Top"
Добавление комнаты
Щелкните «Новый актив» еще раз и выберите «Комната» в меню. Назовите ее «Level_01» и в панели «Свойства комнаты» с иконкой шестеренки установите размер представления 1024x576.
Затем нарисуйте свой уровень! Выберите инструмент «Добавить копии», щелкните по шаблону слева и нарисуйте их мышью в большой области справа. Не забудьте о роботе!
Вы можете расширить свой уровень во все стороны, и копии не должны находиться внутри синей рамки. Эта рамка, которая управляется размером представления, просто устанавливает видимой часть вашего уровня.
Я нарисовал это. Трудно застрять здесь как игрок, но это учит прыжку. Мы также можем добавить кристаллы на платформе из камня позже и какой-нибудь секрет в окне под последним холмом.
Теперь давайте изменим цвет фона. Нажмите инструмент «Свойства комнаты» снова и установите цвет фона на #D0F4F7
.
Если мы сохраним проект сейчас и нажмем кнопку «Запустить» в верхней части, мы сможем увидеть небольшую часть нашего уровня, нарисованного в окне отладки. Пока ничего нельзя перемещать, но это все еще хорошее начало!
Добавление модулей для клавиатуры и столкновений
Нам понадобится слушать события клавиатуры и обнаруживать столкновения между Роботом и землей. Для этих суперспособностей нам понадобятся Катмодс! Нажмите на вкладку "Проект", а затем на вкладку "Катмодс" слева. Нажмите на модуль клавиатуры в разделе доступных модулей, чтобы у него появился зеленый флажок и маленькая вращающаяся круглая точка (возможно, он уже включен!). Делайте то же самое с модулем place
.
У каждого модуля есть своя документация на вкладке "Справка". Мы позже выделим некоторые из его частей.
Добавление действий для событий клавиатуры
Действия позволяют слушать события с клавиатуры, мыши, игрового контроллера и т. д. Более подробно о них можно прочитать здесь. С их помощью мы создадим слушатели для клавиш WASD и стрелок.
Перейдите в панель Проекта, а затем нажмите вкладку "Действия и методы ввода" слева.
Затем создайте схему ввода, как показано на следующем изображении. Для этого сначала нажмите кнопку "Создать с нуля", чтобы не использовать шаблон. Затем нажмите кнопку "Добавить действие", дайте ему название и добавьте методы ввода в правой колонке. Вы можете использовать функцию поиска, чтобы быстро добавить необходимые клавиши.
Совет
Хотя эта схема может быть упрощена до всего двух действий (см. примеры на странице действий), у нас будут два отдельных действия для движения влево или вправо, чтобы не усложнять учебник.
Here is the translation of the provided text from English to Russian:
Код коллизии и движения
Сейчас откройте вкладку "Шаблоны" в верхней части экрана и откройте шаблон Rocks
. В правом столбце заполните поле "Коллиджная группа" значением Solid
:
Это расшифрует команду place.add
в place
, что означает, что этот шаблон принадлежит к специальной группе коллизий под названием "Solid". Имя этой группы может быть любого значения, и количество таких групп не ограничено. На данный момент одной группы достаточно.
Добавьте ту же строку в шаблоны Rocks_Top
и Rocks_Platform
.
Теперь откройте шаблон Robot
. Если вы ранее прошли руководство "Space Shooter", вы можете вспомнить, что движение достигалось либо прямым манипулированием параметрами копии, либо использованием встроенных переменных, таких как this.speed
или this.direction
. Правда, эти не работали с платформером, даже вне ct.js! Нам нужно написать что-то более сложное. Готовьтесь! 😃
Идея бокового движения заключается в том, чтобы установить значение, к которому мы хотим двигаться, а затем проверить, есть ли препятствия на каждом шаге.
Давайте установим некоторые переменные на событии "Создание". Нажмите на "Добавить событие" для вызова меню событий и найдите событие "Создание", затем добавьте:
this.jumpSpeed = -600;
this.gravity = 1800;
this.hspeed = 0; // Horizontal speed
this.vspeed = 0; // Vertical speed
@jumpSpeed = -600
@gravity = 1800
@hspeed = 0 # Horizontal speed
@vspeed = 0 # Vertical speed
Совет
this
- это копия, которая выполняет написанный код. В нашем случае это Robot
.
Теперь перейдите на вкладку "Начало кадра". Удалите строку this.move();
, а добавьте следующий код:
this.movespeed = 240; // Max horizontal speed
if (actions.MoveLeft.down) {
// If the A key or left arrow on a keyboard is down, then move to left
this.hspeed = -this.movespeed;
} else if (actions.MoveRight.down) {
// If the D key or right arrow on a keyboard is down, then move to right
this.hspeed = this.movespeed;
} else {
// Don't move horizontally if no input
this.hspeed = 0;
}
// If there is ground underneath the Robot…
if (place.occupied(this, this.x, this.y + 1, 'Solid')) {
// …and the W key or the spacebar is down…
if (actions.Jump.down) {
// …then jump!
this.vspeed = this.jumpSpeed;
} else {
// Reset our vspeed. We don't want to be buried underground!
this.vspeed = 0;
}
}
@movespeed = 240 # Max horizontal speed
if actions.MoveLeft.down
# If the A key or left arrow on a keyboard is down, then move to left
@hspeed = -@movespeed
else if actions.MoveRight.down
# If the D key or right arrow on a keyboard is down, then move to right
@hspeed = @movespeed
else
# Don't move horizontally if no input
@hspeed = 0
# If there is ground underneath the Robot…
if place.occupied(this, @x, @y + 1, 'Solid')
# …and the W key or the spacebar is down…
if actions.Jump.down
# …then jump!
@vspeed = @jumpSpeed
else
# Reset our vspeed. We don't want to be buried underground!
@vspeed = 0
Совет
"Frame start" выполняется каждый кадр для каждой копии. Движение и другая игровая логика обычно идут здесь.
Совет
actions.YourAction.down
проверяет, удерживается ли какая-либо из указанных вами клавиш в данном действии. Также есть actions.YourAction.pressed
и actions.YourAction.released
.
place.occupied(copy, x, y, group)
проверяет наличие столкновений с данной копией в заданных координатах с конкретной группой. Если группа не нужна, вы можете обойтись без нее. Этот метод возвращает либо false
(нет столкновения), либо первую копию, которая столкнулась с другой.
Это установит переменные hspeed
и vspeed
, но они ничего не сделают сами по себе. Также мы не хотим задеть стену или двигаться, когда мы рядом с «Solid». К счастью, мы можем добавить эту волшебную строку в конец, чтобы персонаж правильно сталкивался с твердыми объектами:
this.moveSmart('Solid');
@moveSmart 'Solid'
Совет
moveSmart
— метод из модуля place
, который постепенно перемещает копию пиксель за пикселем, останавливаясь рядом с препятствиями. Это отлично подходит для платформеров и когда нужны точные скольжения.
Теперь мы можем перемещать нашего Робота!
Примечание
Ваш персонаж может игнорировать ямы шириной в одну клетку. Проверьте это. Если это происходит, вам нужно сделать коллизию Робота немного более худой.
Сделать так, чтобы камера следовала за роботом
Если мы запустим игру сейчас, мы сможем перемещать Робота. Однако есть одна проблема: камера не двигается!
Это не такая уж и большая проблема. Если мы изучим документацию ct.js, мы найдем сущность camera
с такими параметрами camera.follow
, camera.borderX
и camera.borderY
, которые позволяют устанавливать следование за копией.
Откройте шаблон "Робот" и его код создания. Добавьте следующий код в конец:
camera.follow = this;
camera.borderX = 450;
camera.borderY = 200;
camera.follow = this
camera.borderX = 450
camera.borderY = 200
Теперь камера будет следовать за роботом.
Добавление ловушек и чекпоинтов
Мы добавим смертельные ловушки и водные преграды, а также чекпоинты, чтобы игрок перезапускался с этих точек, а не с начала уровня.
Создайте новые шаблоны для следующих активов:
PlatformPack_Tile17
, названныйWater
;PlatformPack_Tile05
, названныйWater_Top
;PlatformPack_Tile43
, названныйSpikes
;PlatformPack_Tile21
, названныйCheckpoint
.
Создайте новую комнату и назовите ее Level_02
. Установите ее размер 1024x576 и сделайте фон снова #D0F4F7
. Создайте опасный уровень с шипами и прудами.
Поставьте точки чекпоинта до и/или после опасных участков. Не стесняйтесь поставить их много, потому что наказывать игрока за ошибки никогда не бывает хорошей идеей! 😉
Здесь предполагаемый конец уровня находится в центре верхней платформы. Я также поместил некоторые платформы снаружи снимка для сбора будущих кристаллов.
Теперь давайте поговорим о шаблоне Block
.
Мы будем проверять столкновение с роботом, и когда это происходит, мы сохраним точку восстановления внутри копии робота. Создайте новое событие «Коллизия с шаблоном» и выберите Робота. Затем добавьте следующий код в событие:
other.savedX = this.x + 32;
other.savedY = this.y + 32;
other.savedX = @x + 32
other.savedY = @y + 32
:: tip
Событие «Коллизия с шаблоном» имеет специальную переменную, которую можно использовать в коде события, называемую other
. Эта переменная хранит ссылку на столкнувшийся экземпляр, который в данном случае является роботом. Будьте внимательны к этим местным специальным переменным при написании событийного кода!
:::
Здесь мы также смещаем сохраненную точку на 32x32 пикселей, потому что ось контрольной точки находится в ее верхнем левом углу, а ось робота находится в среднем нижнем пункте. Из-за этого робот будет перезапущен чуть левее и выше желаемой центральной точки.
Мы хотим сделать контрольные точки невидимыми во время игры. Откройте раздел «Внешний вид» справа и отключите флажок «Видим».
Теперь перейдем к шаблону Крюки
и установим их столкновение как «Убивающее» в правой колонке, в разделе «Коллизия группы».
Тот же код примените к шаблонам Вода
и Вода_Верхний
.
Теперь откройте снова шаблон Робот
, и добавьте новое событие «Коллизия с группой». В имени группы используйте «Убивающее». Затем в коде события добавьте следующее:
this.x = this.savedX;
this.y = this.savedY;
this.hspeed = 0;
this.vspeed = 0;
@x = @savedX
@y = @savedY
@hspeed = 0
@vspeed = 0
Мы также должны написать этот код для события "Создание", чтобы по умолчанию точка возрождения находилась в месте создания, на случай, если что-то пойдет не так:
this.savedX = this.x;
this.savedY = this.y;
@savedX = @x
@savedY = @y
Для тестирования конкретной комнаты откройте вкладку «Ассеты» вверху, затем щелкните правой кнопкой мыши по нужной комнате и выберите «Установить в качестве начальной комнаты».
Трансформация и анимация робота
На этом этапе будет мудро добавить несколько анимаций к нашему роботу. Как вы помните, у нас есть три разных ассета под названием PlatformChar_Idle
, PlatformChar_Jump
и PlatformChar_Walk1
.
Добавьте эту строку в код "Создание" робота:
this.animationSpeed = 0.2;
@animationSpeed = 0.2
0,2
означает, что мы хотим воспроизводить 0,2×60 (что составляет 12) кадров в секунду. Для большей читаемости мы также можем записать это как 12/60
.
Откройте код "Frame start" робота и измените раздел движения так, чтобы текстура, которая отображается, зависела от ввода пользователя и положения робота в пространстве:
this.movespeed = 240; // Max horizontal speed
if (actions.MoveLeft.down) {
// If the A key or left arrow on a keyboard is down, then move to left
this.hspeed = -this.movespeed;
// Set the walking animation and transform the robot to the left
if (this.tex !== 'PlatformChar_Walk1') {
this.tex = 'PlatformChar_Walk1';
this.play();
}
this.scale.x = -1;
} else if (actions.MoveRight.down) {
// If the D key or right arrow on a keyboard is down, then move to right
this.hspeed = this.movespeed;
// Set the walking animation and transform the robot to the right
if (this.tex !== 'PlatformChar_Walk1') {
this.tex = 'PlatformChar_Walk1';
this.play();
}
this.scale.x = 1;
} else {
// Don't move horizontally if no input
this.hspeed = 0;
this.tex = 'PlatformChar_Idle';
}
// If there is ground underneath the Robot…
if (place.occupied(this, this.x, this.y + 1, 'Solid')) {
// …and the W key or the spacebar is down…
if (actions.Jump.down) {
// …then jump!
this.vspeed = this.jumpSpeed;
} else {
// Reset our vspeed. We don't want to be buried underground!
this.vspeed = 0;
}
} else {
// If there is no ground
// Set jumping animation!
this.tex = 'PlatformChar_Jump';
}
this.moveSmart('Solid');
@movespeed = 240 # Max horizontal speed
if actions.MoveLeft.down
# If the A key or left arrow on a keyboard is down, then move to left
@hspeed = -@movespeed
# Set the walking animation and transform the robot to the left
if @tex isnt 'PlatformChar_Walk1'
@tex = 'PlatformChar_Walk1'
@play()
@scale.x = -1
else if actions.MoveRight.down
# If the D key or right arrow on a keyboard is down, then move to right
@hspeed = @movespeed
# Set the walking animation and transform the robot to the right
if @tex isnt 'PlatformChar_Walk1'
@tex = 'PlatformChar_Walk1'
@play()
@scale.x = 1
else
# Don't move horizontally if no input
@hspeed = 0
@tex = 'PlatformChar_Idle'
# If there is ground underneath the Robot…
if place.occupied(this, @x, @y + 1, 'Solid')
# …and the W key or the spacebar is down…
if actions.Jump.down
# …then jump!
@vspeed = @jumpSpeed
else
# Reset our vspeed. We don't want to be buried underground!
@vspeed = 0
else
# If there is no ground
# Set jumping animation!
@tex = 'PlatformChar_Jump'
@moveSmart 'Solid'
По мере того как наша вертикальная движение не зависит от горизонтального, анимация переопределяется в прыжковом состоянии, если под роботом нет земли.
Робот теперь будет перевернуться в текущем направлении и изменить текстуру в зависимости от движения. Посмотри на этого мальчика!
Добавление переходов между уровнями
Задумка такая:
- Каждая комната будет хранить имя следующей комнаты в качестве переменной.
- Будут выходы на уровень, которые будут сталкиваться с Роботом.
- Когда они сталкиваются, выход читает переменную комнаты и переходит к следующей комнате.
Создайте новый шаблон и назовите его "Exit". Установите его текстуру. Затем создайте событие "Коллизия" для Робота и напишите следующий код:
Совет
Здесь rooms.current
указывает на текущую комнату. Функция rooms.switch
выходит из текущей комнаты и переходит к другой комнате с указанным именем.
Теперь перейдите на вкладку "Ассеты", откройте уровень Level_01
, нажмите кнопку "Events" и введите следующий код в поле "Room start":
this.nextRoom = 'Level_02';
@nextRoom = 'Level_02'
Поместите выход в комнату.
Сохраните комнату и пометьте Level_01
как стартовую комнату, щелкнув правой кнопкой мыши на нее и протестируйте переход.
Самостоятельно!
Создайте дополнительные выходы, ведущие к секретным подуровням и обратно. Получите больше ассетов отсюда, если вам это нужно.
Коллекционные предметы: подсчет и отображение
Добавление кристаллов
Создайте новый шаблон под названием GreenCrystal
и установите его спрайт. Создайте событие «Коллизия Робота» для текущего комнаты и напишите следующий код:
rooms.current.crystals ++;
this.kill = true;
rooms.current.crystals++
@kill = true
Совет
this.kill = true;
(Destroy this copy) указывает, что текущая копия должна быть удалена из текущей комнаты. Это произойдет после всех событий «Начало кадра», но до события «Конец кадра».
Как вы, возможно, уже догадались, количество собранных кристаллов будет храниться в комнате.
Но если мы продолжим добавлять больше функций в коды, специфичные для комнат, мы скоро попадем в ловушку багов из-за забывчивости при копировании и вставке фрагментов кода. Кстати, это будет скучная работа для третьей комнаты. (И у нас обязательно будет третья комната!)
Так что нам нужно создавать повторяющиеся функции сейчас. Это может показаться странным, но на самом деле это не так сложно.
Создайте новый ассет и на этот раз выберите «Поведения». Затем выберите поведение для комнат и назовите его inGameRoomStart
. Это позволит нам писать код, который затем можно применять к многим комнатам без необходимости повторять код!
Поведения для комнат имеют такие же события, как и комнаты. Создайте событие «Начало комнаты» и напишите следующий код:
rooms.current.crystals = 0;
rooms.current.crystalsTotal = templates.list['GreenCrystal'].length;
rooms.current.crystals = 0
rooms.current.crystalsTotal = templates.list['GreenCrystal'].length
Совет
templates.list['TemplateName']
возвращает массив всех копий данного шаблона в комнате. length
возвращает длину массива.
Теперь перейдите в каждую комнату, нажмите кнопку "Свойства комнаты" в боковой панели и затем нажмите на "Добавить поведение" и выберите только что созданное нами поведение.
Теперь это поведение подключено к комнате, и когда срабатывает событие "Старт комнаты", оно само устанавливает параметры crystals
и crystalsTotal
, не требуя писать такой код непосредственно в комнате.
Так мы собираем и считаем кристаллы, но нам также нужно создать простой интерфейс для отображения их количества и сделать это с стилем. ✨
К счастью, есть инструмент для создания стильных текстовых стилей внутри ct.js. Откройте вкладку "Ассеты" в верхней части экрана и создайте новый стиль. Назовите его CrystalCounter
.
Затем активируйте раздел "Шрифт", установите размер шрифта 24 и вес 600. Выровнять по левому краю и установить высоту строки 32.
Затем откройте вкладку "Заполнение", активируйте ее и установите цвет заполнения зеленым. Я выбрал #00A847
. Другие хорошие варианты включают основные цвета кристалла, такие как #2ECC71
и #28B463
.
Мы также можем добавить толстую белую линию к нашему тексту. Откройте вкладку "Линия", затем установите цвет линии в белый и ширину 5. Если вы не видите результат справа, попробуйте переключиться на темную тему интерфейса на некоторое время, нажав на меню гамбургера в верхней части.
Теперь нам нужно создать два новых шаблона, CrystalsWidget
и CrystalsWidgetText
. Первый будет отображать иконку кристалла, а второй - счетчик. Установите спрайт CrystalsWidget
на зеленый кристалл, а в CrystalsWidgetText
установите его на Текст вместо спрайта. Теперь установите стиль CrystalCounter
с призрачной кошкой в качестве иконки.
Чтобы завершить работу, добавьте это в конец кода рамки CrystalsWidgetText:
this.text = `${rooms.current.crystals} / ${rooms.current.crystalsTotal}`;
# Note the double quotes!
@text = "#{rooms.current.crystals} / #{rooms.current.crystalsTotal}"
Нам понадобится создать специальную комнату для наших элементов интерфейса. Создайте новую комнату и назовите ее LayerUI
. Установите ее размер одинаковым с другими комнатами, 1024x576. Затем добавьте только что созданный CrystalsWidget
и CrystalsWidgetText
в верхний левый угол комнаты:
Вы можете выровнять текст по центру, перейдя в инструменты интерфейса и установив выравнивание там после выбора текста. Вы также можете установить текст по умолчанию, чтобы увидеть, как он будет выглядеть, если число станет очень высоким, чтобы убедиться, что выравнивание установлено правильно!
Добавление элементов интерфейса в отдельную комнату позволяет проектировать интерфейс визуально, а затем импортировать его в другие комнаты с помощью кода. Ct.js также имеет специальную флажок, который фиксирует слои интерфейса, поэтому вы можете свободно перемещать, масштабировать и даже поворачивать камеру, а элементы интерфейса останутся правильно расположенными. Перейдите в настройки комнаты и установите флажок "Это слой интерфейса?", чтобы LayerUI
был зафиксирован на экране игры.
Теперь, чтобы импортировать слой интерфейса в другую комнату, перейдите в наше поведение inGameRoomStart
в представлении активов и добавьте этот код:
rooms.append('LayerUI');
rooms.append 'LayerUI'
Вот как это должно выглядеть на русском языке:
Совет
Метод rooms.append
(а также rooms.prepend
) также можно использовать для повторного использования других вещей, помимо слоев интерфейса. Например, мы можем поместить все фоновые изображения в отдельный слой, а затем вызвать rooms.prepend("YourBackgroundRoom");
, чтобы импортировать их. Это особенно полезно при создании сложных слоенных фонов с эффектом параллаксного сдвига.
Если вы сейчас запустите свою игру, вы должны увидеть счетчик кристаллов в левом верхнем углу:
Добавление жизней и бонусов сердца
Это в основном похоже на сбор кристаллов, но есть некоторые изменения:
- Начально у нас 3 жизни.
- Мы не можем иметь более 3 жизней одновременно.
- Если мы потеряли последнюю жизнь, уровень перезагружается.
Сделай это сам!
Попробуй сделать все самостоятельно! Если ты запутался, просто ищи инструкции ниже. Не скроль вниз! 😃
Создайте новый шаблон под названием Heart
и назначьте соответствующую спрайт. Добавьте следующий код в событие Collides Robot шаблона:
if (rooms.current.lives < 3) {
rooms.current.lives++;
this.kill = true;
}
if rooms.current.lives < 3
rooms.current.lives++
@kill = true
Не забудьте разместить фактические сердца на своих уровнях!
Мы также должны создать стиль для счетчика жизней. Процесс тот же, и подходящий цвет - #E85017
. Мы даже можем дублировать существующий стиль! Назовите этот стиль HeartCounter
.
Мы нуждаемся еще в двух шаблонах для здоровья. Создайте новый шаблон под названием HeartsWidget
, и установите спрайт сердца. Затем создайте HeartsWidgetText
и установите его как текст, а не спрайт. Теперь примените стиль HeartCounter
.
Добавьте следующий код в конец события Frame
шаблона HeartsWidgetText
:
this.text = rooms.current.lives;
@text = rooms.current.lives
Затем добавьте оба этих новых шаблона в слой LayerUI
. Не забудьте настроить выравнивание текста сердца!
Измените код перезагрузки Robot
, чтобы он терял одну жизнь при каждом перерыве (в событии с коллизией с группой «Deadly»):
this.x = this.savedX;
this.y = this.savedY;
this.hspeed = 0;
this.vspeed = 0;
// remove one life
rooms.current.lives --;
if (rooms.current.lives <= 0) {
// Restart a room: switch to the room of its own name
rooms.switch(rooms.current.name);
}
@x = @savedX
@y = @savedY
@hspeed = 0
@vspeed = 0
# remove one life
rooms.current.lives--
if rooms.current.lives <= 0
# Restart a room: switch to the room of its own name
rooms.switch rooms.current.name
И не забудьте отредактировать поведение inGameRoomStart
, чтобы инициализировать количество жизней в комнате:
rooms.current.crystals = 0;
rooms.current.lives = 3;
rooms.current.crystalsTotal = templates.list['GreenCrystal'].length;
rooms.append('LayerUI');
rooms.current.crystals = 0
rooms.current.lives = 3
rooms.current.crystalsTotal = templates.list['GreenCrystal'].length
rooms.append 'LayerUI'
Это все! Пора протестировать.
Добавление движущихся платформ
Создайте новый шаблон под названием Platform
и выберите соответствующую спрайт-шаблон. Создайте новую уровень под названием Level_03
, который включает в себя широкие лужайки или длинные ловушки с платформами, которые движутся вам навстречу.
Движущиеся платформы будут действовать следующим образом:
- Они движутся горизонтально, начиная движение, скажем, вправо.
- Если платформа обнаруживает, что она будет касаться объекта
Solid
в следующем кадре, её направление меняется. - Платформы движутся роботом, если он оказывается прямо над платформой.
Давайте откроем шаблон платформы и инициализируем его скорость:
this.speed = 120;
@speed = 120
Также, установите группу столкновений платформы как Solid
в правом столбце редактора шаблонов.
Затем, добавьте следующий код в раздел "Frame start":
var robot = place.meet(this, this.x, this.y - 1, 'Robot');
if (robot) {
robot.x += this.hspeed * u.time;
}
robot = place.meet this, @x, @y - 1, 'Robot'
if robot
robot.x += @speed * u.time
И логика движения:
if (place.occupied(this, this.x + this.hspeed * u.time, this.y, 'Solid')) {
// Flip direction
this.direction += 180;
}
this.move();
if place.occupied this, @x + @speed, @y, 'Solid'
# Flip direction
@direction += 180
@move()
Вот это просто! Может быть, даже слишком просто. А проблема в том, что если Робот касается левой или правой стороны платформы, он застревает навсегда! Нам нужно сделать платформы твердыми только в том случае, если они не пересекаются друг с другом.
Вот более хороший код:
var robot = place.meet(this, this.x, this.y, 'Robot');
if (robot) {
this.cgroup = undefined;
} else {
this.cgroup = 'Solid';
robot = place.meet(this, this.x, this.y - 1, 'Robot');
if (robot) {
robot.x += this.hspeed * u.time;
}
}
if (place.occupied(this, this.x + this.hspeed * u.time, this.y, 'Solid')) {
// Flip direction
this.direction += 180;
}
this.move();
robot = place.meet this, @x, @y, 'Robot'
if robot
@cgroup = undefined
else
@cgroup = 'Solid'
robot = place.meet this, @x, @y - 1, 'Robot'
if robot
robot.x += @hspeed * u.time
if place.occupied this, @x + @hspeed * u.time, @y, 'Solid'
# Flip direction
@direction += 180
@move()
Что происходит здесь? Во-первых, мы проверяем, не пересекается ли робот с платформой. Если да, мы сообщаем, что платформа должна стать нестабильной с помощью cgroup = undefined
, чтобы робот мог пройти через платформу вместо того, чтобы застрять в ней. 'cgroup' - это поле группы столкновений, которое мы редактировали в левой колонке редактора шаблона! Если между платформой и роботом нет столкновения, платформа становится стабильной (cgroup = 'Solid'
), и мы снова ищем робота, но теперь на один пиксель выше платформы. У нас идеальное столкновение по пикселям, поэтому одного пикселя достаточно.
Сделай сам!
Добавь движущиеся вертикально платформы! И убедись, что они не раздавляют Робота. 😉
Это всё!
Уф, это был довольно длинный учебник. Несмотря на это, есть ещё много возможностей для улучшения.
Вот как можно улучшить эту игру:
- Добавьте врагов и смертоносные движущиеся цепочки! Вы можете получить спрайты их и гораздо больше здесь.
- Создайте историю и расскажите её через NPC, заметки на деревянных досках или просто через субтитры!
- Улучшите процесс возрождения. Убедитесь, что Робот не попадает в ловушки после возрождения. Это можно сделать, заблокировав ввод игрока на полсекунды или просто сделав области контрольных точек более безопасными.
- Добавьте звуковые эффекты! Ничто не делает игру более живой, чем качественные SFX.
- Убедитесь, что Робот возрождается, если он иногда выпадает из уровня.
- Просто добавьте больше уровней. 😉 Украсьте их растениями, создайте миры разных цветов.
Заметки на полях
Посмотрите, как новые функции в вашем коде постепенно появляются в ваших уровнях! Это хороший способ представить игрокам новые вещи. Предоставьте им одно новое понятие за раз, но сохраните предыдущие с увеличивающейся сложностью. Это совет по проектированию уровней от Comigo 😎
Счастливого кодинга!
Comigo