多边形碰撞 -- SAT方法
检测凸多边形碰撞的一种简单的方法是SAT(Separating Axis Theorem),即分离轴定理。
原理:将多边形投影到一条向量上,看这两个多边形的投影是否重叠。如果不重叠,则认为这两个多边形是分离的,否则找下一条向量来继续投影。我们不需要比较很多条向量,因为已经在数学上证明,多边形每条边的垂直向量就是我们需要的向量。
1.AABB
让我们首先以AABB开始(AABB是一种两边分别平行于X-Y轴的矩形)
判断两个AABB是否碰撞,我们只需要投影两次,分别是投影在平行于X轴和Y轴的向量上
由上图可以看见,因为在Y轴方向的投影是分离的,因此可以直接得出结论,即这两个AABB是分离的。
function AABBvsAABB(aabb1, aabb2) {
//check X axis
if(aabb1.xMin > aabb2.xMax)
return false;
if(aabb1.xMax < aabb2.xMin)
return false;
//check Y axis
if(aabb1.yMin > aabb2.yMax)
return false;
if(aabb1.yMax < aabb2.yMin)
return false; return true;
}
效果:---点击运行---
(点击产生AABB,碰撞的变红,否则变黄)
2.圆
圆的碰撞检测也能用SAT,就是要把两个圆投影在两个圆心连线的向量上。比较半径和与圆心距离,如果半径和大于圆心距离则碰撞。
代码:
注:通常为了优化,都是用平方而不是开方(sqrt好慢的)
function CircleVsCircle(c1, c2) {
var xSqr = c1.centerX - c2.centerX;
xSqr *= xSqr;
var ySqr = c1.centerY - c2.centerY;
ySqr *= ySqr;
//get the distance^2
var distanceSqr = xSqr + ySqr; var radiusSum = c1.radius + c2.radius; if(distanceSqr <= radiusSum*radiusSum)
return true;
else
return false;
}
效果:---点击运行---
(点击产生圆)
3.多边形
(1)找出两个多边形所有边的垂直向量;
(2)将两个多边形投影到垂直向量上,判断投影是否相交,如果不相交则两个多边形不相交,否则选下一条垂直向量继续进行投影判断。
代码:
function PolyVsPoly(p1, p2) {
//check the normal in p1
for(var i = 0; i < p1.points.length-1; i++) {
var edge = Minus(p1.points[i], p1.points[i+1]);
var normal = Normal(edge); var isOverlap = CheckCollide(normal, p1, p2);
if(!isOverlap)
return false;
} //check normal in p2
for(var i = 0; i < p2.points.length-1; i++) {
var edge = Minus(p2.points[i], p2.points[i+1]);
var normal = Normal(edge); var isOverlap = CheckCollide(normal, p1, p2);
if(!isOverlap)
return false;
} return true;
} function CheckCollide(axis, p1, p2) {
var min1 = Dot(p1.points[0], axis);
var max1 = Dot(p1.points[0], axis);
for(var k = 1; k < p1.points.length; k++) {
var v = Dot(p1.points[k], axis);
if(v > max1)
max1 = v;
if(v < min1)
min1 = v;
} var min2 = Dot(p2.points[0], axis);
var max2 = Dot(p2.points[0], axis);
for(var k = 1; k < p2.points.length; k++) {
var v = Dot(p2.points[k], axis);
if(v > max2)
max2 = v;
if(v < min2)
min2 = v;
} if(!IsOverlap(min1, max1, min2, max2))
return false; return true;
}
效果:---点击运行---
(使用方向键来移动,碰撞的变红,否则变黄)
4.圆与多边形
(1)找出多边形每条边的垂直向量,多边形最接近圆心的点到圆形的直线的垂直向量
(2)将圆和多边形投影到垂直向量上,再进行判断。
(其实和多边形之间的碰撞很像,这里就不浪费篇幅了)
总结:
SAT很简单,就是投影 + 重叠判断。
SAT只适用于凸体,毕竟凹体中间空缺的部分在投影后信息就消失了。
一些关于SAT的网站:
多边形碰撞 -- SAT方法的更多相关文章
- 解决Hash碰撞冲突方法总结
Hash碰撞冲突 我们知道,对象Hash的前提是实现equals()和hashCode()两个方法,那么HashCode()的作用就是保证对象返回唯一hash值,但当两个对象计算值一样时,这就发生了碰 ...
- 2D多边形碰撞器优化器
http://www.unity蛮牛.com/thread-19827-1-1.html http://pan.baidu.com/s/1qW2mWS8 Asset Store Link: http: ...
- H5游戏开发之多边形碰撞检测
2D多边形碰撞检测介绍这是一篇论证如何在2D动作游戏中执行碰撞检测的文章(Mario,宇宙入侵者等),为了保证它的高效性和精确性,碰撞检测是以多边形为基础的,而不是以sprite为基础.这是两种不同的 ...
- [Unity2D]Box Collider 2D盒子碰撞器
盒子碰撞器(BoxCollider2D)是Unity2D中常用的碰撞器,所有为碰撞器,顾名思义,就是用于检测物体之间的碰撞情况的,Unity2D里面除了BoxCollider2D碰撞器之外还集成Box ...
- cocos 碰撞系统
前面的话 本文将简要介绍 Cocos Creator 中的碰撞系统,Cocos Creator 内置了一个简单易用的碰撞检测系统,支持圆形.矩形以及多边形相互间的碰撞检测 编辑碰撞组件 当添加了一个碰 ...
- 结合谷歌地图多边形(polygon)与Sql Server 2008的空间数据类型计算某个点是否在多边形内的注意事项
首先在利用 GEOGRAPHY::STPolyFromText(@GeoStr, 4326) 这样的函数把字符串转换为Geography类型时,字符串里经纬度的顺序是 “经度[空格]纬度”,即“lon ...
- HDOJ(1115)多边形重心
Lifting the Stone http://acm.hdu.edu.cn/showproblem.php?pid=1115 题目描述:输入n个顶点(整数),求它们围成的多边形的重心. 算法:以一 ...
- unity触发器和碰撞器
Unity中检测碰撞的方法有两种,一种是触发器一种是碰撞器,现在我来解释一下两种的区别. 触发器:有三种方法,分别是OnTriggerEnter,OnTriggerStay,OnTriggerExit ...
- iOS7 UIKit动力学-碰撞特性UICollisionBehavior 下
上文讲到了为window加一个边界.实现碰撞的效果,接下来我们将提到一个托付方法: - (void)collisionBehavior:(UICollisionBehavior *)behavior ...
随机推荐
- PHP判断文件或者目录是否可写
在PHP中,可用is_writable()函数来判断一个 文件/目录 是否可写,详情如下: 参考 is_writable (PHP 4, PHP 5) is_writable — 判断给定的文件名是否 ...
- Swift3.0P1 语法指南——控制流
原档:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programmi ...
- js parseInt 显示0
parseInt 有第二个参数, 就是进制参数 parseInt("08", 10); //表示这个数字是十进制的就不会出错了.
- log4net 运行时改变日志级别
((log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository()).Root.Level = Level.Debug; ((log ...
- libevent在windows平台下通过vs进行编译
1.vs中新建一个静态库项目 2.配置头文件目录,将./compat../include../WIN32-Code三个目录添加到文件目录中 3.用记事本打开Makefile.nmake文件,可以看到里 ...
- 总是有一个程序的bug没找到
算法训练 Lift and Throw 时间限制:3.0s 内存限制:256.0MB 问题描述 给定一条标有整点(1, 2, 3, ...)的射线. 定义两个点之间的距离为其下标之 ...
- 使用VS2010编译64的Geos库
Geos库在cmake中总是报错,所以我决定试试nmake编译64位的库.现将编译过程记录如下: 1.下载Geos,我下的是最新版3.5.0,地址在 http://trac.osgeo.org/geo ...
- poj 1651 Multiplication Puzzle
题目链接:http://poj.org/problem?id=1651 思路:除了头尾两个数不能取之外,要求把所有的数取完,每取一个数都要花费这个数与相邻两个数乘积的代价,需要这个代价是最小的 用dp ...
- pm2无法自动重启
在服务器上有个上传文件的服务,之前是pm2启动,每当有文件上传会自动重启 现在为了应对服务器宕机,我把启动脚本放在了另一文件夹内,所以就无法自动重启, 原文在 http://pm2.keymetric ...
- JDK常用工具集——jps
该命令的作用是罗列出目标系统(target system)中所有具有访问权限到的Java进程. 一.命令简介: jps [option] [hostid] 二.参数说明: option ...