1. 首页 > 知识

JS/HTML5游戏常用算法之碰撞检测包围盒检测算法详解凹多边?

JS/HTML5游戏常用算法之碰撞检测包围盒检测算法详解凹多边?

本文实例讲述了JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法。分享给大家供大家参考,具体如下:概述分离轴定理是一项用于检测碰撞的算法。其适用范围较广,涵盖检测圆与多边形,多边形与多边形的碰撞;缺点在于无法检测凹多边形的碰撞。本demo使用Js进行算法实现,HTML5 canvas进行渲染。
详细一、准备工作,熟悉分离轴定理 算法原理从根本上来讲,分离轴定理(以及其他碰撞算法)的用途就是去检测并判断两个图形之间是否有间隙。分离轴定理中用到的方法使算法本身显得十分独特。我所听到过分离轴定理的最好类比方式是这样的:假想你拿一个电筒从不同的角度照射到两个图形上,那么会有怎样的一系列的阴影投射到它们之后的墙壁上呢?如果你用这个方式从每一个角度上对这两个图形进行处理,并都找不到任何的间隙,那么这两个图形就一定接触。
如果你找到了一个间隙,那么这两个图形就显而易见地没有接触。从编程的角度来讲,从每个可能的角度上去检测会使处理变得十分密集。不过幸运的是,由于多边形的性质,你只需要检测其中几个关键的角度。你需要检测的角度数量就正是这个多边形的边数。也就是说,你所需检测的角度最大数量就是你要检测碰撞的两个多边形边数之和。
举个例子,两个五边形就需要检测10个角度。这是一个简易但比较啰嗦的方法,以下是基本的步骤:步骤一:从需要检测的多边形中取出一条边,并找出它的法向量(垂直于它的向量),这个向量将会是我们的一个“投影轴”。步骤二:循环获取第一个多边形的每个点,并将它们投影到这个轴上。
(记录这个多边形投影到轴上的最高和最低点)步骤三:对第二个多边形做同样的处理。步骤四:分别得到这两个多边形的投影,并检测这两段投影是否重叠。如果你发现了这两个投影到轴上的“阴影”有间隙,那么这两个图形一定没有相交。但如果没有间隙,那么它们则可能接触,你需要继续检测直到把两个多边形的每条边都检测完。
如果你检测完每条边后,都没有发现任何间隙,那么它们是相互碰撞的。这个算法基本就是如此的。顺带提一下,如果你记录了哪个轴上的投影重叠值最小(以及重叠了多少),那么你就能用这个值来分开这两个图形。那么如何处理圆呢?在分离轴定理中,检测圆与检测多边形相比,会有点点奇异,但仍然是可以实现的。
最值得注意的是,圆是没有任何的边,所以是没有明显的用于投影的轴。但它有一条“不是很明显的”的投影轴。这条轴就是途经圆心和多边形上离圆心最近的顶点的直线。在这以后就是按套路遍历另一个多边形的每条投影轴,并检测是否有投影重叠。噢,对了,万一你想知道如何把圆投影到轴上,那你只用简单地把圆心投影上去,然后加上和减去半径就能得到投影长度了。
二、完整实例:<DOCTYPE html><html lang="en"><head> <meta name="viewport" content="width=device-width, initial-scale=1。
0, maximum-scale=1。0, user-scalable=0"> <meta charset="UTF-8"> <title>盒包围碰撞算法-凸多边形分离轴检测算法</title> <style> #stage { border: 1px solid lightgray; } </style></head><body><h1>是否碰撞:<span class="hitTest">否</span></h1><canvas id="stage"></canvas></body><script> window。
onload = function () { var stage = document。querySelector('#stage'), ctx = stage。getContext('2d'); stage。width = 400; stage。
height = 400; var starPointArr = [];// 绘制五角星 function drawStar(ctx,r,R,x,y,rot,c){ ctx。beginPath(); for(var i =0;i<5;i++){ var startPosX = Math。
cos((18 + i*72 - rot)/180 * Math。PI )*R + x, startPosY = - Math。sin((18 + i*72 - rot)/180 * Math。PI)*R + y, endPosX = Math。
cos((54 + i*72 - rot)/180 * Math。PI )*r + x, endPosY = - Math。sin((54 + i*72 - rot)/180 * Math。PI)*r + y; ctx。lineTo(startPosX,startPosY); ctx。
lineTo(endPosX, endPosY); starPointArr。push(startPosX,startPosY,endPosX,endPosY); } ctx。closePath(); ctx。fillStyle = c; ctx。
lineWidth = 3; ctx。lineJoin = "round"; ctx。fill(); ctx。stroke(); } var polygonPointArr = [];// 绘制多边形 function drawpolygon(numSides,radius,x,y){ ctx。
beginPath(); for(i = 1;i<=numSides; i++){ var xPos = x+radius*Math。cos(2*Math。PI*i/numSides); var yPos = x+radius*Math。
sin(2*Math。PI*i/numSides); polygonPointArr。push(xPos,yPos); ctx。lineTo(xPos,yPos); } //创建完成 闭合路径 ctx。closePath(); ctx。lineWidth = 3; //线宽 ctx。
lineJoin = "round"; ctx。fillStyle = '#00f'; ctx。fill(); ctx。stroke(); } //两个向量的点积 function dotV2(v1,v2) { return v1。x*v2。
x+v1。y*v2。y; } //计算polyArr在轴线axis上的投影,polyArr是一系列点坐标的集合,数组表示 function calcProj(axis,polyArr) { var v = {"x":polyArr[0],"y":polyArr[1]}; var d,min,max; min = max = dotV2(axis,v);//计算投影轴与第一个坐标点的点积 for(var i=2;i<polyArr。
length-1;i+=2) { v。x=polyArr[i]; v。y=polyArr[i+1]; d = dotV2(axis,v);//计算v到投影轴的距离,遍历出最小和最大区间 min = (d<min)?d:min; max = (d>max)?d:max; } return [min,max]; } //计算同一个轴上线段的距离s1(min1,max1),s2(min2,max2),如果距离小于0则表示两线段有相交; function segDist(min1,max1,min2,max2) { if(min1<min2) { return min2-max1; } else { return min1-max2; } } //判断两个多边形是否相交碰撞,p1,p2用于保存多边形点的数组 function isCollide(p1,p2) { //定义法向量 var e = {"x":0,"y":0}; var p = p1,idx=0,len1=p1。
length,len2=p2。length,px,py;//p缓存形状p1的数据 for(var i=0,len = len1+len2;i<len-1;i+=2)//遍历所有坐标点,i+=2代表xy轴两个坐标点 { idx = i; //计算两个多边形每条边 if(i>len1) {//当p1遍历完毕后,p缓存形状p2的数据,从新遍历 p=p2; idx=(i-len1);//len2 } if(i===p。
length-2) {//p包含的点数据组成的最后一个坐标点 px=p[0]-p[idx];//首尾的x轴相连 py=p[1]-p[idx+1];//首尾的y轴相连 } else { px = p[idx+2]-p[idx];//递增的x轴相连 py = p[idx+3]-p[idx+1];//递减的y轴相连 } //得到边的法向量【垂直相交】,即投影轴 e。
x = -py; e。y = px; //计算两个多边形在法向量上的投影 var pp1 = calcProj(e,p1);//涵盖到投影轴的最小值与最大值 var pp2 = calcProj(e,p2); //计算两个线段在法向量上距离,如果大于0则可以退出,表示无相交 if(segDist(pp1[0],pp1[1],pp2[0],pp2[1])>0) { return false; } } return true; } document。
onkeydown = function (event) { var e = event || window。event || arguments。callee。caller。arguments[0]; //根据地图数组碰撞将测 switch (e。
keyCode) { case 37: console。log("Left"); if (starPosX > 0) { starPosX -= 2; } break; case 38: console。log("Top"); if (starPosY > 0) { starPosY -= 2; } break; case 39: console。
log("Right"); if (starPosX < stage。width) { starPosX += 2; } break; case 40: console。log("Bottom"); if (starPosY < stage。
height) { starPosY += 2; } break; default: return false; } }; var starPosX = stage。width/2,starPosY = stage。height/2; stage。
addEventListener('click', function (event) { var x = event。clientX - stage。getBoundingClientRect()。left; var y = event。clientY - stage。
getBoundingClientRect()。top; starPosX = x; starPosY = y; }); function update() { ctx。clearRect(0, 0, 400, 400); starPointArr = []; polygonPointArr = []; drawpolygon(7,50,300,300); drawStar(ctx,30,50,starPosX,starPosY,30,"yellow"); document。
querySelector('。hitTest')。innerHTML = "否"; var flag = isCollide(starPointArr, polygonPointArr); if (flag) { document。querySelector('。
hitTest')。innerHTML = "是"; } requestAnimationFrame(update); } update(); };</script></html>这里使用在线HTML/CSS/JavaScript代码运行工具:http://tools。
jb51。net/code/HtmlJsRun 测试上述代码运行结果如下:github地址:https://github。com/krapnikkk/JS-gameMathematics参考文章:http://www。demodashi。com/demo/10423。
html。

相关推荐

  • 北京房屋抵押贷款申请需要哪些条件和要求?

    北京房屋抵押贷款申请需要哪些条件和要求?

    条件,北京,申请办理,贷款,计算,在北京有套房,现在急需用钱,请问如何申请房屋抵押贷款?在北京申请办理房产抵押贷款对房产的要求:1.房屋的产权要明晰,符合国家规定的上市交易的条件,可进入房地产市场流通,未做任何其他抵押;2.房龄(从房屋竣工日起计算)与贷款年限相加不能超过40年;3.所抵押房屋未列入当地城市改造拆迁规划,并有房产部门、土地管理部门核发的房产证和土地证。房产抵押贷款对借款人的要求:1.年龄在18-60周岁的自然人(港澳台,内...

  • 住房公积金如何提取出来还房贷?

    住房公积金如何提取出来还房贷?

    本金,余额,贷款,房贷,计算,我购买了一套房子,商业贷款15年,请问我怎样才可以把我的住房公积金提取出来还房贷?需要什么手续呢?谢谢解答!有以下两种方法可以提取住房公积金,你可以参考一下:1、将公积金帐户内的余额全部提出来冲还贷款本金(帐户内需留有一定余额,各地规定不同),冲还本金后,贷款的本金减少,总利息也减少。月供或年限将重新计算:如果选择年限不变的,重新计算后月供将减少;如果选择月供不变的,还款年限将减少。2、提取公积金后与你的还贷...

  • 办理信用贷款,额度10万,分期3年,请利息怎么计算,具体是多

    办理信用贷款,额度10万,分期3年,请利息怎么计算,具体是多

    计算,办理,是多少,利息,贷款,本人在银行办理了10万块的信用贷款,分期为3年,请问利率是多少,利息怎么计算?具体请康我也不太清楚,我只办理过10万,两年的分期,所以,你可以根据我列出的24期分期,来推算估计一下你的36分期月供吧。以10万元分24期还款计算:分期手续费=100000*0.68%=680元;分期本金=100000/24=4166.66元;每月还款=4166.66+680=4846.66元。对了,我是在招行办理的,分24期的...

  • 请用纯公积金办理贷款的话,额度的上下限是多少?

    请用纯公积金办理贷款的话,额度的上下限是多少?

    额度,办理,购买,贷款,是多少,本人打算办理公积金贷款,请问公积金贷款中,对于额度的规定是怎么计算的?用纯公积金来办理公积金贷款的话,对于额度的计算是你所要购买的房子的价值来计算的,公积金贷款最高额度原则上按:1、房屋面积在90平方米商品房,公积金贷款额度不低于总价款的80%;2、在个贷率低于85%的城市,购买面积120平方米商品房,纯公积金贷款的额度按总房款的70%确定。3、此外,缴存职工家庭使用住房公积金贷款购买首套普通自住房,最低首...

  • 如果我在建设银行申请信用贷款,额度1万的话,分期1年的利

    如果我在建设银行申请信用贷款,额度1万的话,分期1年的利

    贷款,利息,信用,额度,期限,本人打算在建设银行申请信用贷款,额度一万且分期一年,请问利息怎么计算?据我所知,建行的信用贷款利息是按年度计算的。原来的年利率为7.2%,目前利率为6.6%。鉴于你贷了1万元,分期一年。因此,银行信用贷款的利息计算公式是:利息=贷款金额*1年利率。因为贷款期限最长只有12个月,所以贷款期限是1。如果贷款为5万,则按原始利率计算为50000×7.2%=3600;但根据利率,则为50000*6.6%=3300。如...

  • 请,如果在花旗银行办理个人消费贷款的话,额度是多少,利息

    请,如果在花旗银行办理个人消费贷款的话,额度是多少,利息

    贷款,利率,花旗银行,计算,六个月,花旗银行对于个人消费贷款利率规定和贷款额度是多少?根据我的了解,花旗银行的利率,相比于央行的同期利率是要低一些的,但是审批过程比较严格,而且手续也比较繁琐。花旗银行贷款年利率(%)六个月以内(含6个月)贷款利率为4.35%六个月至一年(含1年)贷款的利率为4.35%一至三年(含3年)贷款的利率为4.75%三至五年(含5年)贷款的利率为4.75%五年以上贷款的利率为4.9%以上便是我所了解到的内容,希望能...

  • 在兴业银行办理个人旅游贷款的话,利率是多少,利息如何计

    在兴业银行办理个人旅游贷款的话,利率是多少,利息如何计

    贷款,个人旅游,利率,计算,利息,本人刚把工作辞了,想要在兴业银行办理个人旅游贷款,出去好好放松一下,请问这种贷款利率是多少?根据我的了解,兴业银行对于个人旅游贷款的贷款执行利率由兴业银行地方分行规定。此外,兴业银行个人旅游贷款的贷款额的初始金额为1万元,最高不超过30万元。并且贷款额不超过贷款重复使用时的剩余信贷额度。而且你要注意,如果贷款在半年以内,还款将一次性支付。贷款期限为1年或更长的贷款将按月按利息支付或按月偿还本金和利息。所以...

  • 在银行办理了信用贷款的客服,如果想要提前还款的话,需要

    在银行办理了信用贷款的客服,如果想要提前还款的话,需要

    违约金,贷款,银行,计算,办理,哥们在银行办理了一笔信用贷款,数额比较大,利息比较高,想提前还上,请问违约金怎么计算的?老哥,这个问题我没法给你具体回答啊,因为不同银行的不同业务,对提前还款的惩罚方式各不一样,有的需要违约金,有的不需要违约金,比如说:华夏银行“易达金”规定贷款发放满三个月能在还款期未到之前即先行偿还贷款,还需缴纳剩余本金的3%为违约金。渣打银行的“现贷派”也规定贷款发放三个月后能在还款期未到之前即先行偿还贷款,需缴纳剩余...

  • 在浙江,家庭申请住房公积金贷款额度是多少?

    在浙江,家庭申请住房公积金贷款额度是多少?

    贷款,额度,账户,余额,是多少,我老婆公积金交了3年多,我一年还没满差几个月,现在想买房,请问能贷款多少?我们是浙江嘉兴的。一般规定,假如按照账户余额申请公积金贷款,申请额度为双方住房公积金账户余额之和的10倍,住房公积金账户余额不足2万的按2万计算。按照最高限额规定,使用本人住房公积金申请住房公积金贷款的,贷款最高限额40万元,同时使用配偶住房公积金申请住房公积金贷款的,贷款最高限额60万元,使用本人住房公积金申请住房公积金贷款,且申请...

  • 同事从银行贷款20万买房,分期十年,请利息如何计算,每月要

    同事从银行贷款20万买房,分期十年,请利息如何计算,每月要

    利息,计算,贷款,基准,金额,按揭20万用于买房,分期十年的话,现行的利率政策,月供是多少?如果你是第一次买房子的话,在银行贷款20万,10年还清,按6.55%人民银行基准贷款利率,相当于本金和利息的还款,本金和利息的金额每月还款2276.05元,10年的本金和总金额273126.11元的利息还款。(1)贷款利率与贷款目的、贷款性质、贷款期限、贷款政策和贷款银行有关。国家规定基准利率,银行根据各种因素确定差别贷款利率,即按基准利率上浮或下...

  • 在成都办理私人贷款的话,会计算复利吗,利率多少,利息怎么

    在成都办理私人贷款的话,会计算复利吗,利率多少,利息怎么

    计算,贷款,复利,利息,利率,朋友在成都私人借贷机构办理了一笔贷款,请问会计算复利吗,利息是怎么计算的?这一点你可以放心,,因为民间贷款的复利计算,是违法的,法律有具体规定如下;1,民间借贷不能计算复利。2、如果私人贷款是成熟的,借款人将贷款凭证补发计算贷款的本金和利息的总和。并且最高法院关于民间借贷的规定第二十八,借款人和借款人使用贷款本金和利息后的贷款本金和更换证书。如果初始利率不超过年利率的24%,信用证的发行可以被定义为迟交贷款的...

  • 在农村信用社办理抵押贷款的话,需要交纳多少利息,如何计

    在农村信用社办理抵押贷款的话,需要交纳多少利息,如何计

    计算,利息,利率,贷款,信用社,本人打算在本地农信社办理抵押贷款,请问利息怎么计算?一般情况下,如果贷款期限是1-3年,利率是4.5%。此外,农民贷款应达到百分之八十,每月8.1%,也就是说,10000元和81元。5万年应该是9720元。因为今天的利息计算可能与实际天数略有不同,大致相同。贷款到期后,第二天到期后,逾期利率为原来利率加上12.15的百分之五十,那么你每月的贷款利息将达到607.5。不过,以上我所计算的数据仅供参考,具体情况...