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 相关文章推荐
发布BlueShow v1.0 图片浏览器(类似lightbox)blueshow.js 打包下载
Jul 21 Javascript
JS event使用方法详解
Apr 28 Javascript
ExtJS 2.0实用简明教程 之Ext类库简介
Apr 29 Javascript
JavaScript.Encode手动解码技巧
Jul 14 Javascript
Javascript面象对象成员、共享成员变量实验
Nov 19 Javascript
JavaScript实现同时调用多个函数的方法
Nov 09 Javascript
Vue.js 表单校验插件
Aug 14 Javascript
js仿手机页面文件下拉刷新效果
Oct 14 Javascript
xmlplus组件设计系列之选项卡(Tabbar)(5)
May 03 Javascript
Vue引用Swiper4插件无法重写分页器样式的解决方法
Sep 27 Javascript
详解小程序用户登录状态检查与更新实例
May 15 Javascript
JavaScript实现英语单词题库
Dec 24 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/05/27 PHP
php 学习资料零碎东西
2010/12/04 PHP
php 地区分类排序算法
2013/07/01 PHP
php cURL和Rolling cURL并发方式比较
2013/10/30 PHP
php析构函数的简单使用说明
2015/08/24 PHP
js操作textarea 常用方法总结
2012/12/03 Javascript
转换字符串为json对象的方法详解
2013/11/29 Javascript
javascript if条件判断方法小结
2014/05/17 Javascript
JavaScript实现的使用键盘控制人物走动实例
2014/08/27 Javascript
影响jQuery使用的14个方面
2014/09/01 Javascript
js实现图片点击左右轮播
2015/07/08 Javascript
JS实现可拖曳、可关闭的弹窗效果
2015/09/26 Javascript
AngularJS入门心得之directive和controller通信过程
2016/01/25 Javascript
在JavaScript中使用JSON数据
2016/02/15 Javascript
Jquery组件easyUi实现表单验证示例
2016/08/23 Javascript
Node.js中路径处理模块path详解
2016/11/14 Javascript
微信小程序(三):网络请求
2017/01/13 Javascript
express启用https使用小记
2019/05/21 Javascript
JavaScript解析JSON数据示例
2019/07/16 Javascript
node.js开发辅助工具nodemon安装与配置详解
2020/02/06 Javascript
原生js实现瀑布流效果
2020/03/09 Javascript
webpack 动态批量加载文件的实现方法
2020/03/19 Javascript
用Python进行基础的函数式编程的教程
2015/03/31 Python
Python实现正弦信号的时域波形和频谱图示例【基于matplotlib】
2018/05/04 Python
快速排序的四种python实现(推荐)
2019/04/03 Python
Python依赖包整体迁移方法详解
2019/08/15 Python
Pytorch 数据加载与数据预处理方式
2019/12/31 Python
python实现井字棋小游戏
2020/03/04 Python
解决flask接口返回的内容中文乱码的问题
2020/04/03 Python
浅谈CSS3鼠标移入图片动态提示效果(transform)
2017/11/06 HTML / CSS
幼儿园安全检查制度
2014/01/30 职场文书
2015年乡镇组织委员工作总结
2015/10/23 职场文书
护士岗前培训心得体会
2016/01/08 职场文书
2016年大学生暑期社会实践活动总结
2016/04/06 职场文书
《鲁班学艺》读后感3篇
2019/11/27 职场文书
如何制作自己的原生JavaScript路由
2021/05/05 Javascript