How to destroy an enemy boss in a delayed matter during a single collision?

Hi guys,

Here my latest headache! I am trying to simulate the destruction of an enemy boss upon collision that last x amount of time. The regular enemy is destroy upon contact. But for the enemy boss, I would like the player to keep aiming a gun cross at the boss for a second or two before it he boss is destroy. I tried using boss.health = boss.health - 1 during a collision but unfortunately while the player is aiming the gun cross over the boss, that seems to count for one collision detection ( global collision listener by the way) so the decreasing only happens if the player move the gun cross away from the boss and move the gun cross over the boss again and again.

That’s not what I which for. The player should keep the contact (collision) until the health of the boss goes down to zero and it get destroy.

Any ideas how to approach this problem.

Thank you guys for any help you can provide.

Mo [import]uid: 100814 topic_id: 25361 reply_id: 325361[/import]

without some code of yours it’s hard for us to solve your problem.

but generally I’d do something like this:

-- put your collision detection in your enterFrame gamelogic function !!!  
  
function gameLogic ()  
 -- check for collision  
 if collisionDetect (gun, boss) then -- use your collisionchecker function  
 boss.health = boss.health - 1  
 if boss.health \<= 0 then   
 destroyBoss() -- some function to trigger boss kill  
 end  
 end  
end  
-- start the game logic  
Runtime:addEventListener("enterFrame", gameLogic);  
  

so every frame the collision is checked and if collisionDetect returns true, a hit is triggered.

hope this helps
-finefin [import]uid: 70635 topic_id: 25361 reply_id: 102419[/import]

@Canupa.

THANKS for the quick response. Yes you are 100% right, I should have pasted some code but it was around 4 am and i was dead!!!

Anyway, please see below an example of my code. I try to remove stuff to make it easier to deal with.

My only fear with your solution is that it will take a lot of CPU to included into enterFrame. I think. Now that I am little bit more fresh, I am thinking maybe more like starting a timer at the beginning of the collision and then stopping it at the end the collision (post collision) and if the timer is higher than X then I would destroy the “boss”

What do you thing? I may try your suggestion as well. I guess we never know, it may not be much of an issue but I am working on fast pace game so speed is critical.

Any other suggestions will be welcomed.

Thanks again for taking the time.

Mo.

----------------------- MY CODE ------------------

[lua]local gunHit(obj1,obj2)

– increase score code here

XXXXXXX

–I AM TRYING TO CHANGE THE DESTRUCTION OF THE ROCK OBJECT FROM ON CONTACT TO --A CERTAIN AMOUNT OF TIME AFTER FIRST COLLISION
–AND ASSUMING THE GUN CROSS IS OVER THE ROCK DURING THAT TIME. FOR REGULAR --ROCK (NOT A BOSS, I WILL DESTROY THEM AT FIRST CONTACT

– destroy rock display object (rock is always obj2 given the logic below)
obj2:removeSelf()
obj2=nil
end


– Global Collision function

local function onRockCollision(event)

if ( event.phase == “began” ) then

local obj1 = event.object1
local obj2 = event.object2

– check if the gun cross hit a rock

if obj1.name == “gun” and obj2.name == “rock” then

gunHit(obj1,obj2)

elseif obj1.name == “rock” and obj2.name == “gun” then

gunHit(obj2,obj1)

end
end

end

[/lua] [import]uid: 100814 topic_id: 25361 reply_id: 102464[/import]

using postCollision instead of collision may solve this issue [import]uid: 36054 topic_id: 25361 reply_id: 102470[/import]

Thanks blastertv. humm…how? I am probably wrong but i thought post collision trigger once (after the collision) So are you saying I should start a counter (updated by an my main enterframe function) and then check if the timer high enough to trigger a destruction of the boss?

Thanks again.

Mo [import]uid: 100814 topic_id: 25361 reply_id: 102471[/import]

Hi Mo,

A timer is a good idea. You could also just start a timer of 2 seconds (or whatever time you want the player to “focus” on the boss), and just cancel it if the gun point moves outside the boss… on phase “ended”. If you “attach” the timer to the boss, i.e. “boss.killTimer = timer.performWithDelay(…)”, it’s easy to reference it for cancellation and restarting.

Obviously, if the timer goes off, the boss will die. :wink:

As with most things in coding, you’ll need to be careful about keeping this clean: making sure you are stopping and starting timers at the proper times, not making duplicate timers, etc.

Does that help?
Brent [import]uid: 9747 topic_id: 25361 reply_id: 102497[/import]

Thanks Brent.

Absolutetly it helps! That should work. Let me try it and report here. Yes I understand about not leaving stuff around…

Thanks to you all.

Mo [import]uid: 100814 topic_id: 25361 reply_id: 102499[/import]

Hi guys,

I was making good progress in finishing my game but I hit a road block and I hope you can help me destroy that road block to pieces:)

