当前位置: 首页 > 图灵资讯 > 技术篇> 线程-应用到坦克大战

线程-应用到坦克大战

来源:图灵教育
时间:2023-05-21 09:24:48

1.线程-应用于坦克战争04版5991.1增加功能599-601

java线程的基本知识,现在让我们实际使用它。添加以下功能:当玩家按下j键时,发射子弹.

线程-应用到坦克大战_java

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

1.1.1思路

1.发射子弹时,相当于启动线程

2.Hero有子弹对象。当我们按下J时,我们将启动发射行为(线程),使子弹不断移动,形成射击效果

3.MyPanel需要不断重绘子弹才能产生这种效果.

4.当子弹移动到面板的边界时,应销毁(销毁启动子弹的线程)

com中的代码.stulzl.Tankgame04.包中测试Tankgame04

package com.stulzl.tankgame04;import javax.swing.*;//主方法  572public class Tankgame04 extends JFrame {    ///定义我们的MyPanel    MyPanel mp = null;    public static void main(String[] args) {        Tankgame04 tankgame0 = new Tankgame04();//调用显示结果    }    /////构造设置窗口信息    public Tankgame04(){        mp = new MyPanel();///初始化面板        ///将mp放入Thread 并启动        Thread thread = new Thread(mp);        thread.start();///启动MyPanel线程        this.add(mp);///将面板添加到窗口        this.setSize(1000,750);//设置窗口大小        this.addKeyListener(mp);///让JFrame监控mp        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭程序        this.setVisible(true);//显示窗口    }}

父类Tank

