【问题标题】:How to use bounding box in Love2d?如何在 Love2d 中使用边界框?
【发布时间】:2017-03-25 07:39:43
【问题描述】:

我一直在使用一些非常庞大的代码来检测简单对象之间的碰撞,并且我听说过边界框。我找不到任何关于如何使用它的教程,所以我在询问如何使用它。以下是我检测碰撞的方法:

    function platform.collision()
if player.x + player.width / 2 <= platform.x + platform.width and
    player.x + player.width / 2 >= platform.x and
    player.y + player.height <= platform.y + platform.height and 
    player.y + player.height >= platform.y then

【问题讨论】:

    标签: lua love2d


    【解决方案1】:

    MDN2D collision detection 上有一篇相当简洁的文章。作为 MDN,这些示例位于 javascript 中,但很容易翻译并适用于任何语言 - 包括 Lua。

    我们来看看:

    轴对齐边界框

    一种更简单的碰撞检测形式是在两个轴对齐的矩形之间进行 - 意味着没有旋转。该算法通过确保矩形的 4 个边之间没有间隙来工作。任何间隙都意味着不存在碰撞。

    他们的例子,翻译成 Lua:

    local rect1 = { x = 5, y = 5, width = 50, height = 50 }
    local rect2 = { x = 20, y = 10, width = 10, height = 10 }
    
    if 
        rect1.x < rect2.x + rect2.width and
        rect1.x + rect1.width > rect2.x and
        rect1.y < rect2.y + rect2.height and
        rect1.height + rect1.y > rect2.y 
    then
        -- collision detected!
    end
    
    -- filling in the values =>
    
    if 
        5 < 30 and
        55 > 20 and
        5 < 20 and
        55 > 10
    then
        -- collision detected!
    end
    

    live example 再次在 JavaScript 中很好地证明了这一点。


    这是一个快速(但不完美)的 Love2D 示例,您可以将其放入 main.lua 并进行尝试。

    local function rect (x, y, w, h, color)
        return { x = x, y = y, width = w, height = h, color = color }
    end
    
    local function draw_rect (rect)
        love.graphics.setColor(unpack(rect.color))
    
        love.graphics.rectangle('fill', rect.x, rect.y,
            rect.width, rect.height)
    end
    
    local function collides (one, two)
        return (
            one.x < two.x + two.width and
            one.x + one.width > two.x and
            one.y < two.y + two.height and
            one.y + one.height > two.y
        )
    end
    
    local kp = love.keyboard.isDown
    local red = { 255, 0, 0, 255 }
    local green = { 0, 255, 0, 255 }
    local blue = { 0, 0, 255, 255 }
    
    local dim1 = rect(5, 5, 50, 50, red)
    local dim2 = rect(20, 10, 60, 40, green)
    
    function love.update ()
        if kp('up') then
            dim2.y = dim2.y - 1
        end
    
        if kp('down') then
            dim2.y = dim2.y + 1
        end
    
        if kp('left') then
            dim2.x = dim2.x - 1
        end
    
        if kp('right') then
            dim2.x = dim2.x + 1
        end
    
        dim2.color = collides(dim1, dim2) and green or blue
    end
    
    function love.draw ()
        draw_rect(dim1)
        draw_rect(dim2)
    end
    

    【讨论】:

    • 非常感谢!这真的很有帮助,因为我正在尝试制作一款高效的平台游戏。我只知道 lua 大约一周,所以我能接受的任何东西都会有所帮助。
    • @LucaLizaranzu 那么,欢迎来到 Lua!这里有一些通用资源可以帮助您。如果您像我一样喜欢阅读这些内容可能会派上用场:Lua Reference Manual (For 5.1)Love2D WikiProgramming in Lua (A Book)。干杯,祝你好运。
    【解决方案2】:

    Oka 解释得很好。这适用于所有矩形,未旋转且轴对齐。你甚至已经这样做了。这非常适合按钮等!

    但我喜欢做的是在物体周围使用(不可见的)圆圈,看看它们是否发生碰撞。这适用于高度与宽度大致相同的所有事物(许多横向滚动平台游戏或自上而下的 RPG 都是这种情况)。
    如果您想让对象以当前位置为中心,这非常方便。在触摸屏设备上模拟手指特别有用,因为手指比鼠标光标大很多。 ;)

    这是一个关于如何使用此方法的示例。你可以把它复制成一个真正的游戏,它会工作的。

    --[[ Some initial default settings. ]]
    
    function love.load()
        settings = {
            mouseHitbox = 5,   -- A diameter around the mouse cursor.
            -- For a finger (thouchscreen) this could be bigger!
        }
    
        objects = {
            [1] = {
                x = 250,   -- Initial X position of object.
                y = 200,   -- Initial Y position of object.
                hitbox = 100,   -- A diameter around the CENTER of the object.
                isHit = false    -- A flag for when the object has been hit.
            },
            [2] = {
                x = 400,
                y = 250,
                hitbox = 250,
                isHit = false
            }
        }
    end
    
    --[[ This is the actual function to detect collision between two objects. ]]
    
    function collisionDetected(x1,y1,x2,y2,d1,d2)
        -- Uses the x and y coordinates of two different points along with a diameter around them.
        -- As long as these two diameters collide/overlap, this function returns true!
        -- If d1 and/or d2 is missing, use the a default diameter of 1 instead.
        local d1 = d1 or 1
        local d2 = d2 or 1
        local delta_x = x2 - x1
        local delta_y = y2 - y1
        local delta_d = (d1 / 2) + (d2 / 2)
        if ( delta_x^2 + delta_y^2 < delta_d^2 ) then
            return true
        end
    end
    
    --[[ Now, some LÖVE functions to give the collisionDetection() some context. ]]
    
    function love.draw()
        for i=1,#objects do   -- Loop through all objects and draw them.
            if ( objects[i].isHit ) then
                love.graphics.setColor(255, 0, 0)   -- If an object is hit, it will flash red for a frame.
                objects[i].isHit = false
            else
                love.graphics.setColor(255, 255, 255)
            end
            love.graphics.circle("line", objects[i].x, objects[i].y, objects[i].hitbox/2)
        end
    end
    
    -- You can use the following to check, if any object has been clicked on (or tapped on a touch screen device).
    
    function love.mousepressed(x,y,button)
        if ( button == 1 ) then
            local i = objectIsHit(x,y)   -- Check, if an object has been hit.
            if ( i ) then
                -- The object number 'i' has been hit. Do something with this information!
                objects[i].isHit = true
            end
        end
    end
    
    function objectIsHit(x,y)
        for i=1,#objects do   -- Loop through all objects and see, if one of them has been hit.
            if ( collisionDetected(x, y, objects[i].x, objects[i].y, settings.mouseHitbox, objects[i].hitbox) ) then
                return i   -- This object has been hit!
            end
        end
    end
    
    -- For the sake of completeness: You can use something like the following to check, if the objects themselves collide.
    -- This would come in handy, if the objects would move around the screen and then bounce from each other, for example.
    
    function love.update(dt)
        if ( collisionDetected(objects[1].x, objects[1].y, objects[2].x, objects[2].y, objects[1].hitbox, objects[2].hitbox) ) then
            -- The objects collided. Do something with this information!
        end
    end
    

    如您所见,collisionDetection() 函数使用起来非常简单直观。

    希望我能给你更多的见解。 享受 LÖVE 2D 的乐趣! :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-17
      • 2015-08-11
      相关资源
      最近更新 更多