2015年6月12日 星期五

[Corona SDK] 如何偵測物體碰撞 - 利用Global Collision

偵測碰撞可以用Local Collision或Global Collision.
以下是利用Global Collision的方法:
local main = display.newImage( "mainRole.png", 160, 240 )
physics.addBody( main, { density = 1.0, friction = 0.3, bounce = 0.2 } )
main.myName = "mainRole"

local fruit1 = display.newImage( "fruit.png", 100, 120 )
physics.addBody( fruit1, { density = 1.0, friction = 0.3, bounce = 0.2 } )
fruit1.myName = "fruit1"

local fruit2 = display.newImage( "fruit.png", 300, 220 )
physics.addBody( fruit2, { density = 1.0, friction = 0.3, bounce = 0.2 } )
fruit2.myName = "fruit2"

local function onGlobalCollision( event )

    if ( event.phase == "began" ) then        
        if((event.object1.myName=="mainRole" and event.object2.myName=="fruit1") or (event.object1.myName=="fruit1 and event.object2.myName=="mainRole")) then
         print( "began: " .. event.object1.myName .. " and " .. event.object2.myName )         
         if(fruit1 ~= nil) then
          print("Remove fruit1")
          fruit1:removeSelf( )
    fruit1 = nil
         end
        elseif((event.object1.myName=="mainRole" and event.object2.myName=="fruit2") or (event.object1.myName=="fruit2" and event.object2.myName=="mainRole")) then
         print( "began: " .. event.object1.myName .. " and " .. event.object2.myName )         
         if(fruit2 ~= nil) then
          print("Remove fruit2")
          fruit2:removeSelf( )
    fruit2 = nil
         end
        end

    elseif ( event.phase == "ended" ) then
        print( "ended: " .. event.object1.myName .. " and " .. event.object2.myName )
    end
end

Runtime:addEventListener( "collision", onGlobalCollision )
我們替每個物體都加上了專屬的名稱,
在碰撞發生時,就可以利用名稱來分辨是那二個物體,

不過,以上的程式執行時,有時會遇到Runtime error,
執行fruit1:removeSelf( )時,它會告訴你fruit1是nil,
怪了,我們明明有檢查if(fruit1 ~= nil),
fruit2一樣有類似的情形,
從log來看,有時print( "began: " .. event.object1.myName .. " and " .. event.object2.myName )會執行好幾次,然後才執行print("Remove fruit1"),
看來,這個function是multi-entry
multi-entry但又缺少critical section的保護機制,然免會出問題,
要解決這個問題,就是把remove的動作移到其它地方去,如下面用法:
local removeFruit1 = false
local removeFruit2 = false
local main = display.newImage( "mainRole.png", 160, 240 )
physics.addBody( main, { density = 1.0, friction = 0.3, bounce = 0.2 } )
main.myName = "mainRole"

local fruit1 = display.newImage( "fruit.png", 100, 120 )
physics.addBody( fruit1, { density = 1.0, friction = 0.3, bounce = 0.2 } )
fruit1.myName = "fruit1"

local fruit2 = display.newImage( "fruit.png", 300, 220 )
physics.addBody( fruit2, { density = 1.0, friction = 0.3, bounce = 0.2 } )
fruit2.myName = "fruit2"

local function onGlobalCollision( event )

    if ( event.phase == "began" ) then        
        if((event.object1.myName=="mainRole" and event.object2.myName=="fruit1") or (event.object1.myName=="fruit1 and event.object2.myName=="mainRole")) then
         print( "began: " .. event.object1.myName .. " and " .. event.object2.myName )         
         removeFruit1 = true
        elseif((event.object1.myName=="mainRole" and event.object2.myName=="fruit2") or (event.object1.myName=="fruit2" and event.object2.myName=="mainRole")) then
         print( "began: " .. event.object1.myName .. " and " .. event.object2.myName )         
         removeFruit2 = true
        end

    elseif ( event.phase == "ended" ) then
        print( "ended: " .. event.object1.myName .. " and " .. event.object2.myName )
    end
end

Runtime:addEventListener( "collision", onGlobalCollision )

local function removeAction()
 if(removeFruit1) then
   if(fruit1 ~= nil) then
      print("Remove fruit1")
      fruit1:removeSelf( )
      fruit1 = nil
      removeFruit1 = false
   end
 end
 if(removeFruit2) then
   if(fruit2 ~= nil) then
     print("Remove fruit2")
     fruit2:removeSelf( )
     fruit2 = nil
     removeFruit2 = false
   end
 end 
end
 
timer.performWithDelay( 50, removeAction,-1 )

沒有留言:

張貼留言