如何在Love2d中使用边界框?

时间:2016-11-11 05:41:06

标签: lua love2d

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

    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

2 个答案:

答案 0 :(得分:0)

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

再次在JavaScript中的live example演示了这一点。

这是一个快速(且不完美)的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

答案 1 :(得分:0)

奥卡非常好地解释了这一点。这适用于矩形,不旋转和轴对齐的所有内容。你甚至已经这样做了。这对按钮等很有用!

但我喜欢做的是在对象周围使用(不可见)圆圈,看看它们是否发生碰撞。这适用于高度与宽度大致相同的所有内容(许多侧面平台或自顶向下的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ÖVE2D一起享受乐趣!:)