[ java ] 坦克大战 4.0 ~

坦克大战4.0
新增功能内容:

  • 敌坦克移动发射,并自动装弹
  • 我方坦克被击中爆炸

5.0版本已上传
提示:爆炸图片需自行按路径放在工程文件的out文件夹对应的包下

画框

package com.hspedu.tankgame04plus;

import javax.swing.*;

/**
 * @ClassName
 * @Description
 * @Author zxk
 * @DateTime 2022-01-14-18:24
 * @Version
 *///第四版加强:敌坦克移动发射->Hero被击中爆炸
public class ZxkTankGame04 extends JFrame {//画框
    //定义画板
    Mypanel mp = null;

    public static void main(String[] args) {
        ZxkTankGame04 zxkTankGame01 = new ZxkTankGame04();//新建画框
    }
    public ZxkTankGame04(){
        mp = new Mypanel();//新建画板
        new Thread(mp).start();//开启画板重绘线程
        this.add(mp);//添加画板到画框
        setSize(1200, 950);//画板大小
        this.addKeyListener(mp);//监听画板的键盘
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭画框的同时关闭jvm
        setVisible(true);//可视化

    }
}


画板

package com.hspedu.tankgame04plus;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

/**
 * @ClassName
 * @Description
 * @Author zxk
 * @DateTime 2022-01-14-18:17
 * @Version
 *///画板
