Статьи

Создайте бесконечную игру для бегунов с нуля: битвы с боссами

Мы уже прошли долгий путь в создании нашей бесконечной игры для раннеров. На этом этапе серии у вас уже должен быть игровой и приятный опыт, но этот урок научит вас, как добавить еще один поворот: битвы с боссами!

К настоящему времени наша игра начинает выглядеть как настоящая игра! У нас есть управляемый персонаж с различными типами препятствий, которые генерируются случайным образом, у нас есть прокрутка параллакса, реализованная в трех разных слоях, и у нас есть базовая система подсчета очков, которая дает нашим игрокам чувство выполненного долга. Все идет нормально. Теперь, возможно, этого достаточно для той игры, которую вы разрабатываете, и это все, что вам нужно. Однако, допустим, вы хотите оживить свою игру чем-то новым. Что-то вроде … битвы с боссом !!! Хотя в большинстве бесконечных игр с прокруткой нет битвы с боссами, будет хорошей идеей посмотреть, как мы будем разрабатывать подобные мероприятия. Итак, начнем!

Вы заметите, что мы снова следуем тому же формату со старой папкой в ​​прилагаемой загрузке, содержащей весь созданный нами проект, и новой папкой, содержащей проект, после того, как мы закончили это руководство. Первое, что нужно сделать, это убедиться, что у нас есть изображения в правильной папке. Вы можете взять boss.png и bossSpit.png из новой папки в прилагаемом файле загрузки. Обратите внимание, что босс не анимированный, а просто одно изображение. Если вы хотите анимированного босса и забыли, как анимировать спрайт в Corona, обратитесь к руководству по анимации спрайтов, выпущенному ранее в этой серии.

Теперь, когда они находятся в той же папке, что и наш файл main.lua, откройте файл main.lua в вашем любимом текстовом редакторе. Я не собираюсь объяснять многое из того, что здесь происходит (Обязательно прочитайте комментарии для подсказок и небольших объяснений!), Так как в этот момент мы уже говорили обо всем несколько раз, и я уверен, что вы просто пропустить это все равно. Это также поможет нам быстро пройти обучение, как и все, что мы делали здесь, мы делали раньше, так что это просто много небольших изменений. Итак, начнем.

Первое, что мы сделаем, это загрузим наши изображения в игру. Опять же, все это должно выглядеть знакомо. Добавьте этот код вверху, где мы загружаем все остальные изображения. Просто убедитесь, что bossSpits объявлен, прежде чем пытаться что-то добавить в него!

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
local boss = display.newImage(«boss.png», 150, 150)
boss.x = 300
boss.y = 550
boss.isAlive = false
boss.health = 10
boss.goingDown = true
boss.canShoot = false
—spitCycle is the only thing that is not self explantory
—every time we move a ground piece back to the right of the
—screen we update the score by one.
—spite cycle.
—the boss will shoot his projectile.
—of that for us!
boss.spitCycle = 0
for a=1, 3, 1 do
bossSpit = display.newImage(«bossSpit.png»)
bossSpit.x = 400
bossSpit.y = 550
bossSpit.isAlive = false
bossSpit.speed = 3
bossSpits:insert(bossSpit)
end

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

1
2
screen:insert(boss)
screen:insert(bossSpits)

Сохраните это и запустите. Попробуйте это в версии для iPhone 4, и вы должны увидеть что-то вроде этого:

Теперь давайте заставим их что-то сделать. То, как мы собираемся справиться с боссом, заключается в том, что, как и другие события, мы случайным образом вступаем в игру, и мы хотим, чтобы это произошло в определенное время. В этом примере мы собираемся установить его на меньшее число, чтобы он быстро попадал на событие, но вы, вероятно, захотите сделать его более разумным в своей игре. Таким образом, каждый раз, когда вашему монстру приходится преодолевать дистанцию, кратную 10, будет происходить босс. По мере появления босса земля становится плоской на земле. Мы также предотвращаем появление невидимых призраков и шипов, чтобы не отвлекаться от боя! Когда он появляется, он выходит на сцену сверху и начинает подпрыгивать, пока плюется жаром в поисках желтых шаров … смерти!

