JavaScript坦克大战实战:基于DOM对象绘制的入门教程

作者:页面旅途时间:2026-10-28 16:47:37浏览:112

本文通过重写网络源码,详细解析如何使用JavaScript面向对象思想开发坦克大战游戏。文章重点讲解如何利用DOM操作替代Canvas进行地图绘制,通过二维数组管理地图数据,并实现坦克的移动、方向控制及游戏主循环逻辑,适合JavaScript面向对象编程初学者参考。

JavaScript坦克大战实战:基于DOM对象绘制的入门教程

说明:本坦克大战游戏基于网络下载的源码进行重写,旨在展示JavaScript面向对象编程的应用。该案例不涉及过于复杂的逻辑,但很好地体现了面向对象的设计思想,非常适合作为JavaScript面向对象的入门教程。

构建基础对象与移动逻辑

第一步:构建基础对象,实现坦克的基本移动功能

1.1 如何在地图中绘制画布?

考虑到浏览器兼容性问题,本文采用操作DOM元素的方式来实现游戏对象的绘制与刷新。关于地图数据的存储,我们使用二维数组来保存地图信息。由于JavaScript原生不支持二维数组,我们可以通过在一维数组中存储数组的方式来模拟实现。

1.2 代码实现

我们将画布设计为一个13 * 13的二维数组,地图中每个元素对应的长宽均为40px。整个地图可以看作是由40px*40px大小的单元格组成的表格,因此整个画布的大小为520px * 520px。在展示代码之前,先提供一张对象关系图以辅助理解:

JavaScript坦克大战实战:基于DOM对象绘制的入门教程

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方法移动坦克。

总结:到这里我们的坦克可以通过按键自由的移动了。下一步我们需要完善地图和碰撞检测。

作者最新文章