【Java】坦克大战 Tank Games

基础内容

绘制游戏区域


首先创建一个包,在包中写4个类,GamePanel是绘图面板,Hero是己方坦克,敌方坦克和己方坦克都都坦克,所以可以写一个父类Tank,TankGames是main函数运行的地方
在这里插入图片描述
Tank:

public class Tank {
    //坦克的坐标(x,y)
    private int x;
    private int y;

    public Tank(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
}

Hero:

public class Hero extends Tank{
    public Hero(int x, int y) {
        super(x, y);
    }
}

GamePanel:Panel类似画板,而Graphics就是一支画笔
paint方法触发机制:
① 第一次在屏幕显示时,系统自动调用 ② 窗口大小变化(最小化/最大化) ③ repaint方法被调用

public class GamePanel extends JPanel {
    //在面板上定义己方的坦克Hero
    Hero hero=null;
    public GamePanel() {
        hero= new Hero(100,100);//设置己方坦克的坐标
    }

    //用画笔开始画
    public void paint(Graphics g){
        //将g设置为画笔
        super.paint(g);
        //填充矩形 fillRect(int x,int y,int width,int height)
        g.fillRect(0,0,1000,750);
    }
}

TankGames:Frame类似画框

public class TankGames extends JFrame {
    public static void main(String[] args) {
        TankGames tankGames = new TankGames();
    }
     //定义面板
    GamePanel gamePanel=null;
    public TankGames(){
        gamePanel=new GamePanel();
        this.add(gamePanel);//将面板添加在画框上
        this.setSize(1000,750);//设置画框高和宽
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//按下x就退出程序
        this.setVisible(true);//画框可视
    }
}

效果如图
在这里插入图片描述

绘制坦克


一个向上的坦克坐标如图:
在这里插入图片描述

绘制坦克在GamePanel类中绘制

public class GamePanel extends JPanel {
    //在面板上定义自己的坦克Hero
    Hero hero=null;
    public GamePanel() {
        hero= new Hero(100,100);//设置自己坦克的坐标
    }

    //用画笔开始画
    public void paint(Graphics g){
        //将g设置为画笔
        super.paint(g);
        //填充矩形 fillRect(int x,int y,int width,int height)
        g.fillRect(0,0,1000,750);
        drawTank(hero.getX(),hero.getY(),g,0,0 );
    }

    /**
     *
     * @param x 坦克左上角的x
     * @param y 坦克左上角的y
     * @param g 画笔
     * @param type 坦克类型:0 己方坦克 1 敌方坦克
     * @param direction 坦克方向: 0向上 1 向右 2向下 3向左
     */
    public void drawTank(int x,int y,Graphics g,int type,int direction){
        /**
         * 设置敌人的颜色为红色,己方的颜色为蓝色
         */
        switch (type){
        case 0:
            g.setColor(Color.blue);
            break;
        case 1:
            g.setColor(Color.red);
            break;
        }

        switch (direction){
            case 0:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y,x+20,y+20);//画出炮筒
            break;
            case 1:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x+40,y+20,x+60,y+20);//画出炮筒
                break;
            case 2:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y+40,x+20,y+60);//画出炮筒
                break;
            case 3:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x,y+20,x+20,y+20);//画出炮筒
                break;
        }
    }

}

效果如图
在这里插入图片描述

控制坦克上下左右行动


让坦克动起来需要添加键盘的操作,也就是添加监听事件
首先需要在TankGames的构造器中让JFrame监听gamePanel(画板)的键盘事件

public class TankGames extends JFrame {
    //定义面板
    GamePanel gamePanel=null;
    public static void main(String[] args) {
        TankGames tankGames = new TankGames();
    }
    public TankGames(){
        gamePanel=new GamePanel();
        this.add(gamePanel);//将面板添加在画框上
        this.setSize(1000,750);//设置画框高和宽
        this.addKeyListener(gamePanel);//给面板增添监听事件,让JFrame监听gamePanel的键盘事件
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//按下x就退出程序
        this.setVisible(true);
    }
}

由于坦克的运动是由速度speed和方向direction决定的,所以可以在Tank中定义速度speed和方向direction属性,并设置默认速度=1以及默认方向=0(向上),用set(),get()方法设置当前速度/方向获取当前速度/方向。

public class Tank {
    //坦克的坐标(x,y)
    private int x;
    private int y;
    private int direction=0;//默认方向为向上
    private int speed=1;//默认速度为1
    public Tank(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }

    public int getDirection() {
        return direction;
    }

    public void setDirection(int direction) {
        this.direction = direction;
    }

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }
    //向上走
    public void makeUp(){
        y=y-speed;
    }
    //向右走
    public void makeRight(){
        x=x+speed;
    }
    //向下走
    public void makeDown(){
        y=y+speed;
    }
    //向左走
    public void makeLeft(){
        x=x-speed;
    }
    
}

增加面板的键盘监听就需要在类声明时继承KeyListener,继承后重写keyTyped() keyPressed() keyReleased(),而控制坦克的移动只需要按下PressedWDSA即可,所以只需要写keyPressed() 方法的内容。
keyPressed() 方法中,当按下W坦克更换方向 hero.setDirection(0)+向上走一步hero.makeUp()其他的按键以此类推,需要注意的是每次更改完坦克的运行状态时都需要调用repain()方法重新绘制面板

GamePanel:

public class GamePanel extends JPanel implements KeyListener {
    //在面板上定义自己的坦克Hero
    Hero hero=null;
    public GamePanel() {
        hero= new Hero(100,100);//设置自己坦克的坐标
    }

    //用画笔开始画
    public void paint(Graphics g){
        //将g设置为画笔
        super.paint(g);
        //填充矩形 fillRect(int x,int y,int width,int height)
        g.fillRect(0,0,1000,750);
        drawTank(hero.getX(),hero.getY(),g,0,hero.getDirection());
    }

    /**
     *
     * @param x 坦克左上角的x
     * @param y 坦克左上角的y
     * @param g 画笔
     * @param type 坦克类型:0 己方坦克 1 敌方坦克
     * @param direction 坦克方向: 0向上 1 向右 2向下 3向左
     */
    public void drawTank(int x,int y,Graphics g,int type,int direction){
        /**
         * 设置敌人的颜色为红色,己方的颜色为蓝色
         */
        switch (type){
        case 0:
            g.setColor(Color.blue);
            break;
        case 1:
            g.setColor(Color.red);
            break;
        }

        switch (direction){
            case 0:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y,x+20,y+20);//画出炮筒
            break;
            case 1:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x+40,y+20,x+60,y+20);//画出炮筒
                break;
            case 2:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y+40,x+20,y+60);//画出炮筒
                break;
            case 3:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x,y+20,x+20,y+20);//画出炮筒
                break;
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode()==KeyEvent.VK_W){ //若键盘按下w
            //坦克改变方向
            hero.setDirection(0);
            //坦克向上走1步
            hero.makeUp();
        }else if(e.getKeyCode()==KeyEvent.VK_D){//若键盘按下D
            hero.setDirection(1);
            hero.makeRight();
        }else if(e.getKeyCode()==KeyEvent.VK_S) {//若键盘按下S
            hero.setDirection(2);
            hero.makeDown();
        }else if(e.getKeyCode()==KeyEvent.VK_A){//若键盘按下A
            hero.setDirection(3);
            hero.makeLeft();
        }
        //重新绘制图像
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
}

绘制敌人坦克


在绘制敌人坦克之前需要添加一个Enemy类添加敌人坦克一些属性如多线程,以区分己方坦克
在这里插入图片描述

public class Enemy extends Tank {
    public Enemy(int x, int y) {
        super(x, y);
    }
}

绘制敌人坦克就需要在GamePanel中绘制,由于敌人有多个而且是多线程的,这样就可以定义Vector容器将敌人放入其中

public class GamePanel extends JPanel implements KeyListener {
    //在面板上定义自己的坦克Hero
    Hero hero=null;
    //在面板上用vector定义敌人坦克
    Vector<Enemy> enemyTank=new Vector<>();
    //设置敌人的坦克个数为3
    int enemyTankSize=3;

    public GamePanel() {

        hero= new Hero(100,100);//设置自己坦克的坐标
        //for循环设置敌人的坦克
        for(int i=0;i<enemyTankSize;i++){
            Enemy enemy=new Enemy(100*(i+1),0);//第一个坦克的坐标为(100,0),第二个为(200,0)以此类推
            enemy.setDirection(2);//设置坦克的方向向下(向下攻击己方坦克)
            enemyTank.add(enemy);
        }
    }

    //用画笔开始画
    public void paint(Graphics g){
        //将g设置为画笔
        super.paint(g);
        //填充矩形 fillRect(int x,int y,int width,int height)
        g.fillRect(0,0,1000,750);
        drawTank(hero.getX(),hero.getY(),g,0,hero.getDirection());
        for(int i=0;i<enemyTankSize;i++){
            drawTank(enemyTank.get(i).getX(),enemyTank.get(i).getY(),g,1,enemyTank.get(i).getDirection());
        }
    }