Поэтому, когда босс стреляет в игрока, игрок должен убить босса, стреляя в него десять раз. Игрок также может защитить себя от косы, стреляя в них. Таким образом, основной стратегией победы будет прыгать и спамить свои навыки стрельбы! Еще пара вещей, на которые стоит обратить внимание: в этой игре я решил не обновлять счет, пока босс жив, так что игрок вынужден победить босса, чтобы продолжать получать более высокие оценки. Последнее, перед тем как мы продолжим, это то, что у меня есть босс, готовый стрелять каждые три обновления блока. Это снова имеет то преимущество, что сложность автоматически масштабируется с игрой. Это также обеспечивает простой способ получить последовательные снимки. Ничего слишком сумасшедшего, но в целом это добавляет приятный поворот в игре.

Чтобы освободить место для босса на экране, я переместил игрока немного дальше назад на экран. Теперь я начинаю героя так:

1
monster.x = 60

Это немного откроет уровень. Следующее, что мы должны сделать, это запустить наши функции, которые обновят босса и плевок босса:

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
45
46
47
48
49
50
function updateBoss()
    —check to make sure that the boss hasn’t been killed
    if(boss.health > 0) then
        —check to see if the boss needs to change direction
        if(boss.y > 210) then
            boss.goingDown = false
        end
        if(boss.y < 100) then
            boss.goingDown = true
        end
        if(boss.goingDown) then
            boss.y = boss.y + 2
        else
            boss.y = boss.y — 2
        end
    else
        —if the boss has been killed make him slowly disappear
        boss.alpha = boss.alpha — .01
    end
        —once the monster has been killed and disappear officially
    —kill him off and reset him back to where he was
    if(boss.alpha <= 0) then
        boss.isAlive = false
        boss.x = 300
        boss.y = 550
        boss.alpha = 1
        boss.health = 10
        inEvent = 0
        boss.spitCycle = 0
    end
    end
function updateBossSpit()
    for a = 1, bossSpits.numChildren, 1 do
                if(bossSpits[a].isAlive) then
                (bossSpits[a]):translate(speed * -1, 0)
                if(bossSpits[a].y > monster.y) then
                    bossSpits[a].y = bossSpits[a].y — 1
                end
                if(bossSpits[a].y < monster.y) then
                    bossSpits[a].y = bossSpits[a].y + 1
                end
                if(bossSpits[a].x < -80) then
                    bossSpits[a].x = 400
                    bossSpits[a].y = 550
                    bossSpits[a].speed = 0
                    bossSpits[a].isAlive = false;
                end
                 end
        end
end

После этого нам просто нужно внести некоторые изменения в некоторые другие наши функции и добавить их в нашу функцию update ():

1
2
3
4
5
6
7
updateBossSpit()
 
    if(boss.isAlive == true) then
 
            updateBoss()
 
        end

Добавьте их в функцию обновления, затем перейдите к функции checkEvent (), где вы увидите код, который выглядит следующим образом:

1
2
3
if(inEvent > 0 and eventRun > 0) then
    —Do nothing
else

Прямо под этим оператором else очищается все, что было там, и заменяется следующим:

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
—this is where we spawn the boss after every 10 blocks
 
—also control the boss’s health from here
 
if(boss.isAlive == false and score%10 == 0) then
 
boss.isAlive = true
 
boss.x = 400
 
boss.y = -200
 
boss.health = 10
 
end
 
—if the boss is alive then keep the event set to 15
 
—this will prevent the other events from spawning
 
if(boss.isAlive == true) then
 
inEvent = 15
 
else
 
—everything down here should be the same as it was before
 
check = math.random(100)
 
if(check > 80 and check < 99) then
 
inEvent = math.random(10)
 
eventRun = 1
 
end
 
if(check > 98) then
 
inEvent = 11
 
eventRun = 2
 
end
 
if(check > 72 and check < 81) then
 
inEvent = 12
 
eventRun = 1
 
end
 
if(check > 60 and check < 73) then
 
inEvent = 13
 
eventRun = 1
 
end
 
end

Там не должно быть ничего слишком сумасшедшего. Если вы новичок в программировании, вы, возможно, не знакомы с символом модуля:%. Для этого нужно взять все имеющиеся у вас числа, разделить первое число на второе и вернуть остаток. Таким образом, если счет равен 15, счет% 10 вернет 5, что не равно 0, поэтому он не вызовет событие босса. То же самое касается любого числа, не кратного 10. Таким образом, мы легко можем контролировать частоту появления чего-либо. Следующий шаг вернется в updateBlocks (). Прямо под утверждением if, которое гласит:

1
if((blocks[a]).x < -40) then

