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

Пишем Space Invaders при помощи Corona. Реализация геймплея. Часть 1

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

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

Пара слов о метатаблицах

Язык программирования Lua по умолчанию не имеет классовой системы, а потому не умеет работать с классами. Тем не менее при помощи метатаблиц в Lua можно эмулировать систему классов. На сайте Corona есть отличный пример, демонстрирующий, как это можно сделать.

Важно отметить, что объекты Display в Corona не могут быть установлены в качестве метатаблиц. Но и эта ситуация не безвыходная: мы установим такие объекты в качестве ключа в новой таблице, которую, в свою очередь, будем считать метатаблицей. Именно такой подход мы и будем использовать в этой статье.

Пульсирующий текст

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

Итак, давайте добавим следующий код в файл pulsatingtext.lua, который был создан нами еще в прошлом уроке (убедитесь, что приведенный код вы вставили перед return):

			
		

Здесь мы создали главную таблицу pulsatingText и метатаблицу pulsatingText_mt. В методе new мы создали новое текстовое поле, добавили его в newPulsatingText, который будет использован в качестве метатаблицы, и вставили сам текст в объект group. Важно понимать, что текст находится на сцене, при удалении которой исчезнет и сам текст.

У нас есть еще два метода, которые имеют доступ к текстовому полю и выполняют над ним определенные действия. Один из них меняет цвет самого текста при помощи метода setFillColor, который принимает в качестве аргументов цвет в формате RGB, определенный 3 числами в диапазоне от 0 до 1. Второй метод использует библиотеку Transition, чтобы создать пульсацию. Текст растет и уменьшается при помощи коэффициентов xScale и yScale. Параметр iterations, равный -1, позволяет повторять пульсацию бесконечно.

Использование пульсирующего текста

Откройте файл start.lua и измените метод scene:create следующим образом:

			function scene:create(event)
    --SNIP--
    local   invadersText =  pulsatingText.new("INVADERZ",
display.contentCenterX,display.contentCenterY-200,"Conquest", 20,group)
    invadersText:setColor( 1, 1, 1 )
    invadersText:pulsate()
end
		

Здесь мы создали новое текстовое поле, в котором написали «INVADERZ», задали ему цвет и вызвали метод pulsate. Обратите внимание на последнюю переменную, переданную в метод new, — это group. Именно на group — объект класса Display — и будет добавляться наш пульсирующий текст.

Для более футуристичного вида пульсирующего текста воспользуемся шрифтом «Conquest». Добавьте его в папку проекта, если вы хотите использовать его. Будьте осторожны, не нарушайте права авторов при использовании сторонних шрифтов.

Для использования стороннего шрифта мы должны изменить файл build.settings:

			settings = {
    orientation =
    {
       default ="portrait",
        supported =
        {
          "portrait"
        },
    },
    iphone =
    {
        plist=
        {
            UIAppFonts = {
                    "Conquest.ttf"
                }
        },
    },
}
		

Если вы запустите игру в том виде, в котором она есть сейчас, то увидите что-то похожее:

Генератор звезд

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

			local starFieldGenerator= {}
local starFieldGenerator_mt = {__index = starFieldGenerator}
 
function starFieldGenerator.new(numberOfStars,theView,starSpeed)
    local starGroup = display.newGroup()
    local allStars     ={} -- Table that holds all the stars
 
    for i=0, numberOfStars do
      local star = display.newCircle(math.random(display.contentWidth),
         math.random(display.contentHeight), math.random(2,8))
      star:setFillColor(1 ,1,1)
      starGroup:insert(star)
      table.insert(allStars,star)
    end
     
    theView:insert(starGroup)
     
    local newStarFieldGenerator = {
        allStars = allStars,
        starSpeed = starSpeed
    }
    return setmetatable(newStarFieldGenerator,starFieldGenerator_mt)
end
 
 
function starFieldGenerator:enterFrame()
    self:moveStars()
    self:checkStarsOutOfBounds()
end
 
 
function starFieldGenerator:moveStars()
        for i=1, #self.allStars do
              self.allStars[i].y = self.allStars[i].y+self.starSpeed
        end
 
end
function  starFieldGenerator:checkStarsOutOfBounds()
    for i=1, #self.allStars do
        if(self.allStars[i].y > display.contentHeight) then
            self.allStars[i].x  = math.random(display.contentWidth)
            self.allStars[i].y = 0
        end
    end
end
 
return starFieldGenerator
		

Сначала мы создаем главную таблицу starFieldGenerator и метатаблицу starFieldGenerator_mt. В методе new мы имеем таблицу allStars, в которой будут храниться все звезды, которые создаются в течение цикла. Количество итераций равно numberOfStars (т. е. количеству звезд), а для рисования самих звезд мы используем метод newCircle объекта Display.

Расположение кружков (звезд) случайное, в пределах границ экрана. Размер варьируется от 2 до 8. Каждая звезда после создания вставляется в таблицу allStars, а затем на ту сцену, которую передали в параметрах метода new.

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

Непосредственно за движение отвечают две функции: starFieldGenerator:moveStars (используется при самом движении) и starFieldGenerator:checkStarsOutOfBounds (используется при выходе звезды за границу экрана).

Если какая-либо звезда исчезает с экрана, то генерируется случайное число x — положение новой звезды по горизонтали. Координата по вертикали задается таким образом, чтобы она была чуть выше верхней части экрана. Таким образом мы можем получить иллюзию нескончаемого потока звезд.

Все вышеописанные функции вызываются в методе starFieldGenerator:enterFrame. Добавьте следующий блок кода в метод scene:create в файле start.lua:

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

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

Порядок (order) можно изменить и вручную. Для этого у класса Display есть два метода: toFront и toBack.

Если вы сейчас запустите игру, то увидите кучу недвижимых звезд с одной кнопкой. Чтобы звезды пришли в движение. добавьте следующий код в метод scene:show в файле start.lua:

			function scene:show(event)
    --SNIP--
   if ( phase == "did" ) then
   startButton:addEventListener("tap",startGame)
   Runtime:addEventListener("enterFrame", starGenerator)
   end
end
		

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

Как говорится, сколько раз new, столько же раз delete. Именно поэтому мы должны удалить слушателя, если он нам больше не нужен. А не нужен он нам будет при удалении сцены:

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

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

Вывод

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

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

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