1. 程式人生 > >lua實現cocos多邊形碰撞檢測

lua實現cocos多邊形碰撞檢測

定義幾個資料型別和函式

function vec(x, y)

    return {x, y}
end


v = vec -- shortcut


function dot(v1, v2)
    return v1[1]*v2[1] + v1[2]*v2[2]
end


function normalize(v)
    local mag = math.sqrt(v[1]^2 + v[2]^2)
    return vec(v[1]/mag, v[2]/mag)
end


function perp(v)
    return {v[2],-v[1]}
end


function segment(a, b)
    local obj = {a=a, b=b, dir={b[1] - a[1], b[2] - a[2]}}
    obj[1] = obj.dir[1]; obj[2] = obj.dir[2]
    return obj
end


function polygon(vertices)
    local obj = {}
    obj.vertices = vertices
    obj.edges = {}
    for i=1,#vertices do
        table.insert(obj.edges, segment(vertices[i], vertices[1+i%(#vertices)]))
    end
    return obj
end
vec為向量或者向量,也可表示點;dot為向量點投影運算;normalize為求模運算;perp計演算法線向量;segment表示線段;polygon為多邊形,包括頂點vertices和邊edges,所有點的順序必須按順時針或者逆時針



演算法的判斷函式
-- We keep a running range (min and max) values of the projection, and then use that as our shadow


function project(a, axis)
    axis = normalize(axis)
    local min = dot(a.vertices[1],axis)
    local max = min
    for i,v in ipairs(a.vertices) do
        local proj =  dot(v, axis) -- projection
        if proj < min then min = proj end
        if proj > max then max = proj end
    end


    return {min, max}
end


function contains(n, range)
    local a, b = range[1], range[2]
    if b < a then a = b; b = range[1] end
    return n >= a and n <= b
end


function overlap(a_, b_)
    if contains(a_[1], b_) then return true
    elseif contains(a_[2], b_) then return true
    elseif contains(b_[1], a_) then return true
    elseif contains(b_[2], a_) then return true
    end
    return false
end

project為計算投影函式,先計算所有邊長的投影,然後算出投影的最大和最小點即起始點;overlap函式判斷兩條線段是否重合






演算法實現函式,使用到上面的資料和函式
function sat(a, b)
    for i,v in ipairs(a.edges) do
        local axis = perp(v)
        local a_, b_ = project(a, axis), project(b, axis)
        if not overlap(a_, b_) then return false end
    end
    for i,v in ipairs(b.edges) do
        local axis = perp(v)
        local a_, b_ = project(a, axis), project(b, axis)
        if not overlap(a_, b_) then return false end
    end


    return true
end
遍歷a和b兩個多邊形的所有邊長,判斷投影是否重合




a = polygon{v(0,0),v(0,5),v(5,4),v(3,0)}
b = polygon{v(4,4),v(4,6),v(6,6),v(6,4)}


print(sat(a,b)) -- true