【问题标题】:Handling Collision Events for multiple objects with physics使用物理处理多个对象的碰撞事件
【发布时间】:2016-10-02 03:10:50
【问题描述】:

所以我正在使用 Corona(在 lua 中)构建一个游戏,其中有多个包含物理属性的对象,并且目前正在尝试以一种可以使碰撞处理更容易的方式存储和操作它们... 这个想法是3个物体中没有2个碰撞.. 对象是 1/ 一个球(可以出现在屏幕上的许多球) 2/ 表(具有一些物理属性) 和 3/ 口袋(最终只是一些不可见的矩形)

经过 2 周的处理,我得出了这个结论

  • 球击中其他球
  • 球击出球台
  • 表格不符合 Pocket(静态主体)
  • 口袋不击球(静态身体)
  • 球打出口袋

代码结构示例 创建 100 个球

balls = {}
local i = 1
function createBalls ()
        for i = 1,100,1 do -- create the 100 and hide them?

        ball = display.newImage("ball.png")
        ball.isVisible = false
        ball.id = tostring( "ball " ..i )
        balls[#ball+1] = ball 
        sceneGroup:insert(ball[#ball])
    end
end

声明6个口袋(使用id作为碰撞处理的标志)

local Pocket1 = display.newRect( screenWidth * .28, screenHeight * .5, 15, 18) --Left Pocket 60pts
physics.addBody( Pocket1, "kinematic", {isSensor = true})
Pocket1:addEventListener( "collision", Pocket1 ) Pocket1.isVisible = true Pocket1.alpha = 0.5
Pocket1.id ="Left Pocket 60pts"

local Pocket2 = display.newRect( screenWidth * .3945, screenHeight * .556, 15, 18) -- Left Pocket 30pts
physics.addBody( Pocket2, "kinematic", {isSensor = true} )
Pocket2:addEventListener( "collision", Pocket2 ) Pocket2.isVisible = false
Pocket2.id ="Left Pocket 30pts"

local Pocket3 = display.newRect( screenWidth * .512, screenHeight * .490, 15, 18) -- Center Pocket 10 pts
physics.addBody( Pocket3, "kinematic", {isSensor = true} )
Pocket3:addEventListener( "collision", Pocket3 ) Pocket3.isVisible = false
Pocket3.id ="Center Pocket 10pts"

local Pocket4 = display.newRect( screenWidth * .613, screenHeight * .556, 15, 18) -- Right Pocket 30 pts
physics.addBody( Pocket4, "kinematic", {isSensor = true} )
Pocket4:addEventListener( "collision", Pocket4 ) Pocket4.isVisible = false
Pocket4.id ="Right Pocket 30pts"

local Pocket5 = display.newRect( screenWidth * .736, screenHeight * .5, 15, 18) -- Far Right Pocket 60pts
physics.addBody( Pocket5, "kinematic", {isSensor = true} )
Pocket5:addEventListener( "collision", Pocket5 ) Pocket5.isVisible = false
Pocket5.id ="Right Pocket 60pts"

local Pocket6 = display.newRect( screenWidth * .512, screenHeight * .638, 50, 10) -- Kill-z Pocketphysics.addBody( Pocket6, "kinematic", {isSensor = true} )
Pocket6:addEventListener( "collision", Pocket6 ) Pocket6.isVisible = false
Pocket6.id ="Kill Pocket"

我的问题,碰撞检测仅适用于最后一个加载的球,

(如果有人要求加载器功能)

--handle loader
function shootBall()
    createBalls() --obviously this will now spawn 100 balls

    if ballLoaded == true then 
    r1 = -687.5 r2 = -668
    r3 = 595 r4 = 645
    ball[k].x = screenWidth * .378 ball[k].y = screenHeight * .638
    ball[k]:scale(0.16,0.16)
    ball[k].isVisible = true
    physics.addBody( ball[k], "dynamic", {radius = 5.5, density=15.0, friction=0.8, bounce=0.0 } )
    ball[k]:setLinearVelocity( math.random(r1,r2), math.random(r3,r4))
    --and here it will have done nothing productive other than fill the screen with balls

    end

回滚编辑这最初是被调用的,但正如你所见,它根本没有组织好,因为最近的代码是一团糟..

local i = 1
local balls  = {}

local function spawnBall()

    if i > 0 or  i < 100 then
     balls[i] = display.newImage("ball.png")
     balls[i].id = "ball "..i
     balls[i].x = screenWidth * .378
     balls[i].y = screenHeight * .638
     balls[i]:scale(0.16,0.16)
     balls[i].isVisible = true

     physics.addBody( balls[i], "dynamic", {radius = 5.5, density=15.0, friction=0.8, bounce=0.0 } )
     balls[i]:setLinearVelocity(math.random(-687.5,-668), math.random(595,645))
     sceneGroup:insert(balls[i])
     print(balls[i].id.. " shot")
    i = i + 1

    end

end`

【问题讨论】:

  • 你的代码中有一些奇怪的(和有味道的)东西。 createBall 函数绝对是错误的。你确定你知道你在这里做什么?您在每个循环中创建一个球表,在其中存储一些东西,然后在表 本身中存储对该表的引用,但在开始时(#ball + 1 将评估为 1,k 更大大于 1)。在您的加载程序函数中,k 是什么?如果它是全局变量,请不要这样做。相信我,你不想这样做。此外,您应该小心缩进,它也有助于发现错误。

标签: lua box2d collision-detection coronasdk physics


【解决方案1】:
function createBalls ()
        for k = 1,100,1 do
        ball = {} -- we do this every loop cycle!!!
        ball[k] = display.newImage("ball.png")
        ball[k].isVisible = false
        ball[k].id = tostring( "ball " ..i )
        ball[#ball+1] = ball[k]
        sceneGroup:insert(ball[#ball])
    end
end

在这里你重新定义全局变量 ball 100 次。

当您在每个循环中重新创建球时,#ball 将始终为 1。 所以你创建一个表格,在索引 k 和 2 处添加各种值,然后重新创建它......所以你的全局桌球完全搞砸了。

shootBall() 中,您使用未在提供的代码中定义的索引k...

逐行浏览您的代码并考虑一下。用笔画一张纸……

请阅读一些关于在 Lua 中使用局部变量的内容!!!!

【讨论】:

  • 我已经发布了对我最初的问题的回滚答案....任何人都会理解 k...keys....v 值....s...搜索的原因,这使最终用户可以随心所欲地释放尽可能多的球,它会在某些时候受到限制,但这个提示绝对是有见地的:)
  • @NealBarry 如果您想生成多个球,请编写一个类似 spawnBalls(numBalls) 的函数,而不是使用全局变量来设置球的数量。您希望尽可能少地保持全局变量的数量。检查您编辑的代码是否有拼写错误。你的 for 循环中仍然有错误。
  • 这实际上让我对方法有了更多的了解,我可能正在使用 lua 的第四周,即使有这么多也让我感到惊讶,个人迫不及待地开始调用 C函数只是为了看看会发生什么......
【解决方案2】:

所以这是我的解决方案,它非常全面。我要感谢 Corona Labs 的 Danny 提供了大部分解决方案,通过函数传递参数在列表中,但不是特别优先,但感谢大部分工作。

--on "Press" event
--Function to spawn an object
local function spawn(params)
    local ball = display.newImage(params.image)
    --Set the objects table to a table passed in by parameters
    ball.Table = params.Table
    --Automatically set the table index to be inserted into the next available table index
    ball.index = #ball.Table + 1
    --Give the object a custom name
    ball.id = "ball : " .. ball.index
    --If the object should have a body create it, else dont.
        if params.hasBody then
            --Allow physics parameters to be passed by parameters:
            ball.x = params.x or contentCenterX
            ball.y = params.y or contentCenterY
            ball.isVisible = params.isVisible or false
            ball.radius = params.radius or nil
            ball.density = params.density or 0
            ball.friction = params.friction or 0
            ball.bounce = params.bounce or 0
            ball.isSensor = params.isSensor or false
            ball.bodyType = params.bodyType or "dynamic"
            physics.addBody(ball, ball.bodyType, {radius = ball.radius, density = ball.density, friction = ball.friction, bounce = ball.bounce, isSensor = ball.isSensor})
            ball:setLinearVelocity(params.xVelocity or 0, params.yVelocity or 0)
            ball:scale(params.xScale or 1,params.yScale or 1)

        end
    --The objects group
    ball.group = params.group or nil
    --If the function call has a parameter named group then insert it into the specified group
    ball.group:insert(ball)
    --Insert the object into the table at the specified index
    ball.Table[ball.index] = ball       
    return ball
end
local displayGroup = display.newGroup()
--Create a table to hold balls
local ballTable = {}

--Create spawns
local function  ballSpawn()
    for i=1 ,1,1 do
        local spawns = spawn(

            {
            image = "ball.png",
            Table = ballTable,
            hasBody = true,
            x = screenWidth * .378,
            y = screenHeight * .638,
            isVisible = true,
            bodyType = "dynamic", radius = 5.5, density= 15.0, friction= 0.8, bounce = 0.0,
            xVelocity = math.random(-687.5,-678),
            yVelocity = math.random(595,645),
            xScale = 0.16, yScale = 0.16,
            group = sceneGroup,
            }
            )   
    end
end

这是代码中比较不典型的部分,我想在一个球是否是 3 或 5 或 25 时进行按键测试,如果 i=5 并且 ball: 3 与测试碰撞袋 I 碰撞想确保打印所有碰撞。

local function onPocketsCollision ( event)
local self = event.object2.id
local other = event.object1.id

    if event.phase == "began"  then

        for i = 1, #ballTable,1 do
            if (self == ballTable[i].id and other == Pocket1.id) then
                print(self .. " hit for " .. Pocket1.id)
                ballTable[i]:removeSelf()
                score.add(1)
            end
            if (self == ballTable[i].id and other == Pocket2.id) then
                print(self .. " hit for " .. Pocket2.id)
                ballTable[i]:removeSelf()
                score.add(1)
            end
            if (self == ballTable[i].id and other == Pocket3.id) then
                print(self .. " hit for " .. Pocket3.id)
                ballTable[i]:removeSelf()
                score.add(1)
            end
            if (self == ballTable[i].id and other == Pocket4.id) then
                print(self .. " hit for " .. Pocket4.id)
                ballTable[i]:removeSelf()
                score.add(1)
            end
            if (self == ballTable[i].id and other == Pocket5.id) then
                print(self .. " hit for " .. Pocket5.id)
                ballTable[i]:removeSelf()
                score.add(1)
            end
            if (self == ballTable[i].id and other == Pocket6.id) then
                print(self .. " hit " .. Pocket6.id)
                ballTable[i]:removeSelf()
                score.add(-1)
            end
        end
    end
end


Runtime:addEventListener( "collision", onPocketsCollision )

太神奇了,它工作得很好,只是减少它的一个例子,所以它看起来不像垃圾......我一定会在未来共享代码时小心一点,必须被逐行阅读的便便......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-02
    • 1970-01-01
    • 1970-01-01
    • 2015-03-25
    相关资源
    最近更新 更多