You are on page 1of 36

Game

Development

Unreal Engine

MIDDLE
Урок 10
Infinity runner

2
Infinity runner

Infinity runner
Infinity runner — это еще одна разновидность игр,
требующих от игроков быстрой реакции. Данный жанр
отличается незамысловатым геймплеем. Главному пер-
сонажу предстоит бежать вперед по бесконечно генери-
руемому миру, полному опасностей и препятствий. По-
путно ему предстоит собирать определенные предметы
и бонусы, необходимые для прокачки. Со временем ско-
рость бега может увеличиться, а препятствия будут ста-
новиться все сложнее.
Самым ярким представителем данного жанра можно
назвать игру Subway Surfers, разработанную в 2012 году
в Дании компаниями Kiloo и SYBO Games. В ней игро-
кам предстоит руководить персонажем, который пыта-
ется спастись от полисмена с собакой, убегая по желез-
нодорожным путям (рис. 1).

Рисунок 1

3
Урок 10

Давайте создадим похожую игру на движке Unreal En-


gine 4 и разберем логику ее игровых механик. При этом
мы постараемся придерживаться стиля другой крутой
игры — Fortnite. К примеру, в нашем проекте персонаж
будет собирать ящики с лутом (рис. 2).

Рисунок 2
Прежде всего нам понадобится новая сцена от треть-
его лица. Давайте немного поменяем местоположение
стандартной камеры, которая смотрит в спину персона-
жу. В играх, наподобие Subway Surfers, камера смотрит
сверху вниз. Чтобы добиться такого же эффекта, откроем
блупринт ThirdPersonCharacter и выделим родительский
объект CameraBoom, который содержит в себе саму ка-
меру. После этого обратимся к окну настроек и повысим
значение Socket Offset по оси Z до 100 (рис. 3).

4
Infinity runner

Рисунок 3
В раннерах персонаж двигается вперед автоматиче-
ски, без вмешательства игрока. Чтобы заставить наше-
го персонажа беспрерывно двигаться вперед, перейдем
в Event Graph, отыщем ветку Movement input и удалим
ноду InputAxis MoveForward (рис. 4).

Рисунок 4
Вместо нее необходимо добавить другую ноду — Event
Tick, чтобы анимация бега персонажа просчитывалась
в каждом кадре (рис. 5).

5
Урок 10

Рисунок 5
Теперь можно запустить проверку игры: наш персо-
наж должен бежать вперед без остановок.
Далее необходимо настроить логику поворота. Для
этого создадим новую переменную CanTurn типа Bool-
ean (рис. 6).

Рисунок 6
Еще одна переменная, которую необходимо создать, —
это DesiredRotation c особым типом Rotator. Именно она
будет отвечать за поворот персонажа в требуемом на-
правлении (рис. 7).

6
Infinity runner

Рисунок 7
Чтобы персонаж реагировал на команды кнопок, под-
ключим переменную Can Turn к ноде клавиши А. Данная
клавиша по умолчанию отвечает за поворот влево (рис. 8).

Рисунок 8
Также, чтобы правильно задать угол и направление
поворота, подключим ноду Desired Rotation к функции
CombineRotation. Зададим требуемое значение поворо-
та: -90° по оси Z, то есть влево (рис. 9).

7
Урок 10

Рисунок 9
После этого соединим две ветки с помощью ноды De-
sired Rotation со значением Set (рис. 10).

Рисунок 10
Такой же скрипт создадим для клавиши D, которая
отвечает за поворот вправо. Единственное отличие —
угол поворота должен равняться 90° (рис. 11).

Рисунок 11

8
Infinity runner

В конце необходимо соединить оба скрипта с помо-


щью ноды Can Turn (рис. 12).

Рисунок 12
Если вам необходимо быстро сгруппировать готовую
ветку, можно воспользоваться функцией комментиро-
вания. Для этого достаточно выделить все необходимые
ноды и нажать клавишу С. В результате будет создана
специальная группирующая рамка, которую можно под-
писать соответственно содержимому (рис. 13).

Рисунок 13

9
Урок 10

Следующий шаг — запрограммировать процесс са-


мого поворота. Для этого создадим Custom Event под на-
званием TurnCorner. Далее необходимо соединить ноды
Get Control Rotation и Desired Rotation. Если их значения
не будут равняться заданному числу, сработает функция
Set Control Rotation, и персонаж повернет.
Дополнительно зададим время, которое персонаж за-
тратит на действие. Для этого нужно добавить в скрипт
ноду RInterp To, которая будет обращаться к значению
World Delta Second. Дополнительно установим скорость
поворота (Interp Speed), к примеру, на 10. Готовый скрипт
показан на рисунке 14.