    /**
     *
     * @param x 坦克左上角的x
     * @param y 坦克左上角的y
     * @param g 画笔
     * @param type 坦克类型:0 己方坦克 1 敌方坦克
     * @param direction 坦克方向: 0向上 1 向右 2向下 3向左
     */
    public void drawTank(int x,int y,Graphics g,int type,int direction){
        /**
         * 设置敌人的颜色为红色,己方的颜色为蓝色
         */
        switch (type){
        case 0:
            g.setColor(Color.blue);
            break;
        case 1:
            g.setColor(Color.red);
            break;
        }

        switch (direction){
            case 0:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y,x+20,y+20);//画出炮筒
            break;
            case 1:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x+40,y+20,x+60,y+20);//画出炮筒
                break;
            case 2:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y+40,x+20,y+60);//画出炮筒
                break;
            case 3:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x,y+20,x+20,y+20);//画出炮筒
                break;
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode()==KeyEvent.VK_W){ //若接受到键盘按下w
            //坦克改变方向
            hero.setDirection(0);
            //坦克向上走1步
            hero.makeUp();
        }else if(e.getKeyCode()==KeyEvent.VK_D){
            hero.setDirection(1);
            hero.makeRight();
        }else if(e.getKeyCode()==KeyEvent.VK_S) {
            hero.setDirection(2);
            hero.makeDown();
        }else if(e.getKeyCode()==KeyEvent.VK_A){
            hero.setDirection(3);
            hero.makeLeft();
        }
        //重新绘制图像
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
}

效果如图
在这里插入图片描述

添加一点

控制坦克发射子弹


我们可以按下J让自己的坦克对敌人坦克发动攻击,如果设计子弹那么可以写一个Shot类,Shot类中有子弹的坐标(x,y),方向,是否存活等属性,坦克每按下J就发射一个子弹其实子弹相当于一个线程,每按下J,hero就创建一个子弹的线程并启动,启动后根据子弹的当前的位置让子弹以速度speed=2朝坦克炮筒前方运动,子弹运动终止条件为:① 碰到游戏区域边界 ② 碰到敌人坦克
Shot:

public class Shot implements Runnable{
    private int x;
    private int y;
    private int direction;
    private int speed=2;//默认速度为2
    private boolean isLive=true;//一旦创建了子弹,那么子弹就是存活的
    public Shot(int x, int y, int direction) {
        this.x = x;
        this.y = y;
        this.direction = direction;
    }

    public boolean isLive() {
        return isLive;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    @Override
    public void run() {
        while(isLive){
            try {
                Thread.sleep(50);//子弹休眠50毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            switch (direction){
                case 0:
                    y=y-speed;
                    break;
                case 1:
                    x=x+speed;
                    break;
                case 2:
                    y=y+speed;
                    break;
                case 3:
                    x=x-speed;
                    break;
            }
            /*有如下两种情况子弹灭亡:
            ① 碰到边界
            ② 碰到敌人坦克(暂时没写)
            * */
            if(x<=0||x>=1000||y<=0||y>=750){
                isLive=false;
            }
        }
    }
}

Hero:这里要注意子弹设置的位置

public class Hero extends Tank{
    //创建子弹
    private Shot shot=null;

    public Shot getShot() {
        return shot;
    }

    public Hero(int x, int y) {
        super(x, y);
    }
    //射击
    public void shotEnemy(){
        switch (getDirection()){
            case 0://hero向上
                shot=new Shot(getX()+20,getY(),0);
                break;
            case 1:
                shot=new Shot(getX()+60,getY()+20,1);
                break;
            case 2:
                shot=new Shot(getX()+20,getY()+60,2);
                break;
            case 3:
                shot=new Shot(getX(),getY()+20,3);
                break;
        }
        new Thread(shot).start();//启动子弹线程
    }
}

在绘制子弹时,如果仿照绘制坦克上下左右移动的代码,如果按下J增加一个键盘监听事件并调用一次this.repaint()重新绘制图像就会出现子弹只显示一次后就再也没有出现的问题,面对这种情况可以将GamePanel类设计成一个线程,在main函数中启动,重写的run()方法中进行不停的绘制图像。
GamePanel:

public class GamePanel extends JPanel implements KeyListener,Runnable{
    //在面板上定义自己的坦克Hero
    Hero hero=null;
    //在面板上用vector定义敌人坦克
    Vector<Enemy> enemyTank=new Vector<>();
    //设置敌人的坦克个数为3
    int enemyTankSize=3;

    public GamePanel() {
        hero= new Hero(100,100);//设置自己坦克的坐标
        hero.setSpeed(3);
        //for循环设置敌人的坦克
        for(int i=0;i<enemyTankSize;i++){
            Enemy enemy=new Enemy(100*(i+1),0);//第一个坦克的坐标为(100,0),第二个为(200,0)以此类推
            enemy.setDirection(2);//设置坦克的方向向下(向下攻击己方坦克)
            enemyTank.add(enemy);
        }
    }

    //用画笔开始画
    public void paint(Graphics g){
        super.paint(g);//将g设置为画笔
        // 填充矩形 fillRect(int x,int y,int width,int height)
        g.fillRect(0,0,1000,750);
        drawTank(hero.getX(),hero.getY(),g,0,hero.getDirection());
        //如果子弹被创建或者子弹还存在就绘制子弹的图
        if(hero.getShot()!=null&&hero.getShot().isLive()){
            drawShot(hero.getX(),hero.getY(),g);
        }
        for(int i=0;i<enemyTankSize;i++){
            drawTank(enemyTank.get(i).getX(),enemyTank.get(i).getY(),g,1,enemyTank.get(i).getDirection());
        }
    }

    /**
     *
     * @param x 坦克左上角的x
     * @param y 坦克左上角的y
     * @param g 画笔
     * @param type 坦克类型:0 己方坦克 1 敌方坦克
     * @param direction 坦克方向: 0向上 1 向右 2向下 3向左
     */
    public void drawTank(int x,int y,Graphics g,int type,int direction){
        /**
         * 设置敌人的颜色为红色,己方的颜色为蓝色
         */
        switch (type){
        case 0:
            g.setColor(Color.blue);
            break;
        case 1:
            g.setColor(Color.red);
            break;
        }

        switch (direction){
            case 0:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y,x+20,y+20);//画出炮筒
            break;
            case 1:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x+40,y+20,x+60,y+20);//画出炮筒
                break;
            case 2:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y+40,x+20,y+60);//画出炮筒
                break;
            case 3:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x,y+20,x+20,y+20);//画出炮筒
                break;
        }
    }

    public void drawShot(int x,int y,Graphics g){
        g.setColor(Color.white);
        g.draw3DRect(hero.getShot().getX(),hero.getShot().getY(),2,2,false);
    }
    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode()==KeyEvent.VK_W) { //若接受到键盘按下w
            //坦克改变方向
            hero.setDirection(0);
            //坦克向上走1步
            hero.makeUp();
        }
      if(e.getKeyCode()==KeyEvent.VK_D) {
          hero.setDirection(1);
          hero.makeRight();
      }
       if(e.getKeyCode()==KeyEvent.VK_S) {
           hero.setDirection(2);
           hero.makeDown();
       }
       if(e.getKeyCode()==KeyEvent.VK_A){
            hero.setDirection(3);
            hero.makeLeft();
        }
        if(e.getKeyCode()==KeyEvent.VK_J){
            hero.shotEnemy();
        }
        //重新绘制图像
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
    @Override
    public void run(){
        while (true){
            try {
                Thread.sleep(100);//子弹每隔0.5s重新绘制图像
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.repaint();
        }
    }
}

main:

public class TankGames extends JFrame {
    //定义面板
    GamePanel gamePanel=null;
    public static void main(String[] args) {
        TankGames tankGames = new TankGames();
    }
    public TankGames(){
        gamePanel=new GamePanel();
        new Thread(gamePanel).start();
        this.add(gamePanel);//将面板添加在画框上
        this.setSize(1000,750);//设置画框高和宽
        this.addKeyListener(gamePanel);//给面板增添监听事件
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//按下x就退出程序
        this.setVisible(true);
    }
}

敌人发动攻击


敌人发动攻击的子弹生命周期是从创建敌人坦克开始,创建好敌人各自的子弹后并启动子弹的线程,注意敌人各自的子弹创建后要放在一个Vector容器中,以方便后序的操作。
Enemy:

public class Enemy extends Tank {
    public Vector<Shot> shots=new Vector<>();//vector容器中存放敌人的子弹
    public Enemy(int x, int y) {
        super(x, y);
    }

}

GamePanel:

