Chap14_碰撞的判断及利用勾股定理计算出距离

[wm_tips]概念: 碰撞,指的是窗口中两张图片是否有交集。如果有交集,则认为两张图片发生碰撞。[/wm_tips]

一 、假想圆

因为图片形状各异,判断两张图片是否有交集,似乎不太好做,所以为了判断方便, 我们把每张图片都看做一个圆,这个圆,就是我们通常所说的假想圆。

二、碰撞距离

有了假想圆,在判断碰撞时就容易多了,我们只需要判断两个假想圆是否有交集就可以了。

通过上图可以看出,当A、B两张图片中心点距离小于A、B两个假想圆的半径之和时

我们就认为两张图片发生了碰撞。

可问题是:两个假想圆的半径是固定的,但AB中心点的距离如何获得呢?

三、利用勾股定理计算距离

如果我们想要获得AB两个中心点距离,那么必须要用上勾股定理了。

[wm_tips]勾股定理:在直角三角形中,两条直角边的平方和,等于斜边的平方[/wm_tips]

  • 虽然现在c边的距离我们不知道,但a边和b边的距离我们是能求出来的
  • a 边的距离长度 = 子弹的y坐标 – 飞机的y坐标
  • b 边的距离长度 = 子弹的x坐标 – 飞机的x坐标
  • 所以通过勾股定理,我们同样可以求出 c 边长度的平方值

计算公式如下

  • 如果两元素距离 小于等于 碰撞距离,则视为两元素发生碰撞
  • 如果两元素距离的平方值 小于等于 碰撞距离的平方值,则视为两元素发生碰撞

四、碰撞判断步骤总结

  1. 根据元素宽高特点划定假想圆,元素锚点为中心,作为假想圆的圆心位置
  2. 计算碰撞距离:两个元素假想圆半径之和,如果两元素间距小于或等于碰撞距离,则视为发生碰撞
  3. 计算两个元素x轴距离与y轴距离(距离既边长)
  4. 计算两个元素间距:根据勾股定理,得出x轴距离平方+y轴距离平方==间距平方
  5. 如果间距的平方<=碰撞距离的平方(间距<=碰撞距离,由于得到的间距是平方值,所以碰撞距离 也要用平方值)

五、多元素碰撞

示例代码

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]

发表评论