package com.stulzl.tankgame04;public class Tank {//父类坦克    private int x;///坦克的横坐标    private int y;///坦克纵坐标    private int direct;//在坦克方向0上 1右 2下 3左   577    private int speed = 1;//控制坦克速度    ///在坦克上右下左移动  577    public void moveUp(){//向上移动        y-=speed;    }    public void moveRight(){//向右移动        x+=speed;    }    public void moveDown(){//向下移动        y+=speed;    }    public void moveLeft(){//左移动        x-=speed;    }    public int getSpeed() {        return speed;    }    public void setSpeed(int speed) {        this.speed = 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;    }}

我们的坦克Hero

package com.stulzl.tankgame04;public class Hero extends Tank {///我们的坦克,设置坦克坐标,打开Shot射击线程    //定义Shot对象,表示射击(线程)    Shot shot = null;    public Hero(int x, int y) {        super(x, y);    }    //射击方法  600    public void shortEnemyTank(){        //创建Shot对象,根据Hero坦克的位置 方向        switch(getDirect()){            case 0://向上                shot = new Shot(getX()+20,getY(),0);///因为射击Shot线程有参构造器,所以要传值                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线程,因为Shot实现了Runnable接口,所以可以直接调用        Thread thread = new Thread(shot);        thread.start();//启动    }}

Shot射击线程

package com.stulzl.tankgame04;//发射子弹线程  600public 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();            }            switch(direct){///根据方向值选择相应的子弹方向                case 0://向上                    y-=speed;                    break;                case 1://向右                    x+=speed;                    break;                case 2://向下                    y+=speed;                    break;                case 3://向左                    x-=speed;                    break;            }            System.out.println("子弹x= "+x+" y= "+y);            //当子弹移动到面板的边界时,应销毁(销毁启动子弹的线程)            if(!(x>=0 && x<=1000 && y>=0 && y<=750){//子弹越界窗口范围                isLive = false;///子弹死了                break;            }        }    }}

敌人坦克Enemytank

package com.stulzl.tankgame04;public class EnemyTank extends Tank{//敌人的坦克    public EnemyTank(int x, int y) {        super(x, y);    }}

MyPanel画板

package com.stulzl.tankgame04;import javax.swing.*;import java.awt.*;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.util.Vector;//坦克绘图区//为响应键盘事件,Keylistener// 不断重绘子弹需要重绘子弹 MyPanel Runnnablele实现 ,作为线程使用  601public class MyPanel extends JPanel implements KeyListener,Runnable{    //定义我们的坦克    Hero hero = null;    //定义敌人坦克,放入Vector中  578    Vector enemyTanks = new Vector<>();    int enemyTanksSize = 3;///敌人坦克数量    ////构造器设置坦克信息    public MyPanel(){        hero = new Hero(100,100);///创建并初始化自己的坦克坐标        hero.setSpeed(2);///改变坦克速度        ///初始化敌人坦克        for (int i = 0; i <enemyTanksSize; i++) {            //创建并设置敌人坦克坐标,每隔100像素放一辆坦克            EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);            ////改变敌人坦克的方向            enemyTank.setDirect(2);            ///舔敌人坦克到Vector            enemyTanks.add(enemyTank);        }    }    ///绘图方法    @Override    public void paint(Graphics g) {        super.paint(g);        g.fillRect(0,0,1000,750);//填矩形,默认黑色,这是坦克的游戏区        //画出自己的坦克,我们把方法封装成一种方法,可以调用  573        drawTank(hero.getX(), hero.getY(), g,hero.getDirect(),1);        ///画hero射击的子弹        if(hero.shot!=null && hero.shot.isLive){///如果子弹存在并存活,就画出来。如果子弹移动到边界,就不会画出来。            g.draw3DRect(hero.shot.x,hero.shot.y,1,1,false);//子弹大小 长1 高1            //this.repaint();//重绘        }        ///画敌人坦克,Vector集合遍历Vector        for (int i = 0; i <enemyTanks.size(); i++) {            //取出敌人坦克            EnemyTank enemyTank = enemyTanks.get(i);            ///画敌人坦克            drawTank(enemyTank.getX(),enemyTank.getY(),g,enemyTank.getDirect(),0);        }    }    /**     * @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;        }        //按坦克方向,绘制相应方向的坦克  577        //direct 表示方向(0: 向上 1 向右 2 向下 3 向左 )        switch(direct){            case 0://表示坦克向上                g.fill3DRect(x,y,10,60,false);//左轮////画3D矩形看起来更像 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);//左轮////画3D矩形看起来更像 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);//左轮////画3D矩形看起来更像 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);//左轮////画3D矩形看起来更像 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 keyTyped(KeyEvent e) {    }    //按键盘,触发    ///处理按下wdsa键的情况   577    @Override    public void keyPressed(KeyEvent e) {        if(e.getKeyCode()==KeyEvent.VK_W){//方向上            //改变坦克的方向            hero.setDirect(0);            hero.moveUp();        }else if(e.getKeyCode()==KeyEvent.VK_D){//方向右            hero.setDirect(1);            hero.moveRight();        }else if(e.getKeyCode()==KeyEvent.VK_S){//方向下            hero.setDirect(2);            hero.moveDown();        }else if(e.getKeyCode()==KeyEvent.VK_A)左方向{///方向            hero.setDirect(3);            hero.moveLeft();        }        //如果用户按J键,就发射子弹        if(e.getKeyCode()==KeyEvent.VK_J){            hero.shortEnemyTank();//调用射击方法        }        this.repaint();//面板重绘    }    ///松开键盘,触发    @Override    public void keyReleased(KeyEvent e) {    }    @Override    public void run() {        while(true){            try {                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }            this.repaint();        }    }}

2.坦克战争05版602-6062.1增加功能

1.让敌人的坦克发射子弹(可以有多颗子弹)

2.当我们的坦克击中敌人的坦克时,敌人的坦克就会消失,如果爆炸效果更好.

3.让敌人的坦克自由上下左右移动

4.控制我们的坦克和敌人的坦克在规定范围内移动分析--->解决

2.1.2思路

线程-应用到坦克大战_坦克大战_02

线程-应用到坦克大战_ide_03

com中的代码.stulzl.Tankgame05.包中测试Tankgame05

package com.stulzl.tankgame05;import javax.swing.*;//主方法  572public class Tankgame05 extends JFrame {    ///定义我们的MyPanel    MyPanel mp = null;    public static void main(String[] args) {        Tankgame05 tankgame0 = new Tankgame05();//调用显示结果    }    /////构造设置窗口信息    public Tankgame05(){        mp = new MyPanel();///初始化面板        ///将mp放入Thread 并启动        Thread thread = new Thread(mp);        thread.start();///启动MyPanel线程        this.add(mp);///将面板添加到窗口        this.setSize(1000,750);//设置窗口大小        this.addKeyListener(mp);///让JFrame监控mp        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭程序        this.setVisible(true);//显示窗口    }}

父类Tank

package com.stulzl.tankgame05;public class Tank {//父类坦克    private int x;///坦克的横坐标    private int y;///坦克纵坐标    private int direct;//在坦克方向0上 1右 2下 3左   577    private int speed = 1;//控制坦克速度    ///在坦克上右下左移动  577    public void moveUp(){//向上移动        y-=speed;    }    public void moveRight(){//向右移动        x+=speed;    }    public void moveDown(){//向下移动        y+=speed;    }    public void moveLeft(){//左移动        x-=speed;    }    public int getSpeed() {        return speed;    }    public void setSpeed(int speed) {        this.speed = 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;    }}

我们的坦克Hero

package com.stulzl.tankgame05;public class Hero extends Tank {///我们的坦克,设置坦克坐标,打开Shot射击线程    //定义Shot对象,表示射击(线程)    Shot shot = null;    public Hero(int x, int y) {        super(x, y);    }    //射击方法  600    public void shortEnemyTank(){        //创建Shot对象,根据Hero坦克的位置 方向        switch(getDirect()){            case 0://向上                shot = new Shot(getX()+20,getY(),0);///因为射击Shot线程有参构造器,所以要传值                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线程,因为Shot实现了Runnable接口,所以可以直接调用        Thread thread = new Thread(shot);        thread.start();//启动    }}

敌人的坦克EnemyTank

package com.stulzl.tankgame05;import java.util.Vector;public class EnemyTank extends Tank implements Runnable{//敌人的坦克    //在敌人坦克类,使用Vector 保存多个Shot    Vector shots = new Vector<>();    boolean isLive = true;///敌人坦克存活    public EnemyTank(int x, int y) {        super(x, y);    }    @Override    public void run() {        while(true){            //继续按照坦克的方向移动   605            switch(getDirect()){                case 0://向上                    ///保持坦克朝一个方向走30步                    for(int i=0;i<30;i++){                        ///控制坦克移动范围不得超过边界,只能在边界内移动  606                        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));//Math.random() [0-1)                                              //Math.random()*4) [0-4)            //结束线程            if(isLive==false){                break;            }        }    }}

Shot射击线程

package com.stulzl.tankgame05;//发射子弹线程  600public 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();            }            switch(direct){///根据方向值选择相应的子弹方向                case 0://向上                    y-=speed;                    break;                case 1://向右                    x+=speed;                    break;                case 2://向下                    y+=speed;                    break;                case 3://向左                    x-=speed;                    break;            }            System.out.println("子弹x= "+x+" y= "+y);            //当子弹移动到面板的边界时,应销毁(销毁启动子弹的线程)            //当子弹击中敌人坦克时,也应该结束次线程            if(!(x>=0 && x<=1000 && y>=0 && y<=750 && isLive)){//子弹越界窗口的范围                isLive = false;///子弹死了                break;            }        }    }}

炸弹Bomb

package com.stulzl.tankgame05;//炸弹 604public 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;        }    }}

MyPanel画板

package com.stulzl.tankgame05;import javax.swing.*;import java.awt.*;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.util.Vector;//坦克绘图区//为响应键盘事件,Keylistener// 不断重绘子弹需要重绘子弹 MyPanel Runnnablele实现 ,作为线程使用  601public class MyPanel extends JPanel implements KeyListener,Runnable{    //定义我们的坦克    Hero hero = null;    //定义敌人坦克,放入Vector中  578    Vector enemyTanks = new Vector<>();    int enemyTanksSize = 3;///敌人坦克数量    //定义Vector,用于储存炸弹    Vector bombs = new Vector<>();    //定义三张炸弹图片来显示爆炸效果    //说明子弹击中坦克时,将Bomb对象添加到bombs中    Image image1 = null;    Image image2 = null;    Image image3 = null;    ////构造器设置坦克信息    public MyPanel(){        ///我们的坦克设置        hero = new Hero(100,100);///创建并初始化自己的坦克坐标        hero.setSpeed(2);///改变坦克速度        //遍历 敌人坦克的初始化        for (int i = 0; i <enemyTanksSize; i++) {            //创建并设置敌人坦克坐标,每隔100像素放一辆坦克            EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);//(100 * (i + 1)), 0敌人坦克坐标            ////改变敌人坦克的方向            enemyTank.setDirect(2);            ////随机启动敌人坦克            Thread thread1 = new Thread(enemyTank);            thread1.start();            ///给enemyTank 加一颗子弹   602            Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());            ///添加enemytankVector 成员            enemyTank.shots.add(shot);            //启动 shot 对象            Thread thread = new Thread(shot);            thread.start();            ///将敌人坦克添加到Vector中            enemyTanks.add(enemyTank);        }        ///初始化图片对象        image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));        image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));        image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));    }    ///绘图方法    @Override    public void paint(Graphics g) {        super.paint(g);        g.fillRect(0,0,1000,750);//填矩形,默认黑色,这是坦克的游戏区        //画出自己的坦克,我们把方法封装成一种方法,可以调用  573        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);//子弹大小 长1 高1            //this.repaint();//重绘        }        //如果bombs集合中有对象,就画出   604        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();            如果bomblife为0,从bombs集合中删除            if(bomb.life==0){                bombs.remove(bomb);            }        }        ///画敌人坦克,Vector集合遍历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 所有子弹   602                for (int j = 0; j < enemyTank.shots.size(); j++) {                    //取出子弹                    Shot shot = enemyTank.shots.get(j);                    //绘制                    if (shot.isLive == true) { ///子弹存活                        g.draw3DRect(shot.x, shot.y, 1, 1, false);//子弹大小 长1 高1                    } 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;        }        //按坦克方向,绘制相应方向的坦克  577        //direct 表示方向(0: 向上 1 向右 2 向下 3 向左 )        switch(direct){            case 0://表示坦克向上                g.fill3DRect(x,y,10,60,false);//左轮////画3D矩形看起来更像 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);//左轮////画3D矩形看起来更像 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);//左轮////画3D矩形看起来更像 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);//左轮////画3D矩形看起来更像 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(“暂时没有其他操作”);        }    }    ///写一个方法来判断我们的子弹是否击中了敌人坦克  603    public  void hitTank(Shot s,EnemyTank 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);////将炸弹添加到金bombsVector集合中                }                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;                    //当我们的子弹击中敌人坦克时,将enemytank从Vector中删除  605                    enemyTanks.remove(enemyTank);                    ///创建Bomb对象,加入bombs集合                    Bomb bomb = new Bomb(enemyTank.getX(),enemyTank.getY());                    bombs.add(bomb);////将炸弹添加到金bombsVector集合中                }                break;        }    }    //三种方法    //有字符输出,触发    public void keyTyped(KeyEvent e) {    }    //按键盘,触发    ///处理按下wdsa键的情况   577    @Override    public void keyPressed(KeyEvent e) {        if(e.getKeyCode()==KeyEvent.VK_W){//方向上            //改变坦克的方向            hero.setDirect(0);            if(hero.getY()>0){///判断我们的坦克,在边界范围内移动                hero.moveUp();            }        }else if(e.getKeyCode()==KeyEvent.VK_D){//方向右            hero.setDirect(1);            if(hero.getX()+60<1000){                hero.moveRight();            }        }else if(e.getKeyCode()==KeyEvent.VK_S){//方向下            hero.setDirect(2);            if(hero.getY()+60<750){                hero.moveDown();            }        }else if(e.getKeyCode()==KeyEvent.VK_A)左方向{///方向            hero.setDirect(3);            if(hero.getX()>0){                hero.moveLeft();            }        }        //如果用户按J键,就发射子弹        if(e.getKeyCode()==KeyEvent.VK_J){            hero.shortEnemyTank();//调用射击方法        }        this.repaint();//面板重绘    }    ///松开键盘,触发    @Override    public void keyReleased(KeyEvent e) {    }    @Override    public void run() {        while(true){            try {                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }            ///判断是否击中敌人坦克  603            if(hero.shot!=null && hero.shot.isLive){//当我的子弹射出(即不是空的)并且 存活                //遍历敌人所有坦克,看看哪辆敌人坦克被击中                for (int i = 0; i < enemyTanks.size(); i++) {                    EnemyTank enemyTank = enemyTanks.get(i);///取出一辆敌人坦克                    hitTank(hero.shot,enemyTank);                }            }            this.repaint();        }    }}

3.坦克战争06版607-6093.1增加功能

1.我们坦克只有在发射子弹消亡后才能发射新子弹.=>扩展(发多颗子弹怎么办?

控制在我们的面板上,最多只有5个)

2.在敌人坦克发射的子弹消亡后,可以重新发射子弹.

3.当敌人的坦克击中我们的坦克时,我们的坦克消失了,爆炸了.

课后练习:让敌人坦克最多发射3颗(在面板上),我们的坦克最多发射3颗.

并且能产生正常的爆炸效果.

3.1.1思路:

线程-应用到坦克大战_构造器_04

线程-应用到坦克大战_构造器_05

com中的代码.stulzl.tankgame06.包中测试Tankgame06

package com.stulzl.tankgame06;import javax.swing.*;//主方法  572public class Tankgame06 extends JFrame {    ///定义我们的MyPanel    MyPanel mp = null;    public static void main(String[] args) {        Tankgame06 tankgame0 = new Tankgame06();//调用显示结果    }    /////构造设置窗口信息    public Tankgame06(){        mp = new MyPanel();///初始化面板        ///将mp放入Thread 并启动        Thread thread = new Thread(mp);        thread.start();///启动MyPanel线程        this.add(mp);///将面板添加到窗口        this.setSize(1000,750);//设置窗口大小        this.addKeyListener(mp);///让JFrame监控mp        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭程序        this.setVisible(true);//显示窗口    }}

父类Tank

package com.stulzl.tankgame06;public class Tank {//父类坦克    private int x;///坦克的横坐标    private int y;///坦克纵坐标    private int direct;//在坦克方向0上 1右 2下 3左   577    private int speed = 1;//控制坦克速度    boolean isLive = true;////我们坦克生存标志    ///在坦克上右下左移动  577    public void moveUp(){//向上移动        y-=speed;    }    public void moveRight(){//向右移动        x+=speed;    }    public void moveDown(){//向下移动        y+=speed;    }    public void moveLeft(){//左移动        x-=speed;    }    public int getSpeed() {        return speed;    }    public void setSpeed(int speed) {        this.speed = 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;    }}

我们的坦克Hero

package com.stulzl.tankgame06;import java.util.Vector;public class Hero extends Tank {///我们的坦克,设置坦克坐标,打开Shot射击线程    ///我们的坦克生存标志islive直接写在父类中,方便    ///定义Shot对象,表示射击(线程)    Shot shot = null;    ///可以发射多颗子弹  607    Vector shots = new Vector<>();    //构造器    public Hero(int x, int y) {        super(x, y);    }    //射击方法  600    public void shortEnemyTank(){        ///最多发射5颗子弹   607//        if(shots.size()==5){/////            return;//        }        //创建Shot对象,根据Hero坦克的位置 方向        switch(getDirect()){            case 0://向上                shot = new Shot(getX()+20,getY(),0);///因为射击Shot线程有参构造器,所以要传值                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的Vector集合中        shots.add(shot);        由于Shot实现了Runnable接口,///启动Shot线程所以可以直接调用        Thread thread = new Thread(shot);        thread.start();//启动    }}

敌人的坦克EnemyTank

package com.stulzl.tankgame06;import java.util.Vector;public class EnemyTank extends Tank implements Runnable{//敌人的坦克    //在敌人坦克类,使用Vector 保存多个Shot子弹    Vector shots = new Vector<>();    boolean isLive = true;///敌人坦克存活    public EnemyTank(int x, int y) {        super(x, y);    }    @Override    public void run() {        while(true){            我们在这里判断,如果shotss, size() = 在shots集合中创建子弹,并启动  608            if(isLive==true && shots.size()==0){//敌人坦克存活,敌人子弹集合Vector为空                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);////将子弹添加到shotsVector集合中                Thread thread = new Thread(s);                thread.start();//启动子弹线程            }            //继续按照坦克的方向移动   605            switch(getDirect()){                case 0://向上                    ///保持坦克朝一个方向走30步                    for(int i=0;i<30;i++){                        ///控制坦克移动范围不得超过边界,只能在边界内移动  606                        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));//Math.random() [0-1)                                              //Math.random()*4) [0-4)            //结束线程            if(isLive==false){                break;            }        }    }}

Shot射击线程

package com.stulzl.tankgame06;//发射子弹线程  600public 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();            }            switch(direct){///根据方向值选择相应的子弹方向                case 0://向上                    y-=speed;                    break;                case 1://向右                    x+=speed;                    break;                case 2://向下                    y+=speed;                    break;                case 3://向左                    x-=speed;                    break;            }            System.out.println("子弹x= "+x+" y= "+y);            //当子弹移动到面板的边界时,应销毁(销毁启动子弹的线程)            //当子弹击中敌人坦克时,也应该结束次线程            if(!(x>=0 && x<=1000 && y>=0 && y<=750 && isLive)){//子弹越界窗口的范围                isLive = false;///子弹死了                break;            }        }    }}

炸弹Bomb

package com.stulzl.tankgame06;//炸弹 604public 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;        }    }}

MyPanel画板

package com.stulzl.tankgame06;import javax.swing.*;import java.awt.*;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.util.Vector;//坦克绘图区//为响应键盘事件,Keylistener// 不断重绘子弹需要重绘子弹 MyPanel Runnnablele实现 ,作为线程使用  601public class MyPanel extends JPanel implements KeyListener,Runnable{    //定义我们的坦克    Hero hero = null;    //定义敌人坦克,放入Vector中  578    Vector enemyTanks = new Vector<>();    int enemyTanksSize = 3;///敌人坦克数量    //定义Vector,用于储存炸弹    Vector bombs = new Vector<>();    //定义三张炸弹图片来显示爆炸效果    //说明子弹击中坦克时,将Bomb对象添加到bombs中    Image image1 = null;    Image image2 = null;    Image image3 = null;    ////构造器设置坦克信息    public MyPanel(){        ///我们的坦克设置        hero = new Hero(500, 100);///创建并初始化自己的坦克坐标        hero.setSpeed(2);///改变坦克速度        //遍历 敌人坦克的初始化        for (int i = 0; i <enemyTanksSize; i++) {            //创建并设置敌人坦克坐标,每隔100像素放一辆坦克            EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);//(100 * (i + 1)), 0敌人坦克坐标            ////改变敌人坦克的方向            enemyTank.setDirect(2);            ////随机启动敌人坦克            Thread thread1 = new Thread(enemyTank);            thread1.start();            ///给enemyTank 添加子弹shotot   602            Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());            ///添加enemytankVector 成员            enemyTank.shots.add(shot);            //启动 shot 子弹对象            Thread thread = new Thread(shot);            thread.start();            ///将敌人坦克添加到Vector中            enemyTanks.add(enemyTank);        }        ///初始化图片对象        image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));        image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));        image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));    }    ///绘图方法    @Override    public void paint(Graphics g) {        super.paint(g);        g.fillRect(0,0,1000,750);//填矩形,默认黑色,这是坦克的游戏区        //画出自己的坦克,我们把方法包装成一种方法,调用即可  573        if(hero !=null && hero.isLive==true) {///我们的坦克不是空的,而是存活的            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);//子弹大小 长1 高1//            //this.repaint();////////重绘///        }        ////画hero子弹集Vector  607        ////遍历绘制        for (int i = 0; i < hero.shots.size(); i++) {            Shot shot = hero.shots.get(i);//取出一颗子弹            //如果子弹存在并存活,就画出来。如果子弹移动到边界,它将不会被绘制。            if(shot!=null && shot.isLive==true) {                g.draw3DRect(shot.x,shot.y, 1, 1, false);//子弹大小 长1 高1            }else{///如果子弹是空的或已经被销毁,从shots的Vector集合中删除                hero.shots.remove(shot);            }        }        //如果bombs集合中有对象,就画出   604        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();            如果bomblife为0,从bombs集合中删除            if(bomb.life==0){                bombs.remove(bomb);            }        }        ///画敌人坦克,Vector集合遍历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 所有子弹   602                for (int j = 0; j < enemyTank.shots.size(); j++) {                    //取出敌人子弹                    Shot shot = enemyTank.shots.get(j);                    //绘制                    if (shot.isLive == true) { ///子弹存活                        g.draw3DRect(shot.x, shot.y, 1, 1, false);//子弹大小 长1 高1                    } 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;        }        //按坦克方向,绘制相应方向的坦克  577        //direct 表示方向(0: 向上 1 向右 2 向下 3 向左 )        switch(direct){            case 0://表示坦克向上                g.fill3DRect(x,y,10,60,false);//左轮////画3D矩形看起来更像 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);//左轮////画3D矩形看起来更像 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);//左轮////画3D矩形看起来更像 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);//左轮////画3D矩形看起来更像 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(“暂时没有其他操作”);        }    }    ///写一个判断子弹击中坦克的方法 方法 603    public  void hitTank(Shot s, Tank tank){//Tank 这里直接用父类Tank接收tank涉及多态,更方便        ///判断子弹s是否击中坦克        switch(tank.getDirect()){            case 0://向上            case 2://向下//如果子弹在坦克区,说明击中坦克                if(s.x>tank.getX() && s.x<tank.getX()+40                && s.y>tank.getY() && s.y<tank.getY()+60){                    s.isLive = false;                    tank.isLive = false;                    //当我们的子弹击中敌人坦克时,将enemytank从Vector中删除                    enemyTanks.remove(tank);                    ///创建bomb对象,加入bombs集合                    Bomb bomb = new Bomb(tank.getX(),tank.getY());                    bombs.add(bomb);///将炸弹添加到bombs的Vector集合中                }                break;            case 1:            case 3:                if(s.x>tank.getX() && s.x<tank.getX()+60                        && s.y>tank.getY() && s.y<tank.getY()+40){                    s.isLive = false;                    tank.isLive = false;                    //当我们的子弹击中敌人坦克时,将enemytank从Vector中删除  605                    enemyTanks.remove(tank);                    ///创建Bomb对象,加入bombs集合                    Bomb bomb = new Bomb(tank.getX(),tank.getY());                    bombs.add(bomb);////将炸弹添加到金bombsVector集合中                }                break;        }    }    //三种方法    //有字符输出,触发    public void keyTyped(KeyEvent e) {    }    //按键盘,触发    ///处理按下wdsa键的情况   577    @Override    public void keyPressed(KeyEvent e) {        if(e.getKeyCode()==KeyEvent.VK_W){//方向上            //改变坦克的方向            hero.setDirect(0);            if(hero.getY()>0){///判断我们的坦克,在边界范围内移动  606                hero.moveUp();            }        }else if(e.getKeyCode()==KeyEvent.VK_D){//方向右            hero.setDirect(1);            if(hero.getX()+60<1000){                hero.moveRight();            }        }else if(e.getKeyCode()==KeyEvent.VK_S){//方向下            hero.setDirect(2);            if(hero.getY()+60<750){                hero.moveDown();            }        }else if(e.getKeyCode()==KeyEvent.VK_A)左方向{///方向            hero.setDirect(3);            if(hero.getX()>0){                hero.moveLeft();            }        }        //如果用户按J键,就发射子弹        if(e.getKeyCode()==KeyEvent.VK_J){            //如果子弹是空的或者子弹被摧毁了,子弹就会被发射 ,一颗子弹只能发射一次 607//            if(hero.shot==null || hero.shot.isLive==false){//                hero.shortEnemyTank();///调用射击方法///            }            ///发射多颗子弹            if(hero.shots.size()<5){///最多发射5颗子弹  607                hero.shortEnemyTank();//调用射击方法            }        }        this.repaint();//面板重绘    }    ///松开键盘,触发    @Override    public void keyReleased(KeyEvent e) {    }    //当我们的坦克能够连续发射子弹时,判断每颗子弹是否击中敌人坦克  607    public void hitEnemyTank(){        for (int j = 0; j < hero.shots.size(); j++) {//遍历子弹集合            Shot shot = hero.shots.get(j);///取出集合子弹            if(shot!=null && shot.isLive){//当我们的子弹射出(即不是空的)并且 存活                //遍历敌人所有坦克的集合,看看哪辆敌人坦克被击中                for (int i = 0; i < enemyTanks.size(); i++) {                    EnemyTank enemyTank = enemyTanks.get(i);///取出一辆敌人坦克                    hitTank(shot,enemyTank);///调用判断是否击中                }            }        }    }    ///编写方法判断敌人坦克子弹是否击中我们坦克子弹  609    public void hitHero(){        ///遍历所有敌人坦克enemytanks的Vector集合        for (int i = 0; i < enemyTanks.size(); i++) {            ///取出一辆敌人坦克            EnemyTank enemyTank = enemyTanks.get(i);            ///遍历敌人坦克所有子弹shots集合Vectortor            for(int j=0;j<enemyTank.shots.size();j++){                //取出子弹                Shot shot = enemyTank.shots.get(j);                ////判断敌人坦克子弹shot是否击中我们的hero坦克                if(hero.isLive && shot.isLive){///我们的坦克存活,敌人子弹也存活                    hitTank(shot,hero);                }            }        }    }    @Override    public void run() {        while(true){            try {                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }            ///判断是否击中敌人坦克  603            //这种方法只能判断当前射出的子弹击中敌人,单颗子弹////            if(hero.shot!=null && hero.shot.isLive){//当我的子弹射出(即不是空的)并且 存活//                //遍历敌人所有坦克,看看哪个敌人坦克被击中///                for (int i = 0; i < enemyTanks.size(); i++) {//                    EnemyTank enemyTank = enemyTanks.get(i);////取出敌人坦克/////                    hitTank(hero.shot,enemyTank);//                }//            }            ///调用多颗子弹击中敌人坦克            hitEnemyTank();            ////调用敌人坦克击中我们的Hero坦克方法            hitHero();            this.repaint();        }    }}