public class GamePanel extends JPanel implements KeyListener,Runnable{
    //在面板上定义自己的坦克Hero
    Hero hero=null;
    //在面板上用vector定义敌人坦克
    Vector<Enemy> enemyTank=new Vector<>();
    //设置敌人的坦克个数为3
    int enemyTankSize=3;

    public GamePanel() {
        hero= new Hero(100,100);//设置hero坦克的坐标
        hero.setSpeed(3);//设置hero的速度
        //for循环设置敌人的坦克
        for(int i=0;i<enemyTankSize;i++){
            Enemy enemy=new Enemy(100*(i+1),0);//第一个坦克的坐标为(100,0),第二个为(200,0)以此类推
            enemy.setDirection(2);//设置坦克的方向向下(向下攻击己方坦克)
            enemyTank.add(enemy);//在vector中添加当前创建的坦克
            Shot shot=new Shot(enemy.getX()+20,enemy.getY()+60,2);//创建当前敌人的子弹
            enemy.shots.add(shot);//将子弹添加在敌人类的vector容器中
            new Thread(shot).start();//启动当前子弹进程
        }
    }

    //用画笔开始画
    public void paint(Graphics g){
        super.paint(g);//将g设置为画笔

        // 填充矩形 fillRect(int x,int y,int width,int height)
        g.fillRect(0,0,1000,750);
        drawTank(hero.getX(),hero.getY(),g,0,hero.getDirection());

        //如果子弹被创建或者子弹还存在就绘制子弹的图
        if(hero.getShot()!=null&&hero.getShot().isLive()){
            drawHeroShot(hero.getX(),hero.getY(),g);
        }
        for(int i=0;i<enemyTankSize;i++){
            //取出一个敌人
            Enemy enemy=enemyTank.get(i);
            //绘制取出的这个敌人
            drawTank(enemy.getX(),enemy.getY(),g,1,enemy.getDirection());

            //绘制当前敌人的子弹
            for(int j=0;j<enemy.shots.size();j++)
            {
                Shot shot=enemy.shots.get(j);//取出当前敌人的子弹
                //如果shot存在,就绘制子弹;如果shot不存在,那么就从vector中移除子弹
                if(shot.isLive()==true){
                    //绘制敌人子弹
                    g.setColor(Color.white);
                    g.draw3DRect(shot.getX(),shot.getY(),2,2,false);
                }
                else{
                    enemy.shots.remove(shot);//将shot从shots中移除
                }
            }
        }
    }

    /**
     *
     * @param x 坦克左上角的x
     * @param y 坦克左上角的y
     * @param g 画笔
     * @param type 坦克类型:0 己方坦克 1 敌方坦克
     * @param direction 坦克方向: 0向上 1 向右 2向下 3向左
     */
    public void drawTank(int x,int y,Graphics g,int type,int direction){
        /**
         * 设置敌人的颜色为红色,己方的颜色为蓝色
         */
        switch (type){
        case 0:
            g.setColor(Color.blue);
            break;
        case 1:
            g.setColor(Color.red);
            break;
        }

        switch (direction){
            case 0:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y,x+20,y+20);//画出炮筒
            break;
            case 1:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x+40,y+20,x+60,y+20);//画出炮筒
                break;
            case 2:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y+40,x+20,y+60);//画出炮筒
                break;
            case 3:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x,y+20,x+20,y+20);//画出炮筒
                break;
        }
    }

    public void drawHeroShot(int x, int y, Graphics g){
        g.setColor(Color.white);
        g.draw3DRect(hero.getShot().getX(),hero.getShot().getY(),2,2,false);
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode()==KeyEvent.VK_W) { //若接受到键盘按下w
            //坦克改变方向
            hero.setDirection(0);
            //坦克向上走1步
            hero.makeUp();
        }
      if(e.getKeyCode()==KeyEvent.VK_D) {
          hero.setDirection(1);
          hero.makeRight();
      }
       if(e.getKeyCode()==KeyEvent.VK_S) {
           hero.setDirection(2);
           hero.makeDown();
       }
       if(e.getKeyCode()==KeyEvent.VK_A){
            hero.setDirection(3);
            hero.makeLeft();
        }
        if(e.getKeyCode()==KeyEvent.VK_J){
            hero.shotEnemy();
        }
        //重新绘制图像
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
    @Override
    public void run(){
        while (true){
            try {
                Thread.sleep(100);//子弹每隔0.5s重新绘制图像
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.repaint();
        }
    }
}

坦克攻击敌人的爆炸效果


爆炸效果是贴图完成的,三张从爆炸从大到小的图片快速切换会出现爆炸的效果,如图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
因此爆炸的本质是图片的切换,图片需要坐标(x,y),切换时间(生命周期),因此可以将其写成一个爆炸Bomb类,还需要写一个生命周期递减函数,给爆炸赋予“时间”。

public class Bomb {
    private int x;
    private int y;
    private boolean isLive=true;//是否存在
    private int lifeCycle=9;//生命周期

    public Bomb(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getLifeCycle() {
        return lifeCycle;
    }

    public boolean isLive() {
        return isLive;
    }

    public void lifeCycleDown(){
        //生命周期递减
        if(lifeCycle>0)
            lifeCycle--;
        else //若生命周期为0则爆炸效果销毁
            isLive=false;
    }
}

在Hero攻击敌人坦克,若攻击到敌人坦克绘制范围内,那么敌人坦克此时应该从Vectoer容器中移除,为了记录当前坦克销毁,在Enemy类中添加是否存活的属性
Enemy:

public class Enemy extends Tank {
    public Vector<Shot> shots=new Vector<>();//vector容器中存放敌人的子弹
    private boolean isLive=true;//敌人坦克是否存活
    public Enemy(int x, int y) {
        super(x, y);
    }

    public boolean isLive() {
        return isLive;
    }

    public void setLive(boolean live) {
        isLive = live;
    }
}

在绘制爆炸效果中,需要定义三张图片并加载到项目中,还需要定义爆炸的vector容器,当hero击中敌人的坦克就创建一个爆炸Bomb放入该容器中,当爆炸生命周期结束时将Bomb移除(remove)后还需要将Enemy本身从vector中移除(remove)。
在游戏过程中,程序需要一直处于“监视”状态来判断敌人坦克是否被击中,所以判断击中函数最好放在线程中每隔100毫秒来判断敌人坦克是否被击中。
GamePanel :

public class GamePanel extends JPanel implements KeyListener,Runnable{
    //在面板上定义自己的坦克Hero
    Hero hero=null;
    //在面板上用vector定义敌人坦克
    Vector<Enemy> enemyTank=new Vector<>();
    //设置敌人的坦克个数为3
    int enemyTankSize=3;
    //用vector定义爆炸
    Vector<Bomb> bombs=new Vector<>();
    //定义爆炸效果图片
    Image[] images=new Image[3];

    public GamePanel() {
        //设置hero
        hero= new Hero(100,100);//设置hero坦克的坐标
        hero.setSpeed(3);//设置hero的速度

        //for循环设置敌人的坦克
        for(int i=0;i<enemyTankSize;i++){
            Enemy enemy=new Enemy(100*(i+1),0);//第一个坦克的坐标为(100,0),第二个为(200,0)以此类推
            enemy.setDirection(2);//设置坦克的方向向下(向下攻击己方坦克)
            enemyTank.add(enemy);//在vector中添加当前创建的坦克
            Shot shot=new Shot(enemy.getX()+20,enemy.getY()+60,2);//创建当前敌人的子弹
            enemy.shots.add(shot);//将子弹添加在敌人类的vector容器中
            new Thread(shot).start();//启动当前子弹进程
        }

        //设置图片
        images[0]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_1.gif");
        images[1]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_2.gif");
        images[2]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_3.gif");
    }

    //用画笔开始画
    public void paint(Graphics g){
        super.paint(g);//将g设置为画笔
        // 填充矩形 fillRect(int x,int y,int width,int height)
        g.fillRect(0,0,1000,750);
        //绘制hero坦克
        drawTank(hero.getX(),hero.getY(),g,0,hero.getDirection());
        //如果子弹被创建或者子弹还存在就绘制子弹的图
        if(hero.getShot()!=null&&hero.getShot().isLive()){
            drawHeroShot(hero.getX(),hero.getY(),g);
        }
        //绘制敌人坦克
        for(int i=0;i<enemyTank.size();i++){
            //取出一个敌人
            Enemy enemy=enemyTank.get(i);
            //判断当前敌人坦克是否存活
            if(enemy.isLive()==true){
                //绘制取出的这个敌人
                drawTank(enemy.getX(),enemy.getY(),g,1,enemy.getDirection());

                //绘制当前敌人的子弹
                for(int j=0;j<enemy.shots.size();j++)
                {
                    Shot shot=enemy.shots.get(j);//取出当前敌人的子弹
                    //如果shot存在,就绘制子弹;如果shot不存在,那么就从vector中移除子弹
                    if(shot.isLive()==true){
                        //绘制敌人子弹
                        g.setColor(Color.white);
                        g.draw3DRect(shot.getX(),shot.getY(),2,2,false);
                    }
                    else{
                        enemy.shots.remove(shot);//将shot从shots中移除
                    }
                }
            }
        }
        //绘制爆炸效果
        for(int i=0;i<bombs.size();i++){
            Bomb bomb=bombs.get(i);
            if(bomb.getLifeCycle()>6){
            }else if(bomb.getLifeCycle()>3){
              g.drawImage(images[1],bomb.getX(),bomb.getY(),60,60,this);
            }else
               g.drawImage(images[2],bomb.getX(),bomb.getY(),60,60,this);
            bomb.lifeCycleDown();//让爆炸生命周期减小
            if(bomb.getLifeCycle()==0)//若爆炸的生命周期为0就将当前bomb从vector中移除
                bombs.remove(bomb);
        }
    }