Anyway, I was able to destroy the “boss” if the collision last more than 300 ms but I have noticed that if the “boss” get hit (collision with a movable cross-hair AND hit a planet at the same time)then I get very strange behavior. For instance if the boss get hit, it will explode (after 300 ms) and start a transition that will move the points won in animation where the points text simply goes up and goes away over a one second (alpha =0) A pretty typical way of showing points in many games.

My issue is that if the boss collide with the cross hair (called GUN in my code below) AND the boss hit the planet then the starting location of the animation/transition seems to be 0,0 on the screen. When it works ok (boss only get to collide with the cross-hair…away from a planet) the animation of the points (text) going up start from where the boss location on the screen is at the time of collision.

I am using a timer (bossTimer) to start the countdown when the collision happens between the cross-hair and the boss and then cancel the timer if the collision do not last at least 300 ms (so no explosion/removal of the boss happens it that case)
I am pretty sure it is a timing issue when the boss hit a planet AND at the “same” time collide with the cross-hair. The fact that the animation of the points text start from the 0,0 of the screen tells me that boss is removed (and so nil) before the transition is over I “think”. I tried many things like detecting if the boss object is not nil before accepting a collision with the planet but no luck.

I have been working on this for more than a week and frankly I am out ideas! Maybe one of you with a fresh eyes may detect something in code below that I missed. I am also thinking of using something else than timers to deal with delayed destruction of the boss. The regular rocks do not give any issue even if the regular rock hit a planet AND collide with the cross hair at the time. Probably because the object (rock) get removed right away (with a timer but only 1 ms delay)

Thank you so much for any suggestions. So sorry for this lengthy post.

Mo

-----------------MY CODE (Removed anything not important)-----------------

[lua]local function startExplosion(obj)

if obj ~= nil then

screenMessage = display.newText( “+”…gameLevel*10, 160, 240, myFont, 24 )
screenMessage:setTextColor( 255, 0, 0, 255 )
screenMessage.alpha = 1.0
screenMessage.x = obj.x
screenMessage.y = obj.y

local destroyMessage = function()

if messageTween then transition.cancel(messageTween) end

if screenMessage ~= nil then
screenMessage:removeSelf()
screenMessage = nil
end
end

if obj ~= nil then
messageTween = transition.to( screenMessage, { time=1000, alpha=0, y= gunCross.y -100, onComplete=destroyMessage } )
end
end

end

local function planetHit(obj1, obj2)

shakeCounter = 20

if fxOn then audio.play ( planetSound ) end

---- reduce planet health

if obj2.type == “normal” then
obj1.health = obj1.health - gameLevel*3
else
obj1.health = obj1.health - gameLevel*6
end

if obj1.health <= 0 then obj1.health = 0 end

---- “destroy” the planet/bar if health<=0

if obj1.health <= 0 then

obj1.health = 0

if fxOn then audio.play ( planetSound ) end

---- “remove” planet

if obj1 ~= nil then
display.remove(obj1)
obj1 = nil
end

else

– remove rock (if not nil)
if obj2 ~= nil then
display.remove(obj2)
obj2 = nil
end

end

end


local function destroyRock (obj)

if fxOn then audio.play ( explosionSound ) end

startExplosion(obj)
if obj.type = “normal” then
score = score + 10*gameLevel
else
— the rock is a “boss”
score = score + 10*gameLevel
end

– remove rock (if not nil)
if obj ~= nil then
display.remove(obj)
obj = nil
end

