Java学习总结之坦克大战项目(三)

V0.7:在这一个版本里主要处理边界问题。

首先是炮弹,炮弹出界后就死亡。先判断是否出界,这个只要通过比较炮弹的坐标和边界坐标即可,比较可以再move中进行,也可以在draw中进行,因为move本身就是在draw中调用,在我看来,差别不大。然后是死亡这个动作,我们通过将子弹对象移出 ArrayList 来表示,这样呢,我们就要在炮弹类中操作 ArrayList ,所以在炮弹类中我们需要一个TankFrame 的引用,添加引用,修改构造方法,然后在出界判断逻辑中调用ArrayList 的 remove 方法。

其次是坦克。坦克更好办。只要判断出界就重置位置坐标就可以了,就是说小于零就置为零,大于窗口宽度或高度就置为窗口宽度或高度。

V0.8:在这个版本中我们要加入敌方坦克。

说实话,刚开始在我自己思考的时候我觉得应该要新建一个RobotTank类,因为敌方坦克的移动、开火,都不是靠我们按键来实现的,也就是说除了构造方法和draw方法,其他的都跟已经写好的Tank类不一样,甚至为了区分敌我,draw 方法使用的颜色也不一样。但是!看了视频发现马士兵老师是直接用的Tank类,这个时候我真的挺纠结的,到底是新建一个类还是使用现有的类。感觉从面向对象的角度来说是应该使用现有的类对吧?毕竟两者都是坦克,只是内部方法略有不同。

而这时候!我又想到了抽象类,就是说将Tank类改为一个抽象类,然后有 MyTank 和 RobotTank 两个子类,将两者相同的部分在抽象类中实现,不同的方法则声明为抽象函数,在各自内部实现。感觉上这应该是最靠谱的解决方案了吧?

可惜的是!博主太懒了,太懒了,太懒了。。。最终还是直接新建一个类,然后复制粘贴了事,因为嫌抽象类改动太大,而使用现有的 Tank 类会在后面将Tank类改动太多,看起来会很杂乱,所以。。。you know ,有兴趣的同学可以自己试一下。

新建一个RobotTank 类,然后将基本属性和构造方法还有draw 方法复制过去之后,就可以在窗口类添加一个 RobotTank 类的ArrayList,临时创建一个RobotTank 对象,加入到ArrayList 中,然后调用其draw 方法来观察效果了。当然,仅仅是用来观察效果,因为博主打算每隔一段时间产生一定数量的坦克,只是还没想好应该在哪个方法中生成敌方坦克,感觉每隔一段时间执行一个操作和调用repaint 方法相似,或许可以新建一个线程?往下看吧。

V0.9:在这个版本中呢,我们处理游戏中最常碰到的一个经典问题,collision (碰撞)。也就是如何判断子弹击中对方坦克的问题。这个问题在任何游戏中都会涉及,比如两人pk时怎么判断攻击到了对方,对于这个问题不同环境下有不同的算法。我们这算是最简单的一个了,因为我们直接使用了Java 提供给我们的一个方法。

具体如下:

在炮弹类和RobotTank 类中分别添加一个getRectangle 方法,用来获取当前对象(圆)的一个外接正方形。

然后在子弹中添加一个collide 方法,遍历敌方坦克的ArrayList,使用Rectangle 类的intersects 方法来判断两个矩形是否相交。若相交则说明发生碰撞,炮弹击中坦克。击中坦克之后则双方都死亡,从各自的ArrayList 中移除。

到此版本的代码如下:

TankClient.java

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

public class TankClient {


 public static void main(String[] args) {
  new TankFrame("TankWar").launchFrame();
 }
}
 
class TankFrame extends Frame {
 public static final int FRAME_H = 600;
 public static final int FRAME_W = 800;
 
 Tank myTank = new Tank(200,200,this);
 private ArrayList<Cannonball> cannonballs = new ArrayList<Cannonball>();
 public ArrayList<RobotTank> robots = new ArrayList<RobotTank>();
 
