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 相关文章推荐
获取元素距离浏览器周边的位置的方法getBoundingClientRect
Apr 17 Javascript
js展开闭合效果演示代码
Jul 24 Javascript
JavaScript时间转换处理函数
Apr 14 Javascript
javascript中setInterval的用法
Jul 19 Javascript
js中作用域的实例解析
Mar 16 Javascript
使用ES6语法重构React代码详解
May 09 Javascript
JavaScript实现自动跳转文本功能
May 25 Javascript
JS实现的JSON数组去重算法示例
Apr 11 Javascript
详解使用vue-admin-template的优化历程
May 20 Javascript
webpack 3.X学习之多页面打包的方法
Sep 04 Javascript
vue2.0获取鼠标位置的方法
Sep 13 Javascript
React传值 组件传值 之间的关系详解
Aug 26 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 curl参数的详解
2013/06/17 PHP
在yii中新增一个用户验证的方法详解
2013/06/20 PHP
基于PHP的简单采集数据入库程序【续篇】
2014/07/30 PHP
javascript利用控件对windows的操作实现原理与应用
2012/12/23 Javascript
Javascript中的Callback方法浅析
2015/03/15 Javascript
Node.js实现JS文件合并小工具
2016/02/02 Javascript
js实现tab切换效果
2017/02/16 Javascript
JS仿Base.js实现的继承示例
2017/04/07 Javascript
关于Mac下安装nodejs、npm和cnpm的教程
2018/04/11 NodeJs
微信小程序scroll-x失效的完美解决方法
2018/07/18 Javascript
代码实例ajax实现点击加载更多数据图片
2018/10/12 Javascript
发布Angular应用至生产环境的方法
2018/12/10 Javascript
JavaScript函数的4种调用方法实例分析
2019/03/05 Javascript
javascript面向对象三大特征之继承实例详解
2019/07/24 Javascript
[05:45]Ti4观战指南(下)
2014/07/07 DOTA
搞笑的程序猿:看看你是哪种Python程序员
2015/06/12 Python
python连接字符串的方法小结
2015/07/13 Python
python 在threading中如何处理主进程和子线程的关系
2020/04/25 Python
CSS3实现文本垂直排列的方法
2018/07/10 HTML / CSS
Sephora丝芙兰菲律宾官方网站:购买化妆品和护肤品
2017/04/05 全球购物
美国花布包包品牌:Vera Bradley
2017/08/11 全球购物
ebookers英国:隶属全球最大的在线旅游公司Expedia
2017/12/28 全球购物
Paper Cape官网:美国婴儿和儿童服装品牌
2019/11/02 全球购物
华为慧通笔试题
2016/04/22 面试题
实践单位评语
2014/04/26 职场文书
美术第二课堂活动总结
2014/07/08 职场文书
2014年秘书工作总结
2014/11/25 职场文书
爱心捐款感谢信
2015/01/20 职场文书
旷工辞退通知书
2015/04/17 职场文书
敬老院义诊活动总结
2015/05/07 职场文书
行政处罚事先告知书
2015/07/01 职场文书
法律服务所工作总结
2015/08/10 职场文书
22句经典语录:送给优柔寡断和胡思乱想的朋友们
2019/12/13 职场文书
Python中zipfile压缩包模块的使用
2021/05/14 Python
python tqdm用法及实例详解
2021/06/16 Python
Spring boot应用启动后首次访问很慢的解决方案
2021/06/23 Java/Android