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); }
现在只创建了玩家坦克,后面我们还会往里添加敌人坦克。
1.2.5 创建游戏装载对象(核心)
// 游戏载入对象 整个游戏的核心对象 GameLoader = function () { this.mapContainer = document.getElementById("divMap"); // 存放游戏地图的div this._selfTank = null; // 玩家坦克 this._gameListener = null; // 游戏主循环计时器id } GameLoader.prototype = { Begin: function () { // 初始化玩家坦克 var selfT = new SelfTank(); selfT.XPosition = 4; selfT.YPosition = 12; selfT.UpdateUI(); this._selfTank = selfT; // 添加按键事件 var warpper = UtilityClass.BindFunction(this, this.OnKeyDown); window.onkeydown = document.body.onkeydown = warpper; warpper = UtilityClass.BindFunction(this, this.OnKeyUp); window.onkeyup = document.body.onkeyup = warpper; // 游戏主循环 warpper = UtilityClass.BindFunction(this, this.Run); /*长定时器监听控制键*/ this._gameListener = setInterval(warpper, 20); } // 键盘按下玩家坦克开始移动 , OnKeyDown: function (e) { switch ((window.event || e).keyCode) { case 37: this._selfTank.Direction = EnumDirection.Left; this._selfTank.MovingState = true; break; //左 case 38: this._selfTank.Direction = EnumDirection.Up; this._selfTank.MovingState = true; break; //上 case 39: this._selfTank.Direction = EnumDirection.Right; this._selfTank.MovingState = true; break; //右 case 40: this._selfTank.Direction = EnumDirection.Down; this._selfTank.MovingState = true; break; //下 } } // 按键弹起停止移动 , OnKeyUp: function (e) { switch ((window.event || e).keyCode) { case 37: case 38: case 39: case 40: this._selfTank.MovingState = false; break; } } /*游戏主循环运行函数,游戏的心脏,枢纽*/ , Run: function () { if (this._selfTank.MovingState) { this._selfTank.Move(); } } };
游戏装载对象代码看起来很多,其实就做了两件事情:
1、创建玩家坦克对象。
2、添加按键监听事件,当玩家按下移动键调用坦克Move方法移动坦克。
总结:到这里我们的坦克可以通过按键自由的移动了。下一步我们需要完善地图和碰撞检测。
javascript制作坦克大战全纪录(1)
- Author -
hebedich声明:登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。
Reply on: @reply_date@
@reply_contents@