    /**
     *
     * @param x 坦克左上角的x
     * @param y 坦克左上角的y
     * @param g 画笔
     * @param type 坦克类型:0 己方坦克 1 敌方坦克
     * @param direction 坦克方向: 0向上 1 向右 2向下 3向左
     */
    public void drawTank(int x,int y,Graphics g,int type,int direction){
        /**
         * 设置敌人的颜色为红色,己方的颜色为蓝色
         */
        switch (type){
        case 0:
            g.setColor(Color.blue);
            break;
        case 1:
            g.setColor(Color.red);
            break;
        }

        switch (direction){
            case 0:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y,x+20,y+20);//画出炮筒
            break;
            case 1:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x+40,y+20,x+60,y+20);//画出炮筒
                break;
            case 2:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y+40,x+20,y+60);//画出炮筒
                break;
            case 3:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x,y+20,x+20,y+20);//画出炮筒
                break;
        }
    }

    public void drawHeroShot(int x, int y, Graphics g){
        g.setColor(Color.white);
        g.draw3DRect(hero.getShot().getX(),hero.getShot().getY(),2,2,false);
    }
    //hero坦克击中敌人坦克
    public void hitEnemy(Shot shot,Enemy enemy){
        switch (enemy.getDirection())
        {
            //如果敌人坦克方向向上/向下(0/2),hero坦克击中
            case 0:
            case 2:
                //hero子弹在当前敌人坦克的区域
                if(shot.getX()<=enemy.getX()+40 && shot.getX()>=enemy.getX() && shot.getY()>=enemy.getY() && shot.getY()<=enemy.getY()+60){
                    shot.setLive(false);//hero子弹销毁
                    enemy.setLive(false);//敌人销毁
                    //敌人销毁后爆炸效果创建
                    Bomb bomb=new Bomb(enemy.getX(),enemy.getY());//创建爆炸效果
                    bombs.add(bomb);//将爆炸效果添加在vector中
                    enemyTank.remove(enemy);
                }
                break;
            case 1:
            case 3:
                if(shot.getX()<=enemy.getX()+60&&shot.getX()>=enemy.getX()&& shot.getY()>=enemy.getY() && shot.getY()<=enemy.getY()+40){
                    shot.setLive(false);//hero子弹销毁
                    enemy.setLive(false);//敌人销毁
                    //敌人销毁后爆炸效果创建
                    Bomb bomb=new Bomb(enemy.getX(),enemy.getY());//创建爆炸效果
                    bombs.add(bomb);//将爆炸效果添加在vector中
                    enemyTank.remove(enemy);
                }
                break;
        }

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode()==KeyEvent.VK_W) { //若接受到键盘按下w
            //坦克改变方向
            hero.setDirection(0);
            //坦克向上走1步
            hero.makeUp();
        }
      if(e.getKeyCode()==KeyEvent.VK_D) {
          hero.setDirection(1);
          hero.makeRight();
      }
       if(e.getKeyCode()==KeyEvent.VK_S) {
           hero.setDirection(2);
           hero.makeDown();
       }
       if(e.getKeyCode()==KeyEvent.VK_A){
            hero.setDirection(3);
            hero.makeLeft();
        }
        if(e.getKeyCode()==KeyEvent.VK_J){
            hero.shotEnemy();
        }
        //重新绘制图像
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
    @Override
    public void run(){
        while (true){
            try {
                Thread.sleep(100);//子弹每隔0.5s重新绘制图像
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //判断是否击中敌人坦克
            //判断之前要求hero子弹不为null且存活
            if(hero.getShot()!=null && hero.getShot().isLive()==true){
                for(int i=0;i<enemyTank.size();i++){
                    hitEnemy(hero.getShot(),enemyTank.get(i));
                }
            }
            this.repaint();
        }
    }
}

效果如下图:
请添加图片描述

敌人坦克自由移动


让敌人坦克各自移动只需要在敌人坦克Enemy类上增加线程,在run()方法中写坦克移动的方式,并在创建敌人坦克时启动线程
Enemy:

public class Enemy extends Tank implements Runnable {
    public Vector<Shot> shots=new Vector<>();//vector容器中存放敌人的子弹
    private boolean isLive=true;//敌人坦克是否存活
    public Enemy(int x, int y) {
        super(x, y);
    }

    public boolean isLive() {
        return isLive;
    }

    public void setLive(boolean live) {
        isLive = live;
    }

    @Override
    public void run() {
        while (isLive){
            //根据当前坦克的方向(0向上1向左...)行走1次休息300毫秒,一共走30次
            int step=50;
            int time=30;
            switch (getDirection()){
                case 0:
                    for(int i=0;i<step;i++){
                        makeUp();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 1:
                    for(int i=0;i<step;i++){
                        makeRight();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 2:
                    for(int i=0;i<step;i++){
                        makeDown();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 3:
                    for(int i=0;i<step;i++){
                        makeLeft();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
            }
            //改变坦克方向[0,4)
            setDirection((int)(Math.random()*4));
        }
    }
}

GamePanel:

public class GamePanel extends JPanel implements KeyListener,Runnable{
    //在面板上定义自己的坦克Hero
    Hero hero=null;
    //在面板上用vector定义敌人坦克
    Vector<Enemy> enemyTank=new Vector<>();
    //设置敌人的坦克个数为3
    int enemyTankSize=3;
    //用vector定义爆炸
    Vector<Bomb> bombs=new Vector<>();
    //定义爆炸效果图片
    Image[] images=new Image[3];

    public GamePanel() {
        //设置hero
        hero= new Hero(100,100);//设置hero坦克的坐标
        hero.setSpeed(3);//设置hero的速度

        //for循环设置敌人的坦克
        for(int i=0;i<enemyTankSize;i++){
            Enemy enemy=new Enemy(100*(i+1),0);//第一个坦克的坐标为(100,0),第二个为(200,0)以此类推
            enemy.setDirection(2);//设置坦克的方向向下(向下攻击己方坦克)
            enemyTank.add(enemy);//在vector中添加当前创建的坦克
            new Thread(enemy).start();
            Shot shot=new Shot(enemy.getX()+20,enemy.getY()+60,2);//创建当前敌人的子弹
            enemy.shots.add(shot);//将子弹添加在敌人类的vector容器中
            new Thread(shot).start();//启动当前子弹进程
        }

        //设置图片
        images[0]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_1.gif");
        images[1]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_2.gif");
        images[2]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_3.gif");
    }

    //用画笔开始画
    public void paint(Graphics g){
        super.paint(g);//将g设置为画笔
        // 填充矩形 fillRect(int x,int y,int width,int height)
        g.fillRect(0,0,1000,750);
        //绘制hero坦克
        drawTank(hero.getX(),hero.getY(),g,0,hero.getDirection());
        //如果子弹被创建或者子弹还存在就绘制子弹的图
        if(hero.getShot()!=null&&hero.getShot().isLive()){
            drawHeroShot(hero.getX(),hero.getY(),g);
        }
        //绘制敌人坦克
        for(int i=0;i<enemyTank.size();i++){
            //取出一个敌人
            Enemy enemy=enemyTank.get(i);
            //判断当前敌人坦克是否存活
            if(enemy.isLive()==true){
                //绘制取出的这个敌人
                drawTank(enemy.getX(),enemy.getY(),g,1,enemy.getDirection());

                //绘制当前敌人的子弹
                for(int j=0;j<enemy.shots.size();j++)
                {
                    Shot shot=enemy.shots.get(j);//取出当前敌人的子弹
                    //如果shot存在,就绘制子弹;如果shot不存在,那么就从vector中移除子弹
                    if(shot.isLive()==true){
                        //绘制敌人子弹
                        g.setColor(Color.white);
                        g.draw3DRect(shot.getX(),shot.getY(),2,2,false);
                    }
                    else{
                        enemy.shots.remove(shot);//将shot从shots中移除
                    }
                }
            }
        }
        //绘制爆炸效果
        for(int i=0;i<bombs.size();i++){
            Bomb bomb=bombs.get(i);
            if(bomb.getLifeCycle()>6){
            }else if(bomb.getLifeCycle()>3){
              g.drawImage(images[1],bomb.getX(),bomb.getY(),60,60,this);
            }else
               g.drawImage(images[2],bomb.getX(),bomb.getY(),60,60,this);
            bomb.lifeCycleDown();//让爆炸生命周期减小
            if(bomb.getLifeCycle()==0)//若爆炸的生命周期为0就将当前bomb从vector中移除
                bombs.remove(bomb);
        }
    }

    /**
     *
     * @param x 坦克左上角的x
     * @param y 坦克左上角的y
     * @param g 画笔
     * @param type 坦克类型:0 己方坦克 1 敌方坦克
     * @param direction 坦克方向: 0向上 1 向右 2向下 3向左
     */
    public void drawTank(int x,int y,Graphics g,int type,int direction){
        /**
         * 设置敌人的颜色为红色,己方的颜色为蓝色
         */
        switch (type){
        case 0:
            g.setColor(Color.blue);
            break;
        case 1:
            g.setColor(Color.red);
            break;
        }

        switch (direction){
            case 0:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y,x+20,y+20);//画出炮筒
            break;
            case 1:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x+40,y+20,x+60,y+20);//画出炮筒
                break;
            case 2:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y+40,x+20,y+60);//画出炮筒
                break;
            case 3:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x,y+20,x+20,y+20);//画出炮筒
                break;
        }
    }

