栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Java】坦克大战 Tank Games(未完)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【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 );
    }

    
    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());
    }

    
    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 enemyTank=new Vector<>();
    //设置敌人的坦克个数为3
    int enemyTankSize=3;

    public GamePanel() {

        hero= new Hero(100,100);//设置自己坦克的坐标
        //for循环设置敌人的坦克
        for(int i=0;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
            drawTank(enemyTank.get(i).getX(),enemyTank.get(i).getY(),g,1,enemyTank.get(i).getDirection());
        }
    }

    
    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 enemyTank=new Vector<>();
    //设置敌人的坦克个数为3
    int enemyTankSize=3;

    public GamePanel() {
        hero= new Hero(100,100);//设置自己坦克的坐标
        hero.setSpeed(3);
        //for循环设置敌人的坦克
        for(int i=0;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
            drawTank(enemyTank.get(i).getX(),enemyTank.get(i).getY(),g,1,enemyTank.get(i).getDirection());
        }
    }

    
    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 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 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
            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
            //取出一个敌人
            Enemy enemy=enemyTank.get(i);
            //绘制取出的这个敌人
            drawTank(enemy.getX(),enemy.getY(),g,1,enemy.getDirection());

            //绘制当前敌人的子弹
            for(int j=0;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中移除
                }
            }
        }
    }

    
    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 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 enemyTank=new Vector<>();
    //设置敌人的坦克个数为3
    int enemyTankSize=3;
    //用vector定义爆炸
    Vector 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
            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
            //取出一个敌人
            Enemy enemy=enemyTank.get(i);
            //判断当前敌人坦克是否存活
            if(enemy.isLive()==true){
                //绘制取出的这个敌人
                drawTank(enemy.getX(),enemy.getY(),g,1,enemy.getDirection());

                //绘制当前敌人的子弹
                for(int j=0;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
            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);
        }
    }

    
    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
                    hitEnemy(hero.getShot(),enemyTank.get(i));
                }
            }
            this.repaint();
        }
    }
}

效果如下图:

敌人坦克自由移动

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

public class Enemy extends Tank implements Runnable {
    public Vector 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
                        makeUp();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 1:
                    for(int i=0;i
                        makeRight();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 2:
                    for(int i=0;i
                        makeDown();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 3:
                    for(int i=0;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 enemyTank=new Vector<>();
    //设置敌人的坦克个数为3
    int enemyTankSize=3;
    //用vector定义爆炸
    Vector 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
            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
            //取出一个敌人
            Enemy enemy=enemyTank.get(i);
            //判断当前敌人坦克是否存活
            if(enemy.isLive()==true){
                //绘制取出的这个敌人
                drawTank(enemy.getX(),enemy.getY(),g,1,enemy.getDirection());

                //绘制当前敌人的子弹
                for(int j=0;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
            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);
        }
    }

    
    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
                    hitEnemy(hero.getShot(),enemyTank.get(i));
                }
            }
            this.repaint();
        }
    }
}
限制敌人+自己坦克移动范围

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

public class Enemy extends Tank implements Runnable {
    public Vector 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
                        if(getY()>0)
                        makeUp();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 1:
                    for(int i=0;i
                        if(getX()+60<1000)
                        makeRight();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 2:
                    for(int i=0;i
                        if(getY()+60<750)
                        makeDown();
                        try {
                            Thread.sleep(time);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 3:
                    for(int i=0;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 enemyTank=new Vector<>();
    //设置敌人的坦克个数为3
    int enemyTankSize=3;
    //用vector定义爆炸
    Vector 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
            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
            //取出一个敌人
            Enemy enemy=enemyTank.get(i);
            //判断当前敌人坦克是否存活
            if(enemy.isLive()==true){
                //绘制取出的这个敌人
                drawTank(enemy.getX(),enemy.getY(),g,1,enemy.getDirection());

                //绘制当前敌人的子弹
                for(int j=0;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
            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);
        }
    }

    
    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
                    hitEnemy(hero.getShot(),enemyTank.get(i));
                }
            }
            this.repaint();
        }
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/894114.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号