Рисунок 14
Ссылку на данный ивент также нужно добавить в скрипт
Event Tick в блупринте персонажа (рис. 15).
Следующее, что необходимо сделать, — сформиро-
вать беговой трек, который будет бесконечно спаунить-
ся, расширяя границы мира.

10
Infinity runner

Рисунок 15
Для этого создадим новый блупринт типа Actor и пе-
реименуем его в BP_FloorTile (рис. 16).

Рисунок 16
Откроем редактор и добавим в данный блупринт Static
Mesh, который назовем Floor. Сразу зададим ему значе-
ния Scale по трем осям: 10, 10, 0.1. Подобные параметры
позволят превратить меш в плоскость (рис. 17).

Рисунок 17

11
Урок 10

В качестве самого объекта используем куб. Также сра-


зу назначим ему текстуру дерева, чтобы создать иллюзию,
будто персонаж бежит по деревянному настилу (рис. 18).
При этом не следует забывать, что мы пытаемся создать
игру в стиле Fortnite. Если стандартные текстуры не со-
ответствуют заданной стилистике, вы можете подобрать
более подходящий вариант в интернете.

Рисунок 18
Помимо самого пола, необходимо создать бортики,
чтобы персонаж случайно не слетел с трека во время бега.
Для этого дважды продублируем компонент Floor, переи-
менуем новые объекты в Wall и поменяем значения Scale,
чтобы получить небольшие вертикальные стены (рис. 19).

Рисунок 19

12
Infinity runner

Разместим их по краям платформы, как на рисунке 20.

Рисунок 20
Следующий компонент, который необходимо до-
бавить, — это стрелка (Arrow). Данный элемент будет
указывать на место спауна следующего участка дороги.
Переименуем его в AttachPoint и сдвинем по оси Х на
1000 единиц (рис. 21).

Рисунок 21
После этого создадим новую функцию GetAttachTrans-
form с одноименным исходящим параметром типа Trans-
form (рис. 22).

Рисунок 22

13
Урок 10

Данная функция будет просчитывать местоположе-


ние точки (Attach Point), в которой каждая следующая
платформа должна присоединяться к предыдущей с по-
мощью ноды GetWorldTransform (рис. 23).

Рисунок 23
Прежде, чем тестировать игру, давайте создадим но-
вый уровень. Для этого откроем меню File => New level
(рис. 24).

Рисунок 24

14
Infinity runner

В качестве шаблона выберем пустой проект, так как


все необходимые элементы будут автоматически спау-
ниться в сцене (рис. 25).

Рисунок 25
Далее откроем блупринт самой игры — ThirdPerson-
GameMode (рис. 26).

Рисунок 26

15
Урок 10

Создадим в нем новую функцию AddFloorTile, кото-


рая будет спаунить новые участки пути (рис. 27).

Рисунок 27
Подключим к данной функции ноду Spawn Actor from
Class с классом BP_FloorTile. Также создадим новую ло-
кальную переменную Next Spawn Point (ПКМ => Promote
to Variable), которую подключим в строку Spawn Trans-
form (рис. 28).

Рисунок 28
В свою очередь SpawnActor должен обращаться к са-
мому объекту — блупринту BP_FloorTile, и присоединять
его в следующей точке спауна (рис. 29).
Также создадим ссылку на данную функцию в ивенте
BeginPlay, чтобы скрипт срабатывал сразу после запуска
игры. Дополнительно добавим ноду ForLoop, которая по-
зволить спаунить несколько частей трека одновременно.

16
Infinity runner

Для этого пропишем максимальное значение создавае-


мых объектов в строке Last Index, например, 9 (рис. 30).
Не стоит прописывать слишком большое число, так как
это действие расходует много ресурсов компьютера.

Рисунок 29

Рисунок 30
Далее вернемся в блупринт BP_FloorTile и добавим
в него новый компонент Box Collision с названием EndTrig-
ger. Пройдя через данную зону, персонаж сможет совер-
шить резкий поворот вправо или влево (рис. 31).

Рисунок 31

17
Урок 10

Зададим данному компоненту параметры Box Extent


по осям Y=500 и Z=200. Также сместим бокс по оси Х на
1050 единиц, чтобы разместить его в конце отрезка тре-
ка (рис. 32).

Рисунок 32
Дополнительно поменяем Collision Preset на Overlap-
OnlyPawn (рис. 33).

Рисунок 33

18
Infinity runner

После этого создадим для компонента ивент On Com-


ponent Begin Overlap (рис. 34).

Рисунок 34
Данная нода должна обращаться к самому персона-
жу и блупринту GameMode, после чего добавлять новый
блок в конце существующего трека (нода Add Floor Tile)
(рис. 35).

