热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

2D游戏中常见的碰撞检测算法思路(附详细思路及部分源码)

目录1点与点的碰撞点与直线点与圆的碰撞点与矩形的碰撞点与多边形的碰撞点与地图格子的碰撞直线与直线的碰撞直线与圆的碰撞直线与矩形多边形的碰撞圆与圆的碰撞圆与矩形多边形的碰撞圆矩形与地

目录1

  1. 点与点的碰撞
  2. 点与直线
  3. 点与圆的碰撞
  4. 点与矩形的碰撞
  5. 点与多边形的碰撞
  6. 点与地图格子的碰撞
  7. 直线与直线的碰撞
  8. 直线与圆的碰撞
  9. 直线与矩形多边形的碰撞
  10. 圆与圆的碰撞
  11. 圆与矩形多边形的碰撞
  12. 圆矩形与地图格子的碰撞
  13. 矩形与矩形多边形的碰撞
  14. 多边形与多边形的碰撞

点与点的碰撞

通过比较两个点坐标是否相同判断

function M.pointPoint(point1, point2)
local ret = false
if (point1.x == point2.x) and (point1.y == point2.y) then
ret = true
end
return ret
end

点与直线

直线:一般不做判断(可以根据直线公式判断)

线段:

  • 先根据线段的直线公式判断点是否在线段所处的直线上
  • 如果处于直线上,在判断该点是否处于线段所在的区间内

也可以使用叉积

点与圆的碰撞

通过计算点到圆心的距离与半径比较判断

function M.pointInCircle(point, circle)
local center = circle.center
local radius = circle.radius
return cc.pGetDistance(point, center) <= radius
end

cc.pGetDistance2 source code:

function cc.pGetDistance(startP,endP)
return cc.pGetLength(cc.pSub(startP,endP))
end
function cc.pGetLength(pt)
return math.sqrt( pt.x * pt.x + pt.y * pt.y )
end
function cc.pSub(pt1,pt2)
return {x = pt1.x - pt2.x , y = pt1.y - pt2.y }
end

点与矩形的碰撞

通过判断点坐标是否在矩形四个顶点围成的坐标区域内

function M.pointInRect(point, rect)
return cc.rectContainsPoint(rect, point)
end

cc.rectContainsPoint3 source code:

function cc.rectContainsPoint( rect, point )
local ret = false
if (point.x >= rect.x) and (point.x <= rect.x + rect.width) and
(point.y >= rect.y) and (point.y <= rect.y + rect.height) then
ret = true
end
return ret
end

点与多边形的碰撞

对于任意多边形,可以运用引射线法:从目标点出发引一条射线,红点是要计算的点,通过该点引一条水平线,计算多边形各边与该水平线的交点(蓝点),如果红点两侧的射线与多边形各边的交点数都是奇数,那么红点在多边形内,反之不在。

《2D游戏中常见的碰撞检测算法思路(附详细思路及部分源码)》

处理特殊情况:

《2D游戏中常见的碰撞检测算法思路(附详细思路及部分源码)》

详细方法可参考下列贴子:

点是否在多边形内

点是否在多边形内GIS

点与地图格子的碰撞

主要是根据获取的地图格子的属性是否是碰撞格来判断,例如该格子是只可碰撞格子,碰撞可移动格子等。

直线与直线的碰撞

直线相交

直线与圆的碰撞

判断圆心到直线的距离与半径的大小即可

直线与矩形多边形的碰撞

取矩形多边形的边与直线判断相交,参考直线与直线的碰撞

线段与矩形:

function M.isLineIntersectRectangle(linePointX1,
linePointY1,
linePointX2,
linePointY2,
rectangleLeftTopX,
rectangleLeftTopY,
rectangleRightBottomX,
rectangleRightBottomY)
local lineHeight = linePointY1 - linePointY2
local lineWidth = linePointX2 - linePointX1 -- 计算叉乘
local c = linePointX1 * linePointY2 - linePointX2 * linePointY1
if (lineHeight * rectangleLeftTopX + lineWidth * rectangleLeftTopY + c >= 0 and lineHeight * rectangleRightBottomX + lineWidth * rectangleRightBottomY + c <= 0)
or (lineHeight * rectangleLeftTopX + lineWidth * rectangleLeftTopY + c <= 0 and lineHeight * rectangleRightBottomX + lineWidth * rectangleRightBottomY + c >= 0)
or (lineHeight * rectangleLeftTopX + lineWidth * rectangleRightBottomY + c >= 0 and lineHeight * rectangleRightBottomX + lineWidth * rectangleLeftTopY + c <= 0)
or (lineHeight * rectangleLeftTopX + lineWidth * rectangleRightBottomY + c <= 0 and lineHeight * rectangleRightBottomX + lineWidth * rectangleLeftTopY + c >= 0) then
if rectangleLeftTopX > rectangleRightBottomX then
local temp = rectangleLeftTopX
rectangleLeftTopX = rectangleRightBottomX
rectangleRightBottomX = temp
end
if rectangleLeftTopY local temp1 = rectangleLeftTopY
rectangleLeftTopY = rectangleRightBottomY
rectangleRightBottomY = temp1
end
if (linePointX1 or (linePointX1 > rectangleRightBottomX and linePointX2 > rectangleRightBottomX)
or (linePointY1 > rectangleLeftTopY and linePointY2 > rectangleLeftTopY)
or (linePointY1 return false
else
return true
end
else
return false
end
end

圆与圆的碰撞

如果两圆的圆心距小于或等于两圆半径和则认为发生碰撞

function M.circleIntersectsCircle(circle1, circle2)
return cc.pGetDistance(circle1.center, circle2.center) <= (circle1.radius + circle2.radius)
end

圆与矩形多边形的碰撞

圆与矩形的碰撞:

function M.rectIntersectsCircle(rect, circle)
local lx = cc.rectGetMidX(rect)
local ly = cc.rectGetMinY(rect)
local rx = cc.rectGetMaxX(rect)
local ry = cc.rectGetMaxY(rect)
local ret = false
local center = circle.center
local radius = circle.radius
if (center.x >= lx - radius) and (center.x <= rx + radius) and (center.y >= ly) and (center.y <= ry) then
ret = true
elseif (center.x >= lx) and (center.x <= rx) and (center.y >= ly - radius) and (center.y <= ry + radius) then
ret = true
else
local d1 = cc.pGetDistance(cc.p(lx, ly), center)
local d2 = cc.pGetDistance(cc.p(lx, ry), center)
local d3 = cc.pGetDistance(cc.p(rx, ly), center)
local d4 = cc.pGetDistance(cc.p(rx, ry), center)
if d1 <= radius or d2 <= radius or d3 <= radius or d4 <= radius then
ret = true
end
end
return ret
end

简单碰撞检测

对于凸多边形分离轴定理:若两个物体没有发生碰撞,则总会存在一条直线,能将两个物体分离 。于是,我们把这条能够隔开两个物体的线称为分离轴。取两个多边形各个顶点在各条边上的对应投影之间是否都有交集,都有则说明发生碰撞

  • 从需要检测的多边形中取出一条边,并找出它的法向量(垂直于它的向量),这个向量将会是我们的一个“投影轴”。

《2D游戏中常见的碰撞检测算法思路(附详细思路及部分源码)》

  • 循环获取第一个多边形的每个点,并将它们投影到这个轴上。(记录这个多边形投影到轴上的最高和最低点)

《2D游戏中常见的碰撞检测算法思路(附详细思路及部分源码)》

  • 对第二个多边形做同样的处理。

《2D游戏中常见的碰撞检测算法思路(附详细思路及部分源码)》

  • 分别得到这两个多边形的投影,并检测这两段投影是否重叠

《2D游戏中常见的碰撞检测算法思路(附详细思路及部分源码)》

如果你发现了这两个投影到轴上的“阴影”有间隙,那么这两个图形一定没有相交。但如果没有间隙,那么它们则可能接触,你需要继续检测直到把两个多边形的每条边都检测完。如果你检测完每条边后,都没有发现任何间隙,那么它们是相互碰撞的。

如果你记录了哪个轴上的投影重叠值最小(以及重叠了多少),那么你就能用这个值来分开这两个图形

如果是圆的话,圆是没有任何的边,所以是没有明显的用于投影的轴。但它有一条“不是很明显的”的投影轴。这条轴就是途经圆心和多边形上离圆心最近的顶点的直线。

把圆投影到轴上,那你只用简单地把圆心投影上去,然后加上和减去半径就能得到投影长度

《2D游戏中常见的碰撞检测算法思路(附详细思路及部分源码)》

详细可参考凸多边形的碰撞检测

圆矩形与地图格子的碰撞

点取样法:可以按照地图格子对圆和矩形的包围盒进行点取样,转换成点的集合与地图格子的碰撞,然后参考点与地图格子的碰撞

矩形与矩形多边形的碰撞

矩形与矩形的碰撞可以对其四个顶点比较

function M.rectIntersectsRect(rect1, rect2)
return cc.rectIntersectsRect(rect1, rect2)
end
function cc.rectIntersectsRect( rect1, rect2 )
local intersect = not ( rect1.x > rect2.x + rect2.width or
rect1.x + rect1.width rect1.y > rect2.y + rect2.height or
rect1.y + rect1.height return intersect
end

也可以用分离轴算法可参考圆与矩形多边形的碰撞

多边形与多边形的碰撞

参考圆与矩形多边形的碰撞

  1. 到页首 &#x21a9;︎

  2. cc.pGetDistance是cocos2d-lua的库函数,用于计算两点之间的距离 &#x21a9;︎

  3. cc.rectContainsPoint是cocos2d-lua的库函数,用于判断点是否在矩形内 &#x21a9;︎


推荐阅读
  • 工作经验谈之-让百度地图API调用数据库内容 及详解
    这段时间,所在项目中要用到的一个模块,就是让数据库中的内容在百度地图上展现出来,如经纬度。主要实现以下几点功能:1.读取数据库中的经纬度值在百度上标注出来。2.点击标注弹出对应信息。3 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
  • 查找给定字符串的所有不同回文子字符串原文:https://www ... [详细]
  • 一维和二维数组的前缀和与差分 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 题目描述http:acm.nyist.netJudgeOnlineproblem.php?pid306Dr.Kong设计的机器人卡多非常爱玩,它常常偷偷跑出实验室,在某个游乐场 ... [详细]
author-avatar
贝贝2602932923
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有