    public void drawHeroShot(int x, int y, Graphics g){
        g.setColor(Color.white);
        g.draw3DRect(hero.getShot().getX(),hero.getShot().getY(),2,2,false);
    }
    //hero坦克击中敌人坦克
    public void hitEnemy(Shot shot,Enemy enemy){
        switch (enemy.getDirection())
        {
            //如果敌人坦克方向向上/向下(0/2),hero坦克击中
            case 0:
            case 2:
                //hero子弹在当前敌人坦克的区域
                if(shot.getX()<=enemy.getX()+40 && shot.getX()>=enemy.getX() && shot.getY()>=enemy.getY() && shot.getY()<=enemy.getY()+60){
                    shot.setLive(false);//hero子弹销毁
                    enemy.setLive(false);//敌人销毁
                    //敌人销毁后爆炸效果创建
                    Bomb bomb=new Bomb(enemy.getX(),enemy.getY());//创建爆炸效果
                    bombs.add(bomb);//将爆炸效果添加在vector中
                    enemyTank.remove(enemy);
                }
                break;
            case 1:
            case 3:
                if(shot.getX()<=enemy.getX()+60&&shot.getX()>=enemy.getX()&& shot.getY()>=enemy.getY() && shot.getY()<=enemy.getY()+40){
                    shot.setLive(false);//hero子弹销毁
                    enemy.setLive(false);//敌人销毁
                    //敌人销毁后爆炸效果创建
                    Bomb bomb=new Bomb(enemy.getX(),enemy.getY());//创建爆炸效果
                    bombs.add(bomb);//将爆炸效果添加在vector中
                    enemyTank.remove(enemy);
                }
                break;
        }

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode()==KeyEvent.VK_W) { //若接受到键盘按下w
            //坦克改变方向
            hero.setDirection(0);
            //坦克向上走1步
            hero.makeUp();
        }
      if(e.getKeyCode()==KeyEvent.VK_D) {
          hero.setDirection(1);
          hero.makeRight();
      }
       if(e.getKeyCode()==KeyEvent.VK_S) {
           hero.setDirection(2);
           hero.makeDown();
       }
       if(e.getKeyCode()==KeyEvent.VK_A){
            hero.setDirection(3);
            hero.makeLeft();
        }
        if(e.getKeyCode()==KeyEvent.VK_J){
            hero.shotEnemy();
        }
        //重新绘制图像
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
    @Override
    public void run(){
        while (true){
            try {
                Thread.sleep(100);//子弹每隔0.5s重新绘制图像
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //判断是否击中敌人坦克
            //判断之前要求hero子弹不为null且存活
            if(hero.getShot()!=null && hero.getShot().isLive()==true){
                for(int i=0;i<enemyTank.size();i++){
                    hitEnemy(hero.getShot(),enemyTank.get(i));
                }
            }
            this.repaint();
        }
    }
}

限制敌人+自己坦克移动范围


只需要在控制敌人/自己坦克时,添加判断范围代码,判断范围要注意(x,y)表示左上角坐标
Enemy:

public class Enemy extends Tank implements Runnable {
    public Vector<Shot> shots=new Vector<>();//vector容器中存放敌人的子弹
    private boolean isLive=true;//敌人坦克是否存活
    public Enemy(int x, int y) {
        super(x, y);
    }

    public boolean isLive() {
        return isLive;
    }

    public void setLive(boolean live) {
        isLive = live;
    }

    @Override
    public void run() {
        while (isLive){
            //根据当前坦克的方向(0向上1向左...)行走1次休息time毫秒,一共走step次
            int step=50;
            int time=30;
            switch (getDirection()){
                case 0:
                    for(int i=0;i<step;i++){
                        if(getY()>0)
                        makeUp();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 1:
                    for(int i=0;i<step;i++){
                        if(getX()+60<1000)
                        makeRight();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 2:
                    for(int i=0;i<step;i++){
                        if(getY()+60<750)
                        makeDown();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 3:
                    for(int i=0;i<step;i++){
                        if(getX()>0)
                        makeLeft();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
            }
            //改变坦克方向[0,4)
            setDirection((int)(Math.random()*4));
        }
    }
}

GamePanel:

public class GamePanel extends JPanel implements KeyListener,Runnable{
    //在面板上定义自己的坦克Hero
    Hero hero=null;
    //在面板上用vector定义敌人坦克
    Vector<Enemy> enemyTank=new Vector<>();
    //设置敌人的坦克个数为3
    int enemyTankSize=3;
    //用vector定义爆炸
    Vector<Bomb> bombs=new Vector<>();
    //定义爆炸效果图片
    Image[] images=new Image[3];

    public GamePanel() {
        //设置hero
        hero= new Hero(100,100);//设置hero坦克的坐标
        hero.setSpeed(3);//设置hero的速度

        //for循环设置敌人的坦克
        for(int i=0;i<enemyTankSize;i++){
            Enemy enemy=new Enemy(100*(i+1),0);//第一个坦克的坐标为(100,0),第二个为(200,0)以此类推
            enemy.setDirection(2);//设置坦克的方向向下(向下攻击己方坦克)
            enemyTank.add(enemy);//在vector中添加当前创建的坦克
            new Thread(enemy).start();
            Shot shot=new Shot(enemy.getX()+20,enemy.getY()+60,2);//创建当前敌人的子弹
            enemy.shots.add(shot);//将子弹添加在敌人类的vector容器中
            new Thread(shot).start();//启动当前子弹进程
        }

        //设置图片
        images[0]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_1.gif");
        images[1]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_2.gif");
        images[2]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_3.gif");
    }

    //用画笔开始画
    public void paint(Graphics g){
        super.paint(g);//将g设置为画笔
        // 填充矩形 fillRect(int x,int y,int width,int height)
        g.fillRect(0,0,1000,750);
        //绘制hero坦克
        drawTank(hero.getX(),hero.getY(),g,0,hero.getDirection());
        //如果子弹被创建或者子弹还存在就绘制子弹的图
        if(hero.getShot()!=null&&hero.getShot().isLive()){
            drawHeroShot(hero.getX(),hero.getY(),g);
        }
        //绘制敌人坦克
        for(int i=0;i<enemyTank.size();i++){
            //取出一个敌人
            Enemy enemy=enemyTank.get(i);
            //判断当前敌人坦克是否存活
            if(enemy.isLive()==true){
                //绘制取出的这个敌人
                drawTank(enemy.getX(),enemy.getY(),g,1,enemy.getDirection());

                //绘制当前敌人的子弹
                for(int j=0;j<enemy.shots.size();j++)
                {
                    Shot shot=enemy.shots.get(j);//取出当前敌人的子弹
                    //如果shot存在,就绘制子弹;如果shot不存在,那么就从vector中移除子弹
                    if(shot.isLive()==true){
                        //绘制敌人子弹
                        g.setColor(Color.white);
                        g.draw3DRect(shot.getX(),shot.getY(),2,2,false);
                    }
                    else{
                        enemy.shots.remove(shot);//将shot从shots中移除
                    }
                }
            }
        }
        //绘制爆炸效果
        for(int i=0;i<bombs.size();i++){
            Bomb bomb=bombs.get(i);
            if(bomb.getLifeCycle()>6){
            }else if(bomb.getLifeCycle()>3){
              g.drawImage(images[1],bomb.getX(),bomb.getY(),60,60,this);
            }else
               g.drawImage(images[2],bomb.getX(),bomb.getY(),60,60,this);
            bomb.lifeCycleDown();//让爆炸生命周期减小
            if(bomb.getLifeCycle()==0)//若爆炸的生命周期为0就将当前bomb从vector中移除
                bombs.remove(bomb);
        }
    }

    /**
     *
     * @param x 坦克左上角的x
     * @param y 坦克左上角的y
     * @param g 画笔
     * @param type 坦克类型:0 己方坦克 1 敌方坦克
     * @param direction 坦克方向: 0向上 1 向右 2向下 3向左
     */
    public void drawTank(int x,int y,Graphics g,int type,int direction){
        /**
         * 设置敌人的颜色为红色,己方的颜色为蓝色
         */
        switch (type){
        case 0:
            g.setColor(Color.blue);
            break;
        case 1:
            g.setColor(Color.red);
            break;
        }

        switch (direction){
            case 0:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y,x+20,y+20);//画出炮筒
            break;
            case 1:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x+40,y+20,x+60,y+20);//画出炮筒
                break;
            case 2:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y+40,x+20,y+60);//画出炮筒
                break;
            case 3:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x,y+20,x+20,y+20);//画出炮筒
                break;
        }
    }

