Написать пост

Пишем Space Invaders при помощи Corona. Настройка проекта

Аватар Типичный программист

В этой серии уроков мы будем писать игру по мотивам старой доброй Space Invaders. В рамках этих статей мы познакомимся с Corona, а именно:

  • с управлением сцен;
  • с таймерами;
  • с перемещением героев;
  • со встроенным физическим движком.

Также мы узнаем, как использовать модули для эмуляции классов на языке программирования Lua. Прилагаем полный список всех статей в этой серии:

  1. Настройка проекта.
  2. Реализация геймплея. Часть 1
  3. Реализация геймплея. Часть 2
  4. Заключение

Создание проекта

Откройте Corona Simulator, нажмите New Project и сконфигурируйте проект так, как показано на изображении ниже. Не забудьте выбрать папку для сохранения проекта и нажмите OK. После этого создастся указанная вами папка, которая будет содержать ряд иконок и три особенно важных файла: main.lua, config.lua и build.settings. Мы поговорим о каждом из них чуть позже.

Пишем Space Invaders при помощи Corona. Настройка проекта 1

Настройка сборки

Файл build.settings, как несложно догадаться, отвечает за настройки сборки проекта. Откройте этот файл и удалите его содержимое, вместо которого напишите следующее:

			settings =
{
    orientation =
    {
        default ="portrait",
        supported =
        {
          "portrait"
        },
    },
}
		

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

Настройка приложения

Файл config.lua отвечает за настройки самого приложения. Откройте этот файл, также удалите его содержимое, вместо которого напишите следующее:

			application =
{
    content =
    {
      width = 768,
      height = 1024,
      scale = "letterbox",
      fps = 30,
    }
}
		

Здесь все просто: мы устанавливаем размер рабочего пространства и задаем частоту кадров. Все подробности в официальной документации.

Примечание переводчика Стоит отдельно рассказать про третью строчку, в которой устанавливается масштаб. Параметр scale может принимать различные значения ("letterbox", "zoomEven", "adaptive" и т.д.). Автор статьи использует "letterbox", и это означает, что если размер экрана отличается от установленного нами, то изображение наше будет масштабироваться до тех пор, пока оно целиком входит в экран. Иными словами, если окно будет размером 800×1024, то слева и справа от изображения будут черные полосы. Проще увидеть, чем прочитать:

Пишем Space Invaders при помощи Corona. Настройка проекта 2

Точка входа

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

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

Вышеупомянутая библиотека достаточно новая, она заменяет уже устаревшую StoryBoard.

Статус бар

В игре статус бар не особо-то и нужен, а потому мы уберем его. Для этого следует в файле main.lua прописать следующий код:

			display.setStatusBar(display.HiddenStatusBar)
		

Точка привязки

Когда мы указываем координаты для некоторого объекта, мы должны учитывать точку привязки, в качестве которой удобнее всего использовать центральную точку. Для этого добавьте в main.lua:

			display.setDefault( "anchorX", 0.5)
display.setDefault( "anchorY", 0.5)
		

Значения параметров anchorX и anchorY лежит в диапазоне от 0 до 1. Отсчет начинается слева и сверху. Например, если вы хотите указать в качестве точки привязки левый верхний угол, то выставьте оба значения в нули.

Зерно генерации

Наша игра будет использовать функцию math.random, и для того, чтобы числа получались по-настоящему случайными, нам надо задать зерно генерации псевдослучайных чисел. Если этого не сделать, то при каждом запуске мы будем получать одни и те же значения.

Хорошим параметром для зерна генерации может послужить функция os.time, которая будет различной при каждом запуске приложения. Для определения этого параметра напишите следующий код:

			math.randomseed( os.time() )
		

«Нет» глобальным переменным

При использовании Corona и, в частности, языка программирования Lua (да и не только Lua) используют глобальные переменные для того, чтобы расширить область их видимости. Чтобы объявить глобальную переменную в Lua, достаточно убрать ключевое слово local перед ее именем.

Например, в следующем блоке кода объявляются две переменные, первая из которых локальная (она видна только в той функции, в которой объявлена), а вторая — глобальная (она видна в любом месте файла после объявления).

			local iamalocalvariable = "local"
iamaglobalvariable = "global"
		

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

			M = {}
return M
		

Мы попросту создали таблицу и вернули ее. Для того, чтобы использовать этот код, мы воспользуемся методом require. Добавьте этот код в main.lua:

			local gameData = require( "gamedata" )
		

Мы можем добавить в gameData ключи, которые будут искусственно глобальными. Взгляните на пример ниже:

			gameData.invaderNum = 1 -- Используется для отслеживания текущего уровня
gameData.maxLevels = 3 -- Максимальное количество уровней в игре
gameData.rowsOfInvaders = 4 -- Сколько рядов захватчиков создавать
		

Всякий раз, когда мы хотим получить эти переменные, мы должны вызвать функцию require, чтобы загрузить gamedata.lua. Каждый раз, когда мы загружаем модуль при помощи вышеупомянутой функции, сам модуль помещается в таблицу package.loaded. При следующем запросе игровые данные не будут заново прогружаться, а попросту извлекутся из кэша.

Загружаем Composer

Прежде чем воспользоваться модулем Composer, его нужно «затребовать». Добавьте в main.lua следующий код:

			local composer = require( "composer" )
		

Первая сцена