Рисунок 35
Также, чтобы не засорять уровень, добавим в скрипт
ноду DestroyActor, которая будет удалять пройденные
участки пути. При этом следует учесть время, необхо-
димое персонажу на прохождение трека. Если блоки бу-
дут удаляться слишком быстро, персонаж просто упадет
с трека. Эту задачу легко решить с помощью ноды Delay
со значением Duration=2 (рис. 36).

19
Урок 10

Рисунок 36
Теперь создадим новый блупринт с классом Actor для
предметов сбора. Переименуем его в BP_Item (рис. 37).

Рисунок 37
В редакторе данного блупринта добавим новый ком-
понент Static Mesh. Как говорилось ранее, мы создаем
игру в стиле Fortnite. Для этого в качестве собираемых
предметов будем использовать не стандартные монеты,
а ящики с припасами. Подобную модель можно легко най-
ти в интернете на специализированных сайтах. Также не
забываем затекстурировать меш (рис. 38).
Зададим Collision Preset для данного объекта — Over-
lapOnlyPawn (рис. 39).
Дополнительно можно добавить в иерархию компо-
нент RotationMovement. Данный элемент отвечает за ани-
мацию меша. В результате, при запуске игры все боксы
будут вращаться вокруг своей оси (рис. 40).

20
Infinity runner

Рисунок 38

Рисунок 39

Рисунок 40
Теперь настроим зону спауна объектов. Перейдем
в BP_FloorTile и добавим еще один компонент Box Col-
lision, который сразу переименуем в BoxArea (рис. 41).

21
Урок 10

Рисунок 41
Разместим его в центре платформы и поменяем его
размеры, чтобы плоскость зоны спауна заняла почти всю
площадь дороги (рис. 42).

Рисунок 42
Далее создаем функцию SpawnBoxes (рис. 43).

Рисунок 43

22
Infinity runner

Подключим к ней ноду Add Child Actor Component


с классом BP_Item (рис. 44).

Рисунок 44
Чтобы новые коробки спаунились в случайном ме-
сте на дороге, создадим следующий скрипт. Подключим
компонент Box Area к целевым нодам Relative Location
и Box Extent, которые необходимо соединить с помощью
функции Random Point in Bounding Box. Готовый скрипт
подключим в строку Relative Transform (рис. 45).

Рисунок 45

Рисунок 46

23
Урок 10

Чтобы увеличить количество ящиков, которые будут


одновременно появляться на пути, добавим в скрипт ноду
ForLoop со значением Last Index=3 (рис. 46).
Финальный этап — подключить ноды спауна (Set
Spawn Points и Spawn Boxes) в Construction Script (рис. 47).

Рисунок 47
В результате, если несколько раз запустить симуля-
цию скрипта, ящики будут случайным образом спаунить-
ся на плоскости.
Чтобы персонаж поднимал ящики в момент столкно-
вения, добавим в его блупринт новую переменную Total-
Boxes типа Integer (рис. 48).

Рисунок 48
После это создадим функцию AddBox (рис. 49).

24
Infinity runner

Рисунок 49
Подключим к ней ноду Total Boxes. При этом коли-
чество собранных ящиков должно постоянно увеличи-
ваться на единицу. Скрипт для решения подобной зада-
чи показан на рисунке 50.

Рисунок 50
Чтобы новая функция заработала, необходимо со-
здать ивент On Component Begin Overlap в блупринте
ящика (рис. 51).

Рисунок 51

25
Урок 10

Соединим данный ивент с нодами персонажа и Add


Box (рис. 52).

Рисунок 52
В конце скрипта добавим ноду DestroyActor, которая
будет удалять собранные ящики из вьюпорта. Дополни-
тельно в игру можно добавить звуковой эффект, кото-
рый будет проигрываться в момент, когда персонаж под-
берет объект. Для этого достаточно добавить ноду Play
Sound at Loction и выбрать подходящий звук из библио-
теки (рис. 53).

Рисунок 53
Теперь давайте визуализируем счетчик собранных
предметов. Для этого создадим новую папку и добавим
в нее блупринт виджета. Переименуем его в RunHUD
(рис. 54).

26
Infinity runner

Рисунок 54
Создадим в данном блупринте иерархию, как на ри-
сунке 55. Разместим все элементы виджета в левом верх-
нем углу вьюпорта.

Рисунок 55
Количество собранных ящиков должно оперативно
меняться. Давайте создадим логическую связь соответ-
ствующего числового виджета с действиями персонажа.
Для этого выделим его, перейдем к панели настроек —
блок Content => Bind => Create Binding (рис. 56).

Рисунок 56

27
Урок 10

