制作项目——坦克大战

继上一周开始做的模拟飞机大战游戏项目之后,本周一直持续在做坦克大战这个游戏项目上,虽然看似简单的游戏,但真正对于我们这刚学了JS的初学者来讲,还有点挑战,因为里面涉及的javascript代码颇多,具有大量的逻辑思维想象,值得研究。好吧,下面一如既往的直奔正题:

 一、需求分析

首先我们对这个游戏做了简单的需求分析,要实现一个坦克大战游戏,游戏中包括我方坦克(玩家)、对方坦克(坏坦克),在游戏窗体中有障碍物,包括土墙、钢砖、水面和草地、我方的基地(Boss老巢)。双方坦克都不能穿越除草地以外的障碍物;游戏的玩家通过键盘控制我方坦克的前进、后退、向左、向右移动 ;对方坦克可以在窗体内自主移动,撞墙或边界后自动改变方向;我方坦克与对方坦克都可以发射子弹,双方坦克被敌方的子弹打中都会产生爆炸。双方子弹打到墙上都有爆炸产生,打中后子弹被移除,可摧毁的墙被子弹打中后也会被移除,土墙被子弹打中后也会被移除;敌方子弹或我方子弹击中我方基地及老巢,玩家输,游戏结束。当对方坦克被全部子弹打中,玩家赢,游戏结束。

二、程序设计

因为里面大部分都涉及到的是javascrip编程,所以采用面向对象的设计方法,首先在JS的文件里建立项目中的以下类:

坦克:我方坦克(玩家Tank)、敌方坦克(Tank001)。

障碍物:土墙(Wall)、钢砖(SteelWall)、水面(Water)、草地(Grass)。

子弹:     子弹(Bullet)。

老巢:   鸟(Boss)。

爆炸:   爆炸(Boom)。

三、编码实现

1、主屏幕:创建一个主屏幕,设置其宽和高,并通过鼠标点击事件让游戏的主窗体在下个窗口的屏幕上显示出来。代码如下:

<div id="game" class="star"> 
  <div class="single" onclick="Game()"></div>  
  <div class="coupe" onclick="Game()"></div>  
  <div class="map" onclick="Game()"></div>  
  <img src="images/select.gif" alt="" style="position: absolute; left: 300px;top: 300px"/>  </div>   
   <script type="text/javascript">  
   /*全局变量 */ 
   var background_position = 0;//定义一个变量,赋值为0;  
   //进入游戏界面
  function Game() {
     /*清空内容区域*/ 
     var game = document.getElementById("game");
     var len = game.children.length; 
     for (var i = 0; i < len; i++) 
     { game.removeChild(game.children[0]); //从第一个开始,每次都删除一个子节点 } 
     
    /*创建新的子节点*/
    winDom = document.createElement("div");//创建一个新的div块 
    winDom.setAttribute("id", "windows"); //设置background属性 
    winDom.setAttribute("class", "background");
    game.appendChild(winDom);//把background节点插入到game里面去

2、游戏地图(map):

在主窗体及游戏地图绘制的时候,如果单个画很费力,而且程序代码比较繁琐,所以采用二维数组的方法来绘制。根据窗体的大小来定义一个二维数组数组的每一个元素值来确定绘制哪种障碍物,这里的0代表Boss老巢、1代表土墙,2代表钢砖,3代表草地、4代表水面、5就是空白的,采用这种方法方便更快捷,容易修改,设计地图。。。其代码如下:

 //定义地图
// 列:13 行:10
var winDom;    
var world = new Array();  
var map = [    
[5, 3, 3, 1, 1, 5, 5, 5, 1, 1, 3, 3, 5],    
[5, 1, 1, 2, 1, 1, 1, 1, 4, 1, 1, 1, 5],    
[5, 1, 4, 1, 3, 1, 1, 1, 1, 2, 1, 1, 5],    
[5, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1, 5],    
[3, 4, 1, 2, 4, 1, 1, 1, 3, 1, 1, 4, 2],    
[1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 3],    
[1, 3, 4, 1, 3, 1, 1, 1, 1, 1, 3, 1, 3],    
[1, 1, 2, 1, 5, 1, 1, 1, 5, 2, 2, 1, 1],    
[1, 3, 3, 1, 5, 2, 2, 2, 5, 1, 2, 4, 1],    
[1, 3, 3, 5, 5, 2, 0, 2, 5, 5, 5, 1, 1]    
];      
// 渲染地图    
for(var i=0;i<map.length; i++){    
for(var j=0; j< map[i].length; j++){    
var cell = map[i][j]; // 1    
var x = j * 60;    
var y = i * 60;    
var obj;    
if(cell == 1){// 土墙    
var obj = new Wall(winDom);    
obj.setLocation(x,y);    
}else if(cell == 2){// 钢砖    
var obj = new SteelWall(winDom);    
obj.setLocation(x, y);    
}else if(cell == 3){ //草地    
var obj = new Grass(winDom);    
obj.setLocation(x, y);    
}else if(cell == 4){ //水面   
var obj = new Water(winDom);    
obj.setLocation(x,y);    
}else if(cell == 0){ // Boss老巢   
var obj = new Boss(winDom);    
obj.setLocation(x,y);    
}    
world.push(obj);    
}    
}

3、分别对项目中类的JS代码进行编写:主要是属性和行为两部分(PS:这里只写了我方坦克(玩家)的代码,其余跳过哈!!)

我方坦克(玩家)——

属性:位置、大小、颜色、生命值、步伐、方向;

行为:显示、开火、移动、爆炸、捡道具 、碰撞检测;

 /*
 坦克类
*/
function Tank(dom){
    //属性
    this.keyU = false;// 描述上键盘被按下为true,抬起为false
    this.keyD = false;
    this.keyL = false;
    this.keyR = false;
   this.oldX;
    this.oldY;
   this.direction = Direction.STOP// 方向 
  this.ptdirection = Direction.TU// 方向 
  
   this.element = document.createElement("div");
   this.element.setAttribute("class","tank");
   this.element.setAttribute("style","left:0;top:0;width:60px; height:60px;");
   dom.appendChild(this.element);   
   
 /*设置坦克位置*/
   
 this.setLocation = function(x , y){
        this.element.style.left = x + "px";
        this.element.style.top = y + "px";
    }

/* 监听keydown事件 */
this.keyDown = function(e){
        var key = e.keyCode;
        switch (key){
            case 87: this.keyU = true; break;
            case 83: this.keyD = true; break;
            case 65: this.keyL = true; break;
            case 68: this.keyR = true; break;
        }
        this.localdirection();
    }

/* 监听keyUp事件 */
    this.keyUp = function(e){
        var key = e.keyCode;
        switch (key){
            case 87: this.keyU = false; break;
            case 83: this.keyD = false; break;
            case 65: this.keyL = false; break;
            case 68: this.keyR = false; break;
        }
        this.localdirection();
    }

 /* 确定坦克和炮筒的方向 */
    this.localdirection = function(){
        if(this.keyU && !this.keyD && !this.keyL && !this.keyR ){// 向上
            this.ptdirection  = this.direction = Direction.TU;
        }else if(!this.keyU && this.keyD && !this.keyL && !this.keyR){//向下
            this.ptdirection  = this.direction = Direction.TD;
        }else if(!this.keyU && !this.keyD && this.keyL && !this.keyR){//向左
            this.ptdirection  = this.direction = Direction.TL;
        }else if(!this.keyU && !this.keyD && !this.keyL && this.keyR){//向右
            this.ptdirection  = this.direction = Direction.TR;
        }else{
            this.direction = Direction.STOP;
        }
    }
    
/* 回到之前的位置 */
    this.stay = function(){
        this.element.style.left =  this.oldX  + "px";
        this.element.style.top  =  this.oldY  + "px";
    }

//行为
    this.move = function(){   //左97 上119 右100 下115
        var x =  parseInt(this.element.style.left);
        var y =  parseInt(this.element.style.top);
        this.oldX = x;
        this.oldY = y;
        switch (this.direction){// 判断坦克的方向,决定行走方向
            case Direction.TU :
                // 调整坦克放向图
                this.element.style.backgroundPosition = -60 + "px 0px";
                // 限制坦克移动范围
                if( y > 0 )
                    this.element.style.top =  y -5+"px";
                break;
            case Direction.TD :
                this.element.style.backgroundPosition = -120+"px 0px";
                if(y<540)
                    this.element.style.top = y+5+"px";
                ; break;
            case Direction.TL :
                this.element.style.backgroundPosition = "0px 0px";
                if(x>0)
                    this.element.style.left = x-5+"px";
                ; break;
            case Direction.TR :
                this.element.style.backgroundPosition = -180+"px 0px";
                if(x<720)
                    this.element.style.left = x+5+"px";
                ; break;
        }
    }
    
 /* 碰撞检测 */
    this.hit = function(obj){
        if(obj != undefined){
            if(obj.pass != undefined){ // 草
                 return false;// 如果是草,那么可以直接通过,不用做碰撞检测
            }else{
                var r1 = obj.getRectangle(); // 被碰撞对象的矩形区域
                var r2 = this.getRectangle();// 子弹矩形区域
                return r2.intersects(r1);
            }
        }
        return false;
    }
    
/* 发射子弹 */
    this.fire = function(){
        var b = new Bullet(dom);
        var x;
        var y;  
        
//把炮筒方向设置给子弹
        b.setDirection(this.ptdirection);
        
        // 解决子弹的初始位置
        x =  parseInt(this.element.style.left) + 30 - 3;
        y =  parseInt(this.element.style.top);  
        
// 计算子弹出现位置x,y
        switch (this.ptdirection){
            case Direction.TU :
                x =  parseInt(this.element.style.left) + 30 - 3;
                y =  parseInt(this.element.style.top);
                break;
            case Direction.TD :
                x =  parseInt(this.element.style.left) + 30 - 3;
                y =  parseInt(this.element.style.top) + 60;
                ; break;
            case Direction.TL :
                x =  parseInt(this.element.style.left);
                y =  parseInt(this.element.style.top) + 30 -3;
                ; break;
            case Direction.TR :
                x =  parseInt(this.element.style.left) + 60;
                y =  parseInt(this.element.style.top) + 30 -3;
                ; break;
        }
        b.setLocation(x ,y);
        // 把子弹交给存放子弹的数组
        bullets.push(b);
    }

/* 获取碰撞检测对象 */
    this.getRectangle = function(){
        var x = parseInt(this.element.style.left);// "111px"
        var y =  parseInt(this.element.style.top);// "111px"
        var width = parseInt(this.element.style.width);
        var height = parseInt(this.element.style.height);
        return new Rectangle(x, y, width, height);
    }

}

障碍物: 土墙、钢砖、水面、草地——

属性:位置、大小、颜色;

行为: 碰撞检测、显示;

子弹——

属性:位置、大小、颜色、生命值、步伐、方向;
行为:显示、移动、爆炸 、碰撞检测 ;

boss(老巢)——

属性:位置、大小、颜色、生命值;

行为:爆炸 、碰撞检测 、显示;

爆炸——
       属性:位置、大小、颜色;
       行为:爆炸;

上面的各类的分析已经写出来了,至于JS代码就没有敲出来了,大体上是按照属性和行为分别进行具体编写的。。。

三、游戏效果图:

1、主屏幕:

174518_VTwo_1439446.jpg

2、游戏中:

191256_4lKA_1439446.jpg

 

四、心得体会:

        这次的坦克大战游戏只做了个半成品,还有好多效果都没有能实现,没有办法,JS学得不是很懂,所以就只能凑合做点初成品。。。下面在谈谈我做的坦克大战半成品的一些小小感悟吧!!!

       在坦克大战中我负责做最简单的障碍物(土墙,钢砖,Boss)这一块,老师举了个其他障碍物的范例,我就照着那代码敲,算是举一反三才模仿出来的吧。至于里面其他的东西,遇到的第一个问题算是通过键盘控制我方坦克(玩家坦克)因为JS学的很垃圾,很多地方没懂,所以完全不知道怎么下手去写,后来老师讲解了思路,再老师的带动下,勉强写完,其实算是模仿老师的代码,敲了下来,自己应该写不出来,但是能略看懂点点。后面那些复杂类的面向对象也一样,比如子弹的发射,当时我完全没有思路,老师也讲了子弹发射的思路,可我就是不会写,来回纠结了一天,直到同桌作出了我方子弹的发射,我看了代码才慢慢开始写,最后也算是逼写出来了。我觉得这就是我的问题,遇到问题还是比较毛躁,不敢下手去写。老师教导我们遇到问题时把问题记下来然后慢慢分析,先把思路想好,再下手去写,大胆想象,要注意逻辑关系。这种方法很好,但由于我的毛躁,这种方法这次没能得到很好的实施,下回一定注意,心态一定要平和。还是觉得自己还没有真正学懂JS,没有清晰的条理和思路,所以遇到问题也就只能想到方法,但是具体的代码写不出来,估计是代码练少了,掌握不熟练。。。 

        第一次写坦克大战还有一个致命错误就是笔误。我记得这次遇到好几次,其中就像我方坦克发不出子弹,草地和水墙画不出来都是笔误的问题,这是一个细节问题,也是一个细心问题,要引起高度的重视。项目中团队合作很重要,就像项目类的分工就是充分的证明,小组进行讨论,最后定出最终分工。在遇到问题自己想不出解决办法时一定要向他人请教,不能不问,敢问才能解决问题,才能进步。坦克大战是在飞机项目后做的第一个项目,总得还是感觉一般般,以后要更加努力,做的更好!拿什么拯救你,我的JS,只有自己多练习,勤能补拙。

 

 

转载于:https://my.oschina.net/web705/blog/204397

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值