 public TankFrame(String s){
  super(s);
 }
 
 public void launchFrame () {
  setLocation(100,100);
  setSize(FRAME_W,FRAME_H);
  setVisible(true);
  addWindowListener(new WindowAdapter() {
   public void windowClosing(WindowEvent e) {
    System.exit(0);
   }
  });
  this.addKeyListener(new KeyMonitor());
  new Thread(new PaintThread()).start();
  
  robots.add(new RobotTank(400,300,this));
 }
 
 public void paint(Graphics g) {
//  g.drawString("Cannonballs number : " + cannonballs.size(), 50, 50);
  
  myTank.draw(g);
  for(int i = 0; i < robots.size(); i++){
   RobotTank rt = robots.get(i);
   rt.draw(g);
  }
  
  for(int i = 0; i < cannonballs.size();i++){
   Cannonball c = cannonballs.get(i);
   c.draw(g);
  }
 }
 
 public void addCannonball(Cannonball c) {
  cannonballs.add(c);
 }
 
 public void deleteCannonball(Cannonball c) {
  cannonballs.remove(c);
 }
 
 class KeyMonitor extends KeyAdapter {

  public void keyPressed(KeyEvent e) {
   myTank.keyPressed(e);
  }
  
  public void keyReleased(KeyEvent e) {
   myTank.keyReleased(e);
  }
 }
 
 class PaintThread implements Runnable {
  public void run() {
   while(true){
    repaint();
    try {
     Thread.sleep(50);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
  }
 }
}

 

Tank.java

import java.awt.*;
import java.awt.event.*;


public class Tank {
 private static final int X_SPEED = 5;
 private static final int Y_SPEED = 5;
 private static final int TANK_R = 25;//坦克圆的半径
 
 private int tank_x = 0;
 private int tank_y = 0;
 private Direction direction = Direction.Up;
 
 private TankFrame client = null;
 private boolean isMoving = false;
 
 public enum Direction {
  Right,Left,Up,Down
 }
 
 public Tank(int x, int y, TankFrame client){
  this.tank_x = x;
  this.tank_y = y;
  this.client = client;
 }
 
 public void draw(Graphics g) {
  Color c = g.getColor();
  g.setColor(Color.GREEN);
  g.fillOval(tank_x, tank_y,TANK_R *2, TANK_R *2);
  
  int x1,x2,y1,y2;
  x1 = x2 = tank_x + 25;
  y1 = y2 = tank_y + 25;
  switch(direction){
  case Up:
   y1 -= TANK_R;
   y2 -= TANK_R * 2;
   break;
  case Down:
   y1 += TANK_R;
   y2 += TANK_R * 2;
   break;
  case Left:
   x1 -= TANK_R;
   x2 -= TANK_R * 2;
   break;
  case Right:
   x1 += TANK_R;
   x2 += TANK_R * 2;
   break;
  }
  g.drawLine(x1, y1, x2, y2);
  g.setColor(c);
  move();
 }
 
 private void move() {
  if(!isMoving) return;
  switch(direction) {
  case Up:
   tank_y -= Y_SPEED;
   break;
  case Down:
   tank_y += Y_SPEED;
   break;
  case Left:
   tank_x -= X_SPEED;
   break;
  case Right:
   tank_x += X_SPEED;
   break;
  }
  if(tank_x < 10) tank_x = 10;
  if(tank_y < 30) tank_y = 30;
  if(tank_x > client.FRAME_W - TANK_R * 2) tank_x = client.FRAME_W - TANK_R * 2;
  if(tank_y > client.FRAME_H - TANK_R * 2) tank_y = client.FRAME_H - TANK_R * 2;
 }

 public void fire(){
  Cannonball c = new Cannonball(tank_x + 20,tank_y + 20,direction,client);
  client.addCannonball(c);
 }
 
