目录

 

前言

一、碰撞

2.1 、假想圆

2.2、碰撞距离

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

2.4、碰撞判断步骤总结

2.5 图层编号

二、定时动画

三、实战

例题一:飞机增益道具

例题一代码:

例题二:子弹碰撞

例题二代码:

总结


前言

为了提高作者的代码编辑水品,作者在使用博客的时候使用的集成工具为 HBuilderX。

下文所有截图使用此集成工具,读者随意。

此系列文章需要:HTML ,JavaScript 基础知识

操作系统:

版本    Windows 11 家庭中文版
版本    23H2
安装日期    ‎2024/‎5/‎28
操作系统版本    22631.3593
体验    Windows Feature Experience Pack 1000.22700.1003.0


一、碰撞

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

如下图所示:

2.1 、假想圆

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

如下图:

上图中,飞机图片和子弹图片都有个红色的圆,这个圆就是假想圆。

2.2、碰撞距离

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

通过上图可以看出,当A B两张图片中心点距离小于A B两个假想圆的半径之和时 我们就认为两张图片发生了碰撞。

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

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

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

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

1  虽然现在c边的距离我们不知道,但a边和b边的距离我们是能求出来的

2  a 边的距离长度   = 子弹的y坐标 飞机的y坐标

3  b 边的距离长度 =   子弹的x坐标 飞机的x坐标

4  所以通过勾股定理,我们同样可以求出 c 长度的平方值

计算公式如下

a2+b2==c2

1  如果两元素距离   小于等于 碰撞距离,则视为两元素发生碰撞

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

如下图:

示例 :飞机被子弹触碰后消失

运行效果

如下图所示

示例代码

		<script type="text/javascript">
			
			var app=new PIXI.Application(500,700);
			
			document.body.appendChild(app.view);																							

			function add(img,x,y){
				//创建图片元素
				var a=new PIXI.Sprite.fromImage(img);
				//将元素添加到页面中
				app.stage.addChild(a);
				//调整位置
				a.x=x
				a.y=y 
				
				//对当前元素直接开启监听
				a.interactive=true;
				
				return a;
			}


			var bg = add("img/bg.jpg",0,0); 
			var enemy=add("img/enemy_02.png",150,100);
			enemy.anchor.set(0.5,0.5)
			var bullet=add("img/bullet_1.png",150,350)
			bullet.anchor.set(0.5,0.5)


			//自定义帧频函数,子弹向上移动
			function animate(){
				//如果子弹与飞机接触则移除飞机元素 
				//计算子弹与飞机y轴距离长度
				var yl = bullet.y - enemy.y
				//计算子弹与飞机x轴距离长度
				var xl = bullet.x - enemy.x
				 //pos  :触碰距离
		      	var pos = 52+25;
		
		      
				if( (yl*yl) + (xl*xl) < pos*pos ){           
					//从应用窗口中移除敌机元素
					app.stage.removeChild( enemy )      
					}
				//子弹向上移动
				bullet.y -= 1;

		 	}
			//添加帧频函数
			app.ticker.add( animate );
 

		
					
					
		</script>
		

2.4、碰撞判断步骤总结

 1、根据元素宽高特点划定假想圆 ,元素锚点为中心,作为假想圆的圆心位置

 2、计算碰撞距离:两个元素假想圆半径之和,如果两元素间距小于或等于碰撞距离,则视为发生碰撞 3  3、计算两个元素x轴距离与y轴距离(距离既边长)

4、计算两个元素间距:根据勾股定理,得出x轴距离平方+y轴距离平方==间距平方

5、如果间距的平方<=碰撞距离的平方(间距<=碰撞距离, 由于得到的间距是平方值,所以碰撞距离 也要用平方值)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

A图片假想圆半径:A图片宽高大约为80像素,那么假想圆的半径约为40像素 B图片假想圆半径:B图片宽高大约为40像素,那么假想圆的半径约为20像素 通过以上得出,碰撞距离为:AB边的距离 < 60,这时我们就认为发生碰撞

计算x轴距(边长) :A图片x轴坐标150,B图片x轴坐标180,B.x-A.x 就是两个元素x轴距 计算y轴距(边长) :A图片y轴坐标50,B图片x轴坐标170,B.y-A.y 就是两个元素y轴距  通过以上得出,x轴距为30,y轴距为120(轴距即边长)

根据勾股定理求出斜边长度的平方,如果斜边长度小于碰撞距离的平方此时发生碰撞 30与120是两个直角边长度,两个直角边长度的平方和等于斜边长度的平方

计算方式: (30*30+120*120) < 60*60 两个元素发生碰撞

可以使用Math.sqrt( );开方

计算方式:Math.sqrt(30*30+120*120) 60

2.5 图层编号

获取/修改图层编号

