
Вступление
В первой части этой серии нам удалось показать начальный экран и перейти на экран уровня игры. В этом уроке мы продолжим с того места, где мы остались, и начнем реализацию игрового процесса.
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.
Вывод
Это завершает второй урок этой серии. В следующей части этой серии мы продолжим игровой процесс. Спасибо за чтение и увидимся там.