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图形界面来实现坦克的绘制,画质比较粗糙,部分的坐标没有那么精确。

原文地址:https://www.cnblogs.com/1693977889zz/p/8444113.html

时间: 2024-11-05 15:38:47

Java坦克大战(三)的相关文章

Java坦克大战(一)

接下来的几篇博客,想记录一下通过学习坦克大战项目来循序渐进的学习Java基础.主要是为了巩固基础知识,当然学习编程重要的还是多敲,问题通常是在敲代码的过程中发现的,积累也是在敲代码中寻求的经验.这个坦克大战项目是利用Java图形界面来做的,比较简陋.但是,在不断的往里面加功能的时候,可以学到很多知识,最重要的还是体会Java的面向对象编程思想.下面介绍几个用的上的Demo,最后是坦克大战的1.0版本. Demo1:回顾事件处理机制 /* * 功能:事件处理机制(ActionListener的应用

Java坦克大战(四)

这是我的坦克游戏大战的最后一版,里面添加很多新的功能.这个坦克大战的有很多不足之处,但是对于初学者来说依然是一个很好的练习项目,从中我们可以学习Java基础知识,将知识与项目结合,学习面向对象编程思想,最主要的是编程的逻辑练习,代码往往不像是写文章从上到下一气呵成完成,中间很可能为增加一个功能来添加一个类一个方法等,中间有很多细节需要我们考虑.文章最后会附加该坦克大战涉及的相关素材. 功能: 1.防止坦克重叠 2.可以分关(闪烁效果) 3.记录成绩(小型游戏都是写在文件中) 4.存盘退出,可以记

Java坦克大战游戏源代码

转载自: http://blog.csdn.net/java_cxrs/article/details/3860870 经过几天的练习和研究终于自己能写出坦克大战游戏了,写完这个程序后感觉收获了很多东西,对JAVA的知识又有了一定的增长,接下来还准备继续写几个小项目来练习J2SE 由于代码太长就不发在博客里了,我上传到了资源下载里,有需要的朋友大家可以去下载 下载地址:http://download.csdn.net/source/988654

Java坦克大战游戏开发

本文介绍: 本文分为多个部分,间断性更新.主要涉及到 面向对象思想,Java GUI绘图,多线程,IO,数据库相关知识. 注:本文内容是整合了韩顺平老师的java项目(代码部分和韩顺平老师有不同)然后加上自己的一些思考写得,本文讲的有些累述,但有提示,如若基础扎实可以直接跳过,一部分面向仅仅学习了JavaSE的语法与面向对象的,一部分是面向已经掌握了GUI,多线程,IO,数据库相关知识的. 本人认为该项目可以很好地加深对面向对象思想的理解,加强对Java各个基础知识的巩固. 基本要求: 观看并且

新手小项目-java坦克大战

1.界面(图形化-前端部分) 图形化用于交互,不管是用文字形式给用户选择,还是图形方式式的选择都是一种交互方式.在java中如果我们需要用到图形界面,就得想到GUI(Graphic user interface),那么我们需要用到什么,就直接去查看API(图形化显示能让我们做完项目后将结果看得舒服,而不是全部都是代码) 要做GUI,就要想到java中的AWT(abstract windows toolkit),我们写图形化都需要用到这个类库.那为什么叫抽象窗口呢?因为java是跨平台的,java

JAVA坦克大战项目练习日4

1.java中键盘事件的getKeyCode() getKeyCode()键盘上每一个按钮都有对应码(Code),可用来查知用户按了什么键, 如[Shift]键code为16.利用getKeyCode()方法就可以得知这个码,不过读者要注意,这个方法在keyTyped() 上是无法检测出来的,因为keyTyped()只管用户输入的字符,而不会管到键盘的对应码.因此你一定要将getKeyCode()方法写keyPressed()或keyReleased()方法中才会有效,因为这两个方法是处理比较低

java坦克大战源码下载

HJZGG: http://files.cnblogs.com/files/hujunzheng/%E5%9D%A6%E5%85%8B%E5%A4%A7%E6%88%98%E6%BA%90%E7%A0%81.zip

JAVA坦克大战项目练习日3

1.如果调用repaint(),则相当于先自动调用update(),再自动调用paint()方法. 2. public abstract boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)绘制指定图像中已缩放到适合指定矩形内部的图像. 图像绘制在此图形上下文坐标空间的指定矩形内部,并且如果需要,则进行缩放.透明像素不影响该处已存在的像素. 此方法在任何情况下都立刻返回,

《Java小游戏实现》:坦克大战(续三)

<Java小游戏实现>:坦克大战(续三) 相关博文: <Java小游戏实现>:坦克大战http://blog.csdn.net/u010412719/article/details/51712663 <Java小游戏实现>:坦克大战(续一):http://blog.csdn.net/u010412719/article/details/51723570 <Java小游戏实现>:坦克大战(续二):http://blog.csdn.net/u010412719/