Вы собираетесь взять раздел ScoreText и поместить его в оператор if, который проверяет, жив ли босс или нет (опять же, мы не собираемся обновлять счет, пока он жив! Как часть оператора if вы собираюсь добавить еще, что дает боссу часть его поведения). Сделайте этот раздел похожим на это:

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
—only update the score if the boss is not alive
if (boss.isAlive == false) then
score = score + 1
    scoreText.text = «score: » .. score
    scoreText:setReferencePoint(display.CenterLeftReferencePoint)
    scoreText.x = 0
    scoreText.y = 30
else
    —have the boss spit every three block passes
    boss.spitCycle = boss.spitCycle + 1
    if(boss.y > 100 and boss.y < 300 and boss.spitCycle%3 == 0) then
        for a=1, bossSpits.numChildren, 1 do
            if(bossSpits[a].isAlive == false) then
                bossSpits[a].isAlive = true
                bossSpits[a].x = boss.x — 35
                bossSpits[a].y = boss.y + 55
                bossSpits[a].speed = math.random(5,10)
                break
            end
        end
    end
end
if(inEvent == 15) then
        groundLevel = groundMin
end

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

Добавьте эти строки в функцию updateBlasts ():

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
—check for collisions with the boss
if(boss.isAlive == true) then
    if(blasts[a].y — 25 > boss.y — 120 and blasts[a].y + 25 < boss.y + 120 and boss.x — 40 < blasts[a].x + 25 and boss.x + 40 > blasts[a].x — 25) then
        blasts[a].x = 800
        blasts[a].y = 500
        blasts[a].isAlive = false
        —everything is the same only 1 hit will not kill the boss so just take a little health away
        boss.health = boss.health — 1
    end
end
—check for collisions between the blasts and the bossSpit
for b = 1, bossSpits.numChildren, 1 do
    if(bossSpits[b].isAlive == true) then
        if(blasts[a].y — 20 > bossSpits[b].y — 120 and blasts[a].y + 20 < bossSpits[b].y + 120 and bossSpits[b].x — 25 < blasts[a].x + 20 and bossSpits[b].x + 25 > blasts[a].x — 20) then
            blasts[a].x = 800
            blasts[a].y = 500
            blasts[a].isAlive = false
            bossSpits[b].x = 400
            bossSpits[b].y = 550
            bossSpits[b].isAlive = false
            bossSpits[b].speed = 0
        end
    end
end

Еще одно обнаружение столкновений, которое нужно проверить, это проверка слюны босса на нашего игрока. Добавьте это в функцию checkCollisions ():

01
02
03
04
05
06
07
08
09
10
11
12
13
14
—make sure the player didn’t get hit by the boss’s spit!
for a = 1, bossSpits.numChildren, 1 do
if(bossSpits[a].isAlive == true) then
    if(((  ((monster.y-bossSpits[a].y))<45)) and ((  ((monster.y-bossSpits[a].y))>-45)) and ((  ((monster.x-bossSpits[a].x))>-45)) ) then
        —stop the monster
            speed = 0
            monster.isAlive = false
            —this simply pauses the current animation
            monster:pause()
            gameOver.x = display.contentWidth*.65
            gameOver.y = display.contentHeight/2
        end
    end
end

Опять же, все это должно выглядеть довольно знакомым. Последнее, что нам нужно сделать, — это зайти в нашу функцию restartGame () и обновить ее информацией босса вместе с его слюной.

Также обратите внимание, что, поскольку мы изменили позицию monster.x в этом уроке, важно, чтобы вместо сброса monster.x на 110 мы теперь обновили monster.x, чтобы отразить его новую позицию, которая равна 60.

01
02
03
04
05
06
07
08
09
10
—reset the boss
boss.isAlive = false
boss.x = 300
boss.y = 550
—reset the boss’s spit
for a = 1, bossSpits.numChildren, 1 do
bossSpits[a].x = 400
     bossSpits[a].y = 550
     bossSpits[a].isAlive = false
end

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

и

Как я уже говорил несколько раз, нового контента действительно не было много, но я подумал, что будет хорошим упражнением показать вам, как легко обновить вашу игру новым контентом. Также он показывает новые подходы к добавлению событий, чтобы они были более случайными по требованию. В большинстве игр такого типа, вероятно, будет реализовано сочетание того и другого. Хорошим примером игры, которая делает это хорошо, является bit.trip runner . Проверьте это, чтобы лучше понять, что можно сделать с этим стилем игры. Если мы обсудили что-то слишком быстро, и у вас есть вопросы, дайте мне знать, если не будете готовы в следующий раз немного лучше организовать нашу игру с хорошей новой системой меню, которая сделает эту игру полной. Спасибо за то, что подписались, и мы увидимся в следующий раз!