Blogger Template by Blogcrowds.

CodeTank Games

CodeTank 是一款基于html5的编程小游戏,由于曾经做过一段时间的机器人足球,类似的小游戏对我来说并不陌生,其主要功能就是为用户提供一系列游戏运行的基本操作,对于这一款游戏来说比如设置tank的运行,tank的雷达的运行和tank火炮的运行,同时还有一系列基础的动作和函数,用户通过这一系列的基础动作和函数设计战术动作从而达到消灭敌人保全自己的目的。
这类游戏的鼻祖为一个叫Robcode的游戏,当然在腾讯刚开始推出这一款编程小游戏时也有不少质疑,很多人觉得这一款游戏是抄袭Robocode,当然也有许多人为腾讯辩护,关于抄袭的这个问题我在这篇文章中并不打算过多的进行讨论,如果大家有兴趣可以参看这篇文章,先不讨论其优劣,我们还是先来看看这一款游戏的界面,通过QQ号可以直接登录(我大企鹅就是牛逼~),登录以后我们遍可以添加自己的tank了,可是我们还没有任何tank呀,所以在这个时候我们需要创建我们的第一个tank,关于新手创建tank的过程在帮助文档中有详细描述,在这篇文章中也会简单的给大家做一个简短的介绍,由于javascript我自己也不是很熟,只是一边自己学习思考一篇记录一下自己的心得体会。
,首先工欲善其事必先利其器,所以我们对codetank提供的代码结构必须要有所了解,并且,最好是能够熟悉其官方示例代码,基于这个原则我们先来了解其基本框架:

Jx().$package(function(J){
 Robot = new J.Class({extend : tank.Robot},{

  /**
  *robot主循环
  **/ 
  run:function(){
   
  },

  /**
  *看到其他robot的处理程序
  **/
  onScannedRobot:function(e){
   
  },

  /**
  *被子弹击中的处理程序
  **/
  onHitByBullet:function(e){
   
  },

  /**
  *和墙碰撞的处理程序
  **/
  onHitWall:function(e){
   
  },

  onRobotDeath:function(e){
   
  }
 });
});
查看其官方示例发现其代码结构比较简单明确,首先我们可以看到,主要的函数接口有5个,分别为主函数接口,扫描到敌人的函数接口,被子弹击中的函数接口,和墙碰撞以及与其他机器人碰撞的接口,这些接口看起来都比较简单,然后我们可以查看几何官方示例代码,主要包括了开炮,运行、旋转等操作,都十分具有代表性,在实际中我们可以参考其示例代码设计自己的战术,通过这几天的学习我设计了一套简单的战术,也许并不是太有效但是毕竟是自己设计的第一个战术,还是很开心的我的战术基本描述为:
1.根据tank位置找到离当前位置最近的角落点
2.让tank运行到最近的角落点,在这个过程中如果发现敌人直接开炮。在运行到角落点的过程中运行顺序为让tank保持方便逆时针运行的方向,这个主要是方便下面步骤进行批处理。
3.运行到角落后扫描整个战场,此时只用扫描90°方向,大大提高了扫描效率
4.在扫描过程中发现敌方的坦克则应该立即开炮,当然以最大火力开炮(暂时不考虑炮身发热)
5.若在角落被击中则以逆时针方向躲避到下一角落,在躲避过程中首先旋转炮管使其与tank运行方法一致,运行到下一个角落进行扫描。
6.若在运行过程中碰撞到其他tank则直接调转炮身刚正面(这个战术有待商榷)
7若与墙壁发生碰撞,则进行调整运行到最近角落
以上为整个战术过程,实际代码如下:
Jx().$package(function(J){
    var corner=false;
    var flag=1;
    var stopWhenSeeRobot;
    var smartTurn=function(angle){
        if(angle>180){
            angle=angle-360;
        }
        else if(angle<-180){
            angle=angle+360;
        }
        return angle;        
    };
    var getGunAngleToTurn=function(angleGunToTurn){
        return (angleGunToTurn+this.getHeading()-this.getGunHeading())%360;
    };    
    var smartFire=function(robot,robotDistance) {
        if (robotDistance > 200 || robot.getEnergy() < 15) {

            robot.fire(1);
  } else if (robotDistance > 50) {
   robot.fire(2);
  } else {
   robot.fire(3);
  }
 }
    var widthorheight=false;
    Robot = new J.Class({extend : tank.Robot},{
     /**
  *robot主函数
  **/ 
  run:function(){
           this.setUI(tank.ui["While"]);
            this.say("square ghost!","#887cff");

        var currentPos=this.getPos();
         var size=this.getBattleFieldSize();
            var sizeTank=this.getSize();
   var heading=this.getHeading();
            var dis1=Math.abs(currentPos[0])+Math.abs(currentPos[1]);
            var dis2=Math.abs(currentPos[0]-size[0])+Math.abs(currentPos[1]);
            var dis3=Math.abs(currentPos[0])+Math.abs(currentPos[1]-size[1]);
            var dis4=Math.abs(currentPos[0]-size[0])+Math.abs(currentPos[1]-size[1]);
            var mindis=Math.min(Math.min(dis1,dis2),Math.min(dis3,dis4));
           if(mindis===(dis1)){
               
                this.say("1");
                this.turnLeft(smartTurn(90-heading),null);
       widthorheight=false;
       this.ahead(currentPos[1]-sizeTank[1]);
       this.turnLeft(90);
       this.ahead(currentPos[0]-sizeTank[0]);
           } 
          else if(mindis===(dis2)){
              
               this.say("2");
                this.turnLeft(smartTurn(360-heading));
       this.ahead(size[0]-sizeTank[0]-currentPos[0]);
                this.turnLeft(90);
       this.ahead(currentPos[1]-sizeTank[1]);
       widthorheight=true;
      
            }
            else if(mindis===dis3){
                
                this.say("3");
                this.turnLeft(smartTurn(180-heading));
       this.ahead(currentPos[0]-sizeTank[0]);
                 this.turnLeft(90);
       this.ahead(size[1]-currentPos[1]-sizeTank[1]);  
                widthorheight=true;
                
            }
            else{
                
                this.say("4");
                this.turnLeft(smartTurn(270-heading));
                this.ahead(size[1]-currentPos[1]-sizeTank[1]);       
                 this.turnLeft(90);
       this.ahead(size[0]-currentPos[0]-sizeTank[0]);
                widthorheight=false;
                
            }
            corner=true;
            this.loop(function(){
                var tankangle=this.getHeading();
                var angleToTurn1=smartTurn(tankangle-this.getGunHeading()+90);
                this.turnGunLeft(angleToTurn1); 
                this.turnGunLeft(90);
    this.turnGunRight(90);
            });
  },
        
     /**
  *看到其他robot的处理程序
  **/ 
  onScannedRobot:function(e){
            this.say("别跑啊亲!~","#887cff");
            var size=this.getBattleFieldSize();
            var sizeTank=this.getSize();
            if (stopWhenSeeRobot){
                var dis=e.getDistance();
                 if(dis<50)
                 {
                    this.fire(3);
                    this.turnLeft(90);
                 if(widthorheight){
                     var dis=size[0]-2*sizeTank[0];
                     this.say(dis.toString());
                     this.ahead(dis);
                 }
                 if(!widthorheight){
                     var dis=size[1]-2*sizeTank[1];
                     this.say(dis.toString());
                     this.ahead(dis);
                 }    
                 widthorheight=!widthorheight;
                 }
    this.stopMove();
             var angleToRobot=e.getBearing();
             var angleGunToTurn=getGunAngleToTurn.call(this,angleToRobot);
             this.turnGunLeft(smartTurn(angleGunToTurn));
   // smartFire(this,e.getDistance());
       this.fire(3);
                this.scan();
   }
   else{
   // smartFire(this,e.getDistance());
             this.fire(3);
   }
            
  },
        /**
  *被子弹击中的处理程序
  **/
  onHitByBullet:function(e){
            var tankangle=this.getHeading();
            var angleToTurn1=smartTurn(tankangle-this.getGunHeading());
            this.say(angleToTurn1.toString());
            this.turnGunLeft(smartTurn(angleToTurn1));
            var currentPos=this.getPos();
            var size=this.getBattleFieldSize();
            var sizeTank=this.getSize(); 
             this.say(corner.toString());
            if(corner){     
                this.turnLeft(90);
                 if(widthorheight){
                     var dis=size[0]-2*sizeTank[0];
                     this.say(dis.toString());
                     this.ahead(dis);
                 }
                 if(!widthorheight){
                     var dis=size[1]-2*sizeTank[1];
                     this.say(dis.toString());
                     this.ahead(dis);
                 }    
                 widthorheight=!widthorheight;
           }
           
        },
        /**
  *和墙碰撞的处理程序
  **/ 
  onHitWall:function(e){  
          var currentPos=this.getPos();
      var size=this.getBattleFieldSize();
            var sizeTank=this.getSize();
   var heading=this.getHeading();
            var dis1=Math.abs(currentPos[0])+Math.abs(currentPos[1]);
            var dis2=Math.abs(currentPos[0]-size[0])+Math.abs(currentPos[1]);
            var dis3=Math.abs(currentPos[0])+Math.abs(currentPos[1]-size[1]);
            var dis4=Math.abs(currentPos[0]-size[0])+Math.abs(currentPos[1]-size[1]);
             var mindis=Math.min(Math.min(dis1,dis2),Math.min(dis3,dis4));
          if(mindis===(dis1)){
                this.say("1");
                this.turnLeft(smartTurn(90-heading));
       widthorheight=false;
       this.ahead(currentPos[1]-sizeTank[1]);
       this.turnLeft(90);
       this.ahead(currentPos[0]-sizeTank[0]);
           } 
          else if(mindis===(dis2)){
               this.say("2");
                this.turnLeft(smartTurn(360-heading));
       this.ahead(size[0]-sizeTank[0]-currentPos[0]);
                this.turnLeft(90);
       this.ahead(currentPos[1]-sizeTank[1]);
       widthorheight=true;
       
            }
            else if(mindis===dis3){
                this.say("3");
                this.turnLeft(smartTurn(180-heading));
       this.ahead(currentPos[0]-sizeTank[0]);
                 this.turnLeft(90);
       this.ahead(size[1]-currentPos[1]-sizeTank[1]);  
                widthorheight=true;
            }
            else{
                this.say("4");
                this.turnLeft(smartTurn(270-heading));
                this.ahead(size[1]-currentPos[1]-sizeTank[1]);       
                 this.turnLeft(90);
       this.ahead(size[0]-currentPos[0]-sizeTank[0]);
                widthorheight=false;
            }
  },
  onHitRobot:function(e){
            var tankangle=this.getHeading();
            var angleToTurn1=smartTurn(tankangle-this.getGunHeading());
            this.turnGunLeft(smartTurn(angleGunToTurn));
            this.fire(3);
  }
 });
});
代码较为冗长且没有足够的注释,各位勉强看一下,以上代码为开源代码,搜索kq2h5可以找到我的代码,欢迎大家来战,同时也欢迎大家提出改进意见。
以上代码的设计思路主要参考示例代码中的corner代码,由于在角落只受到来自某一个象限的攻击,所以极大的保护了自己,特别是在混战当中,另外位于角落的tank只要将炮身旋转90°即可扫描整个战场,大大提高了扫描战场的效率,当然也就更加容易发现“敌人”,基于此目的我参考了corner示例代码,然而示例代码不管tank在任何位置都要跑到左上角,这无疑给敌人提供了许多攻击的机会,所以我选择最近的角落,另外若是受到攻击不进行躲避的话也就成了活靶子,所以我设计了一个躲避算法,当然,这个躲避算法太有规律了,并不是很好的算法,整个战术还有待改进和提高。

0 Comments:

Post a Comment



较新的博文 较早的博文 主页