 public void keyPressed(KeyEvent e){
  int code = e.getKeyCode();
  switch(code) {
  case KeyEvent.VK_UP:
   direction = Direction.Up;
   isMoving = true;
   break;
  case KeyEvent.VK_DOWN:
   direction = Direction.Down;
   isMoving = true;
   break;
  case KeyEvent.VK_LEFT:
   direction = Direction.Left;
   isMoving = true;
   break;
  case KeyEvent.VK_RIGHT:
   direction = Direction.Right;
   isMoving = true;
   break;
  case KeyEvent.VK_CONTROL:
   fire();
   break;
  }
 }

 public void keyReleased(KeyEvent e) {
  int code = e.getKeyCode();
  switch(code) {
  case KeyEvent.VK_UP:
  case KeyEvent.VK_DOWN:
  case KeyEvent.VK_LEFT:
  case KeyEvent.VK_RIGHT:
   isMoving = false;
   break;
  }
 }
}

 

RobotTank.java

import java.awt.*;

public class RobotTank {
 private static final int X_SPEED = 5;
 private static final int Y_SPEED = 5;
 private static final int TANK_R = 25;//坦克圆的半径
 
 private int tank_x = 0;
 private int tank_y = 0;
 private Tank.Direction direction = Tank.Direction.Down;
 
 private TankFrame client = null;
 
 public RobotTank(int x, int y, TankFrame client){
  this.tank_x = x;
  this.tank_y = y;
  this.client = client;
 }
 
 public void draw(Graphics g) {
  Color c = g.getColor();
  g.setColor(Color.BLUE);
  g.fillOval(tank_x, tank_y,TANK_R *2, TANK_R *2);
  
  int x1,x2,y1,y2;
  x1 = x2 = tank_x + 25;
  y1 = y2 = tank_y + 25;
  switch(direction){
  case Up:
   y1 -= TANK_R;
   y2 -= TANK_R * 2;
   break;
  case Down:
   y1 += TANK_R;
   y2 += TANK_R * 2;
   break;
  case Left:
   x1 -= TANK_R;
   x2 -= TANK_R * 2;
   break;
  case Right:
   x1 += TANK_R;
   x2 += TANK_R * 2;
   break;
  }
  g.drawLine(x1, y1, x2, y2);
  g.setColor(c);
 }
 
 public Rectangle getRectangle(){
  return new Rectangle (tank_x ,tank_y ,TANK_R *2, TANK_R *2);
 }
}

 

Cannonball.java

import java.awt.*;


public class Cannonball {
 private static final int X_SPEED = 10;
 private static final int Y_SPEED = 10;
 
 private int x = 0;
 private int y = 0;
 private Tank.Direction direction = null;
 private TankFrame client = null;
 
 public Cannonball(int x, int y, Tank.Direction dir,TankFrame t) {
  this.x = x;
  this.y = y;
  this.direction = dir;
  this.client = t;
 }
 
 public void draw(Graphics g) {
  collide();
  Color c = g.getColor();
  g.setColor(Color.BLACK);
  g.fillOval(x, y, 10, 10);
  g.setColor(c);
  move();
 }

 private void move() {
  switch(direction) {
  case Up :
   y -= Y_SPEED;
   break;
  case Down :
   y += Y_SPEED;
   break;
  case Left :
   x -= X_SPEED;
   break;
  case Right :
   x += X_SPEED;
   break;
  }
  
  if (x < 0 || y < 0  || x > client.FRAME_W || y > client.FRAME_H) client.deleteCannonball(this);
 }
 
 public Rectangle getRectangle(){
  return new Rectangle (x ,y ,10,10);
 }
 
 public void collide () {
  for(int i = 0; i < client.robots.size(); i++){
   RobotTank rt = client.robots.get(i);
   if (this.getRectangle().intersects(rt.getRectangle())) {
    client.deleteCannonball(this);
    client.robots.remove(rt);
   }
  }
 }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值