Java项目整理(1)

本文详细介绍了使用Java编程实现坦克大战游戏的关键技术,包括敌方坦克的随机移动、多线程实现的炮弹运动、坦克碰撞检测以及坦克击中后的爆炸效果。通过键盘事件监听控制我方坦克移动和发射炮弹,坦克和炮弹的状态管理确保游戏的实时性。
摘要由CSDN通过智能技术生成

入门项目–坦克大战

参考资料:韩顺平老师讲Java

需求分析

首先分析下坦克大战的需求,主要功能包括:

  1. 敌我方坦克
  2. 敌方坦克随机移动,我方坦克键盘控制移动
  3. 敌方坦克随机发射炮弹,我方坦克键盘控制发射炮弹
  4. 坦克击中爆炸并消失
  5. 记录玩家成绩
  6. 恢复上局游戏或开始新游戏
  7. 坦克大战背景音乐

设计阶段

根据需求分析的整理的主要功能,设计项目UML类图设计、开发流程设计、模块设计、数据库设计、项目架构设计等。坦克大战项目比较简单,不涉及模块设计、数据库设计、项目架构设计。

  1. UML类图设计
    从主要功能分析出发,项目包括的类主要有:坦克类、炮弹类、玩家类、坦克信息类
    坦克大战UML图

实现阶段

  1. 有了坦克类,炮弹类怎么显示坦克和炮弹?
    Java绘图技术
  • 绘图原理
    • Component类提供了两个和绘图相关的重要方法
      paint(Graphics g) – 绘制组件的外观
      repaint() – 刷新组件的外观
    • 当组件第一次在屏幕显示的时候,程序会自动的调用paint()方法来绘制组件,以下情况也会自动调用paint()方法
      窗口最小化,再最大化
      窗口的大小发生变化
      repaint被调用
  • Graphics类
    常用方法
    • 画直线 drawLine(int x1, int y1, int x2, int y2)
    • 画矩形边框 drawRect(int x, int y, int width, int height)
    • 画椭圆边框 drawOval(int x, int y, int width, int height)
    • 填充矩形 fillRect(int x, int y, int width, int height)
    • 填充椭圆 fillOval(int x, int y, int width, int height)
    • 画图片 drawImage(Image img, int x, int y, …)
    • 画字符串 drawString(String str, int x, int y)
    • 设置画笔的字体 setFont(Font font)
    • 设置画笔的颜色 setColor(Color c)

问题1: 敌方坦克随机移动?

  • 敌方坦克实现多线程,解决每个敌方坦克随机移动的问题
public class EnemyTank extends Tank implements Runnable {
    /**
     * 每颗子弹都是独立线程,用Vector保存
     */
    Vector<Bullet> bullets = new Vector<Bullet>();

