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 相关文章推荐
Flash+XML滚动新闻代码 无图片 附源码下载
Nov 22 Javascript
JavaScript Cookie显示用户上次访问的时间和次数
Dec 08 Javascript
javascript模版引擎-tmpl的bug修复与性能优化分析
Oct 23 Javascript
用JavaScript获取DOM元素位置和尺寸大小的方法
Apr 12 Javascript
『jQuery』.html(),.text()和.val()的概述及使用
Apr 22 Javascript
使用Jquery实现点击文字后变成文本框且可修改
Sep 21 Javascript
Jquery使用css方法改变样式实例
May 18 Javascript
微信小程序 教程之数据绑定
Oct 18 Javascript
JS实现的五级联动菜单效果完整实例
Feb 23 Javascript
vue使用video.js进行视频播放功能
Jul 18 Javascript
JS实现关闭小广告特效
Jan 29 Javascript
解决vue下载后台传过来的乱码流的问题
Dec 05 Vue.js
使用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开发模式(简写版)
2007/03/15 PHP
Linux下PHP安装mcrypt扩展模块笔记
2014/09/10 PHP
几个优化WordPress中JavaScript加载体验的插件介绍
2015/12/17 PHP
php处理json格式数据经典案例总结
2016/05/19 PHP
在php的yii2框架中整合hbase库的方法
2018/09/20 PHP
PHP常用函数之根据生日计算年龄功能示例
2019/10/21 PHP
javaScript 简单验证代码(用户名,密码,邮箱)
2009/09/28 Javascript
javascript 单例/单体模式(Singleton)
2011/04/07 Javascript
cookie在javascript中的使用技巧以及隐私在服务器端的设置
2012/12/03 Javascript
js如何判断不同系统的浏览器类型
2013/10/28 Javascript
两种方法实现在HTML页面加载完毕后运行某个js
2014/06/16 Javascript
JS使用oumousemove和oumouseout动态改变图片显示的方法
2015/03/31 Javascript
JavaScript弹出新窗口后向父窗口输出内容的方法
2015/04/06 Javascript
chrome调试javascript详解
2015/10/21 Javascript
老生常谈JavaScript 函数表达式
2016/09/01 Javascript
JS获取html元素的标记名实现方法
2016/10/08 Javascript
解决layui中onchange失效以及form动态渲染失效的问题
2019/09/27 Javascript
vue中js判断长时间不操作界面自动退出登录(推荐)
2020/01/22 Javascript
pyqt5实现绘制ui,列表窗口,滚动窗口显示图片的方法
2019/06/20 Python
python set内置函数的具体使用
2019/07/02 Python
在python3中使用shuffle函数要注意的地方
2020/02/28 Python
python将音频进行变速的操作方法
2020/04/08 Python
利用python3筛选excel中特定的行(行值满足某个条件/行值属于某个集合)
2020/09/04 Python
django使用channels实现通信的示例
2020/10/19 Python
scrapy在python爬虫中搭建出错的解决方法
2020/11/22 Python
详解移动端h5页面根据屏幕适配的四种方案
2020/04/15 HTML / CSS
Html5嵌入钉钉的实现示例
2020/06/04 HTML / CSS
美国最大的万圣节服装网站:HalloweenCostumes.com
2017/10/12 全球购物
斯巴达比赛商店:Spartan Race
2019/01/08 全球购物
2014年大班元旦活动方案
2014/02/26 职场文书
小学生作文评语大全
2014/04/21 职场文书
文明好少年事迹材料
2014/08/19 职场文书
2014企业领导班子四风对照检查材料思想汇报
2014/09/17 职场文书
庆六一开幕词
2015/01/29 职场文书
教学质量月活动总结
2015/05/11 职场文书