转载一篇-------javascript 小游戏 –飞机大战 (单体单例)
原文博客地址:https://blog.csdn.net/weixin_42955598/article/details/81812171
最近跟着教学视频一边学习一边做了一个javascript的实战小游戏
话不多说 直接附上码源
<!DOCTYPE HTML>
<html>
<head>
<title>please enter your title</title>
<meta charset="utf-8">
<meta name="Author" content="潭州学院-阿飞老师">
<style type='text/css'>
*{ margin:0; padding:0;font-family:"Microsoft yahei";}
body{ overflow:hidden;}
</style>
</head>
<body>
<script type="text/javascript">
/*单例模式*/
window.onload = function(){
//通过加载对象的方式开启
Game.exe();
};
var Game = {
//启动程序
exe : function(){
//设置整个页面为黑色
document.body.style.background = '#000';
//创建div盒子节点
var oDiv = document.createElement('div');
//给盒子添加id属性 GameBox
oDiv.id = 'GameBox';
//设置盒子样式
oDiv.style.cssText = 'width:300px;height:500px;border:10px solid #fff;margin:50px auto;text-align:center;position:relative;overflow:hidden;';
//将div节点添加到body中 添加节点和删除节点可以参考手册
document.body.appendChild( oDiv );
//调用init初始化游戏方法
this.init();
},
//定义分数
score : 0,
//判断是否结束
ifEnd : false,
//初始化
init : function(){
//将game对象this存储起来,方便之后用的时候出现this代指不一样
var This = this;
//找id --GameBox 也就是前面定义div盒子时添加的
var oDiv = document.getElementById('GameBox');
//清楚内容,,,,
//介绍一下:innerHTML可以清空里面的标签,也可以添加标签,innerTEXT不能添加标签(纯文本信息)
oDiv.innerHTML = '';
Game.score = 0;
Game.ifEnd = false;
//创建标题 飞机大战v1.0 h1标签及样式
var oH = document.createElement('h1');
oH.innerHTML = '飞机大战v1.0';
oH.style.cssText = 'color:#fff;font-size:26px;font-weight:normal;padding-top:50px;';
//添加到游戏盒子中 id=GameBox
oDiv.appendChild( oH );
//通过for循环创建一个选项,,,简单模式,,一般模式,,困难模式,,开挂模式
for (var i=0;i<4;i++ )
{
//创建p标签及样式来当按钮
var oP = document.createElement('p');
oP.index = i;
oP.style.cssText = 'font-size:14px;color:#000;width:150px;height:40px;margin:50px auto;text-align:center;line-height:40px;background:#fff;cursor:pointer;';
var html = '';
//onmouseover、onmouseout和下面两个用法其实一样,
//就是一对作用下面所有标签,包括自己,一对只是作用于自己,其他标签不管
//p的鼠标监听 onmouseenter 移入鼠标回调的函数 和onmouseleave 一起使用
oP.onmouseenter = function(){
this.style.background = '#f60';
this.style.color = '#fff';
};
//p的鼠标监听 onmouseleave 移出鼠标回调的函数 和onmouseenter 一起使用
oP.onmouseleave = function(){
this.style.background = '#fff';
this.style.color = '#000';
};
//设置点击事件 点击即可开始游戏,这里This这就是上面所说需要game对象调用start,
//不然这里用的this就相当于oP这个按钮对象,,可以通过console查看
oP.onclick = function(e){
//e参数也就是点击事件自带一个even,可以获取当前位置 x y对应宽高
e = e||window.event;
This.start( this.index , oDiv , e );
};
//设置按钮文字 和特殊样式
switch ( i )
{
case 0:
html = '简单难度';
break;
case 1:
html = '中等难度';
break;
case 2:
html = '困难难度';
break;
case 3:
html = '飞哥附体';
oP.style.color = '#f00';
oP.style.fontWeight = 'bold';
oP.onmouseenter = function(){
this.style.background = '#f60';
};
oP.onmouseleave = function(){
this.style.background = '#fff';
};
break;
}
//将文字添加到按钮p上
oP.innerHTML = html;
//将按钮p添加到div中 也就是盒子中
oDiv.appendChild(oP);
};
},
//游戏开始
start : function( index , oGameBox , e ){
//开始游戏 innerHTML清除里面所有东西
oGameBox.innerHTML = '';
//创建span节点
var oS = document.createElement('span');
//添加分数,左上角,left:15px,,top10px,,设置分数
oS.innerHTML = this.score;
oS.style.cssText = 'position:absolute;left:15px;top:10px;font-size:14px;color:#fff';
//添加到盒子中
oGameBox.appendChild( oS );
//获取飞机 自身 的属性和方法
this.plane( oGameBox , e , index);
//获取飞机 敌人 的属性和方法
this.enemy( oGameBox , oS , index );
},
//关于飞机
plane : function( oGameBox , e , index ){
//获取点击按钮触发的位置 x坐标和y坐标相对于浏览器
var x = e.pageX,
y = e.pageY;
//js提供了一个Image对象,等同于document.createElement('img');
var oPlane = new Image(); // document.createElement('img');
//设置小飞机图片及属性 本身
oPlane.src = 'img/plane.png';
oPlane.width = 60;
oPlane.height = 36;
oPlane.id = 'plane';
//飞机需要设置的y 和 x
var tY = oGameBox.offsetTop+parseInt(oGameBox.style.borderWidth)+oPlane.height/2;
var lX = oGameBox.offsetLeft+parseInt(oGameBox.style.borderWidth)+oPlane.width/2;
//50 10 18= 78
//523 10 30= 563
//这里用了一个回调方法onresize,这个是window的方法,当浏览器尺寸发送变化调用
//用来监听x变化(宽度)号设置 x值
window.onresize = function(){
lX = oGameBox.offsetLeft+parseInt(oGameBox.style.borderWidth)+oPlane.width/2;
};
//开始游戏时使用觉对定位将飞机定位在选择模式的位置上的地图上
var top = y-tY;
var left = x-lX;
oPlane.style.cssText = 'display:block;position:absolute;top:'+top+'px;left:'+left+'px;';
//添加到盒子中
oGameBox.appendChild( oPlane );
//计算飞机能在页面上的最小值和最大值等 也是通过定位来显示
var leftMin = - oPlane.width/2;
var leftMax = oGameBox.clientWidth - oPlane.width/2;
var topMin = 0;
var topMax = oGameBox.clientHeight - oPlane.height;
//鼠标在元素上移动时回调的方法监听
document.onmousemove = function(e){
//先判断是否结束(或死亡)了
if ( !Game.ifEnd )
{
e = e || window.event;
var top = e.pageY - tY;
var left = e.pageX - lX;
//这几句就是判断 鼠标在盒子区域内,不能大于最大值,如果大于就取最大,如果小于最小值就取最小,
top = Math.min( top , topMax );
top = Math.max( top , topMin );
left = Math.min( left , leftMax );
left = Math.max( left , leftMin );
//设置定位的位置,,也就是飞机跟着鼠标移动,鼠标移出去了,飞机就在边上,不能出去
oPlane.style.left = left + 'px';
oPlane.style.top = top + 'px';
}
};
//调用飞机子弹 谁调用 在那里显示 index就是游戏难度的下标
this.biubiubiu( oPlane , oGameBox , index );
},
//飞机子弹
biubiubiu : function( oPlane , oGameBox , index ){
//子弹速度
var speed;
switch ( index )
{
case 0:
speed = 200;
break;
case 1:
speed = 300;
break;
case 2:
speed = 400;
break;
case 3:
speed = 10;
break;
}
//this.BiuTimer等同于为biubiubiu函数创建了一个对象,用来找到定时器
//开启一个定时器,,定时器有两种,,一种是setInterval(a(),time毫秒)每隔多少时间执行一次函数a()
//另一种setTimeout(a(),1000)则是只调用一次,意思就是 一秒过后调用一次a()
this.BiuTimer = setInterval( function(){
//创建image对象,来显示子弹及属性特征
var oBiu = new Image();
oBiu.src = 'img/bullet.png';
oBiu.width = 6;
oBiu.height = 22;
oBiu.className = 'biubiubiu';
//第一个子弹位置,,
//top就是飞机的top位置,减去子弹自身高度,再减去3,能实现子弹在飞机上面3px效果
var top = oPlane.offsetTop - oBiu.height + 3;
//获取子弹left大小,
//飞机的left加上飞机的一般宽度,减去子弹一般的宽度,这样就能实现,子弹中线和飞机对齐
var left = oPlane.offsetLeft + oPlane.width/2 - oBiu.width/2;
oBiu.style.cssText = 'position:absolute;top:'+top+'px;left:'+left+'px';
//子弹添加到盒子中
oGameBox.appendChild( oBiu );
//为每一颗子弹设置一个定时器 oBiu.timer 不然的话子弹就会一直在原地
oBiu.timer = setInterval( function(){
if ( !oBiu.parentNode )
{
clearInterval( oBiu.timer );
}
//通过修改top定位值 每次减10px 就能达到类似子弹在往上走的样子
oBiu.style.top = oBiu.offsetTop - 10 + 'px';
//如果子弹到达最上面,则清楚定时器,,不然很浪费内存资源
if ( oBiu.offsetTop < - oBiu.height )
{
clearInterval( oBiu.timer );
//移除节点(其中一个子弹)
oBiu.parentNode.removeChild( oBiu );
}
} , 13 );//13则为子弹飞行速度了,,用定时器完成的
//speed 是之前有一个index判断速度 难度不同速度不同,,值越大,速度越慢,
//可以在页面测试,f12修改属性
} , speed); // ****************** 子弹速度
},
//敌军
enemy : function(oGameBox , oS , index){
//判断游戏难度 给定速度
var a , x;
switch ( index )
{
case 0:
a = 1;
x = 500;
break;
case 1:
a = 3;
x = 300;
break;
case 2:
a = 5;
x = 200;
break;
case 3:
a = 5;
x = 100;
break;
}
//创建敌人定时器 this.EnemyTimer,之所以先创建定时器,因为,每次执行,就需要一个敌人,不能就一个
this.EnemyTimer = setInterval( function(){
//创建敌人 同创建飞机 自身 一样
var oEnemy = new Image();
oEnemy.src = 'img/enemy.png';
oEnemy.width = 23;
oEnemy.height = 30;
var lMin = 0;
var lMax = oGameBox.clientWidth - oEnemy.width;
//这里的随机,是为了在a的范围内创建敌人,不然敌人一直从一个地方出来
var left = Math.random() * (lMax-lMin) + lMin;
oEnemy.style.cssText = 'position:absolute;top:'+(-oEnemy.height)+'px;left:'+left+'px;'
oGameBox.appendChild( oEnemy );
//这里的随机,是为了随机一个速度出来
var b = Math.random() * a + 1;
//开启敌人运动的定时器oEnemy.timer
oEnemy.timer = setInterval(function(){
//敌人往下运动,每次运动 bpx距离
oEnemy.style.top = oEnemy.offsetTop + b + 'px'; // ***********敌军下落速度
if ( oEnemy.offsetTop >= oGameBox.clientHeight )
{
clearInterval( oEnemy.timer );
//判断敌人是否到达最下面,是的话就删除这个敌人
oEnemy.parentNode.removeChild( oEnemy );
};
},13);
//getClass是和子弹的碰撞检测 返回一个子弹集合
var allBiu = Game.getClass('biubiubiu');
//定时器oEnemy.pzBiu 用来检测子弹和飞机碰撞没?
oEnemy.pzBiu = setInterval(function(){
//变量子弹集合
for (var i=0;i<allBiu.length;i++ )
{
//Game.boom判断子弹和是否敌人碰撞
if ( Game.boom( oEnemy , allBiu[i] ) )
{
//分数加1
Game.score ++;
oS.innerHTML = Game.score;
//替换为敌人被炸毁的图片
oEnemy.src = 'img/boom.png';
//清楚当前子弹击中的敌人和子弹的定时器
clearInterval( oEnemy.pzBiu );
clearInterval( oEnemy.pzPlane );
//移除子弹所在数组节点
allBiu[i].parentNode.removeChild( allBiu[i] );
setTimeout(function(){
if ( oEnemy.parentNode )
{
//移除敌人节点
oEnemy.parentNode.removeChild( oEnemy );
}
},300);
break;
}
}
},50);
//和战机的碰撞检测
//和上面子弹差不多,也就是自身飞机 和敌人飞机的检测
var oPlane = document.getElementById('plane');
oEnemy.pzPlane = setInterval(function(){
//先判断是否游戏结束
if ( Game.ifEnd )
{
clearInterval( oEnemy.pzPlane );
}
//判断是否碰撞
if ( Game.boom( oEnemy , oPlane ) )
{
Game.ifEnd = true;
clearInterval( oEnemy.pzPlane );
clearInterval( Game.BiuTimer );
clearInterval( Game.EnemyTimer );
//两个飞机碰撞,,游戏结束,并且两个飞机图片都替换成撞毁的图片
oEnemy.src = 'img/boom.png';
oPlane.src = 'img/boom2.png';
//开启一次性定时器setTimeout,前面说过这个 一秒后执行Game的over函数
setTimeout(function(){
Game.over( oGameBox );
},1000);
}
},50);
} , x ); // *********** 敌军生成速度
},
//碰撞检测
boom : function( obj1 , obj2 ){
//假设obj1是敌人飞机 obj2是自己飞机 这里的y 和 x就是 整个页面top顶端和left侧端到目标的距离
//T1 可以这么理解,敌人飞机为一个正方形,ti则是上面线的y的距离
//B1 可以理解为,敌人飞机下面线的y距离
//L1 可以理解为,敌人飞机左侧到浏览器left边的距离
//。。。。。。。。。。
var T1 = obj1.offsetTop;
var B1 = T1 + obj1.clientHeight;
var L1 = obj1.offsetLeft;
var R1 = L1 + obj1.clientWidth;
var T2 = obj2.offsetTop;
var B2 = T2 + obj2.clientHeight;
var L2 = obj2.offsetLeft;
var R2 = L2 + obj2.clientWidth;
//R2 < L1 飞机的右边距离比敌人飞机左边小,肯定撞不到
//L2 > R1 飞机的左边距离比敌人飞机右边远,肯定撞不到
//B2 < T1 飞机的下边距离比敌人飞机上边远,肯定撞不到
//T2 > B1 飞机的上边距离比敌人飞机下边远,肯定撞不到
if ( R2 < L1 || L2 > R1 || B2 < T1 || T2 > B1 )
{
return false; // 没撞上
}
else
{
return true; // 撞上了
}
},
//游戏结束 没什么可将的了,,就是清楚页面,然后新建结束页面 ,
//其中重新开始,也就是再调用一次Game的init初始化方法
over : function(oGameBox){
oGameBox.innerHTML = '';
var oDiv = document.createElement('div');
oDiv.style.cssText = 'width:200px;height:400px;margin:50px;background:#fff;';
var oT = document.createElement('h3');
oT.innerHTML = 'Game Over';
oT.style.cssText = 'padding-top:50px;;'
var oP1 = document.createElement('p');
oP1.innerHTML = '您的得分是:' + '<span style="color:#f00;font-weight:bold;">' + this.score + '</span>';
oP1.style.cssText = 'font-size:16px;color:#000';
var oRestart = document.createElement('div');
oRestart.style.cssText = 'width:100px;height:40px;font-size:14px;text-align:center;line-height:40px;color:#000;background:#990;margin:20px auto;cursor:pointer;';
oRestart.innerHTML = '重新开始';
oRestart.onclick = function(){
Game.init();
};
oDiv.appendChild( oT );
oDiv.appendChild( oP1 );
oDiv.appendChild( oRestart );
oGameBox.appendChild( oDiv );
},
//getClass方法 这个方法写得很好,是我觉得的,遍历所有的节点,并返回所需要的节点数组
//getClass方法 虽然外面调用的时候只有一个参数,但是这里面还是补上了
getClass : function( cName , parent ){
parent = parent || document;
if ( document.getElementsByClassName )
{
return parent.getElementsByClassName(cName);
}
else
{
//这个 我是这么理解的。。获取当前游戏的时候所有节点,,返回一个数组
//通过后面if判断( if ( arrClass[j] == cName ))是否是自己需要(cName)的元素,添加到数组中
var all = parent.getElementsByTagName('*');
var arr = [];
for ( var i=0;i<all.length;i++ )
{
var arrClass = all.className.split(' ');
for ( var j=0;j<arrClass.length;j++ )
{
//判断是否是自己需要的name,,,这里所运用到的就是判断是否是子弹节点
if ( arrClass[j] == cName )
{
//push方法就是放数组中添加一个节点
arr.push( all[i] );
break;
}
}
}
//最后返回获取到的 例如 获取到的子弹数组
return arr;
}
},
};
</script>
</body>
</html
需要用到的图片,可以自己设计一下
1.自己的飞机
2.敌人飞机
3.boom两种图片都可以用这一张
本文只是转载之后
原文博客地址:https://blog.csdn.net/weixin_42955598/article/details/81812171