我写坦克大战的笔记主要是挑着重要的版本写一下今天要写的是一个非常重要的版本就是0.7和0.8版本,在这个版本中主要是要实现一个面向对象的思考方式,马士兵老师举了一个例子很重要。比如我们要去新疆,按照原先的那种面向过程的编程方式就是第一步,第二步骤,第三步等等一步步都要告诉该怎么做,而面向对象的思维方式就是把一些方法都封装在一个类中直接去调用它就行了。这样能够省下许多重复的工作。就我们拿一个例子来说:比如军区司令,他的任务是很明确的就是指挥那些战士的下达命令,但是他不是叫士兵怎么样拿坦克炮弹放到哪个角度射击,至于那些问题那还会有别人去管我到时候直接运行就OK了分工是很明确的。
Tankclient:
import java.awt.*; import java.awt.event.*; import java.awt.event.*; public class TankClient extends Frame{ private static final Color c = null; public static final int GAME_WIDTH=800; public static final int GAME_HEIGHT=600; //点击TankClient然后重写方法 Tank myTank= new Tank(50,50); Image offScreenImage=null;//然后要重写update方法 public void paint(Graphics g) { myTank.draw(g); } public void update(Graphics g) {//创建一个虚拟的图片 g是屏幕的画笔 if(offScreenImage==null){ offScreenImage=this.createImage(GAME_WIDTH,GAME_HEIGHT); } Graphics gOffScreen=offScreenImage.getGraphics();//拿到画笔 Color color=gOffScreen.getColor(); gOffScreen.setColor(color.GREEN); gOffScreen.fillRect(0,0,GAME_WIDTH,GAME_HEIGHT); gOffScreen.setColor(c); paint(gOffScreen);//gOffScreen背后图片的画笔 g.drawImage(offScreenImage,0,0,null);}//里面有四个参数,第一个是画一张图片, //第二个是图片左上角点的位置,第三个是一个观察对象,第四个是null public void lauchFrame(){ this.setLocation(400,300); this.setSize(GAME_WIDTH,GAME_HEIGHT); this.setTitle("TankWar");//改一下标题栏的名字 this.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0);//正常退出 } }); this.setResizable(false); this.setBackground(Color.green);//设置背景色 this.addKeyListener(new KeyMonitor());//把KeyMonitor事件加载到frame里来 setVisible(true); new Thread(new PaintThread()).start();//启动线程 } public static void main(String[] args){ TankClient tc=new TankClient(); tc.lauchFrame(); } private class PaintThread implements Runnable { //定义一个线程,使用的是内部类,主要是实现重画的线程 public void run() { while(true) { repaint(); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } } private class KeyMonitor extends KeyAdapter { public void keyPressed(KeyEvent e) { myTank.keyPressed(e); } } }
Tank.java
import java.awt.Color; import java.awt.Graphics; import java.awt.event.*; public class Tank { public static final int XSPEED=5; public static final int YSPEED=5; private int x,y; private boolean bL=false,bU=false,bR=false,bD=false; enum Direction {L,LU,U,RU,R,RD,D,LD,STOP}; private Direction dir=Direction.STOP; public Tank(int x, int y) { this.x = x; this.y = y; } public void draw(Graphics g){ Color c=g.getColor(); g.setColor(Color.RED); g.fillOval(x,y, 30, 30);//画一个实心圆 g.setColor(c);//把原来的颜色设回来 move(); } void move(){ switch(dir){ case L: x-=XSPEED; break; case LU: x-=XSPEED; y-=YSPEED; break; case U: y-=YSPEED; break; case RU: x+=XSPEED; y-=YSPEED; break; case R: x+=XSPEED; break; case RD: x+=XSPEED; y+=YSPEED; break; case D: y+=YSPEED; break; case LD: x-=XSPEED; y+=YSPEED; break; case STOP: break; } } //按下键后根据方向定义下一个位置,坦克移动朝八个方向移动 public void keyPressed(KeyEvent e){ int key = e.getKeyCode(); switch(key) { 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; } locataDirection();//按下键以后重新定位一下方向 } void locataDirection(){ 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; } }
在Tank这个程序中我们已经把draw的一些属性封装在这个类中了至于这个Tank怎么画,炮弹等等的位置画哪里其实我们不管,我给draw这个传一个画笔让它自己去描述就得了不用你操心这个不是你该管的,到时候我们直接在clinent调用draw就行了,但是我们传递了画笔还得引入一个包import.java.awt.*;这个是其中的一个应用,还有一个地方就是我要控制的就是坦克自己的移动,那我们想坦克自己移动的各个方向那都是坦克自己的事,我们所关心的就是坦克运动起来就行了至于他怎么样运动,沿着那个方向运动那是坦克自己的事情,我们把这个些方法都封装在一个类中到时候直接调用那就可以减少很多重复的代码。
【说明】1 在写程序的时候控制方向的时候要特别注意一般取的是右和下为正方向,因为这个是根据屏幕而定的屏幕的左上角为原点所以往下和往右都是正方向这个要注意,特别是在写方向的时候是“+“还是“—”要搞清楚
2此程序运行的结果还是有一点怪异的地方;比如我让他往左或者右都是能运行的,但是我让他往下那就会发生问题。他会斜着走,这个问题在以后的版本中会解决