Статьи

Corona SDK: создайте игру с препятствиями для вертолета

В этом уроке я покажу вам, как создать игру, избегающую препятствий, используя Corona SDK. Вы узнаете больше о сенсорном управлении, обнаружении столкновений и физике. Цель игры состоит в том, чтобы избежать как можно большего количества препятствий для получения наибольшего количества очков. Давайте начнем.


Обзор приложения

Используя готовую графику, мы создадим развлекательную игру с использованием языка программирования Lua и API Corona SDK. Игрок сможет перемещать вертолет по экрану и должен избегать любых препятствий, с которыми он сталкивается. Вы можете изменить параметры в коде, чтобы настроить игру.


Целевое устройство

Первое, что нам нужно сделать, это выбрать платформу, на которой мы хотим запустить наше приложение, чтобы мы могли выбрать размер для изображений, которые мы будем использовать.

Платформа iOS предъявляет следующие требования:

  • iPad 1/2 / Mini: 1024px x 768px, 132 ppi
  • Сетчатка iPad: 2048px x 1536px, 264 ppi
  • iPhone / iPod Touch: 320px x 480px, 163 ppi
  • Сетчатка iPhone / iPod: 960 x 640 пикселей, 326 ppi
  • iPhone 5 / iPod Touch: 1136 пикселей x 640 пикселей, 326 пикселей на дюйм

Поскольку Android является открытой платформой, существует множество различных устройств и разрешений. Вот некоторые из наиболее распространенных характеристик экрана:

  • Asus Nexus 7 Tablet: 800px x 1280px, 216 ppi
  • Motorola Droid X: 854 x 480 пикселей, 228 ppi
  • Samsung Galaxy SIII: 720px x 1280px, 306 ppi

В этом уроке мы сосредоточимся на платформе iOS с точки зрения графики. В частности, мы будем разрабатывать для iPhone и iPod Touch. Тем не менее, код этого руководства также может быть использован в вашей целевой платформе Android.


Интерфейс

Мы будем использовать простой пользовательский интерфейс, включающий несколько фигур, кнопок, растровых изображений и многое другое. Графики, которые мы будем использовать для этого урока, можно найти в проекте, включенном в этот урок.


Экспорт графики

В зависимости от выбранного устройства вам может потребоваться преобразовать графику в рекомендованное разрешение (ppi), что вы можете сделать в своем любимом графическом редакторе. Я использовал параметр « Изменить размер…» в меню « Инструменты» приложения «Просмотр» в OS X. Не забудьте дать изображениям описательное имя и сохранить их в папке проекта.


Мы будем использовать файл конфигурации config.lua , чтобы приложение работало на всех устройствах в полноэкранном режиме. Файл конфигурации показывает исходный размер экрана и метод, используемый для масштабирования содержимого в случае, если приложение запускается с другим разрешением.

1
2
3
4
5
6
7
8
9
application =
{
    content =
    {
        width = 320,
        height = 480,
        scale = «letterbox»
    },
}

Давайте напишем фактическое приложение. Откройте предпочитаемый вами редактор Lua. Подойдет любой текстовый редактор, но рекомендуется использовать текстовый редактор с подсветкой синтаксиса. Создайте новый файл и сохраните его как main.lua в папке вашего проекта.


Мы будем структурировать наш код, как если бы он был классом. Если вы знакомы с ActionScript или Java, вы должны найти структуру проекта знакомой.

01
02
03
04
05
06
07
08
09
10
11
Necessary Classes
 
Variables and Constants
 
Declare Functions
 
    constructor (Main function)
 
    class methods (other functions)
 
call Main function

1
display.setStatusBar(display.HiddenStatusBar)

Этот фрагмент кода скрывает строку состояния. Строка состояния — это строка в верхней части экрана устройства, на которой отображаются время, сигнал и другие индикаторы.


Мы будем использовать библиотеку физики для обработки столкновений. Импортируйте библиотеку, используя фрагмент кода, показанный ниже.

