Java实现坦克大战2.0

发布时间:2023-05-08 09:10:54

线程-坦克大战0.3

当用户按下J键时,我们的坦克会发射一颗子弹:

  1. 当发射子弹时,它相当于启动一个线程
  2. Hero有子弹对象。当我们按下J时,我们将启动发射行为(线程),使子弹不断移动,形成射击效果。
  3. 为了产生这种效果,我们的MyPanel需要不断重绘子弹.
  4. 当子弹移动到面板的边界时,应销毁(销毁启动子弹的线程)
坦克大战0.4

增加功能

  1. 让敌人的坦克也能发射子弹(可以有多颗子弹)
  1. 在敌人坦克类中,使用Vector保存多个Shott
  2. 当每个敌人坦克对象被创建时,一个Shot对象被初始化为敌人坦克对象,同时启动Shot对象
  3. 在绘制敌人坦克时,需要通过敌人坦克对象Vector绘制所有子弹,当子弹islive时 == false从Vector中删除
  1. 当我们的坦克击中敌人的坦克时,敌人的坦克就会消失。如果能更好地爆炸.
  2. 让敌人的坦克也可以自由上下移动
  1. 因为敌人的坦克需要自由移动,所以需要使用敌人的坦克作为线程
  2. 我们需要Enemy Tank implements Runnable
  3. 在run方法中写下我们相应的业务代码.
  4. 在创建敌人坦克对象时,启动线程
  1. 控制我们的坦克和敌人的坦克在规定范围内移动分析->解决

增加功能

  1. 我们坦克只有在发射子弹消亡后才能发射新子弹.=>扩展(如何发送多颗子弹,控制在我们的面板上,最多只有5颗子弹)-课后改进

1.按下J键,我们判断hero目前的子弹是否已经销毁。

2.如果没有销毁,就不要触发shotenemytank

3.在触发shotenemyTank之前,如果已经销毁了

4.如果要发射多颗子弹,则使用Vector保存

5.绘制我们的子弹时,需要遍历Vector集合

  1. 在敌人坦克发射的子弹消亡后,可以再次发射子弹
  2. 当敌人的坦克击中我们的坦克时,我们的坦克消失了,并有爆炸性的想法:编写方法,判断敌人的坦克是否击中了我的坦克
  3. 课后练习:让敌人坦克最多发射3颗(面板E),我们的坦克可发射3颗。并且可以产生正常的爆炸效果.