页面中每个图片都有自己所对应的图层以及编号,编号从0开始,编号越大图层越高 可以通过修改图层编号设置图片的图层

通过修改图层,可以让子弹一直处于飞机图层的下级

获取图层编号

1  app.stage.getChildIndex(classify3);

设置图层编号

1  //将元素的图层设置为指定编号级别

2  app.stage.setChildIndex(元素 ,图层编号);

注意:如果两元素图层一致,后添加的元素会置于制定编号位置,先添加的元素会自动提高一级。


二、定时动画

概念:让元素按照一定时间间隔变化

实现方式 帧频函数每秒执行60次,可以自定义计数变量,当帧频开始执行时计数变量+1 当计数变量的值为60时,函数执行了60次,时间过了一秒。

			//定时器
			var count = 1;
			function animate(){
				//判断每60次执行一次
				if(count == 60){
				var enemy1 = add("img/enemy_02.png",Math.random()*395,Math.random()*625);
				count = 0;
				}
			//定时器增加时间
			count++;
			}
			app.ticker.add(animate);

count的值变为60,帧频函数执行了60次,证明时间过去了一秒。

count的值变为60后,执行一次动画效果并将count的值重置,重新计数


三、实战

例题一:飞机增益道具

  • 1. 创建一个名为 app 的应用,宽:500,高:768
  • 2.利用碰撞判断,判断飞机是否与增益道具发生碰撞,如果发生碰撞则提高飞机子弹发射速率

示范图:

例题一代码:

		<script type="text/javascript">
			
			var app=new PIXI.Application(500,768);
			
			document.body.appendChild(app.view);																							

			function add(img,x,y){
				//创建图片元素
				var a=new PIXI.Sprite.fromImage(img);
				//将元素添加到页面中
				app.stage.addChild(a);
				//调整位置
				a.x=x
				a.y=y 
				
				//对当前元素直接开启监听
				a.interactive=true;
				
				return a;
			}


			var bg = add("img/bg.jpg",0,0)
			var plane=add("img/plane.png",250,450)
			plane.anchor.set(0.5,0.5)

			


			//记录帧频函数执行次数(计数器)
			var count = 0
			//记录帧频函数执行次数(计数器2)
			var count2 = 0
			//创建存储子弹元素的数组
			var bs =  [];
			//创建存储exp元素的数组
			var es = [];
			//定义变量控制每等级生成子弹的时间
			var ct = [60,50,40,30,20,15,5,3,1];
			//飞机等级,-1用作下标获取对应生成子弹的时间   
			var level = 1;
			//自定义帧频函数【核心代码】
			//每秒生成一颗子弹,让子弹向上移动
			//等级显示
			var dengji = new PIXI.Text("等级:"+level)
			dengji.style.fill = "#00000"
			app.stage.addChild(dengji)
			dengji.x = 350
			dengji.y = 10



			bg.on("mousemove" , planeMove );
			//战机移动函数
			function planeMove( event ){
				var pos = event.data.getLocalPosition( app.stage );
				plane.x = pos.x;
				plane.y = pos.y;
				bullet.x = pos.x;
				bullet.y = pos.y;
			}



			function animate(){ 
				//每3秒生成一个exp元素
				if(count2 == 180){
					// //添加图片元素(exp图标)
					var xs=Math.random()*(500- 79 +1)
					var exp = add("img/exp.png",xs,0);
			        //设置子弹图片锚点为中心
					exp.anchor.set(0.5,0.5);         
					//在bs数组中添加子弹元素
					es.push( exp );           
					//计数器归零
					count2 = 0; 

				}


				//每秒生成一颗子弹
				if(count == ct[level-1]){           
					//添加图片元素(子弹)
					var bullet = add("img/bullet_1.png",plane.x,plane.y);
					//设置子弹图片锚点为中心
					bullet.anchor.set(0.5,0.5);	         
					//在bs数组中添加子弹元素
					bs.push( bullet );          
					//计数器归零
					count = 0;
				      
				}

			    //所有exp元素向下移动
				for(var i=0; i<es.length; i++){
					es[i].y += 3;
					//如果exp与飞机发生碰撞
					//飞机图片宽度:117
					//exp图片宽度:79
					//碰撞距离为:98((117/2)  + (70/2))
					var pos = 98;
					//如果exp元素距离与飞机距离低于碰撞距离则发生碰撞
					//获取 x 轴间距长度
					var xl =  plane.x - es[i].x;              
					//获取 y 轴间距长度
					var yl =  plane.y - es[i].y;              
					//碰撞判断
					if(Math.sqrt(xl*xl+yl*yl)<=pos){                  
						//提升飞机等级 ,并限制上限
						if(level<=8)
						level++;
						//等级更新
						dengji.text = "等级:"+level;
						app.stage.addChild(dengji)	
									                  
						//计数器归零
						count  =  0;
						//经验值图片消失
						es[i].y = 768;
						console.log(  ct +"   "+level);               
					}

					//如果exp超出窗口,从数组中移除元素,从应用窗口中移除元素
					if( es[i].y>=768 ){
						//从应用窗口中移除元素
						app.stage.removeChild( es[i] );                   //从数组中移除元素
					
						es.splice(i,1);              
					}
					

				}

				
				//子弹
				for (var i = 0; i < bs.length; i++) {
					var en = bs[i];
					en.y -= 3;
					//判断子弹是否超出边界
					if(en.y < 0){
						bs.splice(i,1);
						//将元素从应用窗口中移除
						app.stage.removeChild(en);
					}
				}




					//帧频函数执行一次,计数器+1
					count++;
					count2++;

			}

				//添加帧频函数
				app.ticker.add( animate )



					
					
					
		</script>