1
2
3
4
— Physics
 
local physics = require(‘physics’)
physics.start()

Фон

Простой фон для пользовательского интерфейса приложения. Фрагмент кода ниже рисует фон на экране.

1
2
3
4
5
— Graphics
 
— [Background]
 
local gameBg = display.newImage(‘gameBg.png’)

Заголовок

Это заголовок. Это первый интерактивный экран, который появится в нашей игре. Эти переменные хранят его компоненты.

1
2
3
4
5
6
— [Title View]
 
local title
local playBtn
local creditsBtn
local titleView

Вид кредитов

Представление «Кредиты» отображает кредиты и авторские права на приложение. Эта переменная используется для ее хранения.

1
2
3
— [CreditsView]
 
local creditsView

инструкции

В начале игры появится сообщение с инструкциями, которое исчезнет после первого нажатия.

1
2
3
— Instructions
 
local ins

Вертолет

Это рисунок вертолета. Игрок будет управлять вертолетом с помощью сенсорного управления.

1
2
3
— Helicopter
 
local helicopter

Блоки

Блоки — это препятствия, которых игрок должен избегать.

1
2
3
— Blocks
 
local blocks = {}

бдительный

Предупреждение отображается, когда игрок пропускает мяч и игра окончена. Он отображает сообщение и заканчивает игру.

1
2
3
— Alert
 
local alertView

Звуки

Чтобы оживить игру, мы будем использовать звуковые эффекты. Звуки, используемые в игре, были получены от as3soundfxr . Я нашел фоновую музыку на playonloop .

1
2
3
4
— Sounds
 
local bgMusic = audio.loadStream(‘POL-rocket-station-short.wav’)
local explo = audio.loadSound(‘explo.wav’)

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

1
2
3
4
5
6
7
8
— Variables
 
local timerSrc —Blocks timer
local yPos = {90, 140, 180} —Possible positions for the blocks
local speed = 5 —Block speed
local speedTimer —Increases blocks speed
local up = false —Used to determine if helicopter is going up
local impulse = -60 —physics value to make helicopter go up

Объявите все функции как local в начале.

01
02
03
04
05
06
07
08
09
10
11
12
13
— Functions
 
local Main = {}
local startButtonListeners = {}
local showCredits = {}
local hideCredits = {}
local showGameView = {}
local gameListeners = {}
local createBlock = {}
local movePlayer = {}
local increaseSpeed = {}
local update = {}
local alert = {}

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

1
2
3
function Main()
  — code…
end

Мы начнем с размещения представления заголовка на сцене и вызовем функцию, которая добавит прослушиватели касаний к кнопкам.

1
2
3
4
5
6
7
8
function Main()
  titleBg = display.newImage(‘titleBg.png’)
  playBtn = display.newImage(‘playBtn.png’, 220, 178)
  creditsBtn = display.newImage(‘creditsBtn.png’, 204, 240)
  titleView = display.newGroup(titleBg, playBtn, creditsBtn)
 
  startButtonListeners(‘add’)
end

Следующая функция добавляет необходимых слушателей к TitleView .

1
2
3
4
5
6
7
8
9
function startButtonListeners(action)
  if(action == ‘add’) then
    playBtn:addEventListener(‘tap’, showGameView)
    creditsBtn:addEventListener(‘tap’, showCredits)
  else
    playBtn:removeEventListener(‘tap’, showGameView)
    creditsBtn:removeEventListener(‘tap’, showCredits)
  end
end

Экран кредитов отображается, когда пользователь нажимает кнопку о. Прослушиватель касаний добавляется в представление кредитов, чтобы отклонить его, когда пользователь нажимает на него.

1
2
3
4
5
6
function showCredits:tap(e)
  playBtn.isVisible = false
  creditsBtn.isVisible = false
  creditsView = display.newImage(‘credits.png’, -110, display.contentHeight-80)
  transition.to(creditsView, {time = 300, x = 55, onComplete = function() creditsView:addEventListener(‘tap’, hideCredits) end})
