Статьи

Создайте бесконечную раннер-игру с нуля: используя спрайты

Добро пожаловать в третий выпуск нашей бесконечной игры про раннеров! В этом уроке будет рассказано, как создавать спрайты с помощью листов спрайтов и анимации нашего игрового персонажа. Пока что в нашей игре у нас должен быть хороший вид с тремя слоями изображений, прокручивающимися на разных скоростях, что дает потрясающую прокрутку параллакса! Следующим логическим шагом для нас будет добавление нашего героя в игру. Мы собираемся сделать это в два этапа. Этот урок охватит первый шаг. Следующий урок будет касаться фактического добавления героя в нашу существующую игру и добавления элементов управления, чтобы он следовал каждой нашей команде.


Теперь, прежде чем мы начнем игру, давайте быстро поговорим о спрайтах, листах спрайтов и анимации в общих чертах. Если у вас есть опыт работы с графикой, анимацией или разработкой игр, это, вероятно, знакомая вам тема. Тем не менее, для нашего обсуждения, мы собираемся предположить, что у вас нет опыта ни с одной из вышеупомянутых тем. Итак, начнем с анимации. Анимация в играх выполняется точно так же, как в мультфильмах и фильмах. Подумайте о том, что происходит, когда вы идете в кино, и они начинают фильм. Когда вы смотрите фильм, вы на самом деле не смотрите, как люди двигаются и разговаривают, но вы смотрите серию мигающих изображений со звуком, воспроизводимым одновременно на барабане, создавая иллюзию, что вы смотрите что-то живое и дыхание. Это то же самое, что происходит с нашими играми. Мы создаем иллюзию «жизни», быстро мигая изображения на экране. Когда это делается достаточно быстро, это становится плавной анимацией. Итак, вопрос в том, как мы можем добавить эти плавные анимации в нашу игру. Ответ заключается в использовании спрайтов. Corona SDK предоставляет нам функциональность спрайтов, поэтому единственное, о чем нам нужно беспокоиться, — это создание наших спрайтов и назначение им анимации. Посмотрите на анимированный GIF ниже:

Corona SDK Figure - Monster Run

Когда вы видите эту анимацию, она выглядит как маленький монстр, бегущий и размахивающий руками. На самом деле вы смотрите на серию изображений, взятых с одного листа спрайта, мигая снова и снова. Обратите внимание, что последнее изображение в последовательности не включено в анимацию. Это простой спрайт лист, и именно так вы будете настраивать изображения для своей игры.

Monster Side Scrolling

Итак, вопрос о том, почему мы используем спрайт-листы, наверняка возник у вас в голове. Ответ двоякий и довольно простой: память и простота. Я хочу, чтобы вы посмотрели на четыре изображения, которые я сделал ниже. Все очень простой, клетчатый дизайн доски (хотя спрайты очень маленькие, поэтому они не выглядят так, но откройте их в любой программе и увеличьте масштаб, и вы увидите шахматную доску: D), с размерами от 8×8 вплоть до 256х256.

Corona SDK Figure - Sprite, пример 1
Corona SDK Figure - SpriteExample 2
Corona SDK Figure - Sprite, пример 3
Corona SDK Figure - Sprite, пример 4

Первая причина, память, станет очень очевидной, если вы загрузите изображения и посмотрите их размеры. Обратите внимание на разницу в размерах от 8×8 до 256×256. Если вы не хотите загружать их, я сэкономлю 30 секунд, которые потребовались бы для этого.

