Вступление
В первой части этой серии нам удалось показать начальный экран и перейти на экран уровня игры. В этом уроке мы продолжим с того места, где мы остались, и начнем реализацию игрового процесса.
1. Локальные переменные
Откройте gamelevel.lua , файл, который мы создали в первом уроке , и добавьте следующее ниже строки local scene = storyboard.newScene()
.
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
26
27
28
29
30
31
32
33
34
|
local playerSpeedY = 0
local playerSpeedX = 0
local playerMoveSpeed = 7
local playerWidth = 60
local playerHeight = 48
local bulletWidth = 8
local bulletHeight = 19
local islandHeight = 81
local islandWidth = 100
local numberofEnemysToGenerate = 0
local numberOfEnemysGenerated = 0
local playerBullets = {} — Holds all the bullets the player fires
local enemyBullets = {} — Hold the bullets from «all» enemy planes
local islands = {} — Holds all the islands
local planeGrid = {} — Holds 0 or 1 (11 of them for making a grid system)
local enemyPlanes = {} — Holds all of the enemy planes
local livesImages = {} — Holds all of the «free life» images
local numberOfLives = 3
local freeLifes = {} — Holds all the ingame free lives
local playerIsInvincible = false
local gameOver = false
local numberOfTicks = 0 — A number that is incremented each frame of the game
local islandGroup — A group to hold all of the islands
local planeGroup — A group that holds all the planes, bullets, etc
local player
local planeSoundChannel — SoundChannel for the plane sound
local firePlayerBulletTimer
local generateIslandTimer
local fireEnemyBulletsTimer
local generateFreeLifeTimer
local rectUp — The «up» control on the DPAD
local rectDown — The «down» control on the DPAD
local rectLeft — The «left» control on the DPAD
local rectRight — The «right» control on the DPAD
|
Большинство из них говорят сами за себя, но я включил комментарии для разъяснения. С этого момента весь код должен быть вставлен над строкой return scene
.
2. createScene
Начните с добавления функции createScene в main.lua . Функция createScene
вызывается, когда вид сцены еще не существует. В эту функцию мы добавим экранные объекты игры.
1
2
3
4
|
function scene:createScene( event )
local group = self.view
end
scene:addEventListener( «createScene», scene )
|
3. setupBackground
1
2
3
4
5
|
function setupBackground ()
local background = display.newRect( 0, 0, display.contentWidth, display.contentHeight)
background:setFillColor( 0,0,1)
scene.view:insert(background)
end
|
В setupBackground
мы создаем синий фон, используя метод newRect
объекта newRect
. Метод setFillColor
принимает значения RGB в процентах. setupBackground
функцию setupBackground
в createScene
как показано ниже.
1
2
3
4
|
function scene:createScene( event )
local group = self.view
setupBackground()
end
|
4. setupGroups
Функция setupGroups
создает экземпляры групп islandGroup
и planeGroup
и вставляет их в представление сцены. GroupObject — это специальный тип экранного объекта, в который можно добавлять другие экранные объекты. Важно сначала добавить islandGroup
в view
чтобы убедиться, что острова находятся ниже плоскостей.
1
2
3
4
5
6
|
function setupGroups()
islandGroup = display.newGroup()
planeGroup = display.newGroup()
scene.view:insert(islandGroup)
scene.view:insert(planeGroup)
end
|
setupGroups
функцию setupGroups
в createScene
как показано ниже.
1
2
3
4
5
|
function scene:createScene( event )
local group = self.view
setupBackground()
setupGroups()
end
|
5. setupDisplay
Функция setupDisplay
рисует черный прямоугольник в нижней части экрана и вставляет изображения dpad и плоскости в view
.
1
2
3
4
5
6
7
8
9
|
function setupDisplay ()
local tempRect = display.newRect(0,display.contentHeight-70,display.contentWidth,124);
tempRect:setFillColor(0,0,0);
scene.view:insert(tempRect)
local logo = display.newImage(«logo.png»,display.contentWidth-139,display.contentHeight-70);
scene.view:insert(logo)
local dpad = display.newImage(«dpad.png»,10,display.contentHeight — 70)
scene.view:insert(dpad)
end
|
Опять же, вызовите эту функцию в createScene
как показано ниже.
1
2
3
4
5
6
|
function scene:createScene( event )
local group = self.view
setupBackground()
setupGroups()
setupDisplay()
end
|
6. setupPlayer
Функция setupPlayer
просто добавляет изображение плеера на экран. Объект Display имеет два свойства только для contentWidth
и contentHeight
, представляющие исходную ширину и высоту содержимого в пикселях. Эти значения по умолчанию соответствуют ширине и высоте экрана, но могут иметь и другие значения, если вы используете масштабирование содержимого в config.lua
. Мы используем эти свойства, чтобы выровнять игрока на сцене.
1
2
3
4
5
|
function setupPlayer()
player = display.newImage(«player.png»,(display.contentWidth/2)-(playerWidth/2),(display.contentHeight — 70)-playerHeight)
player.name = «Player»
scene.view:insert(player)
end
|
setupPlayer
функцию createScene
в createScene
.
1
2
3
4
5
6
7
|
function scene:createScene( event )
local group = self.view
setupBackground()
setupGroups()
setupDisplay()
setupPlayer()
end
|
7. setupLivesImages
Функция setupLivesImages
устанавливает шесть изображений жизни и setupLivesImages
их в верхнем левом углу экрана. Затем мы вставляем эти изображения в таблицу livesImages
, чтобы мы могли ссылаться на них позже. Наконец, мы следим за тем, чтобы были видны только первые три изображения.
01
02
03
04
05
06
07
08
09
10
|
function setupLivesImages()
for i = 1, 6 do
local tempLifeImage = display.newImage(«life.png», 40* i — 20, 10)
table.insert(livesImages,tempLifeImage)
scene.view:insert(tempLifeImage)
if( i > 3) then
tempLifeImage.isVisible = false;
end
end
end
|
Функция setupLivesImages
также вызывается в функции createScene
.
1
2
3
4
5
6
7
8
|
function scene:createScene( event )
local group = self.view
setupBackground()
setupGroups()
setupDisplay()
setupPlayer()
setupLivesImages()
end
|
8. setupDPad
Функция setupDPad
устанавливает четыре прямоугольника rectUp
, rectDown
, rectLeft
и rectRight
. Мы осторожно размещаем их поверх изображения dpad, настраиваем их так, чтобы они не были видны, и isHitTestable
свойство isHitTestable
установлено в значение true
.
Если вы установите экранные объекты невидимыми, вы изначально не сможете с ними взаимодействовать. Однако, установив для свойства isHitTestable
значение true
, это поведение переопределяется.
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
26
27
28
29
|
function setupDPad()
rectUp = display.newRect( 34, display.contentHeight-70, 23, 23)
rectUp:setFillColor(1,0,0)
rectUp.id =»up»
rectUp.isVisible = false;
rectUp.isHitTestable = true;
scene.view:insert(rectUp)
rectDown = display.newRect( 34,display.contentHeight-23, 23,23)
rectDown:setFillColor(1,0,0)
rectDown.id =»down»
rectDown.isVisible = false;
rectDown.isHitTestable = true;
scene.view:insert(rectDown)
rectLeft = display.newRect( 10,display.contentHeight-47,23, 23)
rectLeft:setFillColor(1,0,0)
rectLeft.id =»left»
rectLeft.isVisible = false;
rectLeft.isHitTestable = true;
scene.view:insert(rectLeft)
rectRight= display.newRect( 58,display.contentHeight-47, 23,23)
rectRight:setFillColor(1,0,0)
rectRight.id =»right»
rectRight.isVisible = false;
rectRight.isHitTestable = true;
scene.view:insert(rectRight)
end
|
Вы уже догадались. Эта функция также вызывается в createScene
.
1
2
3
4
5
6
7
8
9
|
function scene:createScene( event )
local group = self.view
setupBackground()
setupGroups()
setupDisplay()
setupPlayer()
setupLivesImages()
setupDPad()
end
|
9. resetPlaneGrid
Функция resetPlaneGrid
сбрасывает таблицу planeGrid
и вставляет одиннадцать нулей. Таблица planeGrid
имитирует одиннадцать точек поперек оси X, в которых можно расположить вражеский самолет. Это будет иметь больше смысла, как только мы начнем создавать вражеские самолеты.
1
2
3
4
5
6
|
function resetPlaneGrid()
planeGrid = {}
for i=1, 11 do
table.insert(planeGrid,0)
end
end
|
Вызовите эту функцию в createScene
.
01
02
03
04
05
06
07
08
09
10
|
function scene:createScene( event )
local group = self.view
setupBackground()
setupGroups()
setupDisplay()
setupPlayer()
setupLivesImages()
setupDPad()
resetPlaneGrid()
end
|
10. enterScene
Теперь, когда все экранные объекты установлены, пришло время добавить прослушиватели событий, таймеры и т. Д. Если вы помните предыдущую часть этого урока, функция enterScene
является хорошим местом для их настройки. Начните со вставки следующего фрагмента кода.
1
2
3
4
|
function scene:enterScene( event )
local group = self.view
end
scene:addEventListener( «enterScene», scene )
|
11. Удаление предыдущего раскадровки
Когда мы входим в эту сцену, нам нужно удалить предыдущую сцену. Для этого добавьте следующий код в функцию enterScene
.
1
2
|
local previousScene = storyboard.getPrevious()
storyboard.removeScene(previousScene)
|
Когда вы входите в новую сцену, на предыдущую сцену, на которой вы находились, можно ссылаться, вызывая getPrevious
объекта storyboard
. Мы полностью удаляем его из раскадровки, вызывая removeScene
для объекта storyboard
.
12. Добавьте прослушиватели событий в прямоугольники Dpad
Добавьте следующий код под кодом, который вы ввели на предыдущем шаге. Этот фрагмент кода добавляет слушателей касания к каждому из прямоугольников, вызывая movePlane
при каждом касании. Давайте посмотрим на эту функцию movePlane
на следующем шаге.
1
2
3
4
|
rectUp:addEventListener( «touch», movePlane)
rectDown:addEventListener( «touch», movePlane)
rectLeft:addEventListener( «touch», movePlane)
rectRight:addEventListener( «touch», movePlane)
|
13. movePlane
Функция movePlane
отвечает за настройку скорости самолетов. Мы проверяем, совпадает ли фаза события касания с началом, что означает, что игрок приземлился, но не поднял палец назад. Если это правда, мы устанавливаем скорость и направление, в соответствии с которым был затронут прямоугольник. Если фаза сенсорного события равна ended
, то мы знаем, что игрок поднял палец, что означает, что мы установили скорость на 0
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
function movePlane(event)
if event.phase == «began» then
if(event.target.id == «up») then
playerSpeedY = -playerMoveSpeed
end
if(event.target.id == «down») then
playerSpeedY = playerMoveSpeed
end
if(event.target.id == «left») then
playerSpeedX = -playerMoveSpeed
end
if(event.target.id == «right») then
playerSpeedX = playerMoveSpeed
end
elseif event.phase == «ended» then
playerSpeedX = 0
playerSpeedY = 0
end
end
|
14. PlaneSound
Давайте добавим немного звука в нашу игру. Добавьте следующий фрагмент кода в функцию enterScene
. Он загружает и играет planesound.mp3 . Если установить для свойства loops
значение -1
, звук будет зацикливаться вечно. Если вы хотите узнать больше об аудио в Corona, обязательно ознакомьтесь с документацией .
1
2
|
local planeSound = audio.loadStream(«planesound.mp3»)
planeSoundChannel = audio.play( planeSound, {loops=-1} )
|
15. событие enterFrame
Мы также добавляем обработчик событий во время выполнения с именем enterFrame
который будет вызывать функция gameLoop
. Частота, с которой enterFrame
событие enterFrame
зависит от значения числа кадров в секунду (FPS), установленного в config.lua . В нашем примере он будет вызываться 30 раз в секунду. Добавьте этот прослушиватель событий в функцию enterScene
.
1
|
Runtime:addEventListener(«enterFrame», gameLoop)
|
16. gameLoop
В функции gameLoop
мы обновляем позиции спрайтов и выполняем любую другую логику, которая должна присутствовать в каждом кадре. Если вы хотите больше узнать о игровых циклах, Майкл Джеймс Уильямс написал отличную статью, в которой объясняется, как работает общий игровой цикл . Добавьте следующий фрагмент кода.
1
2
3
|
function gameLoop()
movePlayer()
end
|
17. movePlayer
Функция movePlayer
управляет перемещением плоскости игрока. Мы перемещаем плоскость в соответствии со значениями playerSpeedX
и playerSpeedY
, которые будут playerSpeedY
7
или 0
, в зависимости от того, касается ли игрок касания DPad или нет. Вернитесь к функции movePlane
если это неясно. Мы также делаем некоторую проверку границ, чтобы убедиться, что самолет не может двигаться за пределы экрана.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
function movePlayer()
player.x = player.x + playerSpeedX
player.y = player.y + playerSpeedY
if(player.x < 0) then
player.x = 0
end
if(player.x > display.contentWidth — playerWidth) then
player.x = display.contentWidth — playerWidth
end
if(player.y < 0) then
player.y = 0
end
if(player.y > display.contentHeight — 70- playerHeight) then
player.y = display.contentHeight — 70 — playerHeight
end
end
|
Если вы протестируете игру сейчас, вы сможете перемещаться по экрану с помощью DPad.
Вывод
Это завершает второй урок этой серии. В следующей части этой серии мы продолжим игровой процесс. Спасибо за чтение и увидимся там.