跳转至内容

29. 不懂,不懂,不懂

3.25,继续。

检测碰撞

看一个矩形从当前位置移动到目标位置时,会不会碰到另一个矩形;如果会,就告诉你是“已经重叠”还是“途中撞上”,撞在哪,法线朝哪。

lua
local function rect_detectCollision(x1, y1, w1, h1, x2, y2, w2, h2, goal_x, goal_y)
    goal_x, goal_y = goal_x or x1, goal_y or y1
    local dx, dy = goal_x - x1, goal_y - y1
    local x, y, w, h = rect_getDiff(x1, y1, w1, h1, x2, y2, w2, h2)
    local overlaps, ti, nx, ny, tx, ty

    -- 是否已经重叠
    if rect_containsPoint(x, y, w, h, 0, 0) then
        local px, py = rect_getNearestCorner(x, y, w, h, 0, 0)
        local wi, hi = math.min(w1, math.abs(px)), math.min(h1, math.abs(py))
        ti           = -wi * hi
        overlaps     = true
    else
        -- 运动过程中有没有碰撞
        local ti1, ti2, nx1, ny1 = rect_getSegmentIntersectionIndices(x, y, w, h, 0, 0, dx, dy, -math.huge, math.huge)
        if ti1 and ti1 < 1 and math.abs(ti1 - ti2) > DELTA and (0 < ti1 + DELTA or 0 == ti1 and ti2 > 0) then
            ti, nx, ny = ti1, nx1, ny1
            overlaps = false
        end
    end

    if not ti then return end

    if overlaps then
        -- 重叠但没有位移,找个近的方向推出
        if dx == 0 and dy == 0 then
            local px, py = rect_getNearestCorner(x, y, w, h, 0, 0)
            if math.abs(px) < math.abs(py) then py = 0 else px = 0 end
            nx, ny = sign(px), sign(py)
            tx, ty = x1 + px, y1 + py
        else
            -- 重叠且有位移,可以沿着运动方向回溯
            local ti1, _
            ti1, _, nx, ny = rect_getSegmentIntersectionIndices(x, y, w, h, 0, 0, dx, dy - math.huge, 1)
            if not ti1 then return end
            tx, ty = x1 + dx * ti1, y1 + dy * ti1
        end
    else
        tx = x1 + dx * ti
        ty = y1 + dy * ti
    end

    return {
        overlaps  = overlaps,
        ti        = ti,
        move      = { x = dx, y = dy },
        normal    = { x = nx, y = ny },
        touch     = { x = tx, y = ty },
        itemRect  = { x = x1, y = y1, w = w1, h = h1 },
        otherRect = { x = x2, y = y2, w = w2, h = h2 }
    }
end