运行结果:

例题二:子弹碰撞

1.创建添加应用,宽500,高700,添加相对应元素

2.设置飞机位置锚点,飞机跟随鼠标移动

3.定义变量,控制帧频函数执行频率

4.在逐帧函数中每秒钟创建敌机元素,将创建好的添加到数组中

5.编写子弹与敌机的碰撞逻辑。

示范图:

例题二代码:

		<script type="text/javascript">
			//创建窗口
			var app = new PIXI.Application(500,700);
			document.body.appendChild(app.view);
			function add(img,x,y){
				//减少程序冗余度,快速添加图片及位置
				var a = new PIXI.Sprite.fromImage(img);
				app.stage.addChild(a);
				a.x=x;
				a.y=y;
				a.interactive = true;//打开对变量的监听
				return a;
				}
			//添加元素
			var bg = add("img/bg_01.png",0,0);
			var bg01 = add("img/bg_01.png",0,-760);
			var plane = add("img/plane_blue_01.png",200,200);
			plane.anchor.set(0.5,0.5);
			bg.on("mousemove" , planeMove );
			//战机移动函数
			function planeMove( event ){
				var pos = event.data.getLocalPosition( app.stage );
				plane.x = pos.x;
				plane.y = pos.y;
				bullet.x = pos.x;
				bullet.y = pos.y;
			}
			//定时器
			var count = 0
			var escount = 0
			//存储敌机的数组
			var eslist = []
			//存储子弹的数组
			var bulletlist = [];
			
			function bulletmove(){
				//背景移动
				bg.y += 1
				if(bg.y == 760){
					bg.y = 0
				}
				bg01.y = bg.y-760
				//发射子弹速度
				if(count == 30){
					var bullet = add("img/bullet_1.png",plane.x,plane.y - 30);
					bullet.anchor.set(0.5,0.5);
					//将生成的子弹都存储到数组中。
					bulletlist.push(bullet);
					count = 0;
				}
				//60为一秒,每一秒随机生成一个x为0的敌机
				if(escount == 60){
					var enemy = add("img/enemy_02.png",Math.random()*450,0);
					enemy.anchor.set(0.5,0.5);
					eslist.push(enemy);
					escount = 0;
				}
				//敌机
				for (var ii = 0; ii < eslist.length; ii++) {
					var enn = eslist[ii];
					enn.y += 3
					//判断敌机是否超出边界
					if(enn.y > 700){
						eslist.splice(ii,1);
						app.stage.removeChild(enn);
					}
				}
				//子弹
				for (var i = 0; i < bulletlist.length; i++) {
					var en = bulletlist[i];
					en.y -= 3;
					//判断子弹是否超出边界
					if(en.y < 0){
						bulletlist.splice(i,1);
						//将元素从应用窗口中移除
						app.stage.removeChild(en);
					}
				}
				count += 1;
				escount += 1;
				//判断子弹与敌机是否相撞
				var pos = 60
				//遍历子弹列表
				for (var i = 0; i < bulletlist.length; i++) {
					//遍历敌机列表
					for (var j = 0; j < eslist.length; j++) {
						//x,y轴与子弹的距离
						var y1 = bulletlist[i].y - eslist[j].y
						var x1 = bulletlist[i].x - eslist[j].x
						//判断是否小于概念⚪半径之和
						if(y1*y1+x1*x1 < pos*pos){
							//发生碰撞,移除子弹元素,移除列表中子弹元素
							app.stage.removeChild(bulletlist[i])
							bulletlist.splice(i,1);
							app.stage.removeChild(eslist[j])
							eslist.splice(j,1);
						break
						}
					}
				}
			}
			
			
			
			app.ticker.add(bulletmove);
			
		</script>

运行结果:

本次文章所用到的图像以及源码:

https://download.csdn.net/download/qq_56376552/89427360


总结

本文 碰撞检测与定时动画 源码 就此结束,

如有错误或者网址更新,步骤更改,代码错误欢迎私信作者进行更正,

感谢您的观看。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