javascript制作坦克大战全纪录(1)


Posted in Javascript onNovember 27, 2014

PS:这个坦克大战是在网上下的一段源码之后,自己进行的重写。本身没有太难的东西,这个案例将js面向对象用的比较好,可以作为js面向对象的入门教程。

1.   创建基本对象,实现坦克简单的移动

1.1    如何在地图中绘制画布

    考虑到浏览器兼容的问题,我们用操作dom的方式来实现游戏对象的绘制和刷新。我们如何存储我们的地图呢? 我们应该把地图用一个二维数组来保存, js中没有二维数组,但是可以通过在一维数组从存储数组来实现。

1.2    代码实现

    我们将画布设计为 13 * 13 的一个二维数组,每个元素在地图中对应的长和宽均为40px,可以把整个地图看成由 40px*40p x大小的单元格组成的一个表格,那么我们整个画布的大小为 520px  *  520px ;
 

上代码前先给大家来一张对象关系图:

javascript制作坦克大战全纪录(1)

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 相关文章推荐
javascript 匿名函数的理解(透彻版)
Jan 28 Javascript
jquery实用代码片段集合
Aug 12 Javascript
使用javascript将时间转换成今天,昨天,前天等格式
Jun 25 Javascript
详解jQuery中的empty、remove和detach
Apr 11 Javascript
HTML5canvas 绘制一个圆环形的进度表示实例
Dec 16 Javascript
js浏览器滚动条卷去的高度scrolltop(实例讲解)
Jul 07 Javascript
推荐VSCode 上特别好用的 Vue 插件之vetur
Sep 14 Javascript
js移动端图片压缩上传功能
Aug 18 Javascript
通过jquery获取上传文件名称、类型和大小的实现代码
Apr 19 jQuery
使用Vue如何写一个双向数据绑定(面试常见)
Apr 20 Javascript
json数据传到前台并解析展示成列表的方法
Aug 06 Javascript
vue-cli配置flexible过程详解
Jul 04 Javascript
使用jsonp完美解决跨域问题
Nov 27 #Javascript
JavaScript变量声明详解
Nov 27 #Javascript
js脚本实现数据去重
Nov 27 #Javascript
实例分析js和C#中使用正则表达式匹配a标签
Nov 26 #Javascript
javascript几个易错点记录
Nov 26 #Javascript
jquery选择器需要注意的问题
Nov 26 #Javascript
jquery操作对象数组元素方法详解
Nov 26 #Javascript
You might like
php 常用类整理
2009/12/23 PHP
PHP中多维数组的foreach遍历示例
2014/06/13 PHP
Laravel 在views中加载公共页面的实现代码
2019/10/22 PHP
php 多继承的几种常见实现方法示例
2019/11/18 PHP
ThinkPHP5&amp;5.1实现验证码的生成、使用及点击刷新功能示例
2020/02/07 PHP
jQuery事件 delegate()使用方法介绍
2012/10/30 Javascript
JQuery验证工具类搜集整理
2013/01/16 Javascript
jQuery之折叠面板的深入解析
2013/06/19 Javascript
jquery mobile动态添加元素之后不能正确渲染解决方法说明
2014/03/05 Javascript
js兼容火狐获取图片宽和高的方法
2015/05/21 Javascript
基于javascript制作经典传统的拼图游戏
2016/03/22 Javascript
JS实现基于拖拽改变物体大小的方法
2018/01/23 Javascript
WEEX环境搭建与入门详解
2019/10/16 Javascript
JavaScript实现打砖块游戏
2020/02/25 Javascript
解决vant的Toast组件时提示not defined的问题
2020/11/11 Javascript
element-ui 弹窗组件封装的步骤
2021/01/22 Javascript
基于vue的video播放器的实现示例
2021/02/19 Vue.js
[03:08]TI9战队档案 - Vici Gaming
2019/08/20 DOTA
基于python log取对数详解
2018/06/08 Python
python文本数据处理学习笔记详解
2019/06/17 Python
python pyinstaller打包exe报错的解决方法
2019/11/02 Python
Python astype(np.float)函数使用方法解析
2020/06/08 Python
解决canvas转base64/jpeg时透明区域变成黑色背景的方法
2016/10/23 HTML / CSS
英国最大的奢侈品零售网络商城:Flannels
2016/09/16 全球购物
玩具反斗城西班牙网上商城:ToysRUs西班牙
2017/01/19 全球购物
意大利专业化妆品品牌:KIKO MILANO
2017/02/01 全球购物
NARS化妆品官方商店:美国彩妆品牌
2017/08/26 全球购物
世界上最好的精品店:Shoptiques
2018/02/05 全球购物
《草原》教学反思
2014/02/15 职场文书
学生请假条
2014/04/11 职场文书
2016消防宣传标语口号
2015/12/26 职场文书
python 实现图与图之间的间距调整subplots_adjust
2021/05/21 Python
Python3中PyQt5简单实现文件打开及保存
2021/06/10 Python
Java中多线程下载图片并压缩能提高效率吗
2021/07/01 Java/Android
K8s部署发布Golang应用程序的实现方法
2021/07/16 Golang
关于k8s环境部署mysql主从的问题
2022/03/13 MySQL