public class Mypanel extends JPanel implements KeyListener,Runnable {//方法的参数坐标都在左上角,除了画字符串在左下角
    //定义自己的坦克
    Hero hero = null;
    Vector<EnemyTank> enemyTanks = new Vector<EnemyTank>();//新建敌人坦克集合
    Vector<Bomb> bombs = new Vector<Bomb>();//新建炸弹集合,当击中坦克时,加入炸弹到集合中
    //定义三张图片,用于显示爆炸效果
    Image image1 = null;
    Image image2 = null;
    Image image3 = null;
    public Mypanel(){//画板构造器内部新建坦克,指明敌坦克及其炮弹的初始位置和方向
        hero = new Hero(100, 100,'w',10);
        for (int i = 0; i < 3; i++) {
            //初始化敌坦克
            EnemyTank enemyTank = new EnemyTank(200 + i * 100, 0, 's', 1);
            new Thread(enemyTank).start();//启动敌坦克线程移动
            //初始化敌坦克第一发子弹
            Bullet bullet = new Bullet(enemyTank.getX() + 20, enemyTank.getY() + 60, 's');
            new Thread(bullet).start();//立即启动子弹的线程
            enemyTank.bullets.add(bullet);//将子弹加入敌坦克的子弹集合中
            enemyTanks.add(enemyTank);

        }

        //初始化图片对象
        image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));
        image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));
        image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));
    }

    @Override
    public void paint(Graphics g) {//重写父类画画方法
        super.paint(g);
        System.out.println("重画过");
        g.fillRect(0,0,1000,750);//画板填充颜色默认黑色

        //绘制敌方坦克及其子弹
        for (int i = 0; i < enemyTanks.size(); i++) {
            //取出敌坦克(因可能被击中做判断)
            EnemyTank enemyTank = enemyTanks.get(i);
            if (enemyTank.alive) {//存活则画出


                drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), false);


                for (int j = 0; j < enemyTank.bullets.size(); j++) {
                    //取出子弹
                    Bullet bullet = enemyTank.bullets.get(j);
                    //绘制存活的子弹,移除死亡的子弹
                    if (bullet.alive) {
                        g.draw3DRect(bullet.x, bullet.y, 2, 2, false);
                    } else {
                        enemyTank.bullets.remove(bullet);
                    }
                }
            } else {
                enemyTanks.remove(enemyTank);//被击中则死亡然后移除,否则只是不画但仍存在
            }
        }

        //绘制我方坦克,后创建的坦克可以显示在先创建的上层(被击中就消失了)
        if (hero.alive) {
            drawTank(hero.getX(), hero.getY(), g, hero.getDirection(), true);
        }
        //绘制Hero的一个子弹
        /*if (hero.bullet != null && hero.bullet.alive) {
            g.draw3DRect(hero.bullet.x,hero.bullet.y,2,2,false);
        }*/
        //绘制Hero的多个子弹
        for (int i = 0; i < hero.ammos.size(); i++) {
            Bullet ammo=hero.ammos.get(i);
            if (ammo != null && ammo.alive) {
                g.draw3DRect(ammo.x, ammo.y, 2, 2, false);
            } else {//子弹集合中移除消亡的子弹
                hero.ammos.remove(ammo);
            }
        }

        //绘制爆炸(如果炸弹集合中有对象就画出)
        for (int i = 0; i < bombs.size(); i++) {
            Bomb bomb = bombs.get(i);
            if (bomb.life > 6) {
                g.drawImage(image1, bomb.x, bomb.y, 60, 60,this);
            }else if (bomb.life > 3) {
                g.drawImage(image2, bomb.x, bomb.y, 60, 60,this);
            }else {
                g.drawImage(image3, bomb.x, bomb.y, 60, 60,this);
            }
            //减少炸弹生命值
            bomb.lifeDown();
            //判断删除炸弹
            if (bomb.life == 0) {
                bombs.remove(bomb);
            }
        }

    }
    public void drawTank(int x,int y,Graphics g,char direct,boolean type){
        //坦克类型不同,颜色不同
        if (type) {
            g.setColor(Color.cyan);
        } else {
            g.setColor(Color.yellow);
        }
        //四种方向
        switch (direct) {
            case 'w'://坦克朝上
                g.fill3DRect(x, y, 10, 60, false);//左车轮
                g.fill3DRect(x + 30, y, 10, 60, false);//右车轮
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//车中间部分
                g.fillOval(x + 10, y + 20, 20, 20);//车盖
                g.drawLine(x + 20, y + 30, x + 20, y);//炮筒
                break;
            case 's':
                g.fill3DRect(x, y, 10, 60, false);
                g.fill3DRect(x + 30, y, 10, 60, false);
                g.fill3DRect(x + 10, y + 10, 20, 40, false);
                g.fillOval(x + 10, y + 20, 20, 20);
                g.drawLine(x + 20, y + 30, x + 20, y+60);
                break;
            case 'a':
                g.fill3DRect(x-10, y+10, 60, 10, false);
                g.fill3DRect(x-10, y+40, 60, 10, false);
                g.fill3DRect(x, y + 20, 40, 20, false);
                g.fillOval(x + 10, y + 20, 20, 20);
                g.drawLine(x + 20, y + 30, x-10, y+30);
                break;
            case 'd':
                g.fill3DRect(x-10, y+10, 60, 10, false);
                g.fill3DRect(x-10, y+40, 60, 10, false);
                g.fill3DRect(x, y + 20, 40, 20, false);
                g.fillOval(x + 10, y + 20, 20, 20);
                g.drawLine(x + 20, y + 30, x+50, y+30);
                break;
        }
    }

    //判断方法:敌人子弹是否击中Hero
    public void hitHero(Bullet bullet) {
        switch (hero.getDirection()) {
            case 'w':
            case 's':
                if (bullet.x > hero.getX() && bullet.x < hero.getX() + 40
                        && bullet.y > hero.getY() && bullet.y < hero.getY() + 60) {
                    bullet.alive = false;
                    hero.alive = false;//当坦克不在存活了就不再画了
                    //创建炸弹对象加入到炸弹集合中
                    Bomb bomb = new Bomb(hero.getX(), hero.getY());
                    bombs.add(bomb);
                }
                break;
            case 'a':
            case 'd':
                if (bullet.x > hero.getX() - 10 && bullet.x < hero.getX() + 50
                        && bullet.y > hero.getY() + 10 && bullet.y < hero.getY() + 50) {
                    bullet.alive = false;
                    hero.alive = false;
                    Bomb bomb = new Bomb(hero.getX(), hero.getY());
                    bombs.add(bomb);
                }
                break;
        }
    }
    //判断方法:子弹是否击中敌人坦克
    public void hitTank(Bullet bullet, EnemyTank enemyTank){
        //子弹击中坦克
        switch (enemyTank.getDirection()) {
            case 'w':
            case 's':
                if (bullet.x > enemyTank.getX() && bullet.x < enemyTank.getX() + 40
                        && bullet.y > enemyTank.getY() && bullet.y < enemyTank.getY() + 60) {
                    bullet.alive = false;
                    enemyTank.alive = false;
                    //创建炸弹对象加入到炸弹集合中
                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                    bombs.add(bomb);
                }
                break;
            case 'a':
            case 'd':
                if (bullet.x > enemyTank.getX() - 10 && bullet.x < enemyTank.getX() + 50
                        && bullet.y > enemyTank.getY() + 10 && bullet.y < enemyTank.getY() + 50) {
                    bullet.alive = false;
                    enemyTank.alive = false;
                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
                    bombs.add(bomb);
                }
                break;
        }
    }
    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override

    public void keyPressed(KeyEvent e) {//键盘事件
        if (e.getKeyCode() == KeyEvent.VK_D) {//坦克车头朝右且位置往右挪
            if (hero.getX() < 950) {//限制坦克不出画框(当移动速度超过10,会出现坦克车头出框)
                hero.moveRight();
            }
            hero.setDirection('d');
        }else if (e.getKeyCode() == KeyEvent.VK_A) {
            if (hero.getX()  > 10) {
                hero.moveLeft();
            }
            hero.setDirection('a');
        }else if (e.getKeyCode() == KeyEvent.VK_W) {
            if (hero.getY() > 0) {
                hero.moveUp();
            }
            hero.setDirection('w');
        }else if (e.getKeyCode() == KeyEvent.VK_S) {
            if (hero.getY() + 60 < 750) {
                hero.moveDown();
            }
            hero.setDirection('s');
        }
        //监听器调用Hero的射击方法
        if (e.getKeyCode() == KeyEvent.VK_J) {
            /*if (hero.bullet==null||!hero.bullet.alive) {//当子弹是空弹(第一次射击)||子弹消亡后才可以射击(子弹消亡即线程结束后并不是子弹为空)
                hero.shotEnemy();
            }*/
            hero.shotEnemy();
        }

        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    //每休眠100ms画板重绘
    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //定时反复判断Hero的子弹是否击中了敌方坦克
            if (hero.ammos!=null) {//首先弹夹不为空
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);
                    for (int j = 0; j < hero.ammos.size(); j++) {//将每颗子弹都与每个坦克比较
                        if (hero.ammos.get(j) != null && hero.ammos.get(j).alive) {
                            hitTank(hero.ammos.get(j),enemyTank);
                        }
                    }

//                    hitTank(hero.bullet,enemyTank);
                }
            }
            //定时反复判断Hero的子弹是否击中了敌方坦克(取出每个坦克的每颗子弹调用hitHero方法)
            for (int i = 0; i < enemyTanks.size(); i++) {
                EnemyTank enemyTank = enemyTanks.get(i);
                for (int j = 0; j < enemyTank.bullets.size(); j++) {
                    Bullet bullet = enemyTank.bullets.get(j);
                    hitHero(bullet);
                    //如果将方法形参改为Tank类型(多态)放入我方或敌坦克,将会丢失子类特有的alive属性
                    //可以分情况向下转型解决问题
                    //hitTank(bullet,hero);
                }

            }

            this.repaint();
        }
    }
}