    /**
     * 敌方坦克构造器
     */
    public EnemyTank(int x, int y) {
        super(x, y);
    }
    /**
     * 每一个敌方坦克都是随机移动的,都是一个独立的线程,线程方法主体中写出坦克随机移动的方法
     * 坦克移动同时发射子弹,写出子弹发射方法
     */
    public void run() {
        while (true) {
            //发射多个子弹
            if (bullets.size() < 3 && isLive) {
                switch (getDirection()) {
                    case 0: //向上
                        bullet = new Bullet(getX() + 20, getY(), 0);
                        break;
                    case 1: //向右
                        bullet = new Bullet(getX() + 60, getY() + 20, 1);
                        break;
                    case 2: //向下
                        bullet = new Bullet(getX() + 20, getY() + 60, 2);
                        break;
                    case 3: //向左
                        bullet = new Bullet(getX(), getY() + 20, 3);
                        break;
                }
                bullets.add(bullet);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                new Thread(bullet).start();
            }
            /**判断坦克的方向,让坦克保持随机方向移动,在某一方向移动一会,后随机转换方向*/
            switch (getDirection()) {
                case 0:
                    for (int i = 0; i < 30; i++) {
                    if (getY() > 10) {
                        //让坦克朝一个方向移动一会
                        moveUp();
                    }
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

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

                    break;
                case 2:
                    for (int i = 0; i < 30; i++) {
                    if (getY() < 690) {

                        moveDown();
                    }
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                    break;
                case 3:
                    for (int i = 0; i < 30; i++) {
                    if (getX() > 10) {

                        moveLeft();
                    }
                            try {
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                    break;
            }
            //设置坦克方向为0,1,2,3随机数
            setDirection((int) (Math.random() * 4));
            if (!isLive) {
                break;
            }
        }
    }
 }

问题2: 所有的炮弹之间的关系?

  • 炮弹实现多线程,解决每个炮弹相互独立,互不影响
public class Bullet implements Runnable{

    /**子弹x坐标*/
    int x;
    /**子弹y坐标*/
    int y;
    /**子弹速度*/
    int speed = 2;
    /**子弹方向*/
    int direction;
    /**子弹是否存活*/
    boolean isLive = true;

    /**子弹构造器*/
    public Bullet(int x, int y, int direction) {
        this.x = x;
        this.y = y;
        this.direction = direction;
    }

    /**
     * 根据子弹方向让子弹移动起来
     */
    public void run() {
        while (true){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            /**判断子弹方向*/
            switch (direction){
                case 0:
                    y -= speed;
                    break;
                case 1:
                    x += speed;
                    break;
                case 2:
                    y += speed;
                    break;
                case 3:
                    x -= speed;
                    break;
            }
            //当子弹碰到敌人坦克时,也应该销毁
            if(!(x >= 0 && x <= 1000 && y >=0 && y <= 750 && isLive)){
                isLive = false;
                break;
            }
        }
    }
}

新增画板类MyPanel,绘制敌我双方坦克和敌我双方炮弹

public class MyPanel extends JPanel{
	/**
     * 我方坦克初始化
     */
    MyTank myTank = null;
	 /**
     * 每一个敌方坦克都是一个独立线程,考虑线程同步问题
     */
    Vector<EnemyTank> vector = new Vector<EnemyTank>();
	 /**
     * 构造器完成初始化
     */
      /**
     * 敌方坦克数量
     */
    int enemyTankSize = 8;
     /**
     * 构造器完成初始化
     */
    public MyPanel() {
        myTank = new MyTank(900, 600);
		for (int j = 0; j < enemyTankSize; j++) {
              //创建一个敌人的坦克
              EnemyTank enemyTank = new EnemyTank((j + 1) * 100, 10);

              //启动敌人坦克线程
              Thread thread = new Thread(enemyTank);
              thread.start();

              // 设置方向
              enemyTank.setDirection(2);

              vector.add(enemyTank);
         }
     }
     
    /**
     * 画笔操作
     *
     * @param g
     */
	  @Override
    public void paint(Graphics g) {
        super.paint(g);
        /**定义坦克移动范围*/
        g.fillRect(0, 0, 1000, 750);
        //画我方坦克
        if (myTank.isLive) {
            drawTank(myTank.getX(), myTank.getY(), g, myTank.getDirection(), 1);
        }
         /**画出我方坦克的子弹*/
        if (myTank.bullets.size() > 0) {
            for (int i = 0; i < myTank.bullets.size(); i++) {
                if (myTank.bullets.get(i) != null && myTank.bullets.get(i).isLive) {
                    g.draw3DRect(myTank.bullets.get(i).x, myTank.bullets.get(i).y, 2, 2, false);
                }
                if (!myTank.bullets.get(i).isLive) {
                    myTank.bullets.remove(i);
                }
            }

        }
 		//画敌方坦克
        for (int i = 0; i < vector.size(); i++) {
            // 取出敌方坦克
            EnemyTank enemyTank = vector.get(i);
            //判断敌人坦克是否还存活
            if (enemyTank.isLive) {
                for (int j = 0; j < enemyTank.bullets.size(); j++) {
                    // 取出子弹
                    Bullet bullet = enemyTank.bullets.get(j);
                    // 判断子弹是否存活
                    if (bullet.isLive) {
                        g.draw3DRect(enemyTank.bullets.get(j).x, enemyTank.bullets.get(j).y, 2, 2, false);
                    } else {//移除子弹
                        enemyTank.bullets.remove(bullet);
                    }
                }
                //画敌人坦克
                drawTank(vector.get(i).getX(), vector.get(i).getY(), g, vector.get(i).getDirection(), 0);
            }
        }
     }
	 /**
     * @param x         坦克横坐标
     * @param y         坦克纵坐标
     * @param direction 坦克方向
     * @param g         画笔
     * @param type      坦克类型
     */
    public void drawTank(int x, int y, Graphics g, int direction, int type) {

        //设置坦克类型颜色
        switch (type) {
            case 0:
                g.setColor(Color.cyan);
                break;
            case 1:
                g.setColor(Color.yellow);
                break;
        }

        /**根据坦克朝向,画出不同方向的坦克*/
        switch (direction) {
            case 0: //表示向上
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y);//画出炮筒
                break;
            case 1: //表示向右
                g.fill3DRect(x, y, 60, 10, false);//画出坦克上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克盖子
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子
                g.drawLine(x + 30, y + 20, x + 60, y + 20);//画出炮筒
                break;
            case 2: //表示向下
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克盖子
                g.fillOval(x + 10, y + 20, 20, 20);//画出圆形盖子
                g.drawLine(x + 20, y + 30, x + 20, y + 60);//画出炮筒
                break;
            case 3: //表示向左
                g.fill3DRect(x, y, 60, 10, false);//画出坦克上边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克下边轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克盖子
                g.fillOval(x + 20, y + 10, 20, 20);//画出圆形盖子
                g.drawLine(x + 30, y + 20, x, y + 20);//画出炮筒
                break;
        }
    }
}
  1. 我方坦克响应键盘,移动和发射炮弹?
    Java事件处理机制
  • 基本说明:Java事件处理是采取“委派事件模型”。当事件发生时,产生事件的对象,会把此“信息”传递给“事件的监听者”处理,这里所说的“信息”实际上就是java.awt.event事件类库里某个类所创建的对象,把它称为“事件的对象”。
  • 事件源:事件源是一个产生事件的对象,比如按钮、窗口等
  • 事件:事件就是承载事件源状态改变时的对象,比如键盘事件、鼠标事件、窗口事件等,会生成一个事件对象,该对象保存着当前事件很多信息,比如KeyEvent对象有含义被按下键的Code值。java.awt.event包和javax.swing.event包中定义了各种事件类型
  • 事件监听接口
    • 当事件源产生一个事件,可以传送给事件监听者处理
    • 事件监听者实际上就是一个类,该类实现了某个事件监听器接口
    • 事件监听接口有多种,不同的事件监听器接口可以监听不同的事件,一个类可以实现多个监听接口
    • 这些接口在java.awt.event包和javax.swing.event包中定义

思路:MyPanel实现KeyListener接口,监听键盘事件,根据键盘输入选择坦克移动方向,根据键盘输入调用MyTank的shotEnemy()方法,实现发射炮弹

  /**
     * 键盘事件监听KeyListener接口中方法,根据按下键的不同完成对应的操作
     *
     * @param e
     */
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) {//按下W键
            //改变坦克的方向
            myTank.setDirection(0);//
            //控制坦克边界
            if (myTank.getY() > 0) {
                myTank.moveUp();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_D) {//D键, 向右
            myTank.setDirection(1);
            if (myTank.getX() < 940) {
                myTank.moveRight();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_S) {//S键
            myTank.setDirection(2);
            if (myTank.getY() < 690) {
                myTank.moveDown();
            }
        } else if (e.getKeyCode() == KeyEvent.VK_A) {//A键
            myTank.setDirection(3);
            if (myTank.getX() > 0) {
                myTank.moveLeft();
            }
        }
		// 按下j发射炮弹
        if (e.getKeyCode() == KeyEvent.VK_J) {
            myTank.shotEnemy();
        }
        // 调用repaint()函数重新绘画坦克和子弹
        this.repaint();
    }
public class MyTank extends Tank{

    /**初始化子弹类*/
    Bullet bullet = null;

    /**多线程利用Vector存储子弹类对象,每一颗子弹都是一个线程*/
    Vector<Bullet> bullets = new Vector<Bullet>();

    /**初始化我方坦克*/
    public MyTank(int x, int y) {
        super(x, y);
        setSpeed(5);
    }

    /**
     * 射击敌方坦克方法,根据坦克方向,创建子弹对象
     */
    public void shotEnemy(){
        /**我方坦克发射子弹数量限制*/
        if(bullets.size() > 2){
            return;
        }
        switch (getDirection()){
            case 0: //向上
                bullet = new Bullet(getX() + 20, getY(), 0);
                break;
            case 1: //向右
                bullet = new Bullet(getX() + 60, getY() + 20, 1);
                break;
            case 2: //向下
                bullet = new Bullet(getX() + 20, getY() + 60, 2);
                break;
            case 3: //向左
                bullet = new Bullet(getX(), getY() + 20, 3);
                break;
        }
        /**加入子弹到多线程*/
        bullets.add(bullet);
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        /**启动子弹线程*/
        new Thread(bullet).start();
    }
}
  1. 敌方坦克随机移动互相碰撞?
    思路:创建保存敌方坦克Vector,遍历Vector判断是否有相互碰撞的坦克
/**
     * 判断两辆坦克是否碰撞
     *
     * @return
     */
    public boolean isCrashed() {

        switch (this.getDirection()) {
            case 0: //目标坦克向上
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);
                    if (enemyTank != this) {
                        switch (enemyTank.getDirection()) {
                            //敌人坦克上下方向
                            case 0:
                            case 2:
                                //当前坦克左上角是否碰撞
                                if (this.getY() <= enemyTank.getY() + 60
                                        && this.getY() >= enemyTank.getY()
                                        && (this.getX() <= enemyTank.getX() + 40
                                        && this.getX() >= enemyTank.getX())) {
                                    return true;
                                }
                                //当前坦克右上角是否碰撞
                                if (this.getY() <= enemyTank.getY() + 60
                                        && this.getY() >= enemyTank.getY()
                                        && (this.getX() <= enemyTank.getX()
                                        && this.getX() >= enemyTank.getX() - 40)) {
                                    return true;
                                }
                                break;
                            //敌人坦克左右方向
                            case 1:
                            case 3:
                                //当前坦克左上角是否碰撞
                                if (this.getY() <= enemyTank.getY() + 40
                                        && this.getY() >= enemyTank.getY()
                                        && (this.getX() <= enemyTank.getX() + 60
                                        && this.getX() >= enemyTank.getX())) {
                                    return true;
                                }
                                //当前坦克右上角是否碰撞
                                if (this.getY() <= enemyTank.getY() + 40
                                        && this.getY() >= enemyTank.getY()
                                        && (this.getX() <= enemyTank.getX() + 20
                                        && this.getX() >= enemyTank.getX() - 40)) {
                                    return true;
                                }
                                break;
                        }
                    }
                }
                break;
            case 2:  // 目标坦克朝下
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);
                    if (enemyTank != this) {
                        switch (enemyTank.getDirection()) {
                            //敌人坦克上下方向
                            case 0:
                            case 2:
                                //当前坦克左下角是否碰撞
                                if (this.getY() <= enemyTank.getY()
                                        && this.getY() >= enemyTank.getY() - 60
                                        && this.getX() <= enemyTank.getX() + 40
                                        && this.getX() >= enemyTank.getX()) {
                                    return true;
                                }
                                //当前坦克右下角是否碰撞
                                if (this.getY() <= enemyTank.getY()
                                        && this.getY() >= enemyTank.getY() - 60
                                        && this.getX() <= enemyTank.getX()
                                        && this.getX() >= enemyTank.getX() - 40) {
                                    return true;
                                }
                                break;
                            //敌人坦克左右方向
                            case 1:
                            case 3:
                                //当前坦克左下角是否碰撞
                                if (this.getY() <= enemyTank.getY() - 20
                                        && this.getY() >= enemyTank.getY() - 60
                                        && this.getX() <= enemyTank.getX() + 60
                                        && this.getX() >= enemyTank.getX()) {
                                    return true;
                                }
                                //当前坦克右下角是否碰撞
                                if (this.getY() <= enemyTank.getY() - 20
                                        && this.getY() >= enemyTank.getY() - 60
                                        && this.getX() <= enemyTank.getX() + 20
                                        && this.getX() >= enemyTank.getX() - 40) {
                                    return true;
                                }
                                break;
                        }
                    }
                }
                break;
            case 1: // 目标坦克朝右
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);
                    if (enemyTank != this) {
                        switch (enemyTank.getDirection()) {
                            //敌人坦克上下方向
                            case 0:
                            case 2:
                                //当前坦克右上角是否碰撞
                                if (this.getY() <= enemyTank.getY() + 60
                                        && this.getY() >= enemyTank.getY()
                                        && this.getX() <= enemyTank.getX() - 20
                                        && this.getX() >= enemyTank.getX() - 60) {
                                    return true;
                                }
                                //当前坦克右下角是否碰撞
                                if (this.getY() <= enemyTank.getY() + 20
                                        && this.getY() >= enemyTank.getY() - 40
                                        && this.getX() <= enemyTank.getX() - 20
                                        && this.getX() >= enemyTank.getX() - 60) {
                                    return true;
                                }
                                break;
                            //敌人坦克左右方向
                            case 1:
                            case 3:
                                //当前坦克右上角是否碰撞
                                if (this.getY() <= enemyTank.getY() + 40
                                        && this.getY() >= enemyTank.getY()
                                        && this.getX() <= enemyTank.getX()
                                        && this.getX() >= enemyTank.getX() - 60) {
                                    return true;
                                }
                                //当前坦克右下角是否碰撞
                                if (this.getY() <= enemyTank.getY()
                                        && this.getY() >= enemyTank.getY() - 40
                                        && this.getX() <= enemyTank.getX()
                                        && this.getX() >= enemyTank.getX() - 60) {
                                    return true;
                                }
                                break;
                        }
                    }
                }
                break;
            case 3: //目标坦克朝左
                for (int i = 0; i < enemyTanks.size(); i++) {
                    EnemyTank enemyTank = enemyTanks.get(i);
                    if (enemyTank != this) {
                        switch (enemyTank.getDirection()) {
                            //敌人坦克上下方向
                            case 0:
                            case 2:
                                //当前坦克左上角是否碰撞
                                if (this.getY() <= enemyTank.getY() + 60
                                        && this.getY() >= enemyTank.getY()
                                        && this.getX() <= enemyTank.getX() + 40
                                        && this.getX() >= enemyTank.getX()) {
                                    return true;
                                }
                                //当前坦克左下角是否碰撞
                                if (this.getY() <= enemyTank.getY() + 20
                                        && this.getY() >= enemyTank.getY() - 40
                                        && this.getX() <= enemyTank.getX() + 40
                                        && this.getX() >= enemyTank.getX()) {
                                    return true;
                                }
                                break;
                            //敌人坦克左右方向
                            case 1:
                            case 3:
                                //当前坦克左上角是否碰撞
                                if (this.getY() <= enemyTank.getY() + 40
                                        && this.getY() >= enemyTank.getY()
                                        && this.getX() <= enemyTank.getX() + 60
                                        && this.getX() >= enemyTank.getX()) {
                                    return true;
                                }
                                //当前坦克左下角是否碰撞
                                if (this.getY() <= enemyTank.getY()
                                        && this.getY() >= enemyTank.getY() - 40
                                        && this.getX() <= enemyTank.getX() + 60
                                        && this.getX() >= enemyTank.getX()) {
                                    return true;
                                }
                                break;
                        }
                    }
                }
                break;
        }
        return false;
    }
  1. 坦克击中爆炸效果?炮弹和坦克消失
    思路:
  • 爆炸效果实现思路:图片快速切换
  • 新增bomb炸弹类,如果子弹击中坦克,新建bomb类
  • Toolkit.getDefaultToolkit().getImage()加载图片
  • 炮弹和坦克的isLive设置为false,状态消失
public class Bomb {
    /**爆炸x坐标*/
    int x;
    /**爆炸x坐标*/
    int 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;
        }
    }
}

项目地址:坦克大战

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值