多边形碰撞检测(分离轴算法Lua实现)

在游戏开发中,我们一般常用的碰撞检测算法有AABB,OBB以及分离轴算法。
AABB与OBB一般用于矩形的碰撞检测,而多边形的碰撞检测一般使用分离轴算法,这里说的都是2D图形的碰撞检测

一、什么是分离轴?

将两个多边形投影到任意的一条轴上,如果能找到至少有一个轴上的两个多边形投影没有重叠,那么就说明这两个多边形没有发生碰撞。
在程序实现中,我们不可能去检测所有的轴,这是不现实的,不过好在多边形的特性,我们只需要以多边形的每一条边的法线为轴,分别检测一遍就好了。
分离轴适用的是凸多边形之间检测,不适用于凹多边形,凹多边形的检测,可以通过算法将凹多边形分割成多个凸多边形再进行计算。

 

分离轴.png
 

多边形A,B在轴Z''上的投影A''与B''是分离的,所以多边形A,B是分离的。

二、算法实现

2.1、多边形与多边形

(1)辅助方法

---获取两点的距离
function GetDis(vec1,vec2)
    local x1 = vec1.x or vec1[1]
    local y1 = vec1.y or vec1[2]
    local x2 = vec2.x or vec2[1]
    local y2 = vec2.y or vec2[2]

    local disX = x1 - x2
    local disY = y1 - y2
    local dis = math.sqrt(disX * disX + disY * disY)
    return dis
end

---向量归一化
function Normalize(vec)
    local x = vec[1] or vec.x
    local y = vec[2] or vec.y
    local mag = math.sqrt(x*x + y*y)
    if type(vec) == "table" then
        vec[1] = x/mag
        vec[2] = y/mag
    end
    vec.x = x/mag
    vec.y = y/mag
end

---点乘
function Dot(vec1,vec2)
    local x1 = vec1.x or vec1[1]
    local y1 = vec1.y or vec1[2]
    local x2 = vec2.x or vec2[1]
    local y2 = vec2.y or vec2[2]
    return x1*x2 + y1*y2
end

---精确到小数点后n位
---num 浮点数
---n 浮点数精确位数
function FloatAccurateN(num,n)
    if type(num) ~= "number" then
        return num;
    end
    n = n or 0;
    n = math.floor(n)
    if n < 0 then
        n = 0;
    end
    local nDecimal = 10 ^ n
    local nTemp = math.floor(num * nDecimal);
    local nRet = nTemp / nDecimal;
    return nRet;
end

---二维向量的向量积
---大小的绝对值表示两个向量构成的三角形的面积的2倍
---正负表示与两个向量构成的平面的法线的方向
function VectorProduct(vec1,vec2)
    local vec1X = vec1.x or vec1[1]
    local vec1Y = vec1.y or vec1[2]
    local vec2X = vec2.x or vec2[1]
    local vec2Y = vec2.y or vec2[2]
    return vec1X*vec2Y - vec2X*vec1Y
end

function Add(pt1,pt2)
    return {x = pt1.x + pt2.x , y = pt1.y + pt2.y }
end

function Sub(pt1,pt2)
    return {x = pt1.x - pt2.x , y = pt1.y - pt2.y }
end

-- 计算圆周上的点位置
-- 返回的是通过圆心与水平夹角为angleRadians度的直径在圆上的两个交点
function CalCirclePos(centerPos, radius, angleRadians)
    return Add(centerPos, {x=math.cos(angleRadians)*radius, y=math.sin(angleRadians)*radius}),Sub(centerPos, {x=math.cos(angleRadians)*radius, y=math.sin(angleRadians)*radius})
end

---将角度转换为逆时针角度
---rotation (0 ~ 180逆时针,0 ~ -180顺时针)
function changeRotationToInverse(rotation)
    rotation = rotation or 0
    if rotation < 0 then
        rotation = rotation + 360
    end
    return rotation or 0
end

(2)创建多边形

--创建一个多边形
--name:多边形名字
--offset:实际点与多边形的偏移量,offset为多边形的原点,多边形的顶点位置都是相对于这个点的偏移量
--vertices : 多边形的顶点数组,位置相对于offset
--rotation : 旋转角度(角度不是弧度(0~180为逆时针,0~-180为顺时针) 
function Polyon(name,offset,vertices,rotation)
    local polyon = {}
    polyon.name = name or "polyon"
    polyon.offset = {offset.x or offset[1] or 0,offset.y or offset[2] or 0}
    -- 弧度
    polyon.rotation = math.rad(changeRotationToInverse(rotation))
    --- 模板顶点,相对于offset为原点的顶点数组
    polyon._tempVertices = {}
    for i, vertice in ipairs(vertices) do
        local x = vertices[i][1]
        local y = vertices[i][2]
        table.insert(polyon._tempVertices,{x=x,y=y})
    end
    --顶点数组,实际顶点坐标
   
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值