Tank类

package com.hspedu.tankgame04plus;

/**
 * @ClassName
 * @Description
 * @Author zxk
 * @DateTime 2022-01-14-18:13
 * @Version
 *///坦克类
public class Tank {
    private int x;
    private int y;
    private char direction;
    private int speed;
    public Tank(int x, int y,char direction,int speed) {
        this.x = x;
        this.y = y;
        this.direction = direction;
        this.speed = speed;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public char getDirection() {
        return direction;
    }

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

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    public void moveUp(){//开坦克:改变坦克位置
        y -= speed;
    }
    public void moveDown(){
        y += speed;
    }
    public void moveLeft(){
        x -= speed;
    }
    public void moveRight(){
        x += speed;
    }
}


Hero类

package com.hspedu.tankgame04plus;

import java.util.Vector;

/**
 * @ClassName
 * @Description
 * @Author zxk
 * @DateTime 2022-01-14-18:15
 * @Version
 *///自己的坦克
public class Hero extends Tank {
    boolean alive = true;
    //添加自己坦克的子弹集合属性->修改射击方法:每次按键J(射击)将加芯后的子弹放入弹夹->绘制时取出子弹分别绘制->修改hit方法的使用(反复判断是否击中坦克)
    Vector<Bullet> ammos = new Vector<Bullet>();
    //构造器指明Hero的初始位置
    public Hero(int x, int y,char direction,int speed) {
        super(x, y,direction,speed);
    }