    public void drawHeroShot(int x, int y, Graphics g){
        g.setColor(Color.white);
        g.draw3DRect(hero.getShot().getX(),hero.getShot().getY(),2,2,false);
    }
    //hero坦克击中敌人坦克
    public void hitEnemy(Shot shot,Enemy enemy){
        switch (enemy.getDirection())
        {
            //如果敌人坦克方向向上/向下(0/2),hero坦克击中
            case 0:
            case 2:
                //hero子弹在当前敌人坦克的区域
                if(shot.getX()<=enemy.getX()+40 && shot.getX()>=enemy.getX() && shot.getY()>=enemy.getY() && shot.getY()<=enemy.getY()+60){
                    shot.setLive(false);//hero子弹销毁
                    enemy.setLive(false);//敌人销毁
                    //敌人销毁后爆炸效果创建
                    Bomb bomb=new Bomb(enemy.getX(),enemy.getY());//创建爆炸效果
                    bombs.add(bomb);//将爆炸效果添加在vector中
                    enemyTank.remove(enemy);
                }
                break;
            case 1:
            case 3:
                if(shot.getX()<=enemy.getX()+60&&shot.getX()>=enemy.getX()&& shot.getY()>=enemy.getY() && shot.getY()<=enemy.getY()+40){
                    shot.setLive(false);//hero子弹销毁
                    enemy.setLive(false);//敌人销毁
                    //敌人销毁后爆炸效果创建
                    Bomb bomb=new Bomb(enemy.getX(),enemy.getY());//创建爆炸效果
                    bombs.add(bomb);//将爆炸效果添加在vector中
                    enemyTank.remove(enemy);
                }
                break;
        }

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode()==KeyEvent.VK_W) { //若接受到键盘按下w
            //坦克改变方向
            hero.setDirection(0);
            //坦克向上走1步
            if(hero.getY()>0)
                hero.makeUp();
        }
      if(e.getKeyCode()==KeyEvent.VK_D) {
          hero.setDirection(1);
          if(hero.getX()+60<1000)
            hero.makeRight();
      }
       if(e.getKeyCode()==KeyEvent.VK_S) {
           hero.setDirection(2);
           if(hero.getY()+60<750)
           hero.makeDown();
       }
       if(e.getKeyCode()==KeyEvent.VK_A){
            hero.setDirection(3);
            if(hero.getX()>0)
            hero.makeLeft();
        }
        if(e.getKeyCode()==KeyEvent.VK_J){
            hero.shotEnemy();
        }
        //重新绘制图像
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
    @Override
    public void run(){
        while (true){
            try {
                Thread.sleep(100);//子弹每隔0.5s重新绘制图像
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //判断是否击中敌人坦克
            //判断之前要求hero子弹不为null且存活
            if(hero.getShot()!=null && hero.getShot().isLive()==true){
                for(int i=0;i<enemyTank.size();i++){
                    hitEnemy(hero.getShot(),enemyTank.get(i));
                }
            }
            this.repaint();
        }
    }
}

控制坦克发射多发子弹


让自己的坦克可以发射多个子弹的思路很简单,首先在Hero中定义一个子弹夹,在按下J实现子弹的创建并将子弹放入夹中,如果发射子弹超出游戏范围或者击中敌人就销毁,在这基础上我们还可以设计坦克弹夹的限制。
Hero:

public class Hero extends Tank{
    //创建子弹
//    private Shot shot=null;
    //创建子弹夹
    Vector<Shot> shots=new Vector<>();

//    public Shot getShot() {
//        return shot;
//    }

    public Hero(int x, int y) {
        super(x, y);
    }
    //射击
    public void shotEnemy(){
        //子弹夹只能有5个子弹
        Shot shot=null;
        if(shots.size()==5)
            return;
        switch (getDirection()){
            case 0://hero向上
                shot=new Shot(getX()+20,getY(),0);
                break;
            case 1:
                shot=new Shot(getX()+60,getY()+20,1);
                break;
            case 2:
                shot=new Shot(getX()+20,getY()+60,2);
                break;
            case 3:
                 shot=new Shot(getX(),getY()+20,3);
                break;
        }
        shots.add(shot);//将创建的子弹放入子弹夹中
        new Thread(shot).start();//启动子弹线程
    }
}

GamePanel:

public class GamePanel extends JPanel implements KeyListener,Runnable{
    //在面板上定义自己的坦克Hero
    Hero hero=null;
    //在面板上用vector定义敌人坦克
    Vector<Enemy> enemyTank=new Vector<>();

    //设置敌人的坦克个数为3
    int enemyTankSize=3;
    //用vector定义爆炸
    Vector<Bomb> bombs=new Vector<>();
    //定义爆炸效果图片
    Image[] images=new Image[3];

    public GamePanel() {
        //设置hero
        hero= new Hero(100,100);//设置hero坦克的坐标
        hero.setSpeed(3);//设置hero的速度

        //for循环设置敌人的坦克
        for(int i=0;i<enemyTankSize;i++){
            Enemy enemy=new Enemy(100*(i+1),0);//第一个坦克的坐标为(100,0),第二个为(200,0)以此类推
            enemy.setDirection(2);//设置坦克的方向向下(向下攻击己方坦克)
            enemyTank.add(enemy);//在vector中添加当前创建的坦克
            new Thread(enemy).start();
            Shot shot=new Shot(enemy.getX()+20,enemy.getY()+60,2);//创建当前敌人的子弹
            enemy.shots.add(shot);//将子弹添加在敌人类的vector容器中
            new Thread(shot).start();//启动当前子弹进程
        }

        //设置图片
        images[0]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_1.gif");
        images[1]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_2.gif");
        images[2]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_3.gif");
    }

    //用画笔开始画
    public void paint(Graphics g){
        super.paint(g);//将g设置为画笔
        // 填充矩形 fillRect(int x,int y,int width,int height)
        g.fillRect(0,0,1000,750);
        //绘制hero坦克
        drawTank(hero.getX(),hero.getY(),g,0,hero.getDirection());
        //如果子弹被创建或者子弹还存在就绘制子弹的图
        //修改:
        for(int i=0;i<hero.shots.size();i++){
            Shot shot=hero.shots.get(i);
            if(shot!=null&&shot.isLive()==true)
            {
                g.setColor(Color.white);
                g.draw3DRect(shot.getX(),shot.getY(),2,2,false);
            }
            else
                hero.shots.remove(shot);
        }


        //绘制敌人坦克
        for(int i=0;i<enemyTank.size();i++){
            //取出一个敌人
            Enemy enemy=enemyTank.get(i);
            //判断当前敌人坦克是否存活
            if(enemy.isLive()==true){
                //绘制取出的这个敌人
                drawTank(enemy.getX(),enemy.getY(),g,1,enemy.getDirection());

                //绘制当前敌人的子弹
                for(int j=0;j<enemy.shots.size();j++)
                {
                    Shot shot=enemy.shots.get(j);//取出当前敌人的子弹
                    //如果shot存在,就绘制子弹;如果shot不存在,那么就从vector中移除子弹
                    if(shot.isLive()==true){
                        //绘制敌人子弹
                        g.setColor(Color.white);
                        g.draw3DRect(shot.getX(),shot.getY(),2,2,false);
                    }
                    else{
                        enemy.shots.remove(shot);//将shot从shots中移除
                    }
                }
            }
        }
        //绘制爆炸效果
        for(int i=0;i<bombs.size();i++){
            Bomb bomb=bombs.get(i);
            if(bomb.getLifeCycle()>6){
            }else if(bomb.getLifeCycle()>3){
              g.drawImage(images[1],bomb.getX(),bomb.getY(),60,60,this);
            }else
               g.drawImage(images[2],bomb.getX(),bomb.getY(),60,60,this);
            bomb.lifeCycleDown();//让爆炸生命周期减小
            if(bomb.getLifeCycle()==0)//若爆炸的生命周期为0就将当前bomb从vector中移除
                bombs.remove(bomb);
        }
    }