Чтобы перейти к какой-либо сцене, следует воспользоваться функцией gotoScene. Причем каждая сцена будет описана в своем файле. Добавьте следующий код, чтобы перейти к сцене start, определенной в файле start.lua (да, ее пока нет, но мы вскоре ее создадим):

			composer.gotoScene( "start" )
		

Обратите внимание, что при использовании функции gotoScene расширение файла писать не нужно.

Запуск сцены

Итак, давайте создадим файл start.lua, в которой и опишем нашу первую сцену. Как уже говорилось выше, для того, чтобы управлять сценами, нам потребуется модуль Composer — самое время его подключить. Добавьте следующий код в start.lua:

			local composer = require( "composer" )
local scene = composer.newScene()
return scene
		

Вызов метода newScene сделает start.lua частью иерархии сцен модуля Composer. Именно поэтому все то, что мы хотим увидеть в первой сцене, должно быть написано между этой строчкой и ключевым словом return.

Локальные переменные

Вот те переменные, которые нам потребуются в файле start.lua:

			local startButton -- используется для начала игры
local pulsatingText = require("pulsatingtext")
-- модуль, поддерживающий пульсирующий текст 
local starFieldGenerator = require("starfieldgenerator")
-- модуль, который будет генерировать звезды 
local starGenerator -- экземпляр модуля starFieldGenerator
		

Важно помнить, что эти строчки будут вызваны лишь единожды. А дальше при вызове метода gotoScene эти переменные уже будут проинициализированы.

Есть несколько способов, как сделать так, чтобы переменные каждый раз переинициализировались. Мы будем использовать самый простой способ: удалим сцену из иерархии модуля Composer с помощью метода removeScene. В этом уроке мы будем использовать именно такой подход.

Мы также будем использовать два кастомных модуля: pulsatingText и starFieldGenerator. Создадим два новых файла в папке проекта с названиями pulsatingtext.lua и starfieldgenerator.lua.

События сцены

Если вы нашли время и прочитали документацию, ссылку на которую мы прилагали в начале статьи, то вы наверняка заметили шаблон, содержащий все возможные события модуля Composer. К каждому событию прилагается комментарий, в котором указывается, для чего оно используется. Нас интересуют следующие функции: scene:create, scene:show и scene:hide.

Шаг 1: scene:create

Добавьте этот отрывок кода в файл start.lua:

			function scene:create( event )
    local group = self.view
    startButton = display.newImage("new_game_btn.png",
     display.contentCenterX,display.contentCenterY+100)
    group:insert(startButton)
end
		

Этот метод вызывается, когда сцена еще не существует. Здесь вы должны проинициализировать все переменные и объекты и добавить их на сцену. Переменная group, являясь экземпляром класса GroupObject, указывает на саму сцену, и именно «на нее» добавляются все изображения и другие визуальные элементы.

Мы создаем кнопку startButton при помощи метода newImage объекта класса Display. Сама функция принимает в качестве аргументов путь к изображению и координаты будущей кнопки.

Шаг 2: scene:show

Этот метод имеет 2 фазы. Фаза will вызывается, когда сцена по-прежнему еще не на экране, но вот-вот будет. Фаза did вызывается, когда сцена уже появилась и видна пользователю. Именно во второй фазе мы и будем «оживлять» нашу игру: запустим таймеры, добавим слушателей, начнем проигрывать музыку и т.д.

В этом уроке фаза will нам не понадобится.

			
		

Мы объявляем локальную переменную phase, в которую и записываем текущую фазу выполнения метода. Так как позднее мы будем к этой сцене возвращаться, то проверим, есть ли предыдущая сцена, и если она есть — удаляем ее. Также мы добавляем слушателя для кнопки startButton (при ее нажатии вызовется метод startGame).

Шаг 3: scene:hide

Метод hide тоже имеет две фазы: will и did. По смыслу они такие же, как и в scene:show. Во время выполнения фазы will мы будем останавливать таймеры, удалять слушателей различных событий, останавливать музыку и т.д. Фаза did вызывается ровно один раз, когда сцена исчезает с экрана. В наших статьях она нам не понадобится.

			function scene:hide( event )
    local phase = event.phase
    if ( phase == "will" ) then
        startButton:removeEventListener("tap",startGame)
    end
end
		

Начало игры

Функция startGame вызывается тогда, когда игрок нажимает на кнопку startButton. В этом методе мы будем вызывать gotoScene и переходить к сцене gamelevel.

			function startGame()
    composer.gotoScene("gamelevel")
end
		

Игровая сцена

Создайте новый файл с именем gamelevel.lua и добавьте в него следующий код:

			local composer = require("composer")
local scene = composer.newScene()
 
return scene
		

Все знакомо, не правда ли? Да, мы здесь попросту создаем новую сцену.

Слушатель сцен

Теперь нам следует добавить слушателя сцен для методов create, show, hide. Для этого напишем в start.lua:

			scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
		

Запуск

Если вы в данный момент запустите игру, то увидите черный экран с одной кнопкой — это сцена start. При нажатии на кнопку вы попадете на другой экран, который пока полностью пустой — это сцена gamelevel.

Вывод

Итак, мы подошли к концу статьи. Мы создали хорошую базу для игры, научились переключаться между сценами и познакомились с основами Corona. В следующей части статьи мы займемся реализацией самого геймплея. Оставайтесь с нами!

Перевод статьи «Create a Space Invaders Game in Corona: Project Setup»

Следите за новыми постами
Следите за новыми постами по любимым темам
5К открытий5К показов