Давайте предположим, что все наши изображения будут иметь размер 16×16 пикселей (конечно, это нереально, но наш пример справедлив и для гораздо больших изображений). Изображения размером 16×16 и занимают 2,74 КБ. Допустим, у нас есть 256 спрайтов, которые составляют наш персонаж. На этих изображениях он может ходить в разных направлениях, прыгать, стрелять из оружия или делать что-то еще, что могут делать ваши персонажи. Если бы мы поместили их в отдельные файлы PNG размером 16×16 (PNG — это распространенный формат для мобильных игр, поскольку они занимают очень мало места в памяти), для хранения всех изображений потребовалось бы до 701,44 КБ. Это не кажется таким большим, потому что большинство устройств имеют много памяти, верно? Да, но помните, что в нашей игре, вероятно, будут сотни таких изображений. Тем не менее, 701K для маленького изображения на мобильном устройстве слишком велико. На iPhone большинство маленьких игр стараются не превышать 20 МБ, потому что это самый большой файл, который вы можете загрузить через 3G. Большие файлы должны быть сделаны через WiFi или загружены через iTunes. Если вы считаете, что ограничение в 20 МБ — это плохо, это было 10 МБ! Теперь давайте посмотрим, почему выгодно группировать наши спрайты в листы спрайтов.

Допустим, вы поместили эти 256 спрайтов 16х16 на один лист спрайтов. Как вы думаете, насколько большим будет получаемый файл? Если вы скачали файлы и посмотрели на размеры, вы знаете, что размер изображения 256×256 составляет всего 3,42 КБ! Это экономия 698,02 КБ! Но как это возможно!?! Ответ связан с тем, как изображения масштабируются и сжимаются, а также с множеством других технических вещей, которые мы не собираемся обсуждать. Важно отметить, что удвоение размера изображения не обязательно удваивает его в памяти. Фактически, если вы посмотрите на другие размеры изображений, вы заметите, что размер изображений от 16×16 до 128×128 спрайтов только увеличивается до 2,98 КБ, а 256×256 только до 3,43 КБ! Я знаю, офигенно верно!?!

Вторая причина, по которой мы это делаем, ради простоты. Листы Sprite предоставляют хороший способ упорядочить все наши изображения. Если вы когда-либо играли в игры на Atari, NES, Sega Saturn, SNES, Gameboy или почти во все, что в 2D, то вы видели, как работают спрайт-листы. В некоторых из этих игр тысячи и тысячи спрайтов. Возьмите игру вроде Final Fantasy 3 на Super Nintendo (мы все знаем, что это на самом деле Final Fantasy 6, верно?). У них есть десятки персонажей, сотни врагов, заклинания, предметы, типы ландшафта и, возможно, несколько десятков других вещей, которые я пропускаю. Так как же они отслеживают все эти отдельные спрайты? Опять же, ответ спрайт листов. Представьте, что вместо того, чтобы иметь десятки спрайтов или листов спрайтов для каждого персонажа, у них были все изображения для каждого символа на 1 листе. Таким образом, они всегда точно знали, на что ссылаться. Жизнь становится значительно проще при работе над большими проектами. В качестве краткого справочного руководства, поищите в Google изображения «Finaly Fantasy 6 Sprite Sheets» и ознакомьтесь с некоторыми из листов спрайтов в Final Fantasy, чтобы понять, как они используются в больших играх.

Весь процесс создания спрайтов с анимацией — довольно простой процесс. Откройте пустой файл и назовите его main.lua. Первое, что нам нужно сделать, это настроить наш обработчик спрайтов. Идем дальше и вставим следующий код:

1
2
3
4
5
6
7
8
—This should look familiar, hides the status bar from view
display.setStatusBar(display.HiddenStatusBar)
—‘sprite’ is what we will be using to create our sprite sheets
—‘require’ lets Corona know that we are making calls out to already
—established functions in another file.
—Corona so we don’t have to do any more work on that end
—We will use sprite as a ‘sprite handler’ to create spritesheets
local sprite = require(«sprite»)

