• 用javascript 面向对象制作坦克大战(三)


      之前,我们完成了坦克的移动和地图的绘制,这次我们来完成碰撞检测和炮弹的发射。

      上代码前来张最新的类图:

    3. 碰撞检测

        前面我们已经完成了坦克的移动和地图的绘制,下面我们开始写碰撞检测。

    3.1    创建碰撞检测对象

            我们创建一个对象来做碰撞检测,由于碰撞检测都是在对象移动的时候进行的所以我们让Mover继承我们的碰撞对象。
     
    HitTestObject.js:
     
     1 // 碰撞检测对象 继承自顶级对象
     2 HitTestObject = function () { }
     3 
     4 HitTestObject.prototype = new TankObject();
     5 // 碰撞检测 参数为地图对象 返回true则不能移动
     6 HitTestObject.prototype.HitTest = function (battleField) {
     7 
     8     var nextObj = this.GetNextBattleFieldCell(battleField);
     9     if (nextObj == null) {
    10         return true;// 场景越界
    11     }
    12     // 检测是否是障碍物
    13     if (nextObj.obj instanceof Barrier) {
    14 
    15         if (nextObj.obj instanceof EmptyB) {
    16             // 判断是否被其他坦克占用  Tank继承自Mover
    17             return nextObj.occupier instanceof Mover;
    18         }
    19         return !nextObj.obj.CanAcross;
    20     }
    21 
    22 
    23 }
    24 
    25 // 返回对象移动下个位置的地图对象
    26 HitTestObject.prototype.GetNextBattleFieldCell = function (battleField) {
    27 
    28     if (this.Direction == EnumDirection.Up && this.YPosition == 0 ||
    29         this.Direction == EnumDirection.Down && this.YPosition == 12 ||
    30         this.Direction == EnumDirection.Left && this.XPosition == 0 ||
    31         this.Direction == EnumDirection.Right && this.XPosition == 12
    32         ) {
    33         return null;/* 场景越界 */
    34     }
    35 
    36     var y = this.YPosition;
    37     var x = this.XPosition;
    38     var nextAxes = this.GetNextAxes(x, y);
    39     return battleField[nextAxes.y][nextAxes.x];
    40 }
    41 
    42 // 得到对象的下个位置的坐标
    43 HitTestObject.prototype.GetNextAxes = function (x, y) {
    44     var point = { x: x, y: y };
    45     switch (this.Direction + "") {    // 加空字符转换为字符串类型
    46         case EnumDirection.Up:
    47             point.y--; break;
    48         case EnumDirection.Right:
    49             point.x++; break;
    50         case EnumDirection.Down:
    51             point.y++; break;
    52         case EnumDirection.Left:
    53             point.x--; break;
    54     }
    55     return point;
    56 }
    57 
    58 
    59 HitTestObject.prototype.OnHitTest = function (battleField) {
    60     //  预留给炮弹对象重写
    61 }
    View Code
      这里我们把之前写的地图二维数组对象充分利用上了。通过对象x,y坐标取对应的地图对象,再根据属性判断是否可被穿过,是否已被占用。

    3.2   调用碰撞检测

      这里需要我们在之前的代码做一系列的更改了。

     更改 Mover.js

      1、继承碰撞检测对象
     
    Mover.prototype = new HitTestObject();
    

      

      2、在Mover方法中调用碰撞检测
    // 碰撞检测
        if (this.HitTest(battleField)) { return this.OnHitTest(battleField); }
    

      

     
      3、移动完成后占用新地图对象,清空原对象地图占用。
     
    battleField[nextPoint.y][nextPoint.x].occupier = This;  /*占用新位置*/
    
    // 清空对象原来位置占有
    battleField[yp][xp].occupier = null;
    

      

    还有一些更改就不一一列出了,大家可以下载源码查看。
     
    更改    Frame.js 给方法加上参数。
    更改 tank.js  UpdateUi方法
    初始化坦克时,占有当前位置。
      

    4.   发射炮弹

         炮弹可以移动,所以继承自我们的Mover对象。炮弹击中障碍物时会有爆炸效果,所以我们先写爆炸对象。

     

    4.1 爆炸效果对象

      Explode.js:

     1 // 爆炸效果类
     2 Explode = function () {
     3     this.container = document.getElementById("divMap");
     4     this.UI = null;
     5     this.step = 8;  // 共8张图
     6     this.speed = 50;    // 动画播放速度
     7 }
     8 
     9 // 播放爆炸效果
    10 Explode.prototype.Play = function (x,y) {
    11     this.UI = UtilityClass.CreateE("div", "", "explode", this.container);
    12     this.MoveTo(x, y);
    13 
    14     var i = 0;
    15     var This = this;
    16     var FxTimer = setInterval(function () {
    17         This.UI.style.backgroundPosition = '0 -' + i * 60 + 'px';
    18         i++;
    19         if (i==This.step) {
    20             clearInterval(FxTimer);
    21             This.Stop();
    22         }
    23     },this.speed);
    24 }
    25 
    26 // 播放位置 
    27 Explode.prototype.MoveTo = function (x,y) {
    28 
    29     if (this.UI != null) {
    30         this.UI.style.left = x * 40 - 10 + "px";
    31         this.UI.style.top = y * 40 - 10 + "px";
    32     }
    33 
    34 }
    35 
    36 // 移除dom元素
    37 Explode.prototype.Stop = function () {
    38     UtilityClass.RemoveE(this.UI, this.container);
    39 }
    View Code


    4.2 炮弹对象

       Bomb.js:
     
     1 //  炮弹对象,这个对象需要放在TANK对象前面,有先后顺序
     2 Bomb = function () {
     3     this.Owner = null;
     4     this.Power = 1;
     5     this.Speed = 7;
     6 }
     7 
     8 Bomb.prototype = new Mover();
     9 Bomb.prototype.Load = function (x,y) {
    10     // 创建炮弹对象,初始化位置
    11     this.UI = UtilityClass.CreateE("div", "", "bomb", document.getElementById("divMap"))
    12     this.SetPosition(x * 40, y * 40);   /*父类方法*/
    13 
    14 }
    15 
    16 // 重写HitTest方法
    17 Bomb.prototype.HitTest = function (battleField) {
    18     var nextObj = this.GetNextBattleFieldCell(battleField);
    19     if (nextObj == null) {
    20         return true;
    21     }
    22     // 检测是否是障碍物
    23     if (nextObj.obj instanceof Barrier) {
    24         // 河流穿过
    25         if (this instanceof Bomb && nextObj.obj instanceof RiverB) {
    26             return false;
    27         }
    28 
    29         return !nextObj.obj.CanAcross;
    30     }
    31 
    32 }
    33 
    34 // 重写OnHitTest方法 当炮弹碰撞到不可穿过对象时调用
    35 Bomb.prototype.OnHitTest = function (battleField) {
    36 
    37     // 播放爆炸效果
    38     var ex = new Explode();
    39     ex.Play(this.XPosition, this.YPosition);
    40     this.Owner.BombUsed--;      /*已用弹药数减一*/
    41     // 清空地图占有位置,移除元素
    42     battleField[this.YPosition][this.XPosition].occupier = null;
    43     UtilityClass.RemoveE(this.UI, document.getElementById("divMap"));
    44 
    45     var nextObj = this.GetNextBattleFieldCell(battleField);
    46     if (nextObj == null) { return; }
    47     // 炮弹打到了障碍物
    48     if (nextObj.obj instanceof Barrier) {
    49         if (nextObj.obj.CanBeAttacked) {
    50             nextObj.obj.DefenVal -= this.Power;
    51             // 障碍物防御值降到0,把障碍物变为空地
    52             if (nextObj.obj.DefenVal <= 0) {
    53                 var to = new EmptyB();
    54                 to.UI = nextObj.obj.UI;
    55                 to.XPosition = nextObj.obj.XPosition;
    56                 to.YPosition = nextObj.obj.YPosition;
    57                 nextObj.obj = to;
    58                 to.UI.className = "";
    59                 battleField[this.YPosition][this.XPosition].obj.UI.className = "";
    60             }
    61         }
    62     }
    63         
    64 }
    View Code
       主要的对象完成了,调用就是水到渠成了,我们需要给坦克添加一个发射炮弹的方法,并在玩家按下空格键时调用就可以了。  大家可以试着自己写下实现。  
     
    TankV3.0 下载地址:
     
     


    编程并没有捷径,真正的成长都是来源于实践、思考和总结。

  • 相关阅读:
    “数学题”——传钱
    kafka笔记——入门介绍
    SpringBoot集成Dubbo+Zookeeper
    MySql基本语法
    动态规划
    总结
    Java反射
    软件清单
    Java IO操作
    Spring Boot AOP的使用
  • 原文地址:https://www.cnblogs.com/simple-blog/p/4126316.html
Copyright © 2020-2023  润新知