return true

end


local function wallHit(obj)

– remove rock (if not nil)
if obj ~= nil then
display.remove(obj)
obj = nil
end
return true

end


– Global Collision function

local function onRockCollision(event)

local phase = event.phase

if “began” == phase then

local obj1 = event.object1
local obj2 = event.object2

– check if a rock hit a planet
if obj1.name == “planet” and obj2.name == “rock” then

timer.performWithDelay( 1, function() planetHit(obj1,obj2) end, 1 )

elseif obj1.name == “rock” and obj2.name == “planet” and bossTimer == nil then

timer.performWithDelay( 1, function() planetHit(obj2,obj1) end, 1 )

end

– check if the gun cross hit a rock

if obj1.name == “gun” and obj2.name == “rock” then

if obj2.type == “boss” and weaponMode == 1 then

bossTimer = timer.performWithDelay(300, function() destroyRock (obj2) end, 1 )

else

– destroy rock (not a boss) right away.
timer.performWithDelay(1, function() destroyRock(obj2) end, 1 )

end

elseif obj1.name == “rock” and obj2.name == “gun” and gunEnable == true then

if obj1.type == “boss” and weaponMode == 1 then

bossTimer = timer.performWithDelay(300, function() destroyRock (obj1) end, 1 )

else

– destroy rock (not a boss) right away.
timer.performWithDelay(1, function() destroyRock(obj1) end, 1 )

end

end

– check if the a rock hit a wall

if obj1.name == “wall” and obj2.name == “rock” then

timer.performWithDelay(1, function() wallHit(obj2) end, 1 )

elseif obj1.name == “rock” and obj2.name == “wall” then

timer.performWithDelay(1, function() wallHit(obj1) end, 1 )

end

elseif phase == “ended” then

– cancel timer if the collision ended (no destruction of boss)
if bossTimer then
timer.cancel(bossTimer)
return true
end
end

end[/lua]

[import]uid: 100814 topic_id: 25361 reply_id: 106723[/import]

Thanks for posting the code, but it’s a bit difficult to look at a large chunk and try to determine what’s intended and what’s not happening as expected.

That being said, a few suggestions…

  1. There are ALOT of timers firing in this game, at different points. Most likely this is causing problems. Try to minimize the amount of timers and carefully control when they happen.

  2. You don’t need 1 millisecond delay timers on any result that will destroy an object. You can destroy (remove) any object directly upon collision. You just can’t do various other “physics manipulation” calls upon collision without a slight delay. But on any occasion that you want to destroy an object, just call it directly in the collision handler and remove the 1 millisecond timer.

  3. I would “pass” your objects in timers differently. The method I prefer is this:

local function destroyRock( event )  
 local thisRock = event.source.rock --thisRock is now the handle to the rock associated with the timer  
 --do whatever to thisRock  
end  
  
local t = timer.performWithDelay( 300, destroyRock )  
t.rock = obj1 --"attach" a rock to this timer  
  1. screenMessage seems to be referring to either a variable you declared somewhere above, or a global variable. If you’re trying to just display a little “float” number that gets destroyed at the end of its fade, I would pull out the “destroyMessage” function and put it above. Then call it like this, after just making each message a new local display object…
local function destroyMessage( event )  
 --in a transition onComplete, 'event' is a pointer to the parent object (message object)  
 display.remove( event )  
 event = nil  
end  
  
--in function that displays the screenMessage...  
local screenMessage = --display it, set x and y, etc.  
--transition it, with onComplete going to function 'destroyMessage' above  

This might seem like a lot to bite off, but tinker around and see what progress you can make. I think it’s very close to working, it just needs a few minor tweaks.

Brent Sorrentino
Ignis Design
[import]uid: 9747 topic_id: 25361 reply_id: 106736[/import]

Thank you so much Brent. First for taking the time to read my “War and Peace” post and for your amazing insights. Yes I now realize that i am using way too many timers! I will also implement your other great suggestions and report here. They make a lot of sense. Hopefully it will help someone else who will try do a similar think in the future.

Once again THANK YOU!

Mo [import]uid: 100814 topic_id: 25361 reply_id: 106738[/import]