end

Когда пользователь нажимает на представление кредитов, оно анимируется со сцены и удаляется.

1
2
3
4
5
function hideCredits:tap(e)
  playBtn.isVisible = true
  creditsBtn.isVisible = true
  transition.to(creditsView, {time = 300, y = display.contentHeight+creditsView.height, onComplete = function() creditsView:removeEventListener(‘tap’, hideCredits) display.remove(creditsView) creditsView = nil end})
end

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

1
2
function showGameView:tap(e)
  transition.to(titleView, {time = 300, x = -titleView.height, onComplete = function() startButtonListeners(‘rmv’) display.remove(titleView) titleView = nil end})

Следующий фрагмент кода добавляет сообщение с инструкциями.

1
2
ins = display.newImage(‘ins.png’, 180, 270)
  transition.from(ins, {time = 200, alpha = 0.1, onComplete = function() timer.performWithDelay(2000, function() transition.to(ins, {time = 200, alpha = 0.1, onComplete = function() display.remove(ins) ins = nil end}) end) end})

Следующий фрагмент кода создает текстовое поле, которое показывает текущий счет игрока в правом верхнем углу сцены.

1
2
3
4
— TextFields
 
  scoreTF = display.newText(‘0’, 450, 5, ‘Marker Felt’, 14)
  scoreTF:setTextColor(255, 255, 255)

Затем пришло время добавить изображение вертолета на сцену, как показано ниже.

1
2
3
— Helicopter
 
  helicopter = display.newImage(‘helicopter.png’, 23, 152)

В следующем фрагменте кода мы используем графический API-интерфейс Corona для создания нескольких строк, которые мы добавим к моделированию физики чуть позже в этом руководстве. Они будут использоваться для обнаружения столкновений с вертолетом.

1
2
3
4
5
6
7
— Walls
 
  local top = display.newRect(0, 60, 480, 1)
  top:setFillColor(34, 34, 34)
  local bottom = display.newRect(0, 260, 480, 1)
  bottom:setFillColor(34, 34, 34)
end

Далее нам нужно добавить необходимую физику к каждому объекту.

1
2
3
4
5
— Add physics
 
  physics.addBody(helicopter)
  physics.addBody(top, ‘static’)
  physics.addBody(bottom, ‘static’)

Мы создаем группу для блоков, gameListeners функцию gameListeners и запускаем фоновую музыку.

1
2
3
4
  blocks = display.newGroup()
  gameListeners(‘add’)
  audio.play(bgMusic, {loops = -1, channel = 1})
end

Следующий фрагмент кода может показаться сложным, но он просто добавляет несколько слушателей для запуска логики игры.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
function gameListeners(action)
  if(action == ‘add’) then
    gameBg:addEventListener(‘touch’, movePlayer)
    Runtime:addEventListener(‘enterFrame’, update)
    timerSrc = timer.performWithDelay(1300, createBlock, 0)
    speedTimer = timer.performWithDelay(5000, increaseSpeed, 5)
    helicopter:addEventListener(‘collision’, onCollision)
  else
    gameBg:addEventListener(‘touch’, movePlayer)
    Runtime:removeEventListener(‘enterFrame’, update)
    timer.cancel(timerSrc)
    timerSrc = nil
    timer.cancel(speedTimer)
    speedTimer = nil
    helicopter:removeEventListener(‘collision’, onCollision)
  end
end

Как видно из createBlock функция createBlock создает блок и выводит его на экран. Полученный объект добавляется в физический движок для проверки столкновений.

01
02
03
04
05
06
07
08
09
10
function createBlock()
  local b
  local rnd = math.floor(math.random() * 4) + 1
  b = display.newImage(‘block.png’, display.contentWidth, yPos[math.floor(math.random() * 3)+1])
  b.name = ‘block’
  — Block physics
  physics.addBody(b, ‘kinematic’)
  b.isSensor = true
  blocks:insert(b)