    /**
     *
     * @param x 坦克左上角的x
     * @param y 坦克左上角的y
     * @param g 画笔
     * @param type 坦克类型:0 己方坦克 1 敌方坦克
     * @param direction 坦克方向: 0向上 1 向右 2向下 3向左
     */
    public void drawTank(int x,int y,Graphics g,int type,int direction){
        /**
         * 设置敌人的颜色为红色,己方的颜色为蓝色
         */
        switch (type){
        case 0:
            g.setColor(Color.blue);
            break;
        case 1:
            g.setColor(Color.red);
            break;
        }

        switch (direction){
            case 0:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y,x+20,y+20);//画出炮筒
            break;
            case 1:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x+40,y+20,x+60,y+20);//画出炮筒
                break;
            case 2:
                g.fill3DRect(x,y,10,60,false);//画出左轮子
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子
                g.fill3DRect(x+30,y,10,60,false);//画出身体
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台
                g.drawLine(x+20,y+40,x+20,y+60);//画出炮筒
                break;
            case 3:
                g.fill3DRect(x,y,60,10,false);//画出左轮子
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子
                g.fill3DRect(x,y+30,60,10,false);//画出身体
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台
                g.drawLine(x,y+20,x+20,y+20);//画出炮筒
                break;
        }
    }