    //填弹(空弹)
    Bullet bullet = null;
    //射击方法(空弹加芯):根据坦克的当前位置(炮筒头部)填入子弹的初始位置
    public void shotEnemy(){
        if (ammos.size() == 5) {//控制同时射出的子弹数为5
            return;
        }

        switch (this.getDirection()) {
            case 'w':
                bullet = new Bullet(getX() + 20, getY(), 'w');
                break;
            case 's':
                bullet = new Bullet(getX() + 20, getY()+60, 's');
                break;
            case 'a':
                bullet = new Bullet(getX() -10, getY()+30, 'a');
                break;
            case 'd':
                bullet = new Bullet(getX() + 50, getY()+30, 'd');
                break;
        }

            ammos.add(bullet);

        //启动子弹线程->按预定轨迹射击->最终消亡
        new Thread(bullet).start();
    }
}


EnemyTank类

package com.hspedu.tankgame04plus;

import java.util.Vector;

/**
 * @ClassName
 * @Description
 * @Author zxk
 * @DateTime 2022-01-14-22:19
 * @Version
 *///敌人坦克
public class EnemyTank extends Tank implements Runnable{
    public EnemyTank(int x, int y, char direction, int speed) {
        super(x, y, direction, speed);
    }

    //创建敌坦克子弹集合
    Vector<Bullet> bullets = new Vector<Bullet>();
    boolean alive = true;

    //子线程提供坦克移动和射击
    @Override
    public void run() {
        while (true) {
            if (alive && bullets.size() < 1) {//每50ms判断敌坦克没子弹了就补充再射击,提示:在画画方法中,判断子弹消亡就移除了
                Bullet bullet = null;
                switch (getDirection()) {
                    case 'w':
                        bullet = new Bullet(getX() + 20, getY(), 'w');
                        break;
                    case 's':
                        bullet = new Bullet(getX() + 20, getY()+60, 's');
                        break;
                    case 'a':
                        bullet = new Bullet(getX() -10, getY()+30, 'a');
                        break;
                    case 'd':
                        bullet = new Bullet(getX() + 50, getY()+30, 'd');
                        break;
                }
                bullets.add(bullet);//添加新子弹
                new Thread(bullet).start();//启动子弹线程使其有轨迹
            }


            //敌坦克朝指定方向移动
            switch (getDirection()) {
                case 'w':
                    for (int i = 0; i < 30; i++) {//前进30步休眠50ms然后随机转向
                        if (getY() > 0) {//限制坦克不出画框
                            moveUp();
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }

                    break;
                case 's':
                    for (int i = 0; i < 30; i++) {
                        if (getY() + 60 < 750) {
                            moveDown();
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }

                    break;
                case 'a':
                    for (int i = 0; i < 30; i++) {
                        if (getX() - 10 > 0) {
                            moveLeft();
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }

                    break;
                case 'd':
                    for (int i = 0; i < 30; i++) {
                        if (getX() + 50 < 1000) {
                            moveRight();
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }

                    break;

            }
            //随机改变坦克方向
            int dic = (int) (Math.random() * 4);
            switch (dic) {
                case 0:
                    setDirection('w');
                    break;
                case 1:
                    setDirection('s');
                    break;
                case 2:
                    setDirection('a');
                    break;
                case 3:
                    setDirection('d');
                    break;
            }
            //判断终止坦克线程
            if (!alive) {
                break;
            }
        }
    }
}


Bullet类

package com.hspedu.tankgame04plus;

/**
 * @ClassName
 * @Description
 * @Author zxk
 * @DateTime 2022-01-19-14:39
 * @Version
 *///子弹类
public class Bullet implements Runnable{
    int x;
    int y;
    int speed = 5;
    char direction;
    boolean alive = true;

    //构造器指定子弹初始初始位置和方向
    public Bullet(int x, int y, char direction) {
        this.x = x;
        this.y = y;
        this.direction = direction;
    }

    //根据方向改变子弹射出后的位置(子弹轨迹)
    @Override
    public void run() {
        while (true) {
            //每休眠50ms改变子弹位置
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            switch (direction) {
                case 'w':
                    y-=speed;
                    break;
                case 's':
                    y+=speed;
                    break;
                case 'a':
                    x-=speed;
                    break;
                case 'd':
                    x+=speed;
                    break;
            }
            //子弹脱离画框当即销毁
            if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750&&alive)) {
                alive = false;
                System.out.println("子弹线程终止");
                break;
            }
        }
    }
}


Bomb类

package com.hspedu.tankgame04plus;

/**
 * @ClassName
 * @Description
 * @Author zxk
 * @DateTime 2022-01-20-10:46
 * @Version
 */
public class Bomb {
    int x, y;
    int life = 9;
    boolean alive = true;

    public Bomb(int x, int y) {
        this.x = x;
        this.y = y;
    }
    //减少生命值
    public void lifeDown() {
        if (life > 0) {
            life--;
        } else {
            alive = false;
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值