package com.hspedu.tankgame4;/** * 炸弹 */public class Bomb {    int x, y; ///炸弹坐标    int life = 9; //炸弹的生命周期    boolean isLive = true; //是否还活着    public Bomb(int x, int y) {        this.x = x;        this.y = y;    }    //减少生命值    public void lifeDown() { ////配合图片爆炸效果        if(life > 0) {            life--;        } else {            isLive = false;        }    }}
package com.hspedu.tankgame4;import java.util.Vector;/** * 敌人的坦克 */@SuppressWarnings({"all"})public class EnemyTank extends Tank implements Runnable {    //在敌人坦克类,使用Vector 保存多个Shot    Vector<Shot> shots = new Vector<>();    boolean isLive = true;    public EnemyTank(int x, int y) {        super(x, y);    }    @Override    public void run() {        while (true) {            我们在这里判断,如果shotss, size() =0, 创建子弹,放入            //shots集合,并启动            if (isLive && shots.size() < 1) {                Shot s = null;                ///判断坦克的方向,创建相应的子弹                switch (getDirect()) {                    case 0:                        s = new Shot(getX() + 20, getY(), 0);                        break;                    case 1:                        s = new Shot(getX() + 60, getY() + 20, 1);                        break;                    case 2: //向下                        s = new Shot(getX() + 20, getY() + 60, 2);                        break;                    case 3://向左                        s = new Shot(getX(), getY() + 20, 3);                        break;                }                shots.add(s);                //启动                new Thread(s).start();            }            //继续按照坦克的方向移动            switch (getDirect()) {                case 0:  //向上                    //让坦克保持一个方向,走30步                    for (int i = 0; i < 30; i++) {                        if (getY() > 0) {                            moveUp();                        }                        //休眠50毫秒                        try {                            Thread.sleep(50);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                    break;                case 1:  //向右                    for (int i = 0; i < 30; i++) {                        if (getX() + 60 < 1000) {                            moveRight();                        }                        //休眠50毫秒                        try {                            Thread.sleep(50);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                    break;                case 2:  //向下                    for (int i = 0; i < 30; i++) {                        if (getY() + 60 < 750) {                            moveDown();                        }                        //休眠50毫秒                        try {                            Thread.sleep(50);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                    break;                case 3:  //向左                    for (int i = 0; i < 30; i++) {                        if (getX() > 0) {                            moveLeft();                        }                        //休眠50毫秒                        try {                            Thread.sleep(50);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                    break;            }            // 然后随机改变坦克的方向 0-3            setDirect((int) (Math.random() * 4));            // 编写并发程序,必须清楚地考虑线程何时结束            if (!isLive) {                break; //退出线程.            }        }    }}
package com.hspedu.tankgame4;import java.util.Vector;/** * 自己的坦克 */public class Hero extends Tank {    //定义Shot对象, 表示射击(线程)    Shot shot = null;    ///可以发射多颗子弹    //Vector<Shot> shots = new Vector<>();    public Hero(int x, int y) {        super(x, y);    }    //射击    public void shotEnemyTank() {        ///发多颗子弹怎么办? 控制在我们的面板上,最多只有5个/////        if(shots.size() == 5) {//            return;//        }        //创建 Shot 对象, Shot是根据当前Hero对象的位置和方向创建的        switch (getDirect()) {///得到Hero对象的方向            case 0: //向上                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;        }        ////将新创建的shot放入shots中        //shots.add(shot);        ////启动我们的Shot线程        new Thread(shot).start();    }}
package com.hspedu.tankgame4;import javax.swing.*;public class Hsptankgame04 extends JFrame {    //定义MyPanel    MyPanel mp = null;    public static void main(String[] args) {        Hsptankgame04 hsptankgame0 = new Hsptankgame04();    }    public Hsptankgame04() {        mp = new MyPanel();        //将mp 放入Thread ,并启动        Thread thread = new Thread(mp);        thread.start();        this.add(mp);///把面板(即游戏的绘图区域)        this.setSize(1200, 950);        this.addKeyListener(mp);//让JFrame 监控mp键盘事件        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        this.setVisible(true);    }}
package com.hspedu.tankgame4;import javax.swing.*;import java.awt.*;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.util.Vector;/** * 坦克大战的绘图区域 */////监听 键盘事件, Keylistener// 不断重绘子弹需要重绘子弹 MyPanel Runnnablele实现 ,使用public作为线程 class MyPanel extends JPanel implements KeyListener, Runnable {    //定义我的坦克    Hero hero = null;    ///定义敌人坦克,放入Vector    Vector<EnemyTank> enemyTanks = new Vector<>();    //定义Vector ,用于储存炸弹    //说明当子弹击中坦克时,将Bomb对象添加到Bombs中    Vector<Bomb> bombs = new Vector<>();    int enemyTankSize = 3;    //定义三张炸弹图片,用于显示爆炸效果    Image image1 = null;    Image image2 = null;    Image image3 = null;    public MyPanel() {        hero = new Hero(500, 100);///初始化自己的坦克        ///初始化敌人坦克        for (int i = 0; i < enemyTankSize; i++) {            ///创建敌人的坦克            EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);            //设定方向            enemyTank.setDirect(2);            //启动敌人坦克线程,让他动起来            new Thread(enemyTank).start();            ///给enemyTank 加一颗子弹            Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());            ///添加enemytankVector 成员            enemyTank.shots.add(shot);            //启动 shot 对象            new Thread(shot).start();            //加入            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);        g.fillRect(0, 0, 1000, 750);///填充矩形,默认黑色        if(hero != null && hero.isLive) {            ///画自己的坦克-包装方法            drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);        }        ///画hero射击的子弹        if (hero.shot != null && hero.shot.isLive == true) {            g.draw3DRect(hero.shot.x, hero.shot.y, 1, 1, false);        }        ////集合hero子弹 shots ,取出绘画/////        for(int i = 0; i < hero.shots.size(); i++) {//            Shot shot = hero.shots.get(i);//            if (shot != null && shot.isLive) {//                g.draw3DRect(shot.x, shot.y, 1, 1, false);////            } else {//如果shot对象无效 ,从shots集合中取出///                hero.shots.remove(shot);//            }//        }        //如果bombs 集合中有对象,就画出        for (int i = 0; i < bombs.size(); i++) {            //取出炸弹            Bomb bomb = bombs.get(i);            ///根据当前bomb对象的life值绘制相应的图片            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();            //如果bomb life 为0, 从bombs开始 集中删除            if (bomb.life == 0) {                bombs.remove(bomb);            }        }        //画敌人的坦克, Vector遍历        for (int i = 0; i < enemyTanks.size(); i++) {            //从Vector 取出坦克            EnemyTank enemyTank = enemyTanks.get(i);            ///判断当前坦克是否还活着            if (enemyTank.isLive) {//当敌人坦克存活时,画坦克                drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 0);                //画出 enemyTank 所有子弹                for (int j = 0; j < enemyTank.shots.size(); j++) {                    //取出子弹                    Shot shot = enemyTank.shots.get(j);                    //绘制                    if (shot.isLive) { //isLive == true                        g.draw3DRect(shot.x, shot.y, 1, 1, false);                    } else {                        //从Vector 移除                        enemyTank.shots.remove(shot);                    }                }            }        }    }    //编写方法,画出坦克    /**     * @param x      x坐标在坦克的左上角     * @param y      y坐标在坦克的左上角     * @param g      画笔     * @param direct 坦克方向(上下左右)     * @param type   坦克类型     */    public void drawTank(int x, int y, Graphics g, int direct, int type) {        //根据不同类型的坦克,设置不同的颜色        switch (type) {            case 0: ///敌人的坦克                g.setColor(Color.cyan);                break;            case 1: ///我的坦克                g.setColor(Color.yellow);                break;        }        //按坦克方向,绘制相应形状的坦克        //direct 表示方向(0: 向上 1 向右 2 向下 3 向左 )        //        switch (direct) {            case 0: //表示向上                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 1: //表示向右                g.fill3DRect(x, y, 60, 10, false);///在坦克上画轮子                g.fill3DRect(x, y + 30, 60, 10, false);///画坦克下面的轮子                g.fill3DRect(x + 10, y + 10, 40, 20, false);///画坦克盖                g.fillOval(x + 20, y + 10, 20, 20);//画圆盖                g.drawLine(x + 30, y + 20, x + 60, y + 20);///画炮筒                break;            case 2: //表示向下                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 3: //表示向左                g.fill3DRect(x, y, 60, 10, false);///在坦克上画轮子                g.fill3DRect(x, y + 30, 60, 10, false);///画坦克下面的轮子                g.fill3DRect(x + 10, y + 10, 40, 20, false);///画坦克盖                g.fillOval(x + 20, y + 10, 20, 20);//画圆盖                g.drawLine(x + 30, y + 20, x, y + 20);///画炮筒                break;            default:                System.out.println(“暂时未处理”);        }    }    //如果我们的坦克能发射多个子弹    ///当判断我们的子弹是否击中敌人坦克时,我们需要集中我们的子弹    //所有子弹,与敌人一起取出所有坦克,进行判断    /////老韩给出的一些代码..    public void hitEnemyTank() {//        ///遍历我们的子弹///        for(int j = 0;j < hero.shots.size();j++) {//            Shot shot = hero.shots.get(j);//            ///判断敌人坦克///            if (shot != null && hero.shot.isLive) {///当我的子弹还活着////                ////遍历敌人所有坦克///                for (int i = 0; i < enemyTanks.size(); i++) {//                    EnemyTank enemyTank = enemyTanks.get(i);//                    hitTank(hero.shot, enemyTank);//                }////            }//        }        ///单子弹。        if (hero.shot != null && hero.shot.isLive) {///当我的子弹还活着的时候            ////遍历敌人所有坦克            for (int i = 0; i < enemyTanks.size(); i++) {                EnemyTank enemyTank = enemyTanks.get(i);                hitTank(hero.shot, enemyTank);            }        }    }    //编写方法,判断敌人坦克是否击中了我的坦克    public void hitHero() {        ////遍历所有敌人坦克        for (int i = 0; i < enemyTanks.size(); i++) {            //取出敌人坦克            EnemyTank enemyTank = enemyTanks.get(i);            ///经历enemyTank 对象的所有子弹            for (int j = 0; j < enemyTank.shots.size(); j++) {                //取出子弹                Shot shot = enemyTank.shots.get(j);                //判断 shot 是否击中了我的坦克                if (hero.isLive && shot.isLive) {                    hitTank(shot, hero);                }            }        }    }    ///编写方法,判断我们的子弹是否击中敌人坦克.    ///什么时候判断? 我们的子弹击中了敌人坦克吗? ? run方法    ///我们将在后面 enemyTank 改成 tank名称    public void hitTank(Shot s, Tank enemyTank) {        //判断s 击中坦克        switch (enemyTank.getDirect()) {            case 0: ///坦克向上            case 2: ///坦克向下                if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 40                        && s.y > enemyTank.getY() && s.y < enemyTank.getY() + 60) {                    s.isLive = false;                    enemyTank.isLive = false;                    //当我的子弹击中敌人坦克时,enemyTank 从Vector开始 拿掉                    enemyTanks.remove(enemyTank);                    ///创建Bomb对象,加入bombs集合                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());                    bombs.add(bomb);                }                break;            case 1: ///坦克向右            case 3: ///坦克向左                if (s.x > enemyTank.getX() && s.x < enemyTank.getX() + 60                        && s.y > enemyTank.getY() && s.y < enemyTank.getY() + 40) {                    s.isLive = false;                    enemyTank.isLive = false;                    ///创建Bomb对象,加入bombs集合                    Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());                    bombs.add(bomb);                }                break;        }    }    @Override    public void keyTyped(KeyEvent e) {    }    ///处理wdsa 按键的情况    @Override    public void keyPressed(KeyEvent e) {        System.out.println(e.getKeyCode());        if (e.getKeyCode() == KeyEvent.VK_W) {//按W键            //改变坦克的方向            hero.setDirect(0);//            ///修改坦克坐标 y -= 1            if (hero.getY() > 0) {                hero.moveUp();            }        } else if (e.getKeyCode() == KeyEvent.VK_D) {///D键, 向右            hero.setDirect(1);            if (hero.getX() + 60 < 1000) {                hero.moveRight();            }        } else if (e.getKeyCode() == KeyEvent.VK_S) {//S键            hero.setDirect(2);            if (hero.getY() + 60 < 750) {                hero.moveDown();            }        } else if (e.getKeyCode() == KeyEvent.VK_A) {//A键            hero.setDirect(3);            if (hero.getX() > 0) {                hero.moveLeft();            }        }        //如果用户按J,就发射        if (e.getKeyCode() == KeyEvent.VK_J) {            ///判断hero子弹是否销毁,发射子弹            if (hero.shot == null || !hero.shot.isLive) {                hero.shotEnemyTank();            }            ///发射多颗子弹            //hero.shotEnemyTank();        }        //让面板重画        this.repaint();    }    @Override    public void keyReleased(KeyEvent e) {    }    @Override    public void run() { //每隔 100毫秒,重绘区域, 刷新绘图区域, 子弹就移动        while (true) {            try {                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }            ///判断是我们的子弹是否击中了敌人坦克            hitEnemyTank();            ///判断敌人坦克是否击中了我们            hitHero();            this.repaint();        }    }}
package com.hspedu.tankgame4;/** * 射击子弹 */public class Shot implements Runnable {    int x; //子弹x坐标    int y; //子弹y坐标    int direct = 0; //子弹方向    int speed = 2; ///子弹速度    boolean isLive = true; //子弹还活着吗?    //构造器    public Shot(int x, int y, int direct) {        this.x = x;        this.y = y;        this.direct = direct;    }    @Override    public void run() {//射击        while (true) {            //休眠 50毫秒            try {                Thread.sleep(50);            } catch (InterruptedException e) {                e.printStackTrace();            }            //按方向改变x,y坐标            switch (direct) {                case 0://上                    y -= speed;                    break;                case 1://右                    x += speed;                    break;                case 2://下                    y += speed;                    break;                case 3://左                    x -= speed;                    break;            }            ///老师考试,在这里,我们输出x、y的坐标            System.out.println("子弹 x=" + x + " y=" + y);            //当子弹移动到面板的边界时,应销毁(销毁启动子弹的线程)            //当子弹遇到敌人坦克时,线程也应该结束            if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750 && isLive)) {                System.out.println(子弹线程退出);                isLive = false;                break;            }        }    }}
package com.hspedu.tankgame4;public class Tank {    private int x;///坦克的横坐标    private int y;///坦克纵坐标    private int direct = 0;///坦克方向 0 上1 右 2下 3左    private int speed = 1;    boolean isLive = true;    public int getSpeed() {        return speed;    }    public void setSpeed(int speed) {        this.speed = speed;    }    //上右下左移动方法    public void moveUp() {        y -= speed;    }    public void moveRight() {        x += speed;    }    public void moveDown() {        y += speed;    }    public void moveLeft() {        x -= speed;    }    public int getDirect() {        return direct;    }    public void setDirect(int direct) {        this.direct = direct;    }    public Tank(int x, int y) {        this.x = x;        this.y = y;    }    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;    }}

上一篇 Java IO流详解
下一篇 编译hdf4和hdf5库的一个注意事项

文章素材均来源于网络,如有侵权,请联系管理员删除。

标签: Java教程Java基础Java编程技巧面试题Java面试题