[wm_tips]概念: 碰撞,指的是窗口中两张图片是否有交集。如果有交集,则认为两张图片发生碰撞。[/wm_tips]
一 、假想圆
因为图片形状各异,判断两张图片是否有交集,似乎不太好做,所以为了判断方便, 我们把每张图片都看做一个圆,这个圆,就是我们通常所说的假想圆。
二、碰撞距离
有了假想圆,在判断碰撞时就容易多了,我们只需要判断两个假想圆是否有交集就可以了。
通过上图可以看出,当A、B两张图片中心点距离小于A、B两个假想圆的半径之和时
我们就认为两张图片发生了碰撞。
可问题是:两个假想圆的半径是固定的,但AB中心点的距离如何获得呢?
三、利用勾股定理计算距离
如果我们想要获得AB两个中心点距离,那么必须要用上勾股定理了。
[wm_tips]勾股定理:在直角三角形中,两条直角边的平方和,等于斜边的平方[/wm_tips]
- 虽然现在c边的距离我们不知道,但a边和b边的距离我们是能求出来的
- a 边的距离长度 = 子弹的y坐标 – 飞机的y坐标
- b 边的距离长度 = 子弹的x坐标 – 飞机的x坐标
- 所以通过勾股定理,我们同样可以求出 c 边长度的平方值
计算公式如下
- 如果两元素距离 小于等于 碰撞距离,则视为两元素发生碰撞
- 如果两元素距离的平方值 小于等于 碰撞距离的平方值,则视为两元素发生碰撞
四、碰撞判断步骤总结
- 根据元素宽高特点划定假想圆,元素锚点为中心,作为假想圆的圆心位置
- 计算碰撞距离:两个元素假想圆半径之和,如果两元素间距小于或等于碰撞距离,则视为发生碰撞
- 计算两个元素x轴距离与y轴距离(距离既边长)
- 计算两个元素间距:根据勾股定理,得出x轴距离平方+y轴距离平方==间距平方
- 如果间距的平方<=碰撞距离的平方(间距<=碰撞距离,由于得到的间距是平方值,所以碰撞距离 也要用平方值)
五、多元素碰撞
示例代码
var app = new PIXI.Application(500,700); document.body.appendChild( app.view ); //添加图片元素(飞机) var plane = new PIXI.Sprite.fromImage("img/plane.png"); plane.x = 250; plane.y = 650; //设置飞机图片锚点为中心 plane.anchor.set(0.5,0.5); app.stage.addChild( plane ); //定义变量,敌机计时器 var escount = 0; //定义变量,子弹计时器 var bscount = 0; //定义数组用于存储敌机元素 var es = []; //定义数组用于存储子弹元素 var bs = []; //自定义帧频函数 function animate(){ //如果帧频函数执行次数等于60,证明时间过了1秒 if(escount == 60){ //添加图片元素(敌机图片) var enemy = new PIXI.Sprite.fromImage("img/enemy.png"); //Math.random() * n 获取0~n-1之间的随机数 enemy.x = Math.random() *(500 - 104 +1); //将创建的每个敌机元素添加到数组中 es.push( enemy ); app.stage.addChild( enemy ); //重置count变量,重新计时 escount=0; } //如果帧频函数执行次数等于120,证明时间过了2秒 if(bscount == 120 ){ //添加图片元素(子弹图片) var bullet = new PIXI.Sprite.fromImage("img/bullet.png"); //位置与飞机一致 bullet.x = plane.x; bullet.y = plane.y; //设置锚点为中心 bullet.anchor.set(0.5,0.5); //添加到数组中 bs.push( bullet ); //添加到应用窗口 app.stage.addChild( bullet ); //计数器归零 bscount = 0; } //遍历数组获取每颗子弹元素,添加动画效果 for(var i=0; i<bs.length; i++){ //子弹向上移动 bs[i].y-=5; //如果敌机移出边界,从数组中移除该元素 if(bs[i].y<=0){ //将子弹从应用窗口中移除 app.stage.removeChild( bs[i] ); //将子弹从数组中移除 bs.splice(i,1); } } //遍历数组获取每架敌机元素,添加动画效果 for(var i=0; i<es.length; i++){ //敌机向下移动 es[i].y+=3; //如果敌机移出边界,从数组中移除该元素 if(es[i].y>=700){ //将敌机从应用窗口中移除 app.stage.removeChild( es[i] ); //将敌机从数组中移除 es.splice(i,1); } } //帧频函数执行一次,计数变量+1 escount++; bscount++; } //添加帧频函数 app.ticker.add( animate );
敌机数组如下图所示
子弹数组如下图所示
多飞机与多子弹碰撞,必须用每一个子弹元素与每一个飞机分别做碰撞判断
原理如下所示
核心代码
//遍历bs数组获取每颗子弹 for(var i = 0; i<bs.length; i++){ //获取子弹元素 var bullet = bs[i]; //与每架敌机 碰撞判断 //遍历es数组获取每架敌机 for(var j=0; j<es.length; j++){ //获取敌机元素 var enemy = es[j]; //判断 bullet 是否与 enemy 发生碰撞 //1、根据元素宽高及特点划定假想圆 //敌机元素宽度 104 ,假想圆半径 52 //子弹元素宽度 50 ,假想圆半径 25 //2、计算碰撞距离:两个元素假想圆半径之和 var pos = 52+25; //3、计算元素x,y间距 //获取x轴间距(边长) var xl = bullet.x - enemy.x; //获取y轴间距(边长) var yl = bullet.y - enemy.y; //4、计算两元素间距 //xl、yl等于两个直角边的边长,根据勾股定理计算 //xl*xl + yl*yl 等于 两个元素 间距的平方 //5、如果两元素间距平方<=碰撞距离平方,则视为两元素发生碰撞 if(xl*xl + yl*yl <= pos*pos){ //从应用窗口中移除子弹元素 app.stage.removeChild( bullet ); //从数中移除子弹元素 bs.splice(i,1); //从应用窗口中移除敌机元素 app.stage.removeChild( enemy ); //从数中移除敌机元素 es.splice(j,1); } } }
获取/修改图层编号
- 页面中每个图片都有自己所对应的图层以及编号,编号从0开始,编号越大图层越高
- 可以通过修改图层编号设置图片的图层
- 通过修改图层,可以让子弹一直处于飞机图层的下级
获取图层编号
app.stage.getChildIndex(classify3);
设置图层编号
//将元素的图层设置为指定编号级别
app.stage.setChildIndex(元素,图层编号);
[wm_warn]注意:如果两元素图层一致,后添加的元素会置于制定编号位置,先添加的元素会自动提高一级。[/wm_warn]