使用Ceramic Tile Engine和Box 2D进行碰撞检测

对于这个问题的跟进,使用 Ceramic Tile Engine 和 碰撞检测的Storyboard仍然是个谜。下面是代码:

-- 隐藏状态栏
display.setStatusBar(display.HiddenStatusBar)
local storyboard = require("storyboard")
-- 设置物理世界
local physics = require("physics")
physics.start()
physics.setGravity(0, 0)
physics.setDrawMode('hybrid')
local scene = storyboard.newScene()
local widget = require("widget")

-- 将Hero添加到物理世界
local hero = display.newImage("images/man.png")
hero.x = 40
hero.y = 80
local heroCollisionFilter = { categoryBits = 4, maskBits = 2 }
local heroBody = { filter=heroCollisionFilter, isSensor=true }
physics.addBody(hero, "dynamic", heroBody)

function scene:createScene( event )
    local group = self.view
    local ceramic = require("Ceramic")
    ceramic.showPrints = false
    local map = ceramic.buildMap("maps/map.lua")
    -- collisionLayer = map.layer['Collision']
    -- collisionLayer.ccName = "map"
    -- physics.addBody(collisionLayer, "static", { friction=0.5, bounce=0.3 } )
    map.y = 0
    map.setCameraDamping(10)
    map.layer['World']:insert(hero)
end

function onGlobalCollision(event)
    if(event.phase == "began") then
        print( "Global report: " .. event.object1.ccName .. " & " .. event.object2.ccName .. " collision began" )
    elseif(event.phase == "ended") then
        print( "Global report: " .. event.object1.ccName .. " & " .. event.object2.ccName .. " collision ended" )
    end
    print( "**** " .. event.element1 .. " -- " .. event.element2 )
end

Runtime:addEventListener("collision", onGlobalCollision)
scene:addEventListener( "createScene", scene )

return scene

屏幕截图如下:

屏幕截图

然而,碰撞从未被触发,因为Terminal中没有出现 print 消息。

我使用的是:

  • Corona SDK
  • Ceramic Tile Engine
  • Corona module: storyboard, physics

如何启用碰撞检测? 参数正确吗?


编辑 2013/10/27

Tiled地图设置如下:

碰撞层设置

在Mac OS X中运行时,碰撞不会发生(只有混合图层的颜色会改变)。

在Windows 7中运行时,代码会在此行崩溃:

ceramic.buildMap("maps/map.lua")

报错如下:

attempt to call global 'reversePolygon' (a nil value) in Ceramic.lua: 617

当我注释掉以下行后,错误就消失了:

collisionLayer = map.layer['Collision']
collisionLayer.ccName = "map"
physics.addBody(collisionLayer, "static", { friction=0.5, bounce=0.3 } )

但碰撞函数并未被调用。

点赞
用户2868291
用户2868291

Box2D 碰撞检测

在 Tiled 编辑器中,可以通过层、图块或对象层中的属性来指定 Box2D 碰撞检测。当 physics:enabled 属性设置为 true 时,Ceramic 会自动添加物理效果。

物理参数也可以通过属性来设置,例如以下命令:

physics.addBody(myObject, {friction = 0.5, bounce = 0.1})

在 Tiled 的属性中,对应的是:

physics:friction              = 0.5
physics:bounce                = 0.1

需要注意的是,以上命令是遵循 markdown 格式编写的。

2013-10-22 12:53:01
用户188331
用户188331

对于那些在使用 Tiled 和 Ceramic Tile Engine 时遇到 Corona SDK 中的碰撞检测问题的开发者(特别是未来的开发者),在进一步的测试中,我发现碰撞事件不触发的问题是因为我使用了错误的一组碰撞事件。有效的碰撞事件如下:

local function onLocalCollision(self, event)
    print("碰撞")
    if event.phase == "began" then
        print("碰撞开始")
    elseif event.phase == "ended" then
        print("碰撞结束")
    end
end

function onGlobalCollision(event)
    if(event.phase == "began") then
        print( "全局报告:" .. event.object1.ccName .. " & " .. event.object2.ccName .. " 碰撞开始" )
    elseif(event.phase == "ended") then
        print( "全局报告:" .. event.object1.ccName .. " & " .. event.object2.ccName .. " 碰撞结束" )
    end
    print( "**** " .. event.element1 .. " -- " .. event.element2 )
end

function onPostCollision(event)
    print("后碰撞")
end

-- 本地碰撞
hero.collision = onLocalCollision
hero:addEventListener("collision", hero)
-- 全局碰撞
Runtime:addEventListener("collision", onGlobalCollision)
Runtime:addEventListener("postCollision", onPostCollision)

每个碰撞对象都必须有一个名称(属性名为 ccName ,你可以选择任何名称,但必须在 Tiled 的对象列表中设置)。

另外,我删除了 categoryBitsmaskBits ,因为这些会使碰撞检测无效。

需要注意的是:

  • 碰撞层不需要通过编程添加到场景中(它将自动添加)。
  • 只需要一组碰撞检测方法(本地/全局)(但可以并行运行两组)。
  • 为了提高性能,在不需要时关闭混合显示模式。
  • 无论图层格式是什么(Base64 / CSV 都可以工作)。
  • 记得在碰撞层属性中添加 physics:enabledphysics:frictionphysics:bounce 是可选的,参考 @CalebP 的评论)。
2013-10-27 05:18:32