В этом уроке мы создадим две новые функции, которые действительно добавят блеска нашей игре: выигрыш и игра окончена. Это может показаться большой работой, но наша игра настроена так, чтобы сделать это быстро и легко. Итак, давайте добавим эти функции и завершим нашу игру!
Первой функцией, которую мы будем решать, является система подсчета очков. Чтобы создать хорошую систему подсчета очков, нам нужно добавить в нашу игру визуально приятный текст. Вы можете начать с загрузки нового шрифта по вашему выбору или с загрузки того шрифта, который я включил в файл загрузки этого руководства. Если вы выбираете свой собственный, убедитесь, что вы загружаете файл «.ttf». Есть много отличных сайтов с бесплатными шрифтами; Вы можете начать с простого поиска «бесплатных шрифтов» и просматривать, пока не найдете то, что вам нравится. Файл загрузок настраивается так же, как и в предыдущих проектах. Существует старая и новая папка: старая папка содержит все, что мы делали до сих пор, а новая папка содержит проект так, как он будет выглядеть в конце этого урока.
Если у вас есть это в папке, содержащей ваш файл main.lua, откройте и файл main.lua, и ваш файл build.settings, и давайте заставим его работать. Первое, что мы собираемся сделать, это работать с нашим файлом build.settings. Именно отсюда мы сообщим программе о включении пользовательского шрифта.
Измените файл build.settings, чтобы он выглядел так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
settings = {
orientation = {
default = «landscapeRight»,
content = «landscapeRight»,
supported = {
«landscapeRight»
},
},
—adds the font BorisBlackBloxx.ttf to our game
—you will still need to reference the name in the
—code, but if you don’t have it referenced here it
—will not work
iphone = {
plist = {
UIAppFonts = {
«BorisBlackBloxx.ttf»
}
},
},
}
|
Обратите внимание, что это будет то же самое, даже если у вас есть устройство Android. Я в основном разработчик iOS, когда дело доходит до разработки игр, поэтому я не проверял это на устройстве Android. Тем не менее, этот точный скрипт должен работать на вашем устройстве Android, а также на вашем устройстве iOS. (Если какие-либо пользователи Android, сталкивающиеся с этим учебным пособием, сталкиваются с проблемами, пожалуйста, дайте мне знать, и я рассмотрю его дальше!) Теперь, когда приведенный выше код готов, вы можете закрыть этот файл, так как нам не нужно его трогать больше Мы проверим, что это сработало, добавив текст в игру.
Давайте откроем наш файл main.lua и предоставим нашим игрокам систему подсчета очков! Прямо выше, где мы создаем наши группы отображения, вставьте следующее:
01
02
03
04
05
06
07
08
09
10
11
12
|
—variable to hold our game’s score
local score = 0
—scoreText is another variable that holds a string that has the score information
—when we update the score we will always need to update this string as well
—*****Note for android users, you may need to include the file extension of the font
— that you choose here, so it would be BorisBlackBloxx.ttf there******
local scoreText = display.newText(«score: » .. score, 0, 0, «BorisBlackBloxx», 50)
—This is important because if you dont have this line the text will constantly keep
—centering itself rather than aligning itself up neatly along a fixed point
scoreText:setReferencePoint(display.CenterLeftReferencePoint)
scoreText.x = 0
scoreText.y = 30
|
Следующее, что мы сделаем, это добавим его на наш экран displayGroup. Поместите это после того, как все другие группы были добавлены в группу экрана:
1
|
screen:insert(scoreText)
|
Давай, беги. Это будет происходить очень быстро, поэтому убедитесь, что все работает правильно, прежде чем двигаться дальше. Вы должны увидеть что-то вроде этого:
После того, как вы проверили это, чтобы убедиться, что оно работает, мы обновим счет, чтобы он сразу имел значение в нашей игре. В функции updateBlocks () прямо под строкой написано:
if ((blocks [a]). x <-40), тогда поместите этот код:
1
2
3
4
5
|
score = score + 1
scoreText.text = «score: » .. score
scoreText:setReferencePoint(display.CenterLeftReferencePoint)
scoreText.x = 0
scoreText.y = 30
|
Это будет просто обновлять нашу оценку на одно очко каждый раз, когда блок проходит с левой стороны экрана и снова вставляется справа. Конечно, это можно использовать по-разному. Это хорошая идея, чтобы обновить счет здесь, потому что он будет держать его согласованным во всех играх. Он основан на том, как далеко продвинулись игроки. Фактически, если вы хотите записать, как далеко они продвинулись, вы просто сохраните счет в переменную под названием distanceTraveled, метры или что-то подобное.
Следующая функция, которую мы рассмотрим, — это то, что происходит, когда игрок умирает. В этом уроке мы будем просты, но вы сможете увидеть, как вы можете включить в него больше, когда мы закончим. Имейте в виду, что добавление к счету действительно довольно просто сделать. Допустим, вы хотели увеличить счет на пять каждый раз, когда убиваете призрака или препятствие. Вы просто поместите приведенный выше код в раздел обнаружения столкновений прямо там, где уничтожаете указанные объекты.
Когда наш персонаж умрет, мы собираемся сделать несколько вещей:
1) Остановить движение игрока.
2) Заставьте игрока вращаться по кругу для драматического эффекта. Мы делаем это здесь, потому что я просто хочу показать вам функцию поворота для экранных объектов. Конечно, вы можете изменить его смерть на то, что хотите.
3) Отображение экрана над игрой, который позволяет игроку перезапустить игру, если они того пожелают.
Во-первых, нам нужно убедиться, что скорость игры установлена на 0. Затем нам нужно добавить переменную к нашему экранному объекту монстра. Сделайте это, добавив следующую строку кода, где мы создаем экземпляр monster:
1
|
monster.isAlive = true
|
После этого мы проверим его статус в нескольких разных местах игры. Первое изменение, которое мы собираемся сделать, — это updateMonster (), сделать так, чтобы updateMonster () выглядел следующим образом:
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
|
function updateMonster()
—if our monster is jumping then switch to the jumping animation
—if not keep playing the running animation
if(monster.isAlive == true) then
if(onGround) then
if(wasOnGround) then
else
monster:prepare(«running»)
monster:play()
end
else
monster:prepare(«jumping»)
monster:play()
end
if(monster.accel > 0) then
monster.accel = monster.accel — 1
end
monster.y = monster.y — monster.accel
monster.y = monster.y — monster.gravity
else
monster:rotate(5)
end
—update the collisionRect to stay in front of the monster
collisionRect.y = monster.y
end
|
Обратите внимание, что прежде чем мы обновим позицию монстра, мы сначала проверяем, жив игрок или нет. Если игрок жив, мы просто идем дальше, как обычно. Если игрок не жив, мы отправляем нашего монстра в бесконечное вращение. Далее нам нужно изменить статус monster.isAlive. Перейдите к функции checkCollisions (), и мы внесем изменения. Внутри проверочных коллизий положение нашего монстра проверяется на предмет столкновений с 3 различными предметами: блоками, призраками и шипами. В каждом из этих разделов мы устанавливаем скорость игры равной 0 при обнаружении столкновения. Теперь вам нужно добавить этот код в каждый из трех разделов сразу после того, как мы установили скорость на 0.
1
2
3
|
monster.isAlive = false
—this simply pauses the current animation
monster:pause()
|
Теперь он установлен так, что любая анимация, которую вы играете, остановится, когда вы умрете. Кроме того, монстр будет вращаться на месте из-за кода, который мы уже добавили в updateMonster (). Запустите игру еще раз, и вы должны увидеть это:
На данный момент у нас есть две из трех сделанных вещей, которые нам нужны, чтобы улучшить процесс смерти в нашей игре. Последнее, что нужно сделать, это сделать маленький экран смерти, который позволит игроку перезапустить игру, если они того пожелают. Вернитесь к началу файла, где мы добавим все displayObjects и добавим это:
1
2
3
4
|
local gameOver = display.newImage(«gameOver.png»)
gameOver.name = «gameOver»
gameOver.x = 0
gameOver.y = 500
|
Поскольку это простое меню, я выбрал одно большое изображение. Я использовал тот же метод, который мы использовали для остальных изображений, и сохранил его за кадром для дальнейшего использования. Теперь нам нужно перемещать это на экране каждый раз, когда умирает наш игрок. Вернитесь к разделу кода, с которым мы только что работали, где мы установили monster.isAlive = false. Прямо под этим добавьте следующее к каждому из этих разделов:
1
2
|
gameOver.x = display.contentWidth*.65
gameOver.y = display.contentHeight/2
|
Обязательно добавлю
1
|
screen:insert(gameOver)
|
в ваш код, чтобы gameOver правильно отображался. Поместите это как последнюю вещь, которая будет добавлена сразу после textScore. Таким образом, он обязательно будет виден, когда мы его переместим.
Это поместит экран «Game Over» справа от вращающегося монстра, чтобы мы могли увидеть наш окончательный счет в верхней левой части экрана. Наконец, чтобы все это работало, нам нужно заставить его что-то делать, когда мы к нему прикасаемся. Далее мы отредактируем функцию touch (). Измените вашу прикосновенную функцию, чтобы она выглядела так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
function touched( event )
if(event.x < gameOver.x + 150 and event.x > gameOver.x — 150 and event.y < gameOver.y + 95 and event.y > gameOver.y — 95) then
restartGame()
else
if(monster.isAlive == true) then
if(event.phase == «began») then
if(event.x < 241) then
if(onGround) then
monster.accel = monster.accel + 20
end
else
for a=1, blasts.numChildren, 1 do
if(blasts[a].isAlive == false) then
blasts[a].isAlive = true
blasts[a].x = monster.x + 50
blasts[a].y = monster.y
break
end
end
end
end
end
end
end
|
Обратите внимание, что мы внесли только одно изменение: вместо того, чтобы сначала проверять, на какой стороне экрана находится касание (как мы определяем прыжок или стрельбу), мы проверяем, не был ли затронут объект gameOverdisplay. Если его не трогали и монстр жив, продолжайте прыгать и стрелять, как обычно. Но если коснуться gameOver, это означает, что игра окончена, потому что она теперь видна, и мы просто вызываем функцию restartGame (). Где-то выше, что добавить функцию restartGame (), и это сделает все за нас.
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
35
36
37
38
39
40
41
42
43
44
|
function restartGame()
—move menu
gameOver.x = 0
gameOver.y = 500
—reset the score
score = 0
—reset the game speed
speed = 5
—reset the monster
monster.isAlive = true
monster.x = 110
monster.y = 200
monster:prepare(«running»)
monster:play()
monster.rotation = 0
—reset the groundLevel
groundLevel = groundMin
for a = 1, blocks.numChildren, 1 do
blocks[a].x = (a * 79) — 79
blocks[a].y = groundLevel
end
—reset the ghosts
for a = 1, ghosts.numChildren, 1 do
ghosts[a].x = 800
ghosts[a].y = 600
end
—reset the spikes
for a = 1, spikes.numChildren, 1 do
spikes[a].x = 900
spikes[a].y = 500
end
—reset the blasts
for a = 1, blasts.numChildren, 1 do
blasts[a].x = 800
blasts[a].y = 500
end
—reset the backgrounds
backgroundfar.x = 480
backgroundfar.y = 160
backgroundnear1.x = 240
backgroundnear1.y = 160
backgroundnear2.x = 760
backgroundnear2.y = 160
end
|
Запустите его и, надеюсь, теперь у вас будет небольшой экран смерти, к которому вы можете прикоснуться, чтобы перезапустить игру.
С этими небольшими изменениями у нас теперь должна быть полностью функциональная игра! Игрок зарабатывает очки, и мы справляемся со смертью немного более изящно. Все, что мы здесь делали, было очень просто, но, надеюсь, теперь у вас есть представление о том, как вы могли бы создавать более крупные меню или как вы могли бы сделать более сложную сцену смерти после смерти. Самый простой способ — добавить пару новых анимаций, подходящих для разных смертей, но я позволю вам решить, что лучше всего подходит для вашей игры. Если у вас есть какие-либо вопросы об изменениях, которые мы внесли, пожалуйста, дайте мне знать в комментариях. Спасибо за подписку!