Подключим к функции ноду персонажа, а также целе-


вую ноду Total Boxes, значение которой будет конверти-
роваться в число. Готовый скрипт показан на рисунке 57.

Рисунок 57
Последний шаг — вывести счетчик на экран. Для это-
го вернемся в блупринт GameMode и подключим к ивен-
ту BeginPlay две ноды: Create Widget с классом RunHUD
и Add to Viewport (рис. 58).

Рисунок 58

Рисунок 59

28
Infinity runner

Теперь давайте сделаем путь персонажа более вариа-


тивным. Для этого создадим дочерний класс блупринта
BP_FloorTile, кликнув по нему ПКМ (рис. 59).
Добавим в него новый Static Mesh, который будет вы-
полнять роль рампы, по которой предстоит подняться
персонажу. Подключим к нему соответствующую модель
(к примеру, Shape_Wedge_B) и затекстурируем ее (рис. 60).
В своем проекте вы можете использовать любую модель
и материалы, которые сделают вашу игру максимально
похожей на Fortnite.

Рисунок 60
Трансформируем рампу так, чтобы ее площадь совпа-
дала с площадью трека, и разместим в конце пути (рис. 61).

Рисунок 61

29
Урок 10

Также необходимо сместить компоненты AttachPoint


и EndTrigger так, как показано на рисунке 62.

Рисунок 62
После этого вернемся в блупринт GameMode, к функ-
ции AddFloorTile. Подключим к ноде SpawnActor новый
класс объектов — переменную массива FloorTiles. Что-
бы участки дороги выбирались случайным образом из
списка существующих, дополним скрипт нодой Random
Integer in Range (рис. 63).

Рисунок 63

30
Infinity runner

После это скомпилируем блупринт и активируем опцию


Class Defaults на верхней панели инструментов (рис. 64).

Рисунок 64
При этом на панели справа появится список элемен-
тов массива Floor Tiles. Чтобы добавить новый пункт, на-
жимаем на знак «+». После этого достаточно подключить
в массив соответствующий блупринт (рис. 65).

Рисунок 65
Давайте создадим еще один дочерний блупринт BP_
FloorTile (рис. 66).

Рисунок 66

31
Урок 10

Поменяем местоположение рампы так, чтобы по ней


персонаж мог спуститься на уровень ниже (рис. 67).

Рисунок 67
Так как массив уже создан, достаточно добавить в него
еще один пункт и подключить соответствующий блупринт.
При этом следует обратить внимание на то, что количество
элементов массива не ограничено. Создавая новые участ­
ки пути, и наполняя их необычными объектами, можно
сгенерировать действительно интересную трассу (рис. 68).

Рисунок 68

32
Infinity runner

В конце самостоятельно реализуйте логику препят­


ствий. Вспомните, с какими опасностями приходится
сталкиваться персонажам Fortnite и добавьте подобные
объекты в готовую игру. Это могут быть модели ужасных
мозгляков или хитроумные ловушки, в которые может
ненароком угодить главный персонаж (рис. 69).

Рисунок 69
Теперь давайте рассмотрим несколько примеров класс-
ных мобильных игр, которые могут достойно предста-
вить игрокам жанр Infinity runner:
■■ Shred it! (рис. 70);

Рисунок 70

33
Урок 10

■■ Lara Croft: Relic Run (рис. 71);

Рисунок 71
■■ Amazing Runner (рис. 72).

Рисунок 72

34
Infinity runner

35
Урок 10
Infinity runner

© Компьютерная Академия «Шаг»


www.itstep.org

Все права на охраняемые авторским правом фото-, аудио- и видеопро-


изведения, фрагменты которых использованы в материале, принадле-
жат их законным владельцам. Фрагменты произведений используются в
иллюстративных целях в объёме, оправданном поставленной задачей, в
рамках учебного процесса и в учебных целях, в соответствии со ст. 1274
ч. 4 ГК РФ и ст. 21 и 23 Закона Украины «Про авторське право і суміжні
права». Объём и способ цитируемых произведений соответствует
принятым нормам, не наносит ущерба нормальному использованию
объектов авторского права и не ущемляет законные интересы автора
и правообладателей. Цитируемые фрагменты произведений на момент
использования не могут быть заменены альтернативными, не охраня-
емыми авторским правом аналогами, и как таковые соответствуют
критериям добросовестного использования и честного использования.
Все права защищены. Полное или частичное копирование материалов
запрещено. Согласование использования произведений или их фраг-
ментов производится с авторами и правообладателями. Согласованное
использование материалов возможно только при указании источника.
Ответственность за несанкционированное копирование и коммерческое
использование материалов определяется действующим законодатель-
ством Украины.

You might also like