zoukankan      html  css  js  c++  java
  • Java坦克大战(三)

    关于这个坦克大战的项目是在学习Java基础的时候,拿来练习的最近看到这些代码,感觉很亲切,就把他们都复制下来,编辑成博客。回首看去,Java基础的学习确实应该建立在找项目练习上,这样才能将学到的基础知识用到实际当中,不然你知道什么是面向对象编程,什么是线程,什么是死锁,概念都了解了一大堆,等到实际应用的时候,还是力不从心。初学者千万不要灰心,真心是敲着敲着就有感觉了。下面还是循序渐进的介绍这个项目的几个版本,注释我写的很详细,新功能添加后部分代码有改动,如果感兴趣,可以看前几篇博客。

    坦克大战(1.4版本)

    1.MyTankGame类:

    /*
     * 删掉很多之前的注释
     * 功能:线程(坦克打子弹)进过分析:子弹是个类
     */
    package com.fanghua3;
    
    import java.awt.*;
    import java.awt.event.KeyEvent;
    import java.util.Vector;
    
    import javax.swing.*;
    
    public class MyTankGame1_4 extends JFrame {
    
        Mypanel1_2 mp = null;
    
        public static void main(String[] args) {
            new MyTankGame1_4();
        }
    
        // 构造函数
        public MyTankGame1_4() {
            mp = new Mypanel1_2();
    
            // 启动mp线程
            Thread t = new Thread(mp);
            t.start();
    
            this.add(mp);
            // 注册监听
            this.addKeyListener(mp);
    
            this.setSize(400, 300);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setVisible(true);
    
        }
    }
    
    // 我的面板,拓宽思路:Panel本身就是一个刷新体
    class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener, Runnable {
    
        // 定义我的坦克
        Hero1_2 hero = null;
        // 定义敌人的坦克(不止一辆,线程安全,集合)
        Vector<EnemyTank> ets = new Vector<EnemyTank>();
        int enSize = 3;// 敌人坦克保持三个
    
        // 构造函数
        public Mypanel1_2() {
            hero = new Hero1_2(10, 10);
            for (int i = 0; i < enSize; i++) {
    
                // 创建一辆敌人的坦克
                EnemyTank et = new EnemyTank((i + 1) * 50, 0);
                et.setColor(0);
                // 坦克默认反向是0(向上),这里改一下
                et.setDirect(2);
                // 加入
                ets.add(et);
    
            }
        }
    
        // 重写paint函数
        public void paint(Graphics g) {
            // 一定要调用
            super.paint(g);
            g.fillRect(0, 0, 400, 300);
            // 画出自己的坦克(将方向填进去)
            this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1);
    
            // 画出子弹(后添加 hero.s.isLive==true,节省资源)
            if (hero.s != null && hero.s.isLive == true) {
                g.draw3DRect(hero.s.x, hero.s.y, 1, 1, false);
            }
    
            // 画出敌人的坦克
            for (int i = 0; i < enSize; i++) {
                this.drawTank(ets.get(i).getX(), ets.get(i).getY(), g, ets.get(i)
                        .getDirect(), 0);
    
            }
    
        }
    
        // 画出坦克的函数
        public void drawTank(int x, int y, Graphics g, int direct, int type) {
            // 坦克类型
            switch (type) {
            case 0:
                g.setColor(Color.green);
                break;
            case 1:
                g.setColor(Color.yellow);
                break;
            }
            // 方向设置
            switch (direct) {
            // 向上
            case 0:
                g.fill3DRect(x, y, 5, 30, false);
                g.fill3DRect(x + 15, y, 5, 30, false);
                g.fill3DRect(x + 5, y + 5, 10, 20, false);
                g.fillOval(x + 5, y + 10, 10, 10);
                g.drawLine(x + 10, y + 15, x + 10, y);
                break;
            // 向右
            case 1:
                g.fill3DRect(x, y, 30, 5, false);
                g.fill3DRect(x, y + 15, 30, 5, false);
                g.fill3DRect(x + 5, y + 5, 20, 10, false);
                g.fillOval(x + 10, y + 5, 10, 10);
                g.drawLine(x + 15, y + 10, x + 30, y + 10);
                break;
            // 向下
            case 2:
                g.fill3DRect(x, y, 5, 30, false);
                g.fill3DRect(x + 15, y, 5, 30, false);
                g.fill3DRect(x + 5, y + 5, 10, 20, false);
                g.fillOval(x + 5, y + 10, 10, 10);
                g.drawLine(x + 10, y + 15, x + 10, y + 30);
                break;
            // 向左
            case 3:
                g.fill3DRect(x, y, 30, 5, false);
                g.fill3DRect(x, y + 15, 30, 5, false);
                g.fill3DRect(x + 5, y + 5, 20, 10, false);
                g.fillOval(x + 10, y + 5, 10, 10);
                g.drawLine(x + 15, y + 10, x, y + 10);
                break;
            }
    
        }
    
        @Override
        public void keyTyped(KeyEvent e) {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void keyPressed(KeyEvent e) {
            // TODO Auto-generated method stub
            // 已更正为顺时针
            if (e.getKeyCode() == KeyEvent.VK_UP 
                    || e.getKeyCode() == KeyEvent.VK_W) {
                this.hero.moveUp();
                this.hero.setDirect(0);
            } else if (e.getKeyCode() == KeyEvent.VK_RIGHT
                    || e.getKeyCode() == KeyEvent.VK_D) {
                this.hero.setDirect(1);
                this.hero.moveRight();
            } else if (e.getKeyCode() == KeyEvent.VK_DOWN
                    || e.getKeyCode() == KeyEvent.VK_S) {
                this.hero.moveDown();
                this.hero.setDirect(2);
            } else if (e.getKeyCode() == KeyEvent.VK_LEFT
                    || e.getKeyCode() == KeyEvent.VK_A) {
                this.hero.moveLeft();
                this.hero.setDirect(3);
            } else if (e.getKeyCode() == KeyEvent.VK_J) {
                // 将J键设置为发出子弹
                this.hero.shotEnemy();
                this.repaint();
            }
    
        }
    
        @Override
        public void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void run() {
            // TODO Auto-generated method stub
            // 每隔100毫秒去重绘
            while (true) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
    
                // 重绘
                this.repaint();
            }
        }
    }

    2.Menbers类:

    package com.fanghua3;
    //子弹类
    class Shot implements Runnable{
        int x;
        int y;
        int direct;
        //设置子弹的消亡(默认活着的)
        boolean isLive=true;
        //speed要给个初始值1,之前给0,按J键,子弹没有动
        int speed=1;
        public Shot(int x, int y,int direct) {
            super();
            this.x = x;
            this.y= y;
            this.direct=direct;
            
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            
            while(true){
                //设置子弹休息50毫秒
                
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    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>400||y<0||y>300){
                    this.isLive=false;
                    break;
                }
            }
        }
    }
    
    //坦克类
    class Tank1_2 {
        
        int x = 0;
        int y = 0;
    
        // 坦克方向:0表示上,1表示右,2表示下,3表示左
        int direct = 0;
        int speed = 1;
        //坦克的颜色
        int color;
    
        public int getColor() {
            return color;
        }
    
        public void setColor(int color) {
            this.color = color;
        }
    
        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 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 Tank1_2(int x, int y) {
            this.x = x;
            this.y = y;
    
        }
    
    }
    //敌人的坦克
    class EnemyTank extends Tank1_2{
        
        public EnemyTank(int x, int y) {
            super(x, y);
            // TODO Auto-generated constructor stub
        }
    }
    
    //我的坦克
    class Hero1_2 extends Tank1_2 {
        //子弹
        Shot s=null;
        public Hero1_2(int x, int y) {
            super(x, y);
        }
        //坦克开火
        public void shotEnemy(){
            
            switch(this.direct){
            case 0:
                s=new Shot(x+10,y,0);
                
                break;
            
            case 1:
                s=new Shot(x+30,y+10,1);
                break;
            
            case 2:
                s=new Shot(x+10,y+30,2);
                break;
            
            case 3:
                s=new Shot(x,y+10,3);
                break;
            }
            //启动子弹线程
            Thread t=new Thread(s);
            t.start();
        }
    
        public void moveUp() {
            y -= speed;
        }
        public void moveRight() {
            x += speed;
        }
        public void moveDown() {
            y += speed;
        }
        public void moveLeft() {
            x -= speed;
        }
    }

    坦克大战(1.5版本)

    1.MyTankGame类:

    /*
     * 删掉很多之前的注释
     * 功能:子弹连发,(线程)最多5颗子弹
     * 敌人坦克消失
     */
    package com.fanghua4;
    
    import java.awt.*;
    import java.awt.event.KeyEvent;
    import java.util.Vector;
    
    import javax.swing.*;
    
    public class MyTankGame1_5 extends JFrame {
    
        Mypanel1_2 mp = null;
    
        public static void main(String[] args) {
            new MyTankGame1_5();
        }
    
        // 构造函数
        public MyTankGame1_5() {
            mp = new Mypanel1_2();
    
            // 启动mp线程
            Thread t = new Thread(mp);
            t.start();
    
            this.add(mp);
            // 注册监听
            this.addKeyListener(mp);
    
            this.setSize(400, 300);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setVisible(true);
    
        }
    }
    
    // 我的面板,拓宽思路:Panel本身就是一个刷新体
    class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener, Runnable {
    
        // 定义我的坦克
        Hero1_2 hero = null;
        // 定义敌人的坦克(不止一辆,线程安全,集合)
        Vector<EnemyTank> ets = new Vector<EnemyTank>();
        int enSize = 3;// 敌人坦克保持三个
    
        // 构造函数
        public Mypanel1_2() {
            hero = new Hero1_2(10, 10);
            for (int i = 0; i < enSize; i++) {
    
                // 创建一辆敌人的坦克
                EnemyTank et = new EnemyTank((i + 1) * 50, 0);
                et.setColor(0);
                // 坦克默认反向是0(向上),这里改一下
                et.setDirect(2);
                // 加入
                ets.add(et);
    
            }
        }
    
        // 重写paint函数
        public void paint(Graphics g) {
            // 一定要调用
            super.paint(g);
            g.fillRect(0, 0, 400, 300);
            // 画出自己的坦克(将方向填进去)
            this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1);
    
            // 从ss中取出每一颗子弹,并画出
            for (int i = 0; i < hero.ss.size(); i++) {
    
                Shot myShot = hero.ss.get(i);
                if (myShot != null && myShot.isLive == true) {
                    g.draw3DRect(myShot.x, myShot.y, 1, 1, false);
    
                    /*
                     * 画出一颗子弹(后添加 hero.s.isLive==true,节省资源) if (hero.s != null
                     * &&hero.s.isLive == true) { g.draw3DRect(hero.s.x, hero.s.y,
                     * 1, 1,false); }
                     */
                }
                if (myShot.isLive == false) {
                    // 从ss(向量)中删除该子弹
                    // hero.ss.remove(i);会报异常。
                    hero.ss.remove(myShot);
                }
            }
    
            // 画出敌人的坦克
            for (int i = 0; i < enSize; i++) {
                EnemyTank et = ets.get(i);
                if (et.isLive) {
                    this.drawTank(et.getX(), et.getY(), g, et.getDirect(), 0);
                }
            }
        }
    
        // 写一个函数 专门判断是否击中敌人坦克
        public void hitTank(Shot s, EnemyTank et) {
            // 判断该坦克的方向
            switch (et.direct) {
            // 敌人坦克的方向是0或2,一致
            case 0:
            case 2:
                if (s.x > et.x && s.x < et.x + 20 && s.y > et.y && s.y < et.y + 30) {
                    // 击中(子弹死亡,敌人四万)
                    s.isLive = false;
                    et.isLive = false;
                }
    break;
    case 1: case 3: if (s.x > et.x && s.x < et.x + 30 && s.y > et.y && s.y < et.y + 20) { // 击中(子弹死亡,敌人四万) s.isLive = false; et.isLive = false; }
    break; } }
    // 画出坦克的函数 public void drawTank(int x, int y, Graphics g, int direct, int type) { // 坦克类型 switch (type) { case 0: g.setColor(Color.green); break; case 1: g.setColor(Color.yellow); break; } // 方向设置 switch (direct) { // 向上 case 0: g.fill3DRect(x, y, 5, 30, false); g.fill3DRect(x + 15, y, 5, 30, false); g.fill3DRect(x + 5, y + 5, 10, 20, false); g.fillOval(x + 5, y + 10, 10, 10); g.drawLine(x + 10, y + 15, x + 10, y); break; // 向右 case 1: g.fill3DRect(x, y, 30, 5, false); g.fill3DRect(x, y + 15, 30, 5, false); g.fill3DRect(x + 5, y + 5, 20, 10, false); g.fillOval(x + 10, y + 5, 10, 10); g.drawLine(x + 15, y + 10, x + 30, y + 10); break; // 向下 case 2: g.fill3DRect(x, y, 5, 30, false); g.fill3DRect(x + 15, y, 5, 30, false); g.fill3DRect(x + 5, y + 5, 10, 20, false); g.fillOval(x + 5, y + 10, 10, 10); g.drawLine(x + 10, y + 15, x + 10, y + 30); break; // 向左 case 3: g.fill3DRect(x, y, 30, 5, false); g.fill3DRect(x, y + 15, 30, 5, false); g.fill3DRect(x + 5, y + 5, 20, 10, false); g.fillOval(x + 10, y + 5, 10, 10); g.drawLine(x + 15, y + 10, x, y + 10); break; } } @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyPressed(KeyEvent e) { // TODO Auto-generated method stub // 已更正为顺时针 if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) { this.hero.moveUp(); this.hero.setDirect(0); } else if (e.getKeyCode() == KeyEvent.VK_RIGHT || e.getKeyCode() == KeyEvent.VK_D) { this.hero.setDirect(1); this.hero.moveRight(); } else if (e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode() == KeyEvent.VK_S) { this.hero.moveDown(); this.hero.setDirect(2); } else if (e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_A) { this.hero.moveLeft(); this.hero.setDirect(3); } else if (e.getKeyCode() == KeyEvent.VK_J) { // 将J键设置为发出子弹 // 子弹连发,J被按几下,发几颗:this.hero.shotEnemy(); // this.repaint();在run函数里,不应该设计在这里 if (this.hero.ss.size() <= 4) { this.hero.shotEnemy(); } } } @Override public void run() { // TODO Auto-generated method stub // 每隔100毫秒去重绘 while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 判断是否击中(写在这里,虽然在每次重绘的时候都要调用,但是没办法) // 每一颗子弹都要和每个坦克进行匹配 for (int i = 0; i < hero.ss.size(); i++) { // 取出子弹 Shot myShot = hero.ss.get(i); // 判断子弹是否有效 if (myShot.isLive) { // 取出每个坦克,与它判断 for (int j = 0; j < ets.size(); j++) { // 取出坦克 EnemyTank et = ets.get(j); if (et.isLive) { this.hitTank(myShot, et); } } } } // 重绘 this.repaint(); } } @Override public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub } }

    2.Menbers类:

    package com.fanghua4;
    
    import java.util.Vector;
    
    //子弹类
    class Shot implements Runnable {
        int x;
        int y;
        int direct;
        // 设置子弹的消亡(默认活着的)
        boolean isLive = true;
        // speed要给个初始值1,之前给0,按J键,子弹没有动
        int speed = 1;
    
        public Shot(int x, int y, int direct) {
            super();
            this.x = x;
            this.y = y;
            this.direct = direct;
    
        }
    
        @Override
        public void run() {
            // TODO Auto-generated method stub
    
            while (true) {
                // 设置子弹休息50毫秒
    
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    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 > 400 || y < 0 || y > 300) {
                    this.isLive = false;
                    break;
                }
            }
        }
    }
    
    // 坦克类
    class Tank1_2 {
    
        int x = 0;
        int y = 0;
    
        // 坦克方向:0表示上,1表示右,2表示下,3表示左
        int direct = 0;
        int speed = 1;
        // 坦克的颜色
        int color;
    
        public int getColor() {
            return color;
        }
    
        public void setColor(int color) {
            this.color = color;
        }
    
        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 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 Tank1_2(int x, int y) {
            this.x = x;
            this.y = y;
    
        }
    
    }
    
    // 敌人的坦克
    class EnemyTank extends Tank1_2 {
    
        boolean isLive = true;
    
    
        public EnemyTank(int x, int y) {
            super(x, y);
            // TODO Auto-generated constructor stub
        }
    }
    
    // 我的坦克
    class Hero1_2 extends Tank1_2 {
        // 多个子弹,用向量创建
        Vector<Shot> ss = new Vector<Shot>();
        // 子弹
        Shot s = null;
    
        public Hero1_2(int x, int y) {
            super(x, y);
        }
    
        // 坦克开火
        public void shotEnemy() {
    
            switch (this.direct) {
            case 0:
                s = new Shot(x + 10, y, 0);
                // 把子弹加入向量
                ss.add(s);
                break;
    
            case 1:
                s = new Shot(x + 30, y + 10, 1);
                // 把子弹加入向量
                ss.add(s);
                break;
    
            case 2:
                s = new Shot(x + 10, y + 30, 2);
                // 把子弹加入向量
                ss.add(s);
                break;
    
            case 3:
                s = new Shot(x, y + 10, 3);
                // 把子弹加入向量
                ss.add(s);
                break;
            }
            // 启动子弹线程
            Thread t = new Thread(s);
            t.start();
        }
    
        public void moveUp() {
            y -= speed;
        }
    
        public void moveRight() {
            x += speed;
        }
    
        public void moveDown() {
            y += speed;
        }
    
        public void moveLeft() {
            x -= speed;
        }
    }

    坦克大战(1.6版本)

    1.MyTankGame类

    /*
     * 功能:
     * 1.实现爆炸效果
     * 2.敌人坦克可移动,可以连发子弹
     * 3.敌人击中我的坦克,我爆炸
     * 4.击中第一个坦克爆炸的效果不明显
     */
    package com.fanghua5;
    
    import java.awt.*;
    import java.awt.event.KeyEvent;
    import java.util.Vector;
    import javax.swing.*;
    
    public class MyTankGame1_6 extends JFrame {
    
        Mypanel1_2 mp = null;
    
        public static void main(String[] args) {
            new MyTankGame1_6();
        }
    
        // 构造函数
        public MyTankGame1_6() {
            mp = new Mypanel1_2();
    
            // 启动mp线程
            Thread t = new Thread(mp);
            t.start();
    
            this.add(mp);
            // 注册监听
            this.addKeyListener(mp);
    
            this.setSize(400, 300);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setVisible(true);
    
        }
    }
    
    // 我的面板,拓宽思路:Panel本身就是一个刷新体
    class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener, Runnable {
    
        // 定义我的坦克
        Hero1_2 hero = null;
        // 定义敌人的坦克(不止一辆,线程安全,集合)
        Vector<EnemyTank> ets = new Vector<EnemyTank>();
    
        // 定义炸弹集合
        Vector<Bomb> bombs = new Vector<Bomb>();
    
        int enSize = 4;// 敌人坦克保持四个
    
        // 定义三张图片(三张图片才能组成一颗炸弹)
        Image image1 = null;
        Image image2 = null;
        Image image3 = null;
    
        // 构造函数
        public Mypanel1_2() {
            hero = new Hero1_2(10, 10);
            for (int i = 0; i < enSize; i++) {
    
                // 创建一辆敌人的坦克
                EnemyTank et = new EnemyTank((i + 1) * 50, 0);
                et.setColor(0);
                // 坦克默认反向是0(向上),这里改一下
                et.setDirect(2);
                // 加入
                ets.add(et);
    
                // 启动敌人的坦克
                Thread t = new Thread(et);
                t.start();
                // 给敌人坦克添加一颗子弹
                Shot s = new Shot(et.x + 10, et.y + 30, 2);
                // 加入给敌人的坦克
                et.ss.add(s);
    
                Thread t2 = new Thread(s);
                t2.start();
                ets.add(et);
    
            }
            // 初始话图片,这样做击中第一个坦克,爆炸的效果不明显。下面优化
            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"));
        
    //        引包:import javax.imageio.ImagesssIO;
    //        try {
    //            image1=ImageIO.read(new File("/bomsb_1.gif"));
    //            image2=ImageIO.read(new File("/bomb_2.gif"));
    //            image3=ImageIO.read(new File("/bomb_3.gif"));
    //        } catch (IOException e) {
    //            // TODO Auto-generated catch block
    //            e.printStackTrace();
    //        }
        }
    
        // 重写paint函数
        public void paint(Graphics g) {
            // 一定要调用
            super.paint(g);
            g.fillRect(0, 0, 400, 350);
            // 画出自己的坦克(将方向填进去)
            if (hero.isLive == true) {
                this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1);
            }
            // 从ss中取出每一颗子弹,并画出
            for (int i = 0; i < hero.ss.size(); i++) {
    
                Shot myShot = hero.ss.get(i);
                if (myShot != null && myShot.isLive == true) {
                    g.draw3DRect(myShot.x, myShot.y, 1, 1, false);
    
                    /*
                     * 画出一颗子弹(后添加 hero.s.isLive==true,节省资源) if (hero.s != null
                     * &&hero.s.isLive == true) { g.draw3DRect(hero.s.x, hero.s.y,
                     * 1, 1,false); }
                     */
                }
                if (myShot.isLive == false) {
                    // 从ss(向量)中删除该子弹
                    // hero.ss.remove(i);会报异常。
                    hero.ss.remove(myShot);
                }
            }
    
            // 画出炸弹
            for (int i = 0; i < bombs.size(); i++) {
                // 取出炸弹
                Bomb b = bombs.get(i);
                if (b.life > 6) {
                    g.drawImage(image1, b.x, b.y, 30, 30, this);
                } else if (b.life > 4) {
                    g.drawImage(image2, b.x, b.y, 30, 30, this);
                } else {
                    g.drawImage(image3, b.x, b.y, 30, 30, this);
                }
                // 让b的生命值减小
                b.lifeDown();
                // 如果炸弹生命值为零,就把该炸弹从bombs向量中去掉
                if (b.life == 0) {
                    bombs.remove(b);
                }
    
            }
    
            // 画出敌人的坦克
            for (int i = 0; i < ets.size(); i++) {
                EnemyTank et = ets.get(i);
                if (et.isLive) {
                    this.drawTank(et.getX(), et.getY(), g, et.getDirect(), 0);
    
                    // 画出敌人的子弹
                    for (int j = 0; j < et.ss.size(); j++) {
                        // 取出子弹
                        Shot enemyShot = et.ss.get(j);
                        if (enemyShot != null && enemyShot.isLive == true) {
                            g.draw3DRect(enemyShot.x, enemyShot.y, 1, 1, false);
                        }
                        if (enemyShot.isLive == false) {
                            // 如果敌人的坦克死亡了,就从Vector中删除
                            et.ss.remove(enemyShot);
                        }
                    }
                }
            }
        }
    
        // 判断敌人的子弹是否击中我
        public void hitMe() {
            // 取出每一个敌人的坦克
            for (int i = 0; i < this.ets.size(); i++) {
                // 取出坦克
                EnemyTank et = ets.get(i);
                // 取出每一颗子弹
                for (int j = 0; j < et.ss.size(); j++) {
                    // 取出子弹
                    Shot enemyShot = et.ss.get(j);
    
                    this.hitTank(enemyShot, hero);
                }
    
            }
        }
    
        // 判断我是否击中敌人的坦克
        public void hitEnemyTank() {
            // 判断是否被击中敌人的坦克
            for (int i = 0; i < hero.ss.size(); i++) {
                // 取出我的子弹与敌人坦克匹配
                Shot myShot = hero.ss.get(i);
                // 判断子弹是否有效
                if (myShot.isLive) {
                    // 取出每个坦克,与它判断
                    for (int j = 0; j < ets.size(); j++) {
                        // 取出坦克
                        EnemyTank et = ets.get(j);
                        if (et.isLive) {
                            this.hitTank(myShot, et);
                        }
                    }
                }
            }
        }
    
        // 写一个函数 专门判断是否击中敌人坦克(原来第二参数: EnemyTank et)
        public void hitTank(Shot s, Tank1_2 et) {
            // 判断该坦克的方向
            switch (et.direct) {
            // 敌人坦克的方向是0或2,一致
            case 0:
            case 2:
                if (s.x >= et.x && s.x <= et.x + 20 && s.y >= et.y
                        && s.y <= et.y + 30) {
                    // 击中(子弹死亡,敌人死亡)
                    s.isLive = false;
                    et.isLive = false;
    
                    // 创建一颗炸弹,放入Vector中
                    Bomb b = new Bomb(et.x, et.y);
                    // 放入
                    bombs.add(b);
                }
    break;
    case 1: case 3: if (s.x >= et.x && s.x <= et.x + 30 && s.y >= et.y && s.y <= et.y + 20) { // 击中(子弹死亡,敌人死亡) s.isLive = false; et.isLive = false; // 创建一颗炸弹,放入Vector中 Bomb b = new Bomb(et.x, et.y); // 放入 bombs.add(b); }
    break; } }
    // 画出坦克的函数 public void drawTank(int x, int y, Graphics g, int direct, int type) { // 坦克类型 switch (type) { case 0: g.setColor(Color.green); break; case 1: g.setColor(Color.yellow); break; } // 方向设置 switch (direct) { // 向上 case 0: g.fill3DRect(x, y, 5, 30, false); g.fill3DRect(x + 15, y, 5, 30, false); g.fill3DRect(x + 5, y + 5, 10, 20, false); g.fillOval(x + 5, y + 10, 10, 10); g.drawLine(x + 10, y + 15, x + 10, y); break; // 向右 case 1: g.fill3DRect(x, y, 30, 5, false); g.fill3DRect(x, y + 15, 30, 5, false); g.fill3DRect(x + 5, y + 5, 20, 10, false); g.fillOval(x + 10, y + 5, 10, 10); g.drawLine(x + 15, y + 10, x + 30, y + 10); break; // 向下 case 2: g.fill3DRect(x, y, 5, 30, false); g.fill3DRect(x + 15, y, 5, 30, false); g.fill3DRect(x + 5, y + 5, 10, 20, false); g.fillOval(x + 5, y + 10, 10, 10); g.drawLine(x + 10, y + 15, x + 10, y + 30); break; // 向左 case 3: g.fill3DRect(x, y, 30, 5, false); g.fill3DRect(x, y + 15, 30, 5, false); g.fill3DRect(x + 5, y + 5, 20, 10, false); g.fillOval(x + 10, y + 5, 10, 10); g.drawLine(x + 15, y + 10, x, y + 10); break; } } @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyPressed(KeyEvent e) { // TODO Auto-generated method stub // 已更正为顺时针 if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) { this.hero.moveUp(); this.hero.setDirect(0); } else if (e.getKeyCode() == KeyEvent.VK_RIGHT || e.getKeyCode() == KeyEvent.VK_D) { this.hero.setDirect(1); this.hero.moveRight(); } else if (e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode() == KeyEvent.VK_S) { this.hero.moveDown(); this.hero.setDirect(2); } else if (e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_A) { this.hero.moveLeft(); this.hero.setDirect(3); } else if (e.getKeyCode() == KeyEvent.VK_J) { // 将J键设置为发出子弹 // 子弹连发,J被按几下,发几颗:this.hero.shotEnemy(); // this.repaint();在run函数里,不应该设计在这里 if (this.hero.ss.size() <= 4) { this.hero.shotEnemy(); } } } @Override public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub } @Override public void run() { // TODO Auto-generated method stub // 每隔100毫秒去重绘 while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 判断是否击中(写在这里,虽然在每次重绘的时候都要调用,但是没办法) // 每一颗子弹都要和每个坦克进行匹配 for (int i = 0; i < hero.ss.size(); i++) { // 取出子弹 Shot myShot = hero.ss.get(i); // 判断子弹是否有效 if (myShot.isLive) { // 取出每个坦克,与它判断 for (int j = 0; j < ets.size(); j++) { // 取出坦克 EnemyTank et = ets.get(j); if (et.isLive) { this.hitTank(myShot, et); } } } } this.hitEnemyTank(); this.hitMe(); // 重绘 this.repaint(); } } }

    2.Menbers类:

    package com.fanghua5;
    
    import java.util.Vector;
    
    //炸弹类(没必要定义为线程,因为它不会移动,没有坐标改变)
    class Bomb {
        // 定义炸弹的坐标
        int x, y;
        int life = 9;// 炸弹的生命(三张图片)
        // 可以看出isLive很有用,它可以决定类(或者对象)要不要展现在面板上
        boolean isLive = true;
    
        public Bomb(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        // 炸弹减少生命值
        public void lifeDown() {
            if (life > 0) {
                life--;
            } else {
                this.isLive = false;
            }
        }
    
    }
    
    // 子弹类
    class Shot implements Runnable {
        int x;
        int y;
        int direct;
        // 设置子弹的消亡(默认活着的)
        boolean isLive = true;
        // speed要给个初始值1,之前给0,按J键,子弹没有动
        int speed = 1;
    
        public Shot(int x, int y, int direct) {
            super();
            this.x = x;
            this.y = y;
            this.direct = direct;
    
        }
    
        @Override
        public void run() {
            // TODO Auto-generated method stub
    
            while (true) {
                // 设置子弹休息50毫秒
    
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    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 > 400 || y < 0 || y > 300) {
                    this.isLive = false;
                    break;
                }
            }
        }
    }
    
    // 坦克类
    class Tank1_2 {
    
        int x = 0;
        int y = 0;
        boolean isLive=true;
    
        // 坦克方向:0表示上,1表示右,2表示下,3表示左
        int direct = 0;
        int speed = 1;
        // 坦克的颜色
        int color;
    
        public int getColor() {
            return color;
        }
    
        public void setColor(int color) {
            this.color = color;
        }
    
        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 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 Tank1_2(int x, int y) {
            this.x = x;
            this.y = y;
    
        }
    
    }
    
    // 敌人的坦克(做成线程,会移动)
    class EnemyTank extends Tank1_2 implements Runnable {
    
        //从父类继承了,去掉:boolean isLive = true;
        int times = 0;// 让time累积
        // 定义向量,可以存放敌人的子弹
        Vector<Shot> ss = new Vector<Shot>();
    
        // 敌人添加子弹,应该刚刚创建坦克和敌人子弹死亡后
    
        public EnemyTank(int x, int y) {
            super(x, y);
        }
    
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while (true) {
                try {
                    // 设置坦克休息一会
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                switch (this.direct) {
                case 0:
                    // 说明坦克正在向上运动(继续往上走,符合实际)
                    // y -= speed;设置坦克平滑移动的效果
                    for (int i = 0; i < 30; i++) {
                        if (y > 0) {
                            y -= speed;
                        }
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    break;
                case 1:
                    for (int i = 0; i < 30; i++) {
                        // 这里注意坐标起点问题不是(400x300)
                        if (x < 350) {
                            x += speed;
                        }
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    break;
                case 2:
                    for (int i = 0; i < 30; i++) {
                        if (y < 250) {
                            y += speed;
                        }
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    break;
                case 3:
                    for (int i = 0; i < 30; i++) {
                        if (x > 0) {
                            x -= speed;
                        }
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    break;
                }
                this.times++;
                // 设置3秒发一颗子弹
                if (times % 2 == 0) {
                    if (isLive) {
                        if (ss.size() < 5) {
                            Shot s = null;
                            // 没有子弹,添加
                            switch (direct) {
                            case 0:
                                s = new Shot(x + 10, y, 0);
                                ss.add(s);
                                break;
                            case 1:
                                s = new Shot(x + 30, y + 10, 1);
                                ss.add(s);
                                break;
                            case 2:
                                s = new Shot(x + 10, y + 30, 2);
                                ss.add(s);
                                break;
                            case 3:
                                s = new Shot(x, y + 10, 3);
                                ss.add(s);
                                break;
                            }
                            // 启动子弹线程
                            Thread t = new Thread(s);
                            t.start();
                        }
                    }
                }
                // 让坦克随机产生一个新的方向
                this.direct = (int) (Math.random() * 4);
                // 判断敌人坦克是否死亡了(双等号)
                if (this.isLive == false) {
                    // 让坦克死亡,后退出线程
                    return;
                }
    
            }
        }
    }
    
    // 我的坦克
    class Hero1_2 extends Tank1_2 {
        // 多个子弹,用向量创建
        Vector<Shot> ss = new Vector<Shot>();
        // 子弹
        Shot s = null;
        
    
        public Hero1_2(int x, int y) {
            super(x, y);
        }
    
        // 坦克开火
        public void shotEnemy() {
    
            switch (this.direct) {
            case 0:
                s = new Shot(x + 10, y, 0);
                // 把子弹加入向量
                ss.add(s);
                break;
    
            case 1:
                s = new Shot(x + 30, y + 10, 1);
                // 把子弹加入向量
                ss.add(s);
                break;
    
            case 2:
                s = new Shot(x + 10, y + 30, 2);
                // 把子弹加入向量
                ss.add(s);
                break;
    
            case 3:
                s = new Shot(x, y + 10, 3);
                // 把子弹加入向量
                ss.add(s);
                break;
            }
            // 启动子弹线程(创建线程,赶紧传参,我在这里吃了大亏!)
            Thread t = new Thread(s);
            t.start();
        }
    
        public void moveUp() {
            y -= speed;
        }
    
        public void moveRight() {
            x += speed;
        }
    
        public void moveDown() {
            y += speed;
        }
    
        public void moveLeft() {
            x -= speed;
        }
    }

    1.6版本(图:基本功能都已经实现)

    之后,我还会继续写一篇博客,来记录该坦克大战的最终版本(2.0),这个坦克大战的项目利用Java图形界面来实现坦克的绘制,画质比较粗糙,部分的坐标没有那么精确。

  • 相关阅读:
    webserver服务器
    轮子哥的网站地址
    构建javaweb服务的docker镜像和容器化启动服务
    spring-cloud-alibaba-gateway
    markdown-记笔记常用语法
    java-生成公私钥命令
    阿里云oss文件服务器
    mybatis-mapper.xml一个标签支持执行多个sql语句
    docker安装nacos
    spring-cloud-alibaba-nacos
  • 原文地址:https://www.cnblogs.com/1693977889zz/p/8444113.html
Copyright © 2011-2022 走看看