一、第一步:创建地图
分析:创建的地图,要制造飞机一直向上飞行的效果,则要背景无缝循环向下轮播,和之前的无缝轮播一直,只是改变的是
top
值;
Html
代码 :
<
div
class=
“map”
>
<
div
class=
“bgmap”
></
div
>
<
div
class=
“bgmap”
></
div
>
</
div
>
封装地图无缝轮播方法:
/*创建地图 地图移动*/
var
map
=
document
.
getElementsByClassName
(
“map”
)[
0
];
(
function
(){
//(function(){})();即自调用函数function(){}
var
bgmap
=
document
.
getElementsByClassName
(
“bgmap”
);
//设置背景图片初始top值
bgmap
[
0
].style.top
=
“-630px”
;
bgmap
[
1
].style.top
=
“0px”
;
//封装背景图片由上自下移动事件
function
bgmove
(){
for
(
var
i
=
0
;
i
<
bgmap
.length;
i
++
){
var
Top
=
parseInt
(
bgmap
[
i
].style.top);
Top
++
;
if
(
Top
>=
630
){
Top
=-
630
;
}
bgmap
[
i
].style.top
=
Top
+
“px”
;
}
}
setInterval
(
bgmove
,
30
);
})();
二、创建用户飞机,使用封装类的方法
分析:
1.
飞机用图片表示,故在构造飞机创建方法是需创建
dom
元素
img;
2.
另外需获取设置用户的
left
,
top
值,根据鼠标移动事件改变用户飞机的
left top
值,让其跟随鼠标移动,鼠标移动事件中
x,y
值的获取与之前放大镜中覆盖层的鼠标移动事件一致,都需获取鼠标坐标减去偏移量以及自身宽高的一半
注意:
鼠标移动事件是创建给跟随对象的上一元素的,即这里创建给地图;
/*创建用户飞机 封装用户类*/
var
user
;
//实例化的全局变量
function
User
(){
this
.
width
=
60
;
this
.
height
=
70
;
this
.
position
=
“absolute”
;
this
.
userf
=null
;
this
.
src
=
“./image/14.gif”
;
this
.
x
;
this
.
y
;
//构造创建用户飞机的方法
this
.
createUser
=function
(){
if
(
this
.
userf
==null
){
this
.
userf
=
document
.
createElement
(
“img”
);
this
.
userf
.style.width
=this
.
width
+
“px”
;
this
.
userf
.style.height
=this
.
height
+
“px”
;
this
.
userf
.style.position
=this
.
position
;
this
.
userf
.style.zIndex
=
1
;
this
.
userf
.
src
=this
.
src
;
this
.
userf
.style.left
=
“170px”
;
//400/2-60/2
this
.
userf
.style.top
=
“530px”
;
//630-70-30
map
.
appendChild
(
this
.
userf
);
}
};
//构造用户飞机移动方法
this
.
UserMove
=function
(x,y){
//传参 利用地图鼠标移动事件获取鼠标坐标控制
this
.
x
=
x;
this
.
y
=
y;
this
.
userf
.style.left
=
x
+
“px”
;
this
.
userf
.style.top
=
y
+
“px”
;
}
}
鼠标移动事件:
//创建地图鼠标移动事件
map
.
onmousemove
=function
(e){
//鼠标位置-偏移量-用户飞机宽/高
var
x
=
e.pageX
-this
.offsetLeft
–
user
.
width
/
2
;
var
y
=
e.pageY
-this
.offsetTop
–
user
.
height
/
2
;
user
.
UserMove
(
x
,
y
);
三、用户飞机的子弹
创建子弹的类,由于子弹也是一组属性一致的数据,所以定义数组存储子弹的实例化对象;每创建一颗子弹向数组中追加一颗;
分析:
1.
创建一个类,并构造子弹的创建方法,子弹同样用一个
png
图片表示,其创建方法与用户飞机的创建方法一致,只是需要注意的是子弹首发应该显示在飞机中间的上方
.(
子
弹坐标
x=
飞机
left+
飞机自身的一半
–
子弹自身一半
y=
飞机
top-
飞机自身的一半
)
2.
创建子弹的移动方法:
子弹移动只需要循环改变
top
值,使子弹的
top
值不停减小,但当第一颗子弹移动到下一移位置,在第一颗再次创建一颗子弹, 虽然对这两颗子弹都在不停减小
top
值,但由于是在第一颗子弹以及减小一次的情况下,才在第一颗子弹的原位置上创建了第二颗子弹,所有第二颗会跟随第一颗子弹的位置移动,依次类推,就形成了不间断的子弹链;
注意:
在子弹飞出地图后,需将子弹移除,在移除子弹时,不仅需移除创建方法中的子弹,还需移除其实例化对象;利用存储实例化子弹数组的截取方法实现;
var
shouter
;
function
Shouter
(){
this
.
width
=
10
;
this
.
height
=
20
;
this
.
shouterf
=null
;
this
.
position
=
“absolute”
;
this
.
src
=
“./image/15.png”
;
this
.
x
;
this
.
y
;
//构造创建子弹的方法
this
.
creatShouter
=function
(User){
if
(
this
.
shouterf
==null
){
this
.
shouterf
=
document
.
createElement
(
“img”
);
this
.
shouterf
.style.width
=this
.
width
+
“px”
;
this
.
shouterf
.style.height
=this
.
height
+
“px”
;
this
.
shouterf
.style.position
=this
.
position
;
this
.
shouterf
.style.zIndex
=
1
;
this
.
shouterf
.
src
=this
.
src
;
map
.
appendChild
(
this
.
shouterf
);
//子弹坐标 x=飞机left+飞机自身的一半-子弹自身一半
//y=飞机top-飞机自身的一半
this
.
x
=
parseInt
(
user
.
userf
.style.left)
+
user
.
width
/
2
-this
.
width
/
2
;
this
.
y
=
parseInt
(
user
.
userf
.style.top)
–
user
.
height
/
2
;
}
this
.
shouterf
.style.left
=this
.
x
+
“px”
;
this
.
shouterf
.style.top
=this
.
y
+
“px”
;
};
//构造子弹移动的方法
this
.
ShouterMove
=function
(index,array){
this
.
y
-=
2
;
//子弹的top值
if
(
this
.
y
<=
0
){
//当子弹飞出屏幕 移除创建的子弹及其实例化对象
this
.
shouterf
.
remove
();
array.
splice
(index,
1
);
//移除实例化数组中的子弹 利用数组截取的方法
}
this
.
creatShouter
();
//改变top后继续创建子弹形成连续发射效果
};
}
由于子弹是动态变化时创建的,所以使用定时器调用子弹类
//实例化子弹 调用创建方法
time_creatShouter
=
setInterval
(
function
(){
shouter
=new
Shouter
();
shouter
.
creatShouter
(
user
);
shout
.
push
(
shouter
);
},
200
);
由于是改变每颗子弹自身的
top
值,所以调用子弹移动方法时需遍历子弹数组,注意先得判断是否有子弹生成
//调用子弹移动方法
time_ShouterMove
=
setInterval
(
function
(){
if
(
shout
.length
>
0
){
for
(
var
i
=
0
;
i
<
shout
.length;
i
++
){
shout
[
i
].
ShouterMove
(
i
,
shout
);
}
},
5
);
四、敌机的创建及移动
分析:
1.
敌机也是一组属性类似的数据,故定义数组来存储;
2.
同样需要创建敌机类,敌机用图片表示,这里创建
2
种敌机,大敌机和小敌机;
注意:
将小敌机的属性设置为默认值,大敌机属性传参数设置;
3.
构造敌机的下落方法与子弹原理一致,即改变每个敌机的
top
属性值;
注意:当敌机飞出地图,需移除创建创建方法的敌机还有其实例化对象,同样用实例化存储敌机的数组截取的方法实现;
/*创建敌机 封装敌机类*/
var
enemy
;
function
Enemy
(width,height,blood,score,s){
//敌机分为2种
this
.
width
=
width
||
40
;
this
.
height
=
height
||
30
;
this
.
blood
=
blood
||
3
;
this
.
score
=
score
||
100
;
this
.
enemyf
=null
;
this
.
src
=
s
||
“./image/17.png”
;
this
.
speed
=
2
;
this
.
position
=
“absolute”
;
this
.
x
;
//x轴 left
this
.
y
;
//y轴 top
//构造创建敌机的方法
this
.
createEnemy
=function
(){
if
(
this
.
enemyf
==null
){
this
.
enemyf
=
document
.
createElement
(
“img”
);
this
.
enemyf
.style.width
=this
.
width
+
“px”
;
this
.
enemyf
.style.height
=this
.
height
+
“px”
;
this
.
enemyf
.style.position
=this
.
position
;
this
.
enemyf
.style.zIndex
=
2
;
this
.
enemyf
.
src
=this
.
src
;
map
.
appendChild
(
this
.
enemyf
);
//随机产生起始线不同位置的敌机
this
.
x
=
Math
.
random
()
*
(
400
-this
.
width
);
this
.
y
=-this
.
height
;
}
this
.
enemyf
.style.left
=this
.
x
+
“px”
;
this
.
enemyf
.style.top
=this
.
y
+
“px”
;
}
//构造敌机下落的方法
this
.
EnemyMove
=function
(index,array){
//改变敌机的top值 赋回去
this
.
y
+=this
.
speed
;
if
(
this
.
y
>
630
){
//敌机飞出界面 移除创建的敌机及实例化对象
this
.
enemyf
.
remove
();
array.
splice
(index,
1
);
//移除实例化数组中的敌机 利用数组截取的方法
count
++
;
}
this
.
enemyf
.style.top
=this
.
y
+
“px”
;
}
实例化敌机类,并调用飞机的创建方法,使用
Math
方法中的随机数方法控制大小敌机创建的比例;
//实例化敌机 调用创建方法
time_createEnemy
=
setInterval
(
function
(){
//利用随机数控制大小敌机创建比例
if
(
Math
.
random
()
<
0.7
){
enemy
=new
Enemy
();
enemy
.
createEnemy
();
em_array
.
push
(
enemy
);
}
else
{
enemy
=new
Enemy
(
50
,
65
,
5
,
300
,
“./image/18.png”
);
enemy
.
createEnemy
();
em_array
.
push
(
enemy
);
}
},
1000
);
敌机的下落方法的调用,与子弹移动方法调用一致,都需循环调用对每个敌机调用该下落方法;
//调用敌机移动方法
time_EnemyMove
=
setInterval
(
function
(){
if
(
em_array
.length
>
0
){
for
(
var
key
in
em_array
){
em_array
[
key
].
EnemyMove
(
key
,
em_array
);
}
}
},
15
)
五、实现击打敌机效果
分析:是否打中敌机,其判断方法和贪吃蛇吃豆豆方法类似,即对比
left
,
top
值,
只是这里子弹击中范围需控制在敌机大小区域内
,并且在击中敌机后这可子弹将被移除,在被子弹击中几次之后,敌机也将被移除。
(
几次将由敌机属性中的血量控制,每被击中一次血量掉一格,血量小于等于
0
时将敌机移除
)
注意:这里移除也需移除创建对象及其实例化的对象
//构造子弹打到敌机移除二者的方法
this
.
ShouterEnemy
=function
(enemyarr,index,shoutarr){
//传参 子弹数组 敌机数组 移除所用缩引
for
(
var
key
in
enemyarr){
//遍历敌机数组
//判断 子弹x y 值范围在敌机区域 移除
if
(
this
.
x
>
enemyarr[
key
].
x
-this
.
width
&&this
.
x
<
enemyarr[
key
].
x
+
enemyarr[
key
].
width
&&this
.
y
>
enemyarr[
key
].
y
-this
.
height
&&this
.
y
<
enemyarr[
key
].
y
+
enemyarr[
key
].
height
){
//大小敌机血量不同 当血量为0时 移除被击打的敌机及其实例化对象
enemyarr[
key
].
blood
-=
1
;
if
(enemyarr[
key
].
blood
<=
0
){
enemyarr[
key
].
enemyf
.
remove
();
enemyarr.
splice
(
key
,
1
);
}
//同时移除击打中敌机的子弹及实例化对象
this
.
shouterf
.
remove
();
shoutarr.
splice
(index,
1
);
}
}
六、飞机敌机相撞
游戏结束
分析:在敌机的下落方法中判断用户飞机是否进入了敌机大小区域,进入即视为相撞,游戏结束并清除所有定时器;
注意:
alter()
优于其他代码,故当点击确定后还会执行一次定时器;
//在敌机下落过程中判断是否与飞机相撞 相撞游戏结束
if
(
user
.
x
>this
.
x
–
user
.
width
+
20
&&
user
.
x
<this
.
x
+this
.
width
–
20
&&
user
.
y
>this
.
y
–
user
.
height
+
20
&&
user
.
y
<this
.
y
+this
.
height
–
20
)
{
alert
(
“Game over”
);
clearInterval
(
time_creatShouter
);
clearInterval
(
time_ShouterMove
);
clearInterval
(
time_createEnemy
);
clearInterval
(
time_EnemyMove
);
map
.
onmousemove
=null
;
return
;
}
七、完善代码:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>飞机大战pre</title>
<style>
*{margin: 0;padding: 0;}
.map{
width: 400px;
height: 630px;
border: 1px solid black;
margin: 2px auto;
/* cursor: none;*/
position: relative;
overflow: hidden;
}
.bgmap{
width: 400px;
height: 630px;
background: url("./image/12.png")0 0 no-repeat;
background-size: 100%;
position: absolute;
}
</style>
</head>
<body>
<div class="map">
<div class="bgmap"></div>
<div class="bgmap"></div>
</div>
<script>
/*创建地图 地图移动*/
var map=document.getElementsByClassName("map")[0];
(function (){ //(function(){})();即自调用函数function(){}
var bgmap=document.getElementsByClassName("bgmap");
//设置背景图片初始top值
bgmap[0].style.top="-630px";
bgmap[1].style.top="0px";
//封装背景图片由上自下移动事件
function bgmove(){
for(var i=0;i<bgmap.length;i++){
var Top=parseInt(bgmap[i].style.top);
Top++;
if(Top>=630){
Top=-630;
}
bgmap[i].style.top=Top+"px";
}
}
setInterval(bgmove,30);
})();
/*创建子弹 封装子弹类*/ /*创建用户飞机 封装用户类*/
var user;//实例化的全局变量
function User(){
this.width=60;
this.height=70;
this.position="absolute";
this.userf=null;
this.src="./image/14.gif";
this.x;
this.y;
//构造创建用户飞机的方法
this.createUser=function(){
if(this.userf==null){
this.userf=document.createElement("img");
this.userf.style.width=this.width+"px";
this.userf.style.height=this.height+"px";
this.userf.style.position=this.position;
this.userf.style.zIndex=1;
this.userf.src=this.src;
this.userf.style.left="170px";//400/2-60/2
this.userf.style.top="530px";//630-70-30
map.appendChild(this.userf);
}
};
//构造用户飞机移动方法
this.UserMove=function(x,y){ //传参 利用地图鼠标移动事件获取鼠标坐标控制
this.x=x;
this.y=y;
this.userf.style.left=x+"px";
this.userf.style.top=y+"px";
}
}
var shouter;
function Shouter(){
this.width=10;
this.height=20;
this.shouterf=null;
this.position="absolute";
this.src="./image/15.png";
this.x;
this.y;
//构造创建子弹的方法
this.creatShouter=function(User){
if(this.shouterf==null){
this.shouterf=document.createElement("img");
this.shouterf.style.width=this.width+"px";
this.shouterf.style.height=this.height+"px";
this.shouterf.style.position=this.position;
this.shouterf.style.zIndex=1;
this.shouterf.src=this.src;
map.appendChild(this.shouterf);
//子弹坐标 x=飞机left+飞机自身的一半-子弹自身一半
//y=飞机top-飞机自身的一半
this.x=parseInt(user.userf.style.left)+user.width/2-this.width/2;
this.y=parseInt(user.userf.style.top)-user.height/2;
}
this.shouterf.style.left=this.x+"px";
this.shouterf.style.top=this.y+"px";
};
//构造子弹移动的方法
this.ShouterMove=function(index,array){
this.y-=2; //子弹的top值
if(this.y<=0){//当子弹飞出屏幕 移除创建的子弹及其实例化对象
this.shouterf.remove();
array.splice(index,1);//移除实例化数组中的子弹 利用数组截取的方法
}
this.creatShouter();//改变top后继续创建子弹形成连续发射效果
};
//构造子弹打到敌机移除二者的方法
this.ShouterEnemy=function(enemyarr,index,shoutarr){ //传参 子弹数组 敌机数组 移除所用缩引
for(var key in enemyarr){ //遍历敌机数组
//判断 子弹x y 值范围在敌机区域 移除
if(this.x>enemyarr[key].x-this.width&&this.x<enemyarr[key].x+enemyarr[key].width
&&this.y>enemyarr[key].y-this.height&&this.y<enemyarr[key].y+enemyarr[key].height){
//大小敌机血量不同 当血量为0时 移除被击打的敌机及其实例化对象
enemyarr[key].blood-=1;
if(enemyarr[key].blood<=0){
enemyarr[key].enemyf.remove();
enemyarr.splice(key,1);
}
//同时移除击打中敌机的子弹及实例化对象
this.shouterf.remove();
shoutarr.splice(index,1);
}
}
}
}
/*创建敌机 封装敌机类*/
var enemy;
function Enemy(width,height,blood,score,s){
//敌机分为2种
this.width=width||40;
this.height=height||30;
this.blood=blood||3;
this.score=score||100;
this.enemyf=null;
this.src=s||"./image/17.png";
this.speed=2;
this.position="absolute";
this.x;//x轴 left
this.y;//y轴 top
//构造创建敌机的方法
this.createEnemy=function(){
if(this.enemyf==null){
this.enemyf=document.createElement("img");
this.enemyf.style.width=this.width+"px";
this.enemyf.style.height=this.height+"px";
this.enemyf.style.position=this.position;
this.enemyf.style.zIndex=2;
this.enemyf.src=this.src;
map.appendChild(this.enemyf);
//随机产生起始线不同位置的敌机
this.x=Math.random()*(400-this.width);
this.y=-this.height;
}
this.enemyf.style.left=this.x+"px";
this.enemyf.style.top=this.y+"px";
}
//构造敌机下落的方法
this.EnemyMove=function(index,array){
//改变敌机的top值 赋回去
this.y+=this.speed;
if(this.y>630){//敌机飞出界面 移除创建的敌机及实例化对象
this.enemyf.remove();
array.splice(index,1);//移除实例化数组中的敌机 利用数组截取的方法
count++;
}
this.enemyf.style.top=this.y+"px";
//在敌机下落过程中判断是否与飞机相撞 相撞游戏结束
if(user.x>this.x-user.width+20&&user.x<this.x+this.width-20
&&user.y>this.y-user.height+20&&user.y<this.y+this.height-20)
{
alert("Game over");
clearInterval(time_creatShouter);
clearInterval(time_ShouterMove);
clearInterval(time_createEnemy);
clearInterval(time_EnemyMove);
map.οnmοusemοve=null;
return;
}
}
}
//定义定时器变量
var time_creatShouter;
var time_ShouterMove;
var time_createEnemy;
var time_EnemyMove;
//定义存储子弹的数组 存储敌机的数组
var shout=[];
var em_array=[];
window.οnlοad=function(){
//实例化用户飞机 调用创建方法
user=new User();
user.createUser();
//实例化子弹 调用创建方法
time_creatShouter=setInterval(function(){
shouter=new Shouter();
shouter.creatShouter(user);
shout.push(shouter);
},200);
//调用子弹移动方法
time_ShouterMove=setInterval(function(){
if(shout.length>0){
for(var i=0;i<shout.length;i++){
shout[i].ShouterMove(i,shout);
if(em_array.length>0){ //当存在敌机时 被击中会移除
if(shout[i]==undefined)return;//处理当飞机飞到顶端的bug
shout[i].ShouterEnemy(em_array,i,shout);
}
}
}
},5);
//实例化敌机 调用创建方法
time_createEnemy=setInterval(function(){
//利用随机数控制大小敌机创建比例
if(Math.random()<0.7){
enemy=new Enemy();
enemy.createEnemy();
em_array.push(enemy);
}
else{
enemy=new Enemy(50,65,5,300,"./image/18.png");
enemy.createEnemy();
em_array.push(enemy);
}
},1000);
//调用敌机移动方法
time_EnemyMove=setInterval(function(){
if(em_array.length>0){
for(var key in em_array){
em_array[key].EnemyMove(key,em_array);
}
}
},15)
//创建地图鼠标移动事件
map.οnmοusemοve=function(e){
//鼠标位置-偏移量-用户飞机宽/高
var x= e.pageX-this.offsetLeft-user.width/2;
var y= e.pageY-this.offsetTop-user.height/2;
user.UserMove(x,y);
}
}
</script>
</body>
</html>