Добро пожаловать во вторую часть учебного пособия « Как взорвать вещи с помощью Corona SDK ». В этом уроке мы усовершенствуем наше демонстрационное приложение из первой части, позволяя пользователю размещать на экране изображение фактической бомбы с замедленным взрывом. Мы также изменим эффект взрыва, чтобы ящики иногда взрывались, а не просто летали с экрана.
В первой части этой серии статей мы познакомились с тем, как настроить динамическую среду с помощью простой в использовании библиотеки физики Corona. Среда включала в себя статические объекты, такие как пол, и программно сгенерированные динамические объекты, такие как ящики. Событие прикосновения пользователя будет генерировать взрывную силу, которая приведет к полету ящиков. Если вы еще не читали первую часть , я предлагаю вам сделать это, прежде чем продолжить. У читателя должно быть понимание основных физических понятий, описанных в части I, чтобы понять часть II.
напоминание
Давайте начнем с небольшого обновления о том, как мы настраиваем нашу физическую среду в части I. Мы включим наш программно сгенерированный набор ящиков, которые укладываются и лежат на полу:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
local physics = require(«physics»)
physics.start()
physics.setScale( 40 )
display.setStatusBar( display.HiddenStatusBar )
— The final «true» parameter overrides Corona’s auto-scaling of large images
local background = display.newImage( «bricks.png», 0, 0, true )
background.x = display.contentWidth / 2
background.y = display.contentHeight / 2
local floor = display.newImage( «floor.png», 0, 280, true )
physics.addBody( floor, «static», { friction=0.5 } )
local crates = {}
for i = 1, 5 do
for j = 1, 5 do
crates[i] = display.newImage( «crate.png», 140 + (i*50), 220 — (j*50) )
physics.addBody( crates[i], { density=0.2, friction=0.1, bounce=0.5 } )
end
end
|
Все действия вышеупомянутого кода полностью объяснены в Части I учебного пособия, поэтому проверьте его, если что-то кажется непонятным.
Установите бомбу!
Для нашего первого шага мы собираемся добавить небольшое графическое обновление в наш метод setBomb. Вместо события касания, немедленно генерирующего взрыв, мы собираемся поместить бомбу на экран как ее собственный физический объект:
1
2
3
4
5
6
7
|
local function setBomb ( event )
if(event.phase == «began») then
local bomb = display.newImage( «bomb.png», event.x,event.y )
physics.addBody( bomb, { density=0.2, friction=0.1, bounce=0.5 } )
end
end
background:addEventListener(«touch»,setBomb)
|
Как и раньше, мы добавляем прослушиватель событий в фоновый режим, чтобы отслеживать любые сенсорные события и запускать метод setBomb при его возникновении. Внутри метода мы изолируем любую деятельность от «начальной» фазы события. Если бы мы не изолировали эту фазу, это привело бы к многократному выполнению кода, поскольку события касания имеют много фаз.
Метод setBomb в его нынешнем виде делает очень мало. Он загружает симпатичную графику бомбы и добавляет ее на экран как динамический физический объект. Теперь мы интегрируем наш метод взрыва обратно в код как локальная функция с именем blast:
01
02
03
04
05
06
07
08
09
10
11
12
|
local circle = «»
local explosion = «»
local function blast( event )
circle = display.newCircle( bomb.x, bomb.y, 80 )
explosion = display.newImage( «explosion.png», bomb.x, bomb.y )
circle:setFillColor(0,0,0, 0)
physics.addBody( circle, «static», {isSensor = true} )
circle.myName = «circle»
circle.collision = onLocalCollision
circle:addEventListener( «collision», circle )
end
blast()
|
Объект круга здесь помогает нам рассчитать радиус взрыва. Мы добавляем прослушиватель событий столкновения, чтобы определить, какой из ящиков попадает в зону взрыва. Кроме того, мы также добавляем изображение взрыва на экран в том же положении, что и изображение бомбы, после того, как взрыв гаснет.
Время взрыва
Если вы попробуете код на этом этапе, вы заметите, что все происходит очень быстро и некоторые артефактные изображения остаются позади. Чтобы сделать его более напряженным, мы заменим вызов функции «blast ()» таймером, который задержит взрыв бомбы на 3 секунды:
1
|
timer.performWithDelay(3000, blast )
|
Просто как тот! Класс таймера имеет функцию executeWithDelay () с двумя параметрами: количество миллисекунд ожидания и метод вызова. Таким образом, в этом случае 3000 миллисекунд равны 3 целым секундам задержки.
Удаление артефактов
Поскольку после 3-секундной задержки бомба взорвется, нам нужно убрать этот объект с экрана, как только произойдет взрыв. Это можно сделать очень легко. Все объекты, присутствующие на экране, снабжены удобной функцией removeSelf (). Как только объект удаляется с экрана, физический движок становится достаточно умным, чтобы собирать мусор и удалять его из всех физических расчетов. Мы можем добавить следующую строку в конец функции взрыва:
1
|
bomb:removeSelf()
|
В дополнение к удалению бомбы мы собираемся удалить наш объект с радиусом взрыва окружности, а также график взрыва, который мы добавили для эффекта. Поскольку нам нужно дать нашему кругу радиуса взрыва немного времени для создания столкновений с нашими ящиками, мы собираемся удалить его на 1/10 секунды после вызова функции взрыва. Это может быть достигнуто путем замены нашего вызова функции timest blast следующим кодом:
1
2
3
4
5
6
|
local function removeStuff( event )
circle:removeSelf()
explosion:removeSelf()
end
timer.performWithDelay(3000, blast )
timer.performWithDelay(3100, removeStuff)
|
Как вы можете видеть, мы вызываем функцию взрыва после 3-секундной задержки от прикосновения к экрану, как мы это делали раньше. Теперь мы добавили еще один отложенный вызов, который выполняется через 3,1 секунды после прикосновения к экрану, который очищает наши остаточные объекты с помощью функции removeSelf ().
Вся созданная нами функция теперь выглядит так:
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
|
local function setBomb ( event )
if(event.phase == «began») then
local bomb = display.newImage( «bomb.png», event.x,event.y )
physics.addBody( bomb, { density=0.2, friction=0.1, bounce=0.5 } )
local circle = «»
local explosion = «»
local function blast( event )
media.playEventSound( explosionSound )
circle = display.newCircle( bomb.x, bomb.y, 80 )
explosion = display.newImage( «explosion.png», bomb.x, bomb.y )
bomb:removeSelf()
circle:setFillColor(0,0,0, 0)
physics.addBody( circle, «static», {isSensor = true} )
circle.myName = «circle»
circle.collision = onLocalCollision
circle:addEventListener( «collision», circle )
end
local function removeStuff( event )
circle:removeSelf()
explosion:removeSelf()
end
timer.performWithDelay(3000, blast )
timer.performWithDelay(3100, removeStuff)
end
end
background:addEventListener(«touch»,setBomb)
|
Создание порога разрушения
В первой части нашего руководства функция обнаружения столкновений выглядела следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
|
local function onLocalCollision( self, event )
if ( event.phase == «began» and self.myName == «circle» ) then
local forcex = event.other.x-self.x
local forcey = event.other.y-self.y
if(forcex < 0) then
forcex = 0-(80 + forcex)-12
else
forcex = 80 — forcex+12
end
event.other:applyForce( forcex, forcey, self.x, self.y )
end
end
|
Он просто нашел все ящики в радиусе взрыва и применил силу, чтобы взорвать их от эпицентра взрыва. Чтобы сделать вещи более интересными, мы собираемся добавить порог разрушения к ящикам, который заставит их взорваться, если сила, приложенная к ним, достаточно высока. Это можно сделать так:
1
2
3
4
5
6
7
8
|
if(math.abs(forcex) > 60 or math.abs(forcey) > 60) then
local explosion = display.newImage( «explosion.png», event.other.x, event.other.y )
event.other:removeSelf()
local function removeExplosion( event )
explosion:removeSelf()
end
timer.performWithDelay( 100, removeExplosion)
end
|
Нам нужно наблюдать силу, которую мы применили к каждому из ящиков, чтобы определить, не превышает ли она 60. 60 в этом случае в произвольном числе на основе нашего расчета силы. Мы используем функцию math.abs, чтобы получить абсолютное значение силы. В нашем примере силы могут быть положительными или отрицательными в зависимости от направления приложенной силы. Мы не беспокоимся о направлении в этом случае, мы просто хотим знать, превышает ли сила порог 60. Не стесняйтесь играть с этим пороговым числом, чтобы изменить, насколько слабые или сильные ящики.
В первой части наша сила взрыва была рассчитана таким образом, чтобы она уменьшалась по мере удаления ящика от эпицентра взрыва. Поэтому ящики, которые находятся ближе к эпицентру, имеют большую вероятность быть уничтоженными, а остальные просто улетят с экрана. Как мы делали раньше с нашим классом таймера, мы отображаем графику взрыва в прежней позиции разрушенного ящика, а затем удаляем его с экрана 1/10 секунды позже. Окончательный метод обнаружения столкновений будет выглядеть так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
local function onLocalCollision( self, event )
if ( event.phase == «began» and self.myName == «circle» ) then
local forcex = event.other.x-self.x
local forcey = event.other.y-self.y
if(forcex < 0) then
forcex = 0-(80 + forcex)-12
else
forcex = 80 — forcex+12
end
event.other:applyForce( forcex, forcey, self.x, self.y )
if(math.abs(forcex) > 60 or math.abs(forcey) > 60) then
local explosion = display.newImage( «explosion.png», event.other.x, event.other.y )
event.other:removeSelf()
local function removeExplosion( event )
explosion:removeSelf()
end
timer.performWithDelay( 50, removeExplosion)
end
end
end
|
Звучать на!
В качестве последнего шага в нашем уроке мы собираемся воспроизвести звуковой эффект взрыва при взрыве нашей бомбы. Как и все остальное в Corona, сделать это на удивление просто. Мы начнем с включения медиа-библиотеки в начало нашего проекта и предварительной загрузки нашего звукового файла:
1
2
|
local media = require(«media»)
local explosionSound = media.newEventSound( «explosion.mp3» )
|
Для воспроизведения звука мы добавим следующую строку в нашу функцию blast (), которая находится внутри нашей функции setBomb ():
1
2
3
4
|
local function blast( event )
media.playEventSound( explosionSound )
…
end
|
Теперь каждый раз, когда вызывается функция blast (), она будет использовать функцию playEventSound из библиотеки мультимедиа для воспроизведения нашего звукового файла «explo.mp3». Это не может быть проще, если мы попробуем!
И там у нас это есть! Теперь у нас есть более полный пример того, как легко создавать взрывы на платформе Corona. Не стесняйтесь загружать почтовые индексы для части I и II учебника и поиграть!