Поскольку Corona уже выполнила большую часть работы за нас, нам остается довольно простой процесс. Вот что вам нужно запомнить. Из нашего обработчика спрайтов мы создаем лист спрайтов. Из нашего спрайт-листа мы создаем «наборы». Из наших наборов мы создаем анимацию и спрайт объекты. Чтобы этот метод создания листа спрайта работал, каждый спрайт должен иметь одинаковое измерение. Таким образом, каждый кадр нашего маленького монстра — 100х100. В этом примере есть один длинный лист спрайтов. Чтобы это работало лучше и эффективнее, спрайт-листы всегда должны иметь степень 2. 2×2, 4×4, 16×16, 32×32, 64×64 и т.д. , но это верно вплоть до 1024×1024. Теоретически вы можете пойти еще больше, но у каждого устройства максимальный размер текстуры, и если вы превысите этот размер текстуры, ваше приложение не сможет загружать листы спрайтов. Поэтому, прежде чем добавлять спрайт-листы размером 4096×4096, обязательно проведите исследование, чтобы убедиться, что целевое устройство может с этим справиться! Еще одна вещь, на которую следует обратить внимание, это то, что когда у вас есть изображения в квадрате, они будут читаться так же, как вы читаете книгу. Сверху вниз, слева направо, вот так:

1 2 3 4

5 6 7 8

9 10 11 12

13 14 15 16

Поэтому, когда вы указываете своему спрайту, что нужно смотреть на кадры с 6 по 12, он автоматически знает, куда идти.

Добавьте этот код в свой проект под строкой «требуемый»:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
—creating a new spritesheet will break the image you put into even blocks that are 100
—by 100, change those parameters to whatever size your images are.
—of sprite creation only works for sprites that are the same size.
—to handle sprites of different sizes, but that is beyond the scope of this tutorial.
local spriteSheet = sprite.newSpriteSheet(«images/monsterSpriteSheet.png», 100, 100)
 
—from our spritesheet we create a spriteSet, this is how we how we can group different sprites
—together for organizational purposes.
—them in the same spritesheet and create 2 different sprite sets each holding the information for
—their respective frames.
local monsterSet = sprite.newSpriteSet(spriteSheet, 1, 7)
 
—next we make animations from our sprite sets.
—function which sprite set to us, next name the animation, give the starting
—frame and the number of frames in the animation, the number of milliseconds
—we want 1 animation to take, and finally the number of times we want the
—animation to run for.
sprite.add(monsterSet, «running», 1, 6, 600, 0)
sprite.add(monsterSet, «jumping», 7, 7, 1, 1)
 
—the last step is to make a sprite out of our sprite set that holds all of the animtions
local hero = sprite.newSprite(monsterSet)

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

Добавьте это ниже последнего бита кода, который вы ввели:

1
2
3
4
5
6
7
8
—finds the center of the screen
x = display.contentWidth/2
y = display.contentHeight/2
—a boolean variable that shows which direction we are moving
right = true
 
hero.x = x
hero.y = y

Этот код поместит наш спрайт в центр экрана. Затем добавьте этот код:

1
2
3
4
—use prepare to let the sprite know which animation it is going to use
hero:prepare(«running»)
—calling play will start the loaded animation
hero:play()

Запустите этот код, и мы должны запустить нашего маленького монстра в центре экрана. Это действительно все, что нужно для создания анимированных спрайтов из листов спрайтов. Мы будем использовать их чуть более подробно в следующих уроках. Для полной ссылки на спрайт листы, вы можете проверить ссылку Corona SDK . Это все, что мы пока расскажем по этой теме, так что, надеюсь, этого достаточно, чтобы вы начали! Чтобы получить последний эффект, прежде чем заставлять нашего монстра бегать по экрану, добавьте следующий код в конец кода:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function update()
    —if we are running right then keep moving right
    if(right) then
        hero.x = hero.x + 3
    —if we are not moving right keep moving left
    else
        hero.x = hero.x — 3
    end
 
    —if our monster has run off the screen have him turn
    —and run in the opposite direction.
    —will flip our sprite horizontally
    if(hero.x > 380) then
        right = false
        hero.xScale = -1
    end
 
    if(hero.x < -60) then
        right = true
        hero.xScale = 1
    end
end
 
—call the update function
timer.performWithDelay(1, update, -1)

Легкие вещи. Вычеркните все комментарии, которые я сделал в коде, объясняющем вещи, и вы увидите, насколько просто Corona позволяет создавать приятные анимированные спрайты. Если у вас есть и вопросы или комментарии, дайте мне знать!

Corona SDK - бегущая фигура