    //hero坦克击中敌人坦克
    public void hitEnemy(){
        for(int i=0;i<hero.shots.size();i++){
            Shot shot=hero.shots.get(i);
            if(shot.isLive()==true&&shot!=null)
            {
                for(int j=0;j<enemyTank.size();j++){
                    Enemy enemy=enemyTank.get(j);
                    switch (enemy.getDirection())
                    {
                        //如果敌人坦克方向向上/向下(0/2),hero坦克击中
                        case 0:
                        case 2:
                            //hero子弹在当前敌人坦克的区域
                            if(shot.getX()<=enemy.getX()+40 && shot.getX()>=enemy.getX() && shot.getY()>=enemy.getY() && shot.getY()<=enemy.getY()+60){
                                shot.setLive(false);//hero子弹销毁
                                hero.shots.remove(shot);//从容器中取出
                                enemy.setLive(false);//敌人销毁
                                //敌人销毁后爆炸效果创建
                                Bomb bomb=new Bomb(enemy.getX(),enemy.getY());//创建爆炸效果
                                bombs.add(bomb);//将爆炸效果添加在vector中
                                enemyTank.remove(enemy);
                            }
                            break;
                        case 1:
                        case 3:
                            if(shot.getX()<=enemy.getX()+60&&shot.getX()>=enemy.getX()&& shot.getY()>=enemy.getY() && shot.getY()<=enemy.getY()+40){
                                shot.setLive(false);//hero子弹销毁
                                hero.shots.remove(shot);//从容器中取出
                                enemy.setLive(false);//敌人销毁
                                //敌人销毁后爆炸效果创建
                                Bomb bomb=new Bomb(enemy.getX(),enemy.getY());//创建爆炸效果
                                bombs.add(bomb);//将爆炸效果添加在vector中
                                enemyTank.remove(enemy);
                            }
                            break;
                    }
                }
            }
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode()==KeyEvent.VK_W) { //若接受到键盘按下w
            //坦克改变方向
            hero.setDirection(0);
            //坦克向上走1步
            if(hero.getY()>0)
                hero.makeUp();
        }
      if(e.getKeyCode()==KeyEvent.VK_D) {
          hero.setDirection(1);
          if(hero.getX()+60<1000)
            hero.makeRight();
      }
       if(e.getKeyCode()==KeyEvent.VK_S) {
           hero.setDirection(2);
           if(hero.getY()+60<750)
           hero.makeDown();
       }
       if(e.getKeyCode()==KeyEvent.VK_A){
            hero.setDirection(3);
            if(hero.getX()>0)
            hero.makeLeft();
        }
        if(e.getKeyCode()==KeyEvent.VK_J){
            //不需要这句判断
//            if(hero.getShot()==null||!hero.getShot().isLive())
                hero.shotEnemy();
        }
        //重新绘制图像
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
    @Override
    public void run(){
        while (true){
            try {
                Thread.sleep(100);//子弹每隔0.5s重新绘制图像
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //判断是否击中敌人坦克
            //判断之前要求hero子弹不为null且存活
            hitEnemy();
            this.repaint();
        }
    }
}

敌人移动发射


要让敌人坦克自己移动,那么就应该在创建敌人坦克后启动这个坦克的进程的函数中添加相关动作。
Enemy:

public class Enemy extends Tank implements Runnable {  
    public Vector<Shot> shots=new Vector<>();//vector容器中存放敌人的子弹  
  
    private int count=3;  
  
    public Enemy(int x, int y) {  
        super(x, y);  
    }  
  
  
    @Override  
    public void run() {  
        while (true){  
              
            if(isLive==true && shots.size()==0){  
                Shot shot=null;  
                    switch (getDirection()){  
                        case 0://hero向上  
                            shot=new Shot(getX()+20,getY(),0);  
                            break;                        case 1:  
                            shot=new Shot(getX()+60,getY()+20,1);  
                            break;                        case 2:  
                            shot=new Shot(getX()+20,getY()+60,2);  
                            break;                        case 3:  
                            shot=new Shot(getX(),getY()+20,3);  
                            break;                    }  
                    shots.add(shot);  
                    new Thread(shot).start();  
  
            }  
            //根据当前坦克的方向(0向上1向左...)行走1次休息time毫秒,一共走step次  
            int step=50;  
            int time=30;  
            switch (getDirection()){  
                case 0:  
                    for(int i=0;i<step;i++){  
                        if(getY()>0)  
                        makeUp();  
                        try {  
                            Thread.sleep(time);  
                        } catch (InterruptedException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                    break;  
                case 1:  
                    for(int i=0;i<step;i++){  
                        if(getX()+60<1000)  
                        makeRight();  
                        try {  
                            Thread.sleep(time);  
                        } catch (InterruptedException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                    break;  
                case 2:  
                    for(int i=0;i<step;i++){  
                        if(getY()+60<750)  
                        makeDown();  
                        try {  
                            Thread.sleep(time);  
                        } catch (InterruptedException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                    break;  
                case 3:  
                    for(int i=0;i<step;i++){  
                        if(getX()>0)  
                        makeLeft();  
                        try {  
                            Thread.sleep(time);  
                        } catch (InterruptedException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                    break;  
            }  
            //改变坦克方向[0,4)  
            setDirection((int)(Math.random()*4));  
        }  
    }  
}

我方被击中爆炸


与判断敌人坦克是否被我方击中一样的思路,在main函数中启动面板进程时添加判断函数hitHero(),这时要注意还需要在paint()方法中对绘制hero加以限制,如果hero存活则绘制,反之游戏结束。
GamePanel:

public class GamePanel extends JPanel implements KeyListener,Runnable{  
    //在面板上定义自己的坦克Hero  
    Hero hero=null;  
    //在面板上用vector定义敌人坦克  
    Vector<Enemy> enemyTank=new Vector<>();  
  
    //设置敌人的坦克个数为3  
    int enemyTankSize=3;  
    //用vector定义爆炸  
    Vector<Bomb> bombs=new Vector<>();  
    //定义爆炸效果图片  
    Image[] images=new Image[3];  
    boolean flag =false;  
  
    public GamePanel() {  
  
        //设置hero  
        hero= new Hero(500,500);//设置hero坦克的坐标  
        hero.setSpeed(3);//设置hero的速度  
  
        //for循环设置敌人的坦克  
        for(int i=0;i<enemyTankSize;i++){  
            Enemy enemy=new Enemy(100*(i+1),0);//第一个坦克的坐标为(100,0),第二个为(200,0)以此类推  
            enemy.setDirection(2);//设置坦克的方向向下(向下攻击己方坦克)  
            enemyTank.add(enemy);//在vector中添加当前创建的坦克  
            new Thread(enemy).start();  
            Shot shot=new Shot(enemy.getX()+20,enemy.getY()+60,2);//创建当前敌人的子弹  
            enemy.shots.add(shot);//将子弹添加在敌人类的vector容器中  
            new Thread(shot).start();//启动当前子弹进程  
        }  
  
        //设置图片  
        images[0]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_1.gif");  
        images[1]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_2.gif");  
        images[2]=Toolkit.getDefaultToolkit().getImage("D:\\java-code\\JavaCode\\src\\TankGames\\bomb_3.gif");  
    }  
  
    //用画笔开始画  
    public void paint(Graphics g){  
        super.paint(g);//将g设置为画笔  
        // 填充矩形 fillRect(int x,int y,int width,int height)        g.fillRect(0,0,1000,750);  
        if(flag==false){  
            g.setColor(Color.white);  
            g.setFont(new Font("arial",Font.BOLD,40));  
            g.drawString("Begin!",400,300);  
        }  
        else  
        {  
            //绘制hero坦克  
            if(hero.isLive()==true&&hero!=null)  
                drawTank(hero.getX(),hero.getY(),g,0,hero.getDirection());  
            else {  
                g.setColor(Color.white);  
                g.setFont(new Font("arial",Font.BOLD,40));  
                g.drawString("YOU ARE LOSS",400,300);  
                flag=false;  
                this.repaint();  
            }  
  
            //如果子弹被创建或者子弹还存在就绘制子弹的图  
            //修改:  
            for(int i=0;i<hero.shots.size();i++){  
                Shot shot=hero.shots.get(i);  
                if(shot!=null&&shot.isLive()==true)  
                {  
                    g.setColor(Color.white);  
                    g.draw3DRect(shot.getX(),shot.getY(),2,2,false);  
                }  
                else  
                    hero.shots.remove(shot);  
            }  
  
  
            //绘制敌人坦克  
            for(int i=0;i<enemyTank.size();i++){  
                //取出一个敌人  
                Enemy enemy=enemyTank.get(i);  
                //判断当前敌人坦克是否存活  
                if(enemy.isLive()==true){  
                    //绘制取出的这个敌人  
                    drawTank(enemy.getX(),enemy.getY(),g,1,enemy.getDirection());  
  
                    //绘制当前敌人的子弹  
                    for(int j=0;j<enemy.shots.size();j++)  
                    {  
                        Shot shot=enemy.shots.get(j);//取出当前敌人的子弹  
                        //如果shot存在,就绘制子弹;如果shot不存在,那么就从vector中移除子弹  
                        if(shot.isLive()==true){  
                            //绘制敌人子弹  
                            g.setColor(Color.white);  
                            g.draw3DRect(shot.getX(),shot.getY(),2,2,false);  
                        }  
                        else{  
                            enemy.shots.remove(shot);//将shot从shots中移除  
                        }  
                    }  
                }  
            }  
            //绘制爆炸效果  
            for(int i=0;i<bombs.size();i++){  
                Bomb bomb=bombs.get(i);  
                if(bomb.getLifeCycle()>6){  
                }else if(bomb.getLifeCycle()>3){  
                    g.drawImage(images[1],bomb.getX(),bomb.getY(),60,60,this);  
                }else  
                    g.drawImage(images[2],bomb.getX(),bomb.getY(),60,60,this);  
                bomb.lifeCycleDown();//让爆炸生命周期减小  
                if(bomb.getLifeCycle()==0)//若爆炸的生命周期为0就将当前bomb从vector中移除  
                    bombs.remove(bomb);  
            }  
        }  
  
    }  
  
    /**  
     *     * @param x 坦克左上角的x  
     * @param y 坦克左上角的y  
     * @param g 画笔  
     * @param type 坦克类型:0 己方坦克 1 敌方坦克  
     * @param direction 坦克方向: 0向上 1 向右 2向下 3向左  
     */  
    public void drawTank(int x,int y,Graphics g,int type,int direction){  
        /**  
         * 设置敌人的颜色为红色,己方的颜色为蓝色  
         */  
        switch (type){  
        case 0:  
            g.setColor(Color.blue);  
            break;        case 1:  
            g.setColor(Color.red);  
            break;        }  
  
        switch (direction){  
            case 0:  
                g.fill3DRect(x,y,10,60,false);//画出左轮子  
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子  
                g.fill3DRect(x+30,y,10,60,false);//画出身体  
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台  
                g.drawLine(x+20,y,x+20,y+20);//画出炮筒  
            break;  
            case 1:  
                g.fill3DRect(x,y,60,10,false);//画出左轮子  
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子  
                g.fill3DRect(x,y+30,60,10,false);//画出身体  
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台  
                g.drawLine(x+40,y+20,x+60,y+20);//画出炮筒  
                break;  
            case 2:  
                g.fill3DRect(x,y,10,60,false);//画出左轮子  
                g.fill3DRect(x+10,y+10,20,40,false);//画出右轮子  
                g.fill3DRect(x+30,y,10,60,false);//画出身体  
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形炮台  
                g.drawLine(x+20,y+40,x+20,y+60);//画出炮筒  
                break;  
            case 3:  
                g.fill3DRect(x,y,60,10,false);//画出左轮子  
                g.fill3DRect(x+10,y+10,40,20,false);//画出右轮子  
                g.fill3DRect(x,y+30,60,10,false);//画出身体  
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形炮台  
                g.drawLine(x,y+20,x+20,y+20);//画出炮筒  
                break;  
        }  
    }  
  
    //hero坦克击中敌人坦克  
    public void hitEnemy(){  
        for(int i=0;i<hero.shots.size();i++){  
            Shot shot=hero.shots.get(i);  
                for(int j=0;j<enemyTank.size();j++){  
                    Enemy enemy=enemyTank.get(j);  
                    if(enemy.isLive()&&shot.isLive()){  
                        hitTank(shot,enemy);  
                    }  
                }  
            }  
        }  
  
    //敌人打hero  
    public void hitHero(){  
        for(int i=0;i<enemyTank.size();i++){  
            Enemy enemy=enemyTank.get(i);  
            for(int j=0;j<enemy.shots.size();j++){  
                Shot shot=enemy.shots.get(j);  
                if(hero.isLive()&&shot.isLive()){  
                    hitTank(shot,hero);  
                }  
  
            }  
        }  
  
    }  
    public void hitTank(Shot shot,Tank tank){  
        switch (tank.getDirection())  
        {  
            //如果敌人坦克方向向上/向下(0/2),hero坦克击中  
            case 0:  
            case 2:  
                //hero子弹在当前敌人坦克的区域  
                if(shot.getX()<=tank.getX()+40 && shot.getX()>=tank.getX() && shot.getY()>=tank.getY() && shot.getY()<=tank.getY()+60){  
                    shot.setLive(false);//hero子弹销毁  
                    tank.setLive(false);//敌人销毁  
                    //敌人销毁后爆炸效果创建  
                    Bomb bomb=new Bomb(tank.getX(),tank.getY());//创建爆炸效果  
                    bombs.add(bomb);//将爆炸效果添加在vector中  
                }  
                break;  
            case 1:  
            case 3:  
                if(shot.getX()<=tank.getX()+60&&shot.getX()>=tank.getX()&& shot.getY()>=tank.getY() && shot.getY()<=tank.getY()+40){  
                    shot.setLive(false);//hero子弹销毁  
                    tank.setLive(false);//敌人销毁  
                    //敌人销毁后爆炸效果创建  
                    Bomb bomb=new Bomb(tank.getX(),tank.getY());//创建爆炸效果  
                    bombs.add(bomb);//将爆炸效果添加在vector中  
                }  
                break;  
        }  
    }  
  
    @Override  
    public void keyTyped(KeyEvent e) {  
  
    }  
  
    @Override  
    public void keyPressed(KeyEvent e) {  
        if(e.getKeyCode()==KeyEvent.VK_1){  
            flag =true;  
            this.repaint();  
        }  
        if(e.getKeyCode()==KeyEvent.VK_W) { //若接受到键盘按下w  
            //坦克改变方向  
            hero.setDirection(0);  
            //坦克向上走1步  
            if(hero.getY()>0)  
                hero.makeUp();  
        }  
      if(e.getKeyCode()==KeyEvent.VK_D) {  
          hero.setDirection(1);  
          if(hero.getX()+60<1000)  
            hero.makeRight();  
      }  
       if(e.getKeyCode()==KeyEvent.VK_S) {  
           hero.setDirection(2);  
           if(hero.getY()+60<750)  
           hero.makeDown();  
       }  
       if(e.getKeyCode()==KeyEvent.VK_A){  
            hero.setDirection(3);  
            if(hero.getX()>0)  
            hero.makeLeft();  
        }  
        if(e.getKeyCode()==KeyEvent.VK_J){  
            //不需要这句判断  
//            if(hero.getShot()==null||!hero.getShot().isLive())  
                hero.shotEnemy();  
        }  
        //重新绘制图像  
        this.repaint();  
    }  
  
    @Override  
    public void keyReleased(KeyEvent e) {  
  
    }  
    @Override  
    public void run(){  
        while (true){  
            try {  
                Thread.sleep(100);//子弹每隔0.5s重新绘制图像  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            //判断是否击中敌人坦克  
            //判断之前要求hero子弹不为null且存活  
            hitEnemy();  
            hitHero();  
            this.repaint();  
        }  
    }  
}

添加亿点

完整代码

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XiYang-DING

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值