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 相关文章推荐
HTML页面如何象ASP一样接受参数
Feb 07 Javascript
JS处理VBArray的函数使用说明
May 11 Javascript
JavaScript字符串对象slice方法入门实例(用于字符串截取)
Oct 16 Javascript
Javascript+CSS实现影像卷帘效果思路及代码
Oct 20 Javascript
JQuery右键菜单插件ContextMenu使用指南
Dec 19 Javascript
AngularJS入门教程之过滤器详解
Aug 19 Javascript
js实现PC端根据IP定位当前城市地理位置
Feb 22 Javascript
vue-cli 使用axios的操作方法及整合axios的多种方法
Sep 12 Javascript
Easyui 去除jquery-easui tab页div自带滚动条的方法
May 10 jQuery
Ajax请求时无法重定向的问题解决代码详解
Jun 21 Javascript
解决vue cli使用typescript后打包巨慢的问题
Sep 30 Javascript
vue 解决computed修改data数据的问题
Nov 06 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缓存技术介绍
2006/11/25 PHP
PHP中设置时区方法小结
2012/06/03 PHP
php随机输出名人名言的代码
2012/10/07 PHP
ThinkPHP控制器里javascript代码不能执行的解决方法
2014/11/22 PHP
php readfile下载大文件失败的解决方法
2017/05/22 PHP
Laravel中错误与异常处理的用法示例
2018/09/16 PHP
PHP中16个高危函数整理
2019/09/19 PHP
一个简单的javascript类定义例子
2009/09/12 Javascript
jquery select选中的一个小问题
2009/10/11 Javascript
js统计录入文本框中字符的个数并加以限制不超过多少
2014/05/23 Javascript
分享我对JS插件开发的一些感想和心得
2016/02/04 Javascript
jQuery获取单击节点对象的方法
2016/06/02 Javascript
基于substring()和substr()的使用以及区别(实例讲解)
2017/12/28 Javascript
AngularJS 将再发布一个重要版本 然后进入长期支持阶段
2018/01/31 Javascript
Vue-cropper 图片裁剪的基本原理及思路讲解
2018/04/17 Javascript
countup.js实现数字动态叠加效果
2019/10/17 Javascript
8个非常实用的Vue自定义指令
2020/12/15 Vue.js
[47:18]完美世界DOTA2联赛循环赛 IO vs FTD BO2第一场 11.05
2020/11/06 DOTA
Python学习笔记(一)(基础入门之环境搭建)
2014/06/05 Python
python实现在无须过多援引的情况下创建字典的方法
2014/09/25 Python
python实现12306火车票查询器
2017/04/20 Python
Python三种遍历文件目录的方法实例代码
2018/01/19 Python
Python3随机漫步生成数据并绘制
2018/08/27 Python
Python类的继承用法示例
2019/01/31 Python
Python3 itchat实现微信定时发送群消息的实例代码
2019/07/12 Python
什么是Python变量作用域
2020/06/03 Python
如何将json数据转换为python数据
2020/09/04 Python
python 图像增强算法实现详解
2021/01/24 Python
纯CSS实现设置半个字符的样式
2014/07/03 HTML / CSS
canvas绘制视频封面的方法
2018/02/05 HTML / CSS
爱国卫生月活动总结范文
2014/04/25 职场文书
干部作风建设个人剖析材料
2014/10/11 职场文书
幼儿园春季开学通知
2015/07/16 职场文书
Java面试题冲刺第十七天--基础篇3
2021/08/07 面试题
python 详解turtle画爱心代码
2022/02/15 Python
Win10多屏显示如何设置?Win10电脑多屏显示设置操作方法
2022/07/07 数码科技