end

В функции movePlayer мы обновляем переменную up . Пока его значение равно true , функция update перемещает вертолет вверх.

1
2
3
4
5
6
7
8
9
function movePlayer(e)
  if(e.phase == ‘began’) then
    up = true
  end
  if(e.phase == ‘ended’) then
    up = false
    impulse = -60
  end
end

Чтобы сделать игру более интересной, таймер увеличивает скорость каждые пять секунд. Значок отображается для предупреждения игрока об изменении скорости.

1
2
3
4
5
6
function increaseSpeed()
  speed = speed + 2
  — Icon
  local icon = display.newImage(‘speed.png’, 204, 124)
  transition.from(icon, {time = 200, alpha = 0.1, onComplete = function() timer.performWithDelay(500, function() transition.to(icon, {time = 200, alpha = 0.1, onComplete = function() display.remove(icon) icon = nil end}) end) end})
end

Функция update проверяет значение up и перемещает вертолет вверх, если оно равно true .

1
2
3
4
5
6
function update(e)
  — Move helicopter up
  if(up) then
    impulse = impulse — 3
    helicopter:setLinearVelocity(0, impulse)
  end

Далее пришло время переместить блоки. Мы используем переменную speed чтобы определить, сколько пикселей должны перемещаться блоки в каждом кадре.

1
2
3
4
5
6
— Move Blocks
  if(blocks ~= nil)then
    for i = 1, blocks.numChildren do
      blocks[i].x = blocks[i].x — speed
    end
  end

Алгоритм обновления счета прост. Счет увеличивается на один каждый кадр до тех пор, пока вертолет не разбился. Просто. Правильно?

1
2
3
  — Score
  scoreTF.text = tostring(tonumber(scoreTF.text) + 1)
end

Функция onCollision проверяет, столкнулся ли вертолет с блоком. Если было обнаружено столкновение, мы воспроизводим звуковой эффект, взрыв, удаляем графику и показываем предупреждение игроку.

1
2
3
4
5
function onCollision(e)
  audio.play(explo)
  display.remove(helicopter)
  alert()
end

Функция alert создает представление оповещения и показывает его пользователю. Затем игра заканчивается.

1
2
3
4
5
function alert()
  gameListeners(‘rmv’)
  alert = display.newImage(‘alert.png’, (display.contentWidth * 0.5) — 105, (display.contentHeight * 0.5) — 55)
  transition.from(alert, {time = 300, xScale = 0.5, yScale = 0.5})
end

Чтобы начать игру, необходимо вызвать функцию Main . С остальной частью кода мы делаем это здесь.

1
Main()

Экран загрузки

На платформе iOS файл с именем Default.png отображается во время запуска приложения. Добавьте это изображение в исходную папку вашего проекта, оно будет автоматически добавлено компилятором Corona.


Икона

Используя графику, которую вы создали ранее, теперь вы можете создать красивый значок. Размеры значков для iPhone без сетчатки составляют 57px x 57px, в то время как версия Retina должна быть 114px x 114px. Иллюстрации для iTunes должны быть размером 1024px x 1024px. Я предлагаю сначала создать обложку iTunes, а затем создать изображения меньшего размера, уменьшив обложку iTunes до нужных размеров. Нет необходимости делать значок приложения глянцевым или добавлять закругленные углы, поскольку об этом позаботится операционная система.


тестирование

Пришло время протестировать наше приложение в симуляторе. Откройте Corona Simulator, перейдите в папку вашего проекта и нажмите «Открыть». Если все работает, как ожидалось, вы готовы к последнему шагу.


Сложение

В Corona Simulator перейдите в File> Build и выберите целевое устройство. Заполните обязательные поля и нажмите « Построить» . Подождите несколько секунд, и ваше приложение готово к тестированию на устройстве и / или будет отправлено для распространения.


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