PS:这个坦克大战是在网上下的一段源码之后,自己进行的重写。本身没有太难的东西,这个案例将js面向对象用的比较好,可以作为js面向对象的入门教程。
1. 创建基本对象,实现坦克简单的移动
1.1 如何在地图中绘制画布?
考虑到浏览器兼容的问题,我们用操作dom的方式来实现游戏对象的绘制和刷新。我们如何存储我们的地图呢? 我们应该把地图用一个二维数组来保存, js中没有二维数组,但是可以通过在一维数组从存储数组来实现。
1.2 代码实现
我们将画布设计为 13 * 13 的一个二维数组,每个元素在地图中对应的长和宽均为40px,可以把整个地图看成由 40px*40p x大小的单元格组成的一个表格,那么我们整个画布的大小为 520px * 520px ;
上代码前先给大家来一张对象关系图:
1.2.1 创建顶级对象
html代码:
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">
<html>
<head>
<title>坦克大战</title>
<link rel=stylesheet href=\"css/main.css\" />
<script src=\"js/Common.js\"></script>
<script src=\"js/TankObject.js\"></script>
<script src=\"js/Mover.js\"></script>
<script src=\"js/Tank.js\"></script>
<script src=\"js/Frame.js\"></script>
<script>
window.onload = function () {
// 调用游戏装载对象
var loader = new GameLoader();
loader.Begin();
}
</script>
</head>
<body>
<!--地图容器-->
<div id=\"divMap\">
</div>
<div id=\"debugInfo\">
</div>
</body>
</html>
TankObject.js文件:
// 顶级对象
TankObject = function () {
this.XPosition = 0; // 对象在地图(13*13)中的X的位置
this.YPosition = 0;
this.UI = null; // dom元素
}
// 更改UI静态方法
TankObject.prototype.UpdateUI = function (battlFiled) { }
// 设置位置,参数是这样:1*40,6*40
TankObject.prototype.SetPosition = function (leftPosition, topPosition) {
// 在地图的位置 Math.round四舍五入
this.XPosition = Math.round(leftPosition / 40);
this.YPosition = Math.round(topPosition / 40);
// 设置在窗体上的位置
if (this.UI != null && this.UI.style != null) {
this.UI.style.left = leftPosition + \"px\";
this.UI.style.top = topPosition + \"px\";
}
}
这里我们用X,Y坐标表示对象在地图上的位置。后面我们会将地图中的每个对象都放入二维数组中,这时可以通过X,Y坐标来取得对应的对象。
然后用css中的left和top来控制我们对象在窗体中的位置。(可以移动的对象:坦克,子弹)
1.2.2 创建公用对象
我们还需要创建一个公共的对象,来写入我们常用的一些方法。
Common.js:
// 坦克移动的四个方向
var EnumDirection = {
Up: \"0\",
Right: \"1\",
Down: \"2\",
Left: \"3\"
};
// 通用方法对象
var UtilityClass = {
// 创建dom元素到parentNode中,可指定id,className
CreateE: function (type, id, className, parentNode) {
var J = document.createElement(type);
if (id) { J.id = id };
if (className) { J.className = className };
return parentNode.appendChild(J);
}, // 移除元素
RemoveE: function (obj, parentNode) {
parentNode.removeChild(obj);
},
GetFunctionName: function (context, argumentCallee) {
for (var i in context) {
if (context[i] == argumentCallee) { return i };
}
return \"\";
}, // 绑定事件,返回func方法,this为传入的obj
BindFunction: function (obj,func) {
return function () {
func.apply(obj, arguments);
};
}
};
1.2.3 创建移动对象
Mover.js
// 移动对象,继承自顶层对象
Mover = function () {
this.Direction = EnumDirection.Up;
this.Speed = 1;
}
Mover.prototype = new TankObject();
Mover.prototype.Move = function () {
if (this.lock) {
return;/* 停用或者尚在步进中,操作无效 */
}
// 根据方向设置坦克的背景图片
this.UI.style.backgroundPosition = \"0 -\" + this.Direction * 40 + \"px\";
// 如果方向是上和下,vp就是top;如果方向是上和左,val就是-1
var vp = [\"top\", \"left\"][((this.Direction == EnumDirection.Up) || (this.Direction == EnumDirection.Down)) ? 0 : 1];
var val = ((this.Direction == EnumDirection.Up) || (this.Direction == EnumDirection.Left)) ? -1 : 1;
this.lock = true;/* 加锁 */
// 把当前对象保存到This
var This = this;
// 记录对象移动起始位置
var startmoveP = parseInt(This.UI.style[vp]);
var xp = This.XPosition, yp = This.YPosition;
var subMove = setInterval(function () {
// 开始移动,每次移动5px
This.UI.style[vp] = parseInt(This.UI.style[vp]) + 5 * val + \"px\";
// 每次移动一个单元格 40px
if (Math.abs((parseInt(This.UI.style[vp]) - startmoveP)) >= 40) {
clearInterval(subMove);
This.lock = false;/* 解锁,允许再次步进 */
// 记录对象移动后在表格中的位置
This.XPosition = Math.round(This.UI.offsetLeft / 40);
This.YPosition = Math.round(This.UI.offsetTop / 40);
}
}, 80 - this.Speed * 10);
}
这里的移动对象继承自我们的顶级对象 ,这里this就代表调用Move方法的对象。
Move对象的功能根据对象的方向和速度进行移动,每次移动5px总共移动40px一个单元格。后面这个对象还会进行扩展,会加入碰撞检测等功能。
1.2.4 创建坦克对象
Tank.js 文件:
//tank对象 继承自Mover
Tank=function(){}
Tank.prototype = new Mover();
// 创建玩家坦克,继承自tank对象
SelfTank = function () {
this.UI = UtilityClass.CreateE(\"div\", \"\", \"itank\", document.getElementById(\"divMap\"));
this.MovingState = false;
this.Speed = 4;
}
SelfTank.prototype = new Tank();
// 设置坦克的位置
SelfTank.prototype.UpdateUI = function () {
this.UI.className = \"itank\";
// 顶级对象方法,设置坦克的位置
this.SetPosition(this.XPosition * 40, this.YPosition * 40);
}