坦克大战(一)
相信大家对坦克大战都不陌生,并且网上也有很多用java实现的小程序,最近用了几天时间将其使用javaScript语言通过面向对象的方式实现,在实现的过程中吸收了很多新的知识,现在趁着程序即将完成之际将其记录下来。
废话不多说,先上程序源码:https://github.com/safemen/TankGame2.0.git
项目需求
在写程序之前,我们需要先大体的了解一下项目的一些需求和注意事项,方便以后的开发。
程序在运行之前会有从下到上的开场动画,然后鼠标点击选择游戏的人数,游戏在进入每一个关卡之前会有第几关的提示,进入游戏后,玩家通过键盘操纵坦克移动,转弯,射击,与敌人交战,直到消灭所有的敌人就算过关。
开发过程
HTML
因为本程序的HTML结构比较简单,所以在此就不多加赘述,只是在引入js文件的时候,需要注意一下引入的顺序即可。
CSS
在css中需要根据精灵图来分配每个小型单位的样式,需要注意的是因为有些图片的缺失使用了一部分css3做出了动画效果来表现为特殊坦克。
javaScript
本程序以javaScript为主,下面我将以在本程序开发中javaScript的编写顺序来讲述一下大体的思路。
在程序中我们会有一个游戏控制构造函数来进行游戏的总体控制,它在其中重要的是使用定时器来控制游戏的更新,也就是我们所做的所有活动都需要定时器来更新。
我们需要define文件保存一些常用的数据,有兴趣的可以自己重新测量一遍,但我感觉没有必要,因为我感觉写一个或者学习一个程序还是以逻辑为主,很多无必要的工作能不做就不做。而mapData中则保存的是我们的地图数据,我们可以对其进行自由的拓展。在core中我们主要保存了一些常用的方法,方便在其他的js调用。
根据我的设计思路是首先将地图构造函数即Map.class.js设计出来,再设计物体构造函数Object.class.js,而其他的所有的对象都会派生自物体构造函数,所以这就需要我们对其他的对象进行一下公有属性和公有方法的提取,再依次设计其他对象的具体构造函数,后面再依次介绍。
首先我们们讲一下地图构造函数的大致思路:
function Map(oParent, oRight, level) {
this.oParent = oParent;
this.oRight = oRight;
this.level = level;
this.eMapLevel = []; //地图数组
this.eMapLength = 0; //地图数组的长度
this.mapEnemyType = []; // 保存敌方坦克的出场顺序
this.lairEnclosure = []; //保存老巢的围墙
this.obstacle = []; //保存所有障碍物
}
因为我们需要对DOM进行操作,所以我们需要写一个创建节点的方法,如下
Map.prototype.createElem = function (sElem, sClass, sId) {
var oElem = document.createElement(sElem);
if (sClass) {
oElem.className = sClass;
}
if (sId) {
oElem.id = sId;
}
return oElem;
}
当我们要对地图初始化时,需要调用initMap方法
Map.prototype.initMap = function () {
this.initLevel();
this.initLeftMap();
};
它需要获取地图数据,并保存到相关的变量中,提前获取地图数组的长度,可以在遍历数组的时候不再重复的获取消耗时间。我只写了3关,如果有兴趣可自行在mapDate.js中添加
Map.prototype.initLevel = function () {
switch (this.level) {
case 1:
this.eMapLevel = eMap.level_1.obstacles;
this.eMapLength = eMap.level_1.obstacles.length;
this.mapEnemyType = eMap.level_1.enemyType;
break;
case 2:
this.eMapLevel = eMap.level_2.obstacles;
this.eMapLength = eMap.level_2.obstacles.length;
this.mapEnemyType = eMap.level_2.enemyType;
break;
case 3:
this.eMapLevel = eMap.level_3.obstacles;
this.eMapLength = eMap.level_3.obstacles.length;
this.mapEnemyType = eMap.level_3.enemyType;
break;
default :
this.eMapLevel = eMap.level_1.obstacles;
this.eMapLength = eMap.level_1.obstacles.length;
this.mapEnemyType = eMap.level_1.enemyType;
break;
}
};
最后一步是我们需要对左侧的地图进行初始化,值得一提的是我们对其的做法,因为我们这个程序主要是侧重于对DOM的操作,所以我们首先对每一个节点div都不设置绝对定位,当我们将地图全部加载完毕后再,将它们转化为绝对定位,这样方便以后在我们的操作中修改和判断。
Map.prototype.initLeftMap = function () {
var oFrag = document.createDocumentFragment();
for (var i = 0; i < this.eMapLength; i++) {
for (var j = 0; j < this.eMapLevel[i].length; j++) {
switch (this.eMapLevel[i][j]) {
case 0://道路
var oBare = this.createElem(DIV, BARE);
oBare.material = 0;//用以分辨类型
oFrag.appendChild(oBare);
break;
case 1://墙
var oWall = this.createElem(DIV, WALL);
oWall.material = 1;//用以分辨类型
oFrag.appendChild(oWall);
break;
case 2://铁(石头)
var oIron = this.createElem(DIV, IRON);
oIron.material = 2;//用以分辨类型
oFrag.appendChild(oIron);
break;
case 3://花
var oFlower = this.createElem(DIV, FLOWER);
oFlower.material = 3;//用以分辨类型
oFrag.appendChild(oFlower);
break;
case 7://墙(老巢周围的墙)
var oWall = this.createElem(DIV, WALL);
oWall.material = 7;//用以分辨类型
oFrag.appendChild(oWall);
break;
case 9://老巢
var oBare = this.createElem(DIV, BARE);
oBare.material = 0;
oFrag.appendChild(oBare);
var oLair = this.createElem(DIV, LAIR, LAIR);
//这个时候设置老巢为绝对定位,使其不在原来的位置不影响div的排列
oLair.style.position = POSITION;
oLair.material = 9;
oFrag.appendChild(oLair);
break;
default :
break;
}
}
}
this.oParent.appendChild(oFrag);
var oElem = this.oParent.getElementsByTagName(DIV);
var iElemLen = oElem.length;
var index = 0;
//需要对每一个方块进行绝对定位,
// 所以要计算每一个相对于左上角的偏移量就是每一个div的offsetLeft
for (var i = 0; i < iElemLen; i++) {
if (oElem[i].id !== LAIR) {//不是老巢
oElem[i].style.left = oElem[i].offsetLeft + PX;
oElem[i].style.top = oElem[i].offsetTop + PX;
}
}
//给每一个元素进行绝对定位
for (var i = 0; i < iElemLen; i++) {
if (oElem[i].id != LAIR) {//不是老巢
oElem[i].style.position = POSITION;
if (oElem[i].material == 7) { //老巢周围的墙
oElem[i].id = index++;
this.lairEnclosure.push(oElem[i]);
this.obstacle.push(oElem[i]);
} else if (oElem[i].material == 1 || oElem[i].material == 2) {
//如果是墙或者是铁(石头),保存到障碍物数组中
this.obstacle.push(oElem[i]);
}
}
}
//获取老巢节点
var oLair = $(LAIR);
//设置老巢节点的偏移量与和它上一个同级的的位置相同
oLair.style.top = oLair.previousSibling.offsetTop + PX;
oLair.style.left = oLair.previousSibling.offsetLeft + PX;
oLair.style.zIndex = 6;
};
好了,今天先暂且写到这里吧,下一次将把物体的构造思路和坦克的构造思路写一下,感觉还是比较有新意的。小弟初识javaScript面向对象设计,如有错误之处,望批评指正。
*:first-child {
margin-top: 0 !important;
}
body>*:last-child {
margin-bottom: 0 !important;
}
/* BLOCKS
=============================================================================*/
p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
}
/* HEADERS
=============================================================================*/
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
}
h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
font-size: inherit;
}
h1 {
font-size: 28px;
color: #000;
}
h2 {
font-size: 24px;
border-bottom: 1px solid #ccc;
color: #000;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
color: #777;
font-size: 14px;
}
body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
margin-top: 0;
padding-top: 0;
}
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}
h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
margin-top: 10px;
}
/* LINKS
=============================================================================*/
a {
color: #4183C4;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* LISTS
=============================================================================*/
ul, ol {
padding-left: 30px;
}
ul li > :first-child,
ol li > :first-child,
ul li ul:first-of-type,
ol li ol:first-of-type,
ul li ol:first-of-type,
ol li ul:first-of-type {
margin-top: 0px;
}
ul ul, ul ol, ol ol, ol ul {
margin-bottom: 0;
}
dl {
padding: 0;
}
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}
dl dt:first-child {
padding: 0;
}
dl dt>:first-child {
margin-top: 0px;
}
dl dt>:last-child {
margin-bottom: 0px;
}
dl dd {
margin: 0 0 15px;
padding: 0 15px;
}
dl dd>:first-child {
margin-top: 0px;
}
dl dd>:last-child {
margin-bottom: 0px;
}
/* CODE
=============================================================================*/
pre, code, tt {
font-size: 12px;
font-family: Consolas, "Liberation Mono", Courier, monospace;
}
code, tt {
margin: 0 0px;
padding: 0px 0px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}
pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}
pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}
pre code, pre tt {
background-color: transparent;
border: none;
}
kbd {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #DDDDDD;
background-image: linear-gradient(#F1F1F1, #DDDDDD);
background-repeat: repeat-x;
border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
border-image: none;
border-radius: 2px 2px 2px 2px;
border-style: solid;
border-width: 1px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
line-height: 10px;
padding: 1px 4px;
}
/* QUOTES
=============================================================================*/
blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}
blockquote>:first-child {
margin-top: 0px;
}
blockquote>:last-child {
margin-bottom: 0px;
}
/* HORIZONTAL RULES
=============================================================================*/
hr {
clear: both;
margin: 15px 0;
height: 0px;
overflow: hidden;
border: none;
background: transparent;
border-bottom: 4px solid #ddd;
padding: 0;
}
/* TABLES
=============================================================================*/
table th {
font-weight: bold;
}
table th, table td {
border: 1px solid #ccc;
padding: 6px 13px;
}
table tr {
border-top: 1px solid #ccc;
background-color: #fff;
}
table tr:nth-child(2n) {
background-color: #f8f8f8;
}
/* IMAGES
=============================================================================*/
img {
max-width: 100%
}
-->