《Java小游戏实现》:坦克大战
《Java小游戏实现》:坦克大战(续一)
博文《Java小游戏实现》:坦克大战(续1)中已经实现到了坦克可以发射一颗子弹了。这篇博文在此基础上继续实现更多的功能。
完成功能:坦克发射多颗子弹
有了坦克发射一颗子弹的基础,发射多颗子弹就相当简单的,只需要在TankClien类中加入一个容器来存放多枚子弹即可。由于容器的容量也是有限的,我们不能一直往里面装。因此,在子弹类中,我们为子弹对象引入了一个live属性,用来判断这个子弹是否还存活。判断子弹是否还存活是根据子弹的位置是否出界。
下面只贴出完成这个功能相关代码
TankClient.java
<code class="hljs cs"> private List<missile> missiles = new ArrayList<missile> (); public List<missile> getMissiles() { return missiles; } @Override public void paint(Graphics g) { //直接调用坦克类的draw方法 tk.draw(g); //画子弹 for(int i=0;i<missiles.size();i++){ code="" missile="" ms="missiles.get(i);"></missiles.size();i++){></missile></missile></missile></code>
Missile.java类
在move方法中根据子弹所在的位置判断子弹是否还存活。
<code class="hljs cs"><code class="hljs cs"> public class Missile { private void move() { if(dir==Direction.L){//L,LU,U,RU,R,RD,D,LD,STOP x -= XSPEED; } else if(dir==Direction.LU){ x -= XSPEED; y -= YSPEED; } else if(dir==Direction.U){ y -= YSPEED; } else if(dir==Direction.RU){ x += XSPEED; y -= YSPEED; } else if(dir==Direction.R){ x += XSPEED; } else if(dir==Direction.RD){ x += XSPEED; y += YSPEED; } else if(dir==Direction.D){ y += YSPEED; } else if(dir==Direction.LD){ x -= XSPEED; y += YSPEED; } //根据子弹所在的位置x,y来判断子弹是否还存活在 if(x<0||x>TankClient.GAME_WIDTH||y<0||y>TankClient.GAME_HEIGHT){ live = false; } } public boolean isLive() { return live; } } </code></code>
Tank.java文件内容如下:
在坦克类中,在keyPressed方法中,每按一次Ctrl键,就发射一颗子弹。
<code class="hljs cs"><code class="hljs cs"> public class Tank { //记录键盘的按键情况 public void keyPressed(KeyEvent e){ int key=e.getKeyCode(); //System.out.println(key); switch(key){ case 17: tc.getMissiles().add(fire()); break; case KeyEvent.VK_LEFT: b_L=true; break; case KeyEvent.VK_UP: b_U=true; break; case KeyEvent.VK_RIGHT: b_R=true; break; case KeyEvent.VK_DOWN: b_D=true; break; } //根据上面的按键情况,确定坦克即将要运行的方向 moveDirection(); } } </code></code>
完整代码下载链接:http://download.csdn.net/detail/u010412719/9555292
完成功能:解决坦克越界问题
坦克越界问题比较简单,只需要判断坦克所在的位置是否越界,如果越界,则将其位置设置为边界位置即可。
实现代码如下:
<code class="hljs cs"><code class="hljs cs"> /* * 函数功能:处理坦克越界问题 * */ private void dealTankBorder() { if(x<0){ x = 0; } else if(x > TankClient.GAME_WIDTH-this.WIDTH){ x = TankClient.GAME_WIDTH-this.WIDTH ; } if(y<0){ y = 0; } else if(y>TankClient.GAME_WIDTH - this.HEIGHT){ y = TankClient.GAME_WIDTH - this.HEIGHT; } }</code></code>
上面函数在move()方法最后进行调用即可。
完成功能:加入敌人的坦克
前面实现的所用功能是自己一个坦克在界面上面运动呀、发子弹呀等等。
下面我们完成在界面上加入一个敌人坦克。
实现敌人坦克有两种方式
1、第一种是再新建一个EnemyTank类,
2、第二种是在原来的Tank类中加入一个属性来表示此坦克的类型。
由于我们有一个坦克类了,为方便起见,这里采用第二种方式:在原来的Tank类中加入一个属性来表示此坦克的类型。
Tank.java中新增加的内容主要有
<code class="hljs cs"><code class="hljs java"> //添加一个属性,表示此坦克是好还是坏 private boolean good; //更改下构造方法 public Tank(int x, int y,boolean good) { this.x = x; this.y = y; this.good = good; } public Tank(int x, int y,boolean good, TankClient tc) { this(x,y,good); this.tc = tc; } //根据坦克的类型给出不同的颜色 public void draw(Graphics g){ Color c = g.getColor(); if(good){ g.setColor(Color.RED); } else{ g.setColor(Color.BLUE); } g.fillOval(x, y, WIDTH, HEIGHT); g.setColor(c); //画一个炮筒 drawGunBarrel(g); move();//根据键盘按键的结果改变坦克所在的位置 }
Missile类没有任何变动。
总管家TankClient.java中需要添加的内容有:
1、new 出两个坦克对象
<code class="hljs cs"><code class="hljs cs">private Tank tk=new Tank(50,50,true,this); private Tank enemy = new Tank(100,100,false,this);</code></code>
2、在paint方法中画出两个坦克
<code class="hljs cs"><code class="hljs cs"> @Override public void paint(Graphics g) { //直接调用坦克类的draw方法 tk.draw(g); enemy.draw(g); //画子弹 for(int i=0;i<missiles.size();i++){ code="" missile="" ms="missiles.get(i);"></missiles.size();i++){></code></code>
<喎�"/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxjb2RlIGNsYXNzPQ=="hljs cs">以上就实现了添加敌对坦克这一功能,但是还没有对其添加随机运动。
完成的功能:子弹打死敌人坦克
经过上面的实现,我们有了一个不会动且不会发子弹的傻傻的敌对坦克,但是我们也不能打死它,下面我们就来实现打死坦克。哈哈,是不是稍微变得有趣一点了。
分析:
1、由于是子弹打死敌人坦克,根据面向对象的思想,在子弹类中,加入一个hitTank方法
<code class="hljs cs"><code class="hljs cs"><code>public boolean hitTank(Tank t){ } </code></code></code>
2、那么hitTank这个方法应该如何来判断是否子弹打中了该坦克呢??这就涉及到一个碰撞的问题。由于我们的子弹和坦克都是矩形,因此碰撞问题就得到了很好的简化,只是判断两个矩形是否有重叠的部分。如果有,则就判断发生了碰撞,子弹就打中了坦克。
因此,在Missile类和Tank类中,,均添加一个getRect()方法,返回子弹和坦克所在的矩形区域对象。
<code class="hljs cs"><code class="hljs cs"><code>public Rectangle getRect(){ return new Rectangle(x, y, WIDTH, HEIGHT); } </code></code></code>
3、当子弹打中了坦克,则子弹和坦克就应该都消失。因此,在坦克中需要引入一个布尔变量来判断坦克是否存活
<code class="hljs cs"><code class="hljs cs"><code class="hljs java"> public boolean hitTank(Tank t){ //首先判断此坦克是否是存活的,如果是死的,就不打了 if(!t.isLive()){ return false; } if(this.getRect().intersects(t.getRect())){//判断是否有碰撞 //碰撞之后,子弹和该坦克就应该都死了 this.live = false;//子弹死了 t.setLive(false);//坦克死了 return true; } else{ return false; } }</code></code></code>
无论是子弹消失,在前面的版本中有处理,但是本版本上的坦克消失,目前的处理方法就是不绘画出来,即在draw方法中,首先判断一下,看此对象是否存活,如果存活,则绘画出来。
代码如下:
<code class="hljs cs"><code class="hljs cs"><code class="hljs cs"> public void draw(Graphics g){ if(!live){ //判断坦克是否存活,如果死了,则不绘画出来,直接返回 return ; } Color c = g.getColor(); if(good){ g.setColor(Color.RED); } else{ g.setColor(Color.BLUE); } g.fillOval(x, y, WIDTH, HEIGHT); g.setColor(c); //画一个炮筒 drawGunBarrel(g); move();//根据键盘按键的结果改变坦克所在的位置 } </code></code></code>
最后,贴下Tank类、Missile类、TankClient类的完整代码:
Tank类
<code class="hljs cs"><code class="hljs cs"><code class="hljs java"> public class Tank { //坦克所在的位置坐标 private int x; private int y; //坦克的高度和宽度 private static final int WIDTH = 30; private static final int HEIGHT = 30; //定义两个常量,表示运动的速度 private static final int XSPEED = 5; private static final int YSPEED = 5; //定义四个布尔类型变量来记录按键的情况,默认状态下为false,表示没有键按下 private boolean b_L,b_U,b_R,b_D; //添加一个属性,表示此坦克是好还是坏 private boolean good; public boolean isGood() { return good; } //用来标识此坦克对象是否存活 private boolean live =true; public boolean isLive() { return live; } public void setLive(boolean live) { this.live = live; } //定义一个枚举类型来表示运行的方向 public enum Direction{ L,LU,U,RU,R,RD,D,LD,STOP } //定义一个变量来表示坦克要运行的方向,初始状态为STOP private Direction dir = Direction.STOP; //炮筒方向 private Direction ptDir = Direction.D; private TankClient tc; public Tank(int x, int y,boolean good) { this.x = x; this.y = y; this.good = good; } public Tank(int x, int y,boolean good, TankClient tc) { this(x,y,good); this.tc = tc; } public void draw(Graphics g){ if(!live){ //判断坦克是否存活,如果死了,则不绘画出来,直接返回 return ; } Color c = g.getColor(); if(good){ g.setColor(Color.RED); } else{ g.setColor(Color.BLUE); } g.fillOval(x, y, WIDTH, HEIGHT); g.setColor(c); //画一个炮筒 drawGunBarrel(g); move();//根据键盘按键的结果改变坦克所在的位置 } private void drawGunBarrel(Graphics g) { int centerX = this.x + this.WIDTH/2; int centerY = this.y + this.HEIGHT/2; if(ptDir==Direction.L){//L,LU,U,RU,R,RD,D,LD,STOP g.drawLine(centerX, centerY, x, y + HEIGHT/2); } else if(ptDir==Direction.LU){ g.drawLine(centerX, centerY, x, y ); } else if(ptDir==Direction.U){ g.drawLine(centerX, centerY, x+ WIDTH/2, y ); } else if(ptDir==Direction.RU){ g.drawLine(centerX, centerY, x + WIDTH, y ); } else if(ptDir==Direction.R){ g.drawLine(centerX, centerY, x+ WIDTH, y + HEIGHT/2); } else if(ptDir==Direction.RD){ g.drawLine(centerX, centerY, x+ WIDTH, y + HEIGHT); } else if(ptDir==Direction.D){ g.drawLine(centerX, centerY, x+ WIDTH/2, y + HEIGHT); } else if(ptDir==Direction.LD){ g.drawLine(centerX, centerY, x, y + HEIGHT); } } //记录键盘的按键情况 public void keyPressed(KeyEvent e){ int key=e.getKeyCode(); //System.out.println(key); switch(key){ // case 17://避免因Ctrl一直按下,一直发射子弹,因此将这一功能放入keyReleased方法中了 // tc.getMissiles().add(fire()); // break; case KeyEvent.VK_LEFT: b_L=true; break; case KeyEvent.VK_UP: b_U=true; break; case KeyEvent.VK_RIGHT: b_R=true; break; case KeyEvent.VK_DOWN: b_D=true; break; } //根据上面的按键情况,确定坦克即将要运行的方向 moveDirection(); } //键盘按键松下时,也要进行记录 public void keyReleased(KeyEvent e) { int key=e.getKeyCode(); switch(key){ case 17: tc.getMissiles().add(fire()); break; case KeyEvent.VK_LEFT: b_L=false; break; case KeyEvent.VK_UP: b_U=false; break; case KeyEvent.VK_RIGHT: b_R=false; break; case KeyEvent.VK_DOWN: b_D=false; break; } } //根据键盘的按键情况来确定坦克的运行方向 private void moveDirection() {//L,LU,U,RU,R,RD,D,LD,STOP if(b_L&&!b_U&&!b_R&&!b_D){ dir = Direction.L; } else if(b_L&&b_U&&!b_R&&!b_D){ dir = Direction.LU; } else if(!b_L&&b_U&&!b_R&&!b_D){ dir = Direction.U; } else if(!b_L&&b_U&&b_R&&!b_D){ dir = Direction.RU; } else if(!b_L&&!b_U&&b_R&&!b_D){ dir = Direction.R; } else if(!b_L&&!b_U&&b_R&&b_D){ dir = Direction.RD; } else if(!b_L&&!b_U&&!b_R&&b_D){ dir = Direction.D; } else if(b_L&&!b_U&&!b_R&&b_D){ dir = Direction.LD; } else{//其它所有情况,都是不动 dir = Direction.STOP; } //将坦克方向赋值给炮筒方向 if(dir!=Direction.STOP){ ptDir = dir; } } //上面有运行方向,但是还缺少具体的运行细节,例如:假设是按下了右键,则应该横坐标x+=XSPEED; private void move(){ if(dir==Direction.L){//L,LU,U,RU,R,RD,D,LD,STOP x -= XSPEED; } else if(dir==Direction.LU){ x -= XSPEED; y -= YSPEED; } else if(dir==Direction.U){ y -= YSPEED; } else if(dir==Direction.RU){ x += XSPEED; y -= YSPEED; } else if(dir==Direction.R){ x += XSPEED; } else if(dir==Direction.RD){ x += XSPEED; y += YSPEED; } else if(dir==Direction.D){ y += YSPEED; } else if(dir==Direction.LD){ x -= XSPEED; y += YSPEED; } else if(dir==Direction.STOP){ //... nothing } //处理坦克越界问题 dealTankBorder(); } /* * 函数功能:处理坦克越界问题 * */ private void dealTankBorder() { if(x<0){ x = 0; } else if(x > TankClient.GAME_WIDTH-this.WIDTH){ x = TankClient.GAME_WIDTH-this.WIDTH ; } if(y<0){ y = 0; } else if(y>TankClient.GAME_WIDTH - this.HEIGHT){ y = TankClient.GAME_WIDTH - this.HEIGHT; } } public Missile fire(){ //计算子弹的位置,并利用炮筒的方向来new一个子弹对象 int x = this.x +(this.WIDTH)/2 - (Missile.WIDTH)/2; int y = this.y + (this.HEIGHT)/2 -(Missile.HEIGHT)/2; Missile ms = new Missile(x,y,this.ptDir); return ms; } /* * 函数功能:得到坦克所在位置的矩形框 * */ public Rectangle getRect(){ return new Rectangle(x, y, WIDTH, HEIGHT); } }</code></code></code>
Missile类
代码如下
<code class="hljs cs"><code class="hljs cs"><code class="hljs java"> public class Missile { //定义两个常量,表示运动的速度 private static final int XSPEED = 10; private static final int YSPEED = 10; //子弹所在的位置 private int x; private int y; //坦克的高度和宽度 public static final int WIDTH = 10; public static final int HEIGHT = 10; //子弹的运行方向 private Direction dir; private boolean live = true; public Missile(int x, int y, Direction dir) { this.x = x; this.y = y; this.dir = dir; } public void draw(Graphics g){ //如果该子弹不是存活的,则不进行绘图 if(!live){ return ; } Color c = g.getColor(); g.setColor(Color.YELLOW); g.fillOval(x, y, WIDTH, HEIGHT); g.setColor(c); move(); } private void move() { if(dir==Direction.L){//L,LU,U,RU,R,RD,D,LD,STOP x -= XSPEED; } else if(dir==Direction.LU){ x -= XSPEED; y -= YSPEED; } else if(dir==Direction.U){ y -= YSPEED; } else if(dir==Direction.RU){ x += XSPEED; y -= YSPEED; } else if(dir==Direction.R){ x += XSPEED; } else if(dir==Direction.RD){ x += XSPEED; y += YSPEED; } else if(dir==Direction.D){ y += YSPEED; } else if(dir==Direction.LD){ x -= XSPEED; y += YSPEED; } //根据子弹所在的位置x,y来判断子弹是否还存活在 if(x<0||x>TankClient.GAME_WIDTH||y<0||y>TankClient.GAME_HEIGHT){ live = false; } } public boolean isLive() { return live; } public Rectangle getRect(){ return new Rectangle(x, y, WIDTH, HEIGHT); } public boolean hitTank(Tank t){ //首先判断此坦克是否是存活的,如果是死的,就不打了 if(!t.isLive()){ return false; } if(this.getRect().intersects(t.getRect())){//判断是否有碰撞 //碰撞之后,子弹和该坦克就应该都死了 this.live = false;//子弹死了 t.setLive(false);//坦克死了 return true; } else{ return false; } } </code></code></code>
TankClient类代码如下:
<code class="hljs cs"><code class="hljs cs"><code class="hljs java"> /* * 此版本添加了子弹打死敌对坦克 * */ public class TankClient extends Frame{ public final static int GAME_WIDTH=600; public final static int GAME_HEIGHT=600; private Tank tk=new Tank(50,50,true,this); private Tank enemy = new Tank(100,100,false,this); private List<missile> missiles = new ArrayList<missile> (); public List<missile> getMissiles() { return missiles; } private Image offScreenImage = null; public static void main(String[] args) { new TankClient().launchFrame(); } @Override 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.darkGray); goffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT); goffScreen.setColor(c); paint(goffScreen); g.drawImage(offScreenImage, 0, 0, null); } @Override public void paint(Graphics g) { //直接调用坦克类的draw方法 tk.draw(g); enemy.draw(g); //画子弹 for(int i=0;i<missiles.size();i++){ catch="" code="" extends="" implements="" interruptedexception="" keyevent="" keymonitor="" missile="" ms="missiles.get(i);" myrepaint="" new="" override="" private="" public="" try="" void="" windowevent=""></missiles.size();i++){></missile></missile></missile></code></code></code>
以上就完成了坦克发射子弹可以击打敌对坦克的功能。
未完,剩余功能见下篇博文
以上就是《Java小游戏实现》:坦克大战(续2)的内容,更多相关内容请关注PHP中文网(www.php.cn)!