Создайте игру Endless Runner / бесконечно бегущий человечек с нуля: Меню игры
() translation by (you can also view the original English article)
Добро пожаловать в последнюю версию серии Endless Runner. В сегодняшнем уроке вы узнаете, как создавать игровое меню с помощью класса Director. Давайте начнем!
Поздравляем вас с этим знаменательным событием! Мы долго шли к этому дню, и теперь у нас есть функциональная игра и, надеюсь, базовое понимание того, как добавить свои собственные компоненты для расширения функционала. Шаг, который мы собираемся сделать сейчас, - это добавить маленький уровень в систему меню, чтобы игра выглядела более полноценной.
Мы будем использовать Director класс, который представляет собой небольшую, и одновременно, профессиональную библиотеку Рикардо Раубера, которая будет делать всю работу за вас. Как только вы увидите, насколько это легко, вы сможете быстро реализовать свои самые интересные идеи.
Первое, что вам нужно сделать, это перейти сюда и загрузить последнюю версию класса. Когда вы загрузите, вы увидите много файлов. Director класс поставляется с с их большим количеством , включает примеры, шаблоны и дополнительные функции, которые могут облегчить вашу жизнь, поэтому не стесняйтесь изучить все, что тут есть. Если вам не нужны все эти дополнения, вы можете загрузить только те файлы, которые нужны нам для урока.
Теперь, когда у нас есть файл director.lua, поместите его в ту же папку, что и ваш main.lua. Говоря о файле main.lua, перейдите к нему и переименуйте. Неважно, какое имя вы ему присвоите, т.к. мы все равно его позже удалим. После этого создайте три новых файла в этой папке. И назовите их main.lua, menu.lua и game.lua. Суть того, как это будет работать, в том, что main.lua будет вызван для запуска игры. Это будет основой нашей программы, в то время как menu.lua и game.lua будут выступать в качестве компонентов (displayGroups), которые отображаются вместе с displayGroup внутри main.lua, почти так же, как и все другие группы в нашей игре, все они содержатся и отображаются на экране displayGroup в нашей текущей игре.
Итак, во-первых, давайте создадим новый файл main.lua. Откройте его и вставьте этот код:
1 |
|
2 |
display.setStatusBar(display.HiddenStatusBar) |
3 |
--by telling Corona to require "director" we are |
4 |
--telling it to include everything in that file, |
5 |
--giving us easy access to its functions. This is |
6 |
--also how you would include any functions or |
7 |
--"classes" that you created in outside files. |
8 |
local director = require("director") |
9 |
local mainGroup = display.newGroup() |
10 |
local main = function() |
11 |
--this creates a view that we will use to load |
12 |
--the other scenes into, so as our game progresses |
13 |
--technically we are staying in the main.lua file |
14 |
--and just loading new views or scenes into it |
15 |
mainGroup:insert(director.directorView) |
16 |
--we tell the director to load the first scene which |
17 |
--is going to be the menu |
18 |
director:changeScene("menu") |
19 |
end |
20 |
--be sure to actually call the main function |
21 |
main() |
Вот и все! Уберите комментарии, и вы увидите, что для запуска director класса требуется всего 5 строк. Как говорится в комментариях, способ, который действительно работает, - main.lua запускается первым, но затем вместо того, чтобы процесс игры был определён в файле main.lua, мы разрешаем классу сделать это. Мы создаем display.newGroup и сохраняем его как основной вид. Поэтому, когда игра действительно загружается, все, что вы видите, фактически просматривается из файла main.lua внутри этой группы. Здорово, не так ли! Итак, как только вы создаёте представление, нам просто нужно сказать классу Director, что сцена будет загружена, и он автоматически перенесёт нас туда. Удобно, правда?
Следующее, что нам нужно сделать, чтобы на самом деле все работало, - создать вид меню. Код действительно прост, большинство которого мы уже видели, поэтому я сначала опубликую весь файл, а затем объясню несколько простых вещей. Давайте откроем menu.lua и посмотрим, как легко создать простую систему меню. Скопируйте следующее в меню menu.lua:
1 |
|
2 |
--this line is required so that director knows that |
3 |
--this is a scene that can be loaded into its view |
4 |
module(..., package.seeall) |
5 |
--we need to be able to access the director class of |
6 |
--course so be sure to include this here |
7 |
local director = require("director") |
8 |
local sprite = require("sprite") |
9 |
--everything that you want this scene to do should be |
10 |
--included in the new function. Everytime the director |
11 |
--loads a new scene it will look here to figure out what |
12 |
--to load up. |
13 |
new = function( params ) |
14 |
--this function will be returned to the director |
15 |
local menuDisplay = display.newGroup() |
16 |
--everything from here down to the return line is what makes |
17 |
--up the scene so... go crazy |
18 |
local background = display.newImage("background.png") |
19 |
background.x = 240 |
20 |
background.y = 160 |
21 |
local spriteSheet = sprite.newSpriteSheet("monsterSpriteSheet.png", 100, 100) |
22 |
local monsterSet = sprite.newSpriteSet(spriteSheet, 1, 7) |
23 |
sprite.add(monsterSet, "running", 1, 6, 600, 0) |
24 |
local monster = sprite.newSprite(monsterSet) |
25 |
monster:prepare("running") |
26 |
monster:play() |
27 |
monster.x = 60 |
28 |
monster.y = 200 |
29 |
local monster2 = sprite.newSprite(monsterSet) |
30 |
monster2:prepare("running") |
31 |
monster2:play() |
32 |
monster2.x = 420 |
33 |
monster2.y = 200 |
34 |
monster2.xScale = monster2.xScale * -1 |
35 |
local title = display.newImage("title.png") |
36 |
title.x = 240 |
37 |
title.y = 80 |
38 |
local playButton = display.newImage("playButton.png") |
39 |
playButton.x = 240 |
40 |
playButton.y = 220 |
41 |
menuDisplay:insert(background) |
42 |
menuDisplay:insert(monster) |
43 |
menuDisplay:insert(monster2) |
44 |
menuDisplay:insert(title) |
45 |
menuDisplay:insert(playButton) |
46 |
--this is what gets called when playButton gets touched |
47 |
--the only thing that is does is call the transition |
48 |
--from this scene to the game scene, "downFlip" is the |
49 |
--name of the transition that the director uses |
50 |
local function buttonListener( event ) |
51 |
director:changeScene( "game", "downFlip" ) |
52 |
return true |
53 |
end |
54 |
--this is a little bit different way to detect touch, but it works |
55 |
--well for buttons. Simply add the eventListener to the display object |
56 |
--that is the button send the event "touch", which will call the function |
57 |
--buttonListener everytime the displayObject is touched. |
58 |
playButton:addEventListener("touch", buttonListener ) |
59 |
--return the display group at the end |
60 |
return menuDisplay |
61 |
end |
Здесь есть и кое-что новое director: changeScene(). Это работает так, как вы себе это представляете. Тем не менее, я хотел указать на второй параметр - downFlip. Есть много встроенных переходов, которые могут сделать вашу игру очень привлекательной при переключении между сценами, это зависит от того, как вы хотите, чтобы ваша игра выглядела. Вот образец нашего прогресса.



Не забудьте попробовать несколько разных переходов, чтобы найти тот, который лучше всего подходит для вашей игры. Вы можете найти их полный список в файле director.lua. Посмотрите все различные эффекты и дайте своим идеям волю. Еще несколько примеров, которые вы можете попробовать, но не хотите далеко копать, - это crossfade", "overfromtop", и "flipFromBottom, и это лишь некоторые из них! Итак, кроме этого, осталось совсем немного того, чего вы не видели раньше. Все это просто создаёт примитивный экран главного меню. Там есть пара вещей, которые вы должны принять к сведению, что потребуется в каждой сцене, которая нужна director. Первое:
1 |
|
2 |
module(..., package.seeall) |
Легко и просто. Вам нужно, чтобы точная строка в верхней части каждого файла *.lua, а именно director использовалась в качестве сцены. После этого у вас есть функция new(), которая вызывается при входе в сцену, и все, что вы хотите, чтобы сцена выполняла, это была включенной. Первое, что вам нужно сделать, это отобразить Object, который будет возвращен к управляющему классу, который и будет показан, а затем убедитесь что он вернул значение в конце новой функции. Это всё. Звучит просто? Это действительно так! Класс director действительно делает все проще. Пока ваши изображения находятся справа в меню, вы должны запустить файл main.lua и запустим его без каких-либо проблем.



До сих пор у нас был основной файл и файл меню. Последнее, что нам нужно сделать, это внести некоторые изменения в игровой файл. Это тоже будет легко. Откройте файл game.lua и добавьте следующий код:
1 |
|
2 |
module(..., package.seeall) |
3 |
local director = require("director") |
4 |
new = function( params ) |
5 |
local gameDisplay = display.newGroup() |
6 |
--paste code here |
7 |
return gameDisplay |
8 |
end |
Это то, что вам нужно для сцены. Кстати, это все, что вам нужно, чтобы получить ваш старый файл main.lua в файл game.lua. Если он у вас уже есть, единственное, что вам нужно сделать, это скопировать весь файл old.lua и вставить его там, где сказано «вставить код здесь». Сделайте это, и вы закончили… .почти! Мы собираемся внести некоторые изменения в то, как будет отображаться наша игра над сообщениями. Вместо того, чтобы создавать большую кнопку, мы возвращаемся в меню. Давайте изменим здесь кое-что (обратите внимание, что файл gameOver.png был изменен, это даст ему возможность соответствовать новому расположению кнопок. Размеры изображения по-прежнему остаются такими же, поэтому вам не придется делать никаких других корректировок). Первыми изменениями станут новые кнопки в игре.



Добавьте этот код туда, где мы добавим все остальные изображения в верхней части файла:
1 |
|
2 |
local yesButton = display.newImage("yesButton.png") |
3 |
yesButton.x = 100 |
4 |
yesButton.y = 600 |
5 |
local noButton = display.newImage("noButton.png") |
6 |
noButton.x = 100 |
7 |
noButton.y = 600 |
Затем обязательно добавьте их и на экран. А также в остальные вкладки экрана:
1 |
|
2 |
screen:insert(yesButton) |
3 |
screen:insert(noButton) |
Следующий этап - это переход к функции touched () и удаление первого оператора if/else, вот так он будет выглядеть:
1 |
|
2 |
function touched( event ) |
3 |
if(monster.isAlive == true) then |
4 |
if(event.phase == "began") then |
5 |
if(event.x < 241) then |
6 |
if(onGround) then |
7 |
monster.accel = monster.accel + 20 |
8 |
end |
9 |
else |
10 |
for a=1, blasts.numChildren, 1 do |
11 |
if(blasts[a].isAlive == false) then |
12 |
blasts[a].isAlive = true |
13 |
blasts[a].x = monster.x + 50 |
14 |
blasts[a].y = monster.y |
15 |
break |
16 |
end |
17 |
end |
18 |
end |
19 |
end |
20 |
end |
21 |
end |
Делая это, он делает функцию touched той, которая только обрабатывает внутриигровые взаимодействия. Мы собираемся переместить логику, которая перезапускает игру до ее собственной функции. Добавьте эти функции ниже функции touched():
1 |
|
2 |
function noListener(event) |
3 |
director:changeScene( "menu", "downFlip" ) |
4 |
return true |
5 |
end |
6 |
function yesListener(event) |
7 |
restartGame() |
8 |
return true |
9 |
end |
Итак, довольно понятно, эти шаги мы делали уже несколько раз. Затем удалите нижнюю часть кода, где мы добавим обработчики событий и добавим еще два обработчика:
1 |
|
2 |
yesButton:addEventListener("touch", yesListener ) |
3 |
noButton:addEventListener("touch", noListener ) |
Итак, последние несколько вещей, которые мы должны сделать, это изменение позиции на две кнопки, когда наш монстр умирает, и когда мы перезагружаем игру. Вот дополнения, которые нам нужны, чтобы убедиться, что они работают правильно. В функции restartGame() добавьте следующее:
1 |
|
2 |
noButton.x = 100 |
3 |
noButton.y = 600 |
4 |
yesButton.x = 100 |
5 |
yesButton.y = 600 |
Затем перейдите к функции collisions check(), где вы должны увидеть эти строки повторяющиеся несколько раз:
1 |
|
2 |
gameOver.x = display.contentWidth*.65 |
3 |
gameOver.y = display.contentHeight/2 |
Добавьте этот блок в любой его экземпляр (всего должно быть 4, по одному для каждого пути):
1 |
|
2 |
yesButton.x = display.contentWidth*.65 - 80 |
3 |
yesButton.y = display.contentHeight/2 + 40 |
4 |
noButton.x = display.contentWidth*.65 + 80 |
5 |
noButton.y = display.contentHeight/2 + 40 |
После того, как вы внесете все изменения, вы должны быть готовы запустить игру из файла main.lua и вернуться к игре через меню, погибнуть, и затем выбрать хотите ли вы продолжить игру или выйти в меню. Итак, если все хорошо, это конец, теперь у нас есть наша игра. Мы делали всё очень быстро, большую часть времени. Если у вас возникнут какие-либо проблемы на любом этапе, дайте мне знать в комментариях, и я помогу вам с этим. Новая папка в загруженном файле также содержит конечный продукт, и также вы всегда можете использовать его в качестве образца. Надеюсь, эта серия помогла вам в том, что теперь вы начали заниматься разработкой игр с помощью Corona SDK. Corona SDK является мощным и очень дружественным инструментом, когда вы освоите основы. Надеюсь, вы сможете продвигаться вперед и создавать разные удивительные игры.
У нас будет ещё один урок в этой серии, в нём мы не будем менять игру, а сосредоточимся на отправке вашей игры в магазин приложений, поскольку это большое приключение, когда вы делаете это впервые. Желаю вам хорошего кода и спасибо за чтение!