J2SE坦克大战(Demo学习总结)


( 纯手绘版坦克大战)

1:制作出显示应用程序窗口

         定义好窗口的大小,布局和背景颜色

         这里主要覆写了父类的paint()和update()方法,在update方法中加入了双缓冲机制具体代码如下:

         Image offScreenImage = null;

public void update(Graphics g) {

       if(offScreenImage == null) {

           offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);

       }

       Graphics gOffScreen = offScreenImage.getGraphics();

       Color c = gOffScreen.getColor();

       gOffScreen.setColor(Color.GREEN);

       gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);

       gOffScreen.setColor(c);

       paint(gOffScreen);   //调用paint方法

       g.drawImage(offScreenImage, 0, 0, null);

    }

 

其次在重绘和按键监听的时候,定义了两个内部类:

/**重绘内部类*/

    private class PaintThread implements Runnable{

 

       @Override

       public void run() {

           while(true){

              repaint();

               try {

                  Thread.sleep(50);

              } catch (InterruptedException e) {

                  e.printStackTrace();

              }

           }

       }

      

    }

   

   

    /**事件监听内部类*/

    private class KeyMonitor extends KeyAdapter{

       public void keyReleased(KeyEvent e){

           myTank.keyReleased(e);

       }

      

       public void keyPressed(KeyEvent e){

           myTank.keyPressed(e);

       }

    }

 

 

this.addKeyListener(new KeyMonitor());

new Thread(new PaintThread()).start();

 

这里在按键的时候,定义了八个方向。代码如下所示:

private boolean bL=false, bU=false, bR=false, bD = false;

enum Direction {L, LU, U, RU, R, RD, D, LD, STOP};

 

public void keyPressed(KeyEvent e) {

       int key = e.getKeyCode();

       switch(key) {

       case KeyEvent.VK_F2 :

           if(!this.live) {

              this.live = true;

              this.life = 100;

           }

           break;

       case KeyEvent.VK_LEFT :

           bL = true;

           break;

       case KeyEvent.VK_UP :

           bU = true;

           break;

       case KeyEvent.VK_RIGHT :

           bR = true;

           break;

       case KeyEvent.VK_DOWN :

           bD = true;

           break;

       }

       locateDirection();

    }

   

    void locateDirection() {

       if(bL && !bU && !bR && !bD) dir = Direction.L;

       else if(bL && bU && !bR && !bD) dir = Direction.LU;

       else if(!bL && bU && !bR && !bD) dir = Direction.U;

       else if(!bL && bU && bR && !bD) dir = Direction.RU;

       else if(!bL && !bU && bR && !bD) dir = Direction.R;

       else if(!bL && !bU && bR && bD) dir = Direction.RD;

       else if(!bL && !bU && !bR && bD) dir = Direction.D;

       else if(bL && !bU && !bR && bD) dir = Direction.LD;

       else if(!bL && !bU && !bR && !bD) dir = Direction.STOP;

    }

 

在区分敌方坦克和自己的坦克的时候,通过一个Boolean变量来区分。

创建敌方坦克的时候,默认给他一个方向,然后通过一个random数值来随机敌方坦克的方向,  放弹也是根据一个随机数来获得。         下面是示例代码:

         private static Random r = new Random();   //定义成静态的,使内存区中只存在一个该实例对象。

    private int step = r.nextInt(12) + 3;

 

然后在move()方法中,开始监听这个变量

if(!good) {       //如果不是好的坦克(说明是敌方) 

           Direction[] dirs = Direction.values();

           if(step == 0) {

              step = r.nextInt(12) + 3;

              int rn = r.nextInt(dirs.length);

              dir = dirs[rn];

           }         

           step --;   //根据step数值来改变敌方玩家的方向

          

           if(r.nextInt(40) > 38) this.fire();

       }    

在和其他物体作碰撞检测的时候,如果碰到某个物体的话,则该坦克不允许再移动,这里解决这个问题的办法是定义另外两个变量oldX, oldY来保存之前的x, y变量。如果碰到物体不可行走则将oldX ,oldY 再付给x,y坐标。 

2:在制作爆炸物特效的时候用到了这样一个判断:

int[] diameter = {4, 7, 12, 18, 26, 32, 49, 30, 14, 6};     //爆破物的直径(由小到大,然后再由大到小,爆破物逐渐消失)

private boolean live = true;

 

public void draw(Graphics g) {

       if(!live) {

           tc.explodes.remove(this);

           return;

       }

      

       if(step == diameter.length) {

           live = false;

           step = 0;

           return;

       }

      

       Color c = g.getColor();

       g.setColor(Color.ORANGE);

       g.fillOval(x, y, diameter[step], diameter[step]);

       g.setColor(c);

      

       step ++;

    }

这样通过一个数组,就可以不通过线程来控制,以后这种方法值得借鉴

 

而下面的血块也是借用了上面一种写法,知识稍微改动了点地方:

    int step = 0;

    private boolean live = true;

   

    //指明血块运动的轨迹,由pos中各个点构成.(目的是让血块按指定的路线动起来)

    private int[][] pos = {

                     {350, 300}, {360, 300}, {375, 275}, {400, 200}, {360, 270}, {365, 290}, {340, 280}

                    };

 

    private void move() {

       step ++;

       if(step == pos.length){

           step = 0;

       }

       x = pos[step][0];

       y = pos[step][1];

    } 

这个也是给明了运动轨迹,只不过是循环多次,直到为死亡状态时循环才结束.

相关内容