Java坦克大战


前言

通过Java程序编写实现经典游戏坦克大战的运行


一、团队成员及任务

组长:韦子豪     计科(智能)22-1 202203200011

负责任务:游戏规则程序代码编写,地图设计,游戏Panel和主界面设计

组员:孙梓容      计科(智能)22-1 202203200019

负责任务:坦克类代码编写,所有砖块类代码编写,子弹类,基地类和爆炸特效代码编写

二、流程图运行结果截图

 

三、设计思路

  1. 创建游戏的主窗口界面,加载菜单及游戏面板。

  2. 在游戏面板中初始化各种参数,并建立各种功能组件。

  3. 利用多线程与线程池的技术创建敌方坦克和所有子弹类。

  4. 利用线程固定刷新游戏界面,利用双缓冲机制防止画面闪烁。

  5. 确定运行逻辑和体积参数,处理各种碰撞问题,优化子弹判定机制

  6. 设置多张游戏地图

  7. 设置游戏通关目标和失败条件,完成目标或失败后游戏结束。

四、具体代码

1.TankWar.java 游戏入口类

代码如下:

package TankWarrrrrrr;

public class TankWar{
    public static void main(String[] args){
        new GameFrame();//坦克大战,启动!
    }
}
 

2.GameFrame.Java游戏窗口

代码如下:


package TankWarrrrrrr;

import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class GameFrame extends JFrame implements ActionListener{

    private GamePanel gamePanel;    //游戏面板

      public GameFrame(){
        try{
            // 定制菜单
            JMenuBar main = new JMenuBar();      // 菜单栏
            JMenu game = new JMenu("游戏");     // 游戏菜单
            game.setFont(new Font("微软雅黑",Font.PLAIN,12));
            JMenuItem newgame = new JMenuItem("新游戏");    // 子菜单
            newgame.setFont(new Font("微软雅黑",Font.PLAIN,12));
            newgame.addActionListener(this);      // 为窗口增加新游戏菜单的事件监听
            newgame.setActionCommand("new");     //新游戏菜单的监听标识
            game.add(newgame);                   // 将新游戏子菜单附加到游戏菜单上
            JMenuItem select = new JMenuItem("选关卡");
            select.setFont(new Font("微软雅黑",Font.PLAIN,12));
            select.addActionListener(this);
            select.setActionCommand("grade");
            game.add(select);
            game.addSeparator();                  // 菜单分隔符
            JMenuItem exit = new JMenuItem("退出");
            exit.setFont(new Font("微软雅黑",Font.PLAIN,12));
            exit.addActionListener(this);
            exit.setActionCommand("exit");
            game.add(exit);
            main.add(game);
            this.setJMenuBar(main);//以上的this都是调用私有变量gamePanel

            // 定制面板
            this.gamePanel = new GamePanel();
            this.add(this.gamePanel);

            // 定制窗口
            this.setTitle("坦克大战");                   // 标题
            this.setLayout(null);                       // 清空布局管理器
            this.setSize(this.gamePanel.getWidth() + 10,this.gamePanel.getHeight() + 60);   // 根据游戏面板大小设置游戏窗口大小
            this.setResizable(false);                   // 程序运行时禁止改变窗口大小尺寸
            this.setLocationRelativeTo(null);           // 窗口居中
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    // 点击窗口X按钮时默认关闭程序
            this.setVisible(true);                      // 显示窗口
        }
        catch (Exception e){
            e.printStackTrace();
            JOptionPane.showMessageDialog(this,"程序出现异常错误,即将退出\r\n"+e.toString(),"提示",JOptionPane.ERROR_MESSAGE);
            System.exit(0);
        }
    }


    @Override
    public void actionPerformed(ActionEvent e) {   //事件监听
        // 监听事件的标识
        String command = e.getActionCommand();
        switch (command) {
            case "new":     // 如果点了new,开始新游戏
                this.gamePanel.newGame();
                break;
            case "grade":          //选关,一共两关
                int gradeCount = GameMap.getGradeCount();
                String[] options = new String[gradeCount];
                for (int i = 0; i < gradeCount; i++)
                    options[i] = i + 1 + "";
                String grade = (String)JOptionPane.showInputDialog(this, "请选择你要进行的关卡:","选关", JOptionPane.INFORMATION_MESSAGE, null, options, options[0]);
                gamePanel.setGrade(Integer.parseInt(grade));
                gamePanel.newGame();
                break;
            case "exit":        //退出
                System.exit(0);
                break;

        }
    }

}


 

3.GamePanel.Java游戏面板

代码如下(示例):

package TankWarrrrrrr;

import java.awt.*;
import javax.swing.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Vector;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;

public class GamePanel extends JPanel implements KeyListener{
	//初始化各种变量
    private final static int GAME_STATE_READY = 0;       // 游戏未开始
    private final static int GAME_STATE_RUNNING = 1;     // 游戏运行中
    private final static int GAME_STATE_OVER = 9;        // 游戏已结束

    public final static int GAME_ACTION_WIDTH = Block.BLOCK_WIDTH * 26;     // 游戏运行场景宽度
    public final static int GAME_ACTION_HEIGHT = Block.BLOCK_HEIGHT * 26;    // 游戏运行场景宽度

    public final static int GAME_PANEL_WIDTH = GAME_ACTION_WIDTH + 150;     // 游戏面板宽度
    public final static int GAME_PANEL_HEIGHT = GAME_ACTION_HEIGHT;      
    // 游戏面板高度

    private BufferedImage bufferedImage = new BufferedImage(GAME_ACTION_WIDTH,GAME_ACTION_HEIGHT,BufferedImage.TYPE_4BYTE_ABGR);
    //利用双缓冲机制防止画面闪烁,创建一张与面板画面一样大小的图片,所有的元素先绘制到该图片上,再将该图片一次性绘制到面板画面上
    
    private int repaintInterval = 20;      // 游戏每秒刷新(1000/repaintInterval)次

    private int gameState = GAME_STATE_READY; //游戏状态

    private Hero hero;//我方坦克

    private Hero heroModel = new Hero(GAME_ACTION_WIDTH + 30,200,Tank.TANK_DIRECTION_RIGHT);    //我方坦克模型,显示在计分榜上

    private Vector<Enemy> enemyPool = new Vector<>();   //敌方坦克池,为了线程安全用Vector,不用ArrayList

    private int enemyPoolMaxNum = 0;		//限制敌方坦克池最大数量

    private int enemyDeadNum = 0;		    //敌方坦克死亡数量

    private Enemy enemyModel = new Enemy(GAME_ACTION_WIDTH + 30,20,Tank.TANK_DIRECTION_RIGHT);	   //敌方坦克模型,显示在计分榜上

    private boolean createEnemyTankThreadRunning = false;	    //标识地方坦克线程是否运行

    private long lastCreateEnemyTankTime = System.currentTimeMillis();	    //记下上次投放时间,用来设置投放坦克最小时间间隔

    private List<Block> blockList = new ArrayList<>();	//块列表

    private List<Bomb> bombList = new ArrayList<>();	//爆炸列表

    private int grade = 1;		//游戏关卡

    private byte[][] gameGradeMap;		    //游戏某关地图

    private Camp camp = new Camp(12 * Block.BLOCK_WIDTH,24 * Block.BLOCK_HEIGHT);		//我方基地


    public GamePanel(){
        this.setSize(GAME_PANEL_WIDTH,GAME_PANEL_HEIGHT);        //设置面板大小

        //监听键盘事件
        this.setFocusable(true);           //让面板得到焦点
        this.addKeyListener(this);      //将监听键盘事件附加到面板上

        GameLogic.setInstance(new GameLogic(this));        //创建游戏逻辑实例
    }


    public void newGame(){		//开始新游戏方法

        gameReset();        //先调用游戏重置方法

        this.gameState = GAME_STATE_RUNNING;        //设置游戏状态为运行中

        loadGameMap();        //加载游戏地图方法

        camp.setState(Camp.CAMP_STATE_RUNNING);        //设置我方基地

        //创建我方坦克
        int heroX = 8 * Block.BLOCK_WIDTH;
        int heroY = (this.gameGradeMap.length - 2) * Block.BLOCK_HEIGHT;
        hero = new Hero(heroX,heroY,Tank.TANK_DIRECTION_UP);
        hero.work();

        //创建敌方坦克方法
        createEnemyTank();

        //启动线程来定时刷新画面
        refresh();

    }


    private void loadGameMap(){  		//加载游戏地图方法

        this.gameGradeMap = GameMap.getGameMap(this.grade);        // 得到本关地图

        int row = this.gameGradeMap.length;   	// 得到地图位置(几行几列)
        int column = this.gameGradeMap[0].length;

        // 开始循环
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < column; j++)
            {
                int mapValue = this.gameGradeMap[i][j];
                switch (mapValue)
                {
                    case Block.BLOCK_KIND_BRICK:
                        Brick brick = new Brick(Block.BLOCK_WIDTH * j,Block.BLOCK_HEIGHT * i);
                        this.blockList.add(brick);
                        break;
                    case Block.BLOCK_KIND_IRON:
                        Iron iron = new Iron(Block.BLOCK_WIDTH * j,Block.BLOCK_HEIGHT * i);
                        this.blockList.add(iron);
                        break;
                }
            }
        }

        this.enemyPoolMaxNum = GameMap.getEnemyTankNum(this.grade);     // 本关敌方坦克数量
    }

    private void gameReset(){		//游戏重置方法
        // 停止上局正在运行的线程
        if(this.gameState == GAME_STATE_RUNNING){this.gameState = GAME_STATE_READY;}
        while (true){
            if(this.createEnemyTankThreadRunning){
                try{
                    Thread.sleep(10);
                }
                catch (InterruptedException e){
                    throw new RuntimeException(e);
                }
            }
            else{
                break;
            }
        }

        // 清空敌方坦克池中的所有坦克及其子弹
        for (int i = 0; i < enemyPool.size(); i++) {       
        	Enemy enemy = enemyPool.get(i);
            enemy.reset();
            for (int j = 0; j < enemy.getBulletPool().size(); j++){
                Bullet bullet = enemy.getBulletPool().get(j);
                bullet.reset();
            }
            enemy.getBulletPool().clear();
        }
        enemyPool.clear();
        enemyDeadNum = 0;

		// 清空我方坦克及其子弹
        if(hero != null) {
            hero.reset();
            for (int i = 0; i < hero.getBulletPool().size(); i++)
            {
                Bullet bullet = hero.getBulletPool().get(i);
                bullet.reset();
            }
            hero.getBulletPool().clear();
        }

        // 清空块池中的所有块
        blockList.clear();

    }

    //创建地方坦克
    private void createEnemyTank(){
    	
        this.createEnemyTankThreadRunning = true;   // 线程运行中
        new Thread(()->{		
            // 记录已投放的坦克数量
            int createEnemyTankNum = 0;
            try{
                while (this.gameState == GAME_STATE_RUNNING){
                    // 休眠一会
                    try{
                        Thread.sleep(repaintInterval);      // 休眠时间短主要是考虑可以迅速退出本线程
                    }
                    catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    // 控制连续投放间隔
                    long curCreateEnemyTankTime = System.currentTimeMillis();
                    if((curCreateEnemyTankTime - this.lastCreateEnemyTankTime) >= 3000) {  // 3秒投放
                        this.lastCreateEnemyTankTime = curCreateEnemyTankTime;
                    }
                    else{
                        continue;
                    }
                    // 投放敌方坦克到达最大值后退出本线程
                    if(createEnemyTankNum >= enemyPoolMaxNum){break;}
                    // 在敌方坦克池中寻找空闲的坦克随机显示在左上角或右上角
                    Enemy enemy = null;
                    for (int i = 0; i < enemyPool.size(); i++) {
                        Enemy tmpEnemy = enemyPool.get(i);
                        if(tmpEnemy.getState() == Tank.TANK_STATE_FREE)
                        {
                            enemy = tmpEnemy;
                            break;
                        }
                    }
                    // 没有就增加一个
                    if(enemy == null) {
                        enemy = new Enemy(-100,-100,Tank.TANK_DIRECTION_DOWN);
                        enemyPool.add(enemy);
                    }
                    // 开始投放(随机投放到左上角与右上角,坦克不能重叠)
                    int enemyX;     // 坦克X坐标
                    int enemyDirection = Tank.TANK_DIRECTION_DOWN;  // 坦克方向默认向下
                    int randomPos = GameLogic.getRandomInt(0,1);    // 随机生成位置(0-左上角,1-右上角)
                    if(randomPos == 0){		// 左上角
                    	enemyX = 0;
                        if(GameLogic.getRandomInt(0,1) == 1){enemyDirection = Tank.TANK_DIRECTION_RIGHT;}
                    }
                    else {   // 右上角
                        enemyX = GAME_ACTION_WIDTH - Tank.TANK_WIDTH;
                        if(GameLogic.getRandomInt(0,1) == 1){enemyDirection = Tank.TANK_DIRECTION_LEFT;}
                    }
                    enemy.setX(enemyX);
                    enemy.setY(0);
                    enemy.setDirection(enemyDirection);
                    // 判断该范围内是否可以投放运行
                    boolean workFlag = true;
                    for (int i = 0; i < enemyPool.size(); i++){
                        Enemy tmpEnemy = enemyPool.get(i);
                        if(tmpEnemy.getState() == Tank.TANK_STATE_RUNNING && enemy != tmpEnemy) {
                            if(GameLogic.getInstance().tankCollideTank(enemy,tmpEnemy)) {  // 敌方坦克占位,不能投放

                                workFlag = false;
                                continue;
                            }
                        }
                    }
                    if(GameLogic.getInstance().tankCollideTank(enemy,hero)) {     // 我方坦克占位,不能投放
                        workFlag = false;
                    }
                    // 不能投放准备下一次
                    if(!workFlag){continue;}
                    // 可以投放了
                    enemy.work();   // 线程,启动!
                    createEnemyTankNum++;
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }
            finally{
                this.createEnemyTankThreadRunning = false;      // 线程结束
            }
        }).start();

    }

    //游戏结束方法
    private void gameOver(){

        // 设置游戏状态
        this.gameState = GAME_STATE_OVER;

        // 清空重置
        gameReset();

    }

    //y游戏胜利方法
    private void gameWin() {
        if(enemyPoolMaxNum - enemyDeadNum <= 0){
            this.grade++;
            newGame();
        }
    }

    //碰撞处理
    private void collide(){
        // 判断我方子弹碰撞
        for (int i = 0; i < hero.getBulletPool().size(); i++){
            Bullet bullet = hero.getBulletPool().get(i);
            if(bullet.getState() == Bullet.BULLET_STATE_RUNNING) { 
                // 判断是否与敌方坦克碰撞
                for (int j = 0; j < enemyPool.size(); j++){	//子弹
                    Enemy enemy = enemyPool.get(j);
                    if(enemy.getState() == Tank.TANK_STATE_RUNNING) {     // 敌方坦克
                        if(GameLogic.getInstance().bulletCollideTank(bullet,enemy)) {   // 如果碰上了
                            // 记录坦克坐标,因为坦克销毁时会改变其坐标
                            int bombX = enemy.getX();
                            int bombY = enemy.getY();
                            // 子弹销毁,坦克受到伤害,判断坦克是否死亡
                            bullet.reset();
                            enemy.hurt(bullet);
                            if(enemy.isDead()){
                                // 坦克销毁,爆炸,每消灭一个敌人判断一次是否胜利
                                enemy.reset();
                                enemyDeadNum++;
                                addBomb(bombX,bombY,Tank.TANK_WIDTH,Tank.TANK_HEIGHT);
                                gameWin();
                            }
                        }
                    }
                }
                // 判断是否与块碰撞
                for (int m = blockList.size() - 1; m >= 0; m--) {
                    Block block = blockList.get(m);
                    if(GameLogic.getInstance().bulletCollideBlock(bullet,block)) {   //如果碰上了
                        // 记录块坐标
                        int bombX = block.getX();
                        int bombY = block.getY();
                        // 子弹销毁
                        bullet.reset();
                        if(block.getBlockKind() == Block.BLOCK_KIND_BRICK){
                            // 砖块销毁,爆炸
                            blockList.remove(m);
                            addBomb(bombX,bombY,Block.BLOCK_WIDTH,Block.BLOCK_HEIGHT);
                        }
                        else{
                            addBomb(bombX,bombY,Block.BLOCK_WIDTH,Block.BLOCK_HEIGHT);
                        }
                    }
                }
                // 判断是否与基地碰撞
                if(camp.getState() == Camp.CAMP_STATE_RUNNING){
                    if(GameLogic.getInstance().bulletCollideCamp(bullet,camp)) {   //基地GG
                        //子弹销毁,基地销毁,基地爆炸,游戏结束
                    	bullet.reset(); 
                        camp.setState(Camp.CAMP_STATE_FREE);
                        addBomb(camp.getX(),camp.getY(),camp.getWidth(),camp.getHeight()); 
                        gameOver(); 	//这样就可以自毁基地了
                    }
                }
            }
        }

        // 判断敌方子弹是否与我方坦克或块或大本营碰撞(不需要判断敌方坦克状态,因为即使坦克销毁子弹可能仍然在飞)
        for (int i = 0; i < enemyPool.size(); i++) {
            // 判断是否与我方坦克碰撞
            Enemy enemy = enemyPool.get(i);
            for (int j = 0; j < enemy.getBulletPool().size(); j++){
                Bullet bullet = enemy.getBulletPool().get(j);
                if(bullet.getState() == Bullet.BULLET_STATE_RUNNING) {
                    // 判断子弹是否与坦克碰撞
                    if(GameLogic.getInstance().bulletCollideTank(bullet,hero)) {   // 坦克GG
                        // 记录坦克坐标,因为坦克销毁时会改变其坐标
                        int bombX = hero.getX();
                        int bombY = hero.getY();
                        //子弹销毁、坦克受伤、判断是否死亡
                        bullet.reset();
                        hero.hurt(bullet);
                        if(hero.isDead()){
                            // 坦克销毁并爆炸,游戏结束
                            hero.reset();
                            addBomb(bombX,bombY,Tank.TANK_WIDTH,Tank.TANK_HEIGHT);
                            gameOver();
                        }
                    }
                    // 判断子弹是否与块碰撞
                    for (int m = blockList.size() - 1; m >= 0; m--) {
                        Block block = blockList.get(m);
                        // 开始判断
                        if(GameLogic.getInstance().bulletCollideBlock(bullet,block)) {  // 如果碰上了
                            // 记录块坐标
                            int bombX = block.getX();
                            int bombY = block.getY();
                            bullet.reset();
                            if(block.getBlockKind() == Block.BLOCK_KIND_BRICK){
                                // 砖块销毁并爆炸
                                blockList.remove(m);
                                addBomb(bombX,bombY,Block.BLOCK_WIDTH,Block.BLOCK_HEIGHT);
                            }
                            else{
                                addBomb(bombX,bombY,Block.BLOCK_WIDTH,Block.BLOCK_HEIGHT);
                            }
                        }
                    }
                    // 判断子弹是否与基地碰撞
                    if(camp.getState() == Camp.CAMP_STATE_RUNNING){
                        if(GameLogic.getInstance().bulletCollideCamp(bullet,camp)) {   // 如果碰上
                            // 子弹销毁,基地销毁,基地爆炸,游戏结束
                            bullet.reset();
                            camp.setState(Camp.CAMP_STATE_FREE);
                            addBomb(camp.getX(),camp.getY(),camp.getWidth(),camp.getHeight());
                            gameOver();
                        }
                    }
                }
            }
        }

    }

    //添加爆炸效果
    private void addBomb(int x,int y,int w,int h){
        // 查找空闲的爆炸
        Bomb bomb = null;
        for (int i = 0; i < bombList.size(); i++) {
            Bomb tmpBomb = bombList.get(i);
            if(tmpBomb.getState() == Bomb.BOMB_STATE_FREE) {
                bomb = tmpBomb;
                break;
            }
        }
        // 没有就增加一个
        if(bomb == null){
            bomb = new Bomb(-100,-100);
            bombList.add(bomb);
        }
        bomb.setX(x);
        bomb.setY(y);
        bomb.setWidth(w);
        bomb.setHeight(h);
        bomb.work();
    }

    //字符被输入
    @Override
    public void keyTyped(KeyEvent e){}

    //某键被按下
    @Override
    public void keyPressed(KeyEvent e){
        // 游戏未开始或结束后禁止按键
        if(this.gameState != GAME_STATE_RUNNING){return;}

        int keyCode = e.getKeyCode();
        switch (keyCode){
            case KeyEvent.VK_W:
            case KeyEvent.VK_UP:	//两个case一个break
                hero.move(Tank.TANK_DIRECTION_UP);
                break;
            case KeyEvent.VK_D:
            case KeyEvent.VK_RIGHT:
                hero.move(Tank.TANK_DIRECTION_RIGHT);
                break;
            case KeyEvent.VK_S:
            case KeyEvent.VK_DOWN:
                hero.move(Tank.TANK_DIRECTION_DOWN);
                break;
            case KeyEvent.VK_A:
            case KeyEvent.VK_LEFT:
                hero.move(Tank.TANK_DIRECTION_LEFT);
                break;
            case KeyEvent.VK_SPACE:
                hero.shoot();
                break;
        }
    }

    //某键被释放
    @Override
    public void keyReleased(KeyEvent e){}

    //利用线程来定时刷新重绘游戏画面
    private void refresh(){
        new Thread(() ->{
            while (this.gameState == GAME_STATE_RUNNING) {
                collide();       // 碰撞处理
                repaint();       // 开始刷新

                try {		     // 延时睡眠
                    Thread.sleep(repaintInterval);
                }
                catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }).start();

    }

    //绘制游戏画面,利用双缓冲机制防止画面闪烁
    @Override
    public void paint(Graphics g){
        // 完成初始化工作,该语句千万不要动
        super.paint(g);
        // 开始游戏时
        if(this.gameState == GAME_STATE_READY){
            // 清背景
            g.setColor(Color.GRAY);
            g.fillRect(0,0,this.getWidth(),this.getHeight());
            // 显示
            g.setColor(Color.ORANGE);
            g.setFont(new Font("微软雅黑",Font.BOLD,60));
            g.drawString("坦  克  大  战", 180,160);
            g.setColor(Color.BLUE);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("2023.6.15", 220,250);
            g.setColor(Color.WHITE);
            g.setFont(new Font("宋体",Font.PLAIN,20));
            g.drawString("面向对象程序设计答辩", 220,420);
            return;
        }

        // 游戏结束时
        if(this.gameState == GAME_STATE_OVER){
            g.setColor(Color.BLACK);
            g.fillRect(0,0,this.getWidth(),this.getHeight());
            g.setColor(Color.RED);
            g.setFont(new Font("宋体",Font.BOLD,60));
            g.drawString("游戏结束\n", 180,170);
            g.setColor(Color.GREEN);
            g.drawString("感谢游玩", 180,280);
            g.setColor(Color.WHITE);
            g.setFont(new Font("宋体",Font.PLAIN,20));
            g.drawString("面向对象程序设计答辩", 200,420);
        }

        // 游戏进行中
        if(this.gameState == GAME_STATE_RUNNING){
            // 设置游戏面板区域
            g.setColor(Color.LIGHT_GRAY);
            g.fillRect(0,0,this.getWidth(),this.getWidth());
            g.setColor(Color.WHITE);
            g.fill3DRect(GAME_ACTION_WIDTH,0,2,GAME_ACTION_HEIGHT,true);
            // 绘制分数
            // 敌方坦克信息
            enemyModel.draw(g);
            g.setColor(Tank.TANK_COLOR_ENEMY);
            g.setFont(new Font("微软雅黑",Font.BOLD,20));
            g.drawString("总数:" + enemyPoolMaxNum,enemyModel.getX() ,enemyModel.getY() + 70);
            g.drawString("死亡:" + enemyDeadNum,enemyModel.getX() ,enemyModel.getY() + 100);
            g.drawString("剩余:" + (enemyPoolMaxNum - enemyDeadNum),enemyModel.getX() ,enemyModel.getY() + 130);
            // 我方坦克信息
            heroModel.draw(g);
            g.setColor(Tank.TANK_COLOR_HERO);
            g.setFont(new Font("微软雅黑",Font.BOLD,20));
            g.drawString("歼敌:"+enemyDeadNum ,heroModel.getX() - 1 ,heroModel.getY() + 70);
            g.drawString("生命:" + hero.getHp() ,heroModel.getX() ,heroModel.getY() + 100);
            // 关口信息
            g.setColor(Color.BLACK);
            int gradeModelX = heroModel.getX();
            int gradeModelY = heroModel.getY() + 150;
            g.fillRect(gradeModelX,gradeModelY,3,40);
            Polygon triangle = new Polygon();
            triangle.addPoint(gradeModelX + 3, gradeModelY);
            triangle.addPoint(gradeModelX + 3, gradeModelY + 20);
            triangle.addPoint(gradeModelX  + 40, gradeModelY + 20);
            g.setColor(Color.RED);
            g.fillPolygon(triangle);
            g.setColor(Color.WHITE);
            g.setFont(new Font("微软雅黑",Font.BOLD,20));
            g.drawString("关数:" + this.grade ,gradeModelX ,gradeModelY + 70);

            //双缓冲机制来重绘画面,先把所有的元素绘制到缓冲图片上,再将该图片一次性绘制到画面上
            Graphics ig = bufferedImage.getGraphics();      //得到缓冲图片的画笔

            // 设置游戏面板区域
            ig.setColor(Color.BLACK);
            ig.fillRect(0,0,GAME_ACTION_WIDTH,GAME_ACTION_HEIGHT);

            // 绘制地图
            for (Block block : this.blockList){block.draw(ig);}

            // 绘制基地
            if(camp.getState() == Camp.CAMP_STATE_RUNNING){camp.draw(ig);}

            // 绘制我方坦克
            hero.draw(ig);

            // 绘制我方子弹
            for (Bullet bullet : hero.getBulletPool()){if(bullet.getState() == Bullet.BULLET_STATE_RUNNING){bullet.draw(ig);}}

            // 绘制敌方坦克、子弹
            for (int i = 0; i < enemyPool.size(); i++) {
                Enemy enemy = enemyPool.get(i);
                // 绘制坦克
                if(enemy.getState() == Tank.TANK_STATE_RUNNING){enemy.draw(ig);}
                // 绘制子弹
                for (Bullet bullet : enemy.getBulletPool()){if(bullet.getState() == Bullet.BULLET_STATE_RUNNING){bullet.draw(ig);}}
            }

            // 绘制爆炸
            for (Bomb bomb : bombList){if(bomb.getState() == Bomb.BOMB_STATE_RUNNING){bomb.draw(ig);}}

            // 将缓冲图片一次性显示到画面上
            g.drawImage(bufferedImage,0,0,null);
        }

    }

    public Hero getHero(){return hero;}

    public Vector<Enemy> getEnemyPool(){return enemyPool;}

    public List<Block> getBlockList(){return blockList;}

    public Camp getCamp(){return camp;}

    public void setGrade(int grade){this.grade = grade;}

}

4.GameLogic.java游戏逻辑

代码如下(示例):

package TankWarrrrrrr;

import java.awt.*;
import javax.swing.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Vector;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;

public class GamePanel extends JPanel implements KeyListener{
	//初始化各种变量
    private final static int GAME_STATE_READY = 0;       // 游戏未开始
    private final static int GAME_STATE_RUNNING = 1;     // 游戏运行中
    private final static int GAME_STATE_OVER = 9;        // 游戏已结束

    public final static int GAME_ACTION_WIDTH = Block.BLOCK_WIDTH * 26;     // 游戏运行场景宽度
    public final static int GAME_ACTION_HEIGHT = Block.BLOCK_HEIGHT * 26;    // 游戏运行场景宽度

    public final static int GAME_PANEL_WIDTH = GAME_ACTION_WIDTH + 150;     // 游戏面板宽度
    public final static int GAME_PANEL_HEIGHT = GAME_ACTION_HEIGHT;      
    // 游戏面板高度

    private BufferedImage bufferedImage = new BufferedImage(GAME_ACTION_WIDTH,GAME_ACTION_HEIGHT,BufferedImage.TYPE_4BYTE_ABGR);
    //利用双缓冲机制防止画面闪烁,创建一张与面板画面一样大小的图片,所有的元素先绘制到该图片上,再将该图片一次性绘制到面板画面上
    
    private int repaintInterval = 20;      // 游戏每秒刷新(1000/repaintInterval)次

    private int gameState = GAME_STATE_READY; //游戏状态

    private Hero hero;//我方坦克

    private Hero heroModel = new Hero(GAME_ACTION_WIDTH + 30,200,Tank.TANK_DIRECTION_RIGHT);    //我方坦克模型,显示在计分榜上

    private Vector<Enemy> enemyPool = new Vector<>();   //敌方坦克池,为了线程安全用Vector,不用ArrayList

    private int enemyPoolMaxNum = 0;		//限制敌方坦克池最大数量

    private int enemyDeadNum = 0;		    //敌方坦克死亡数量

    private Enemy enemyModel = new Enemy(GAME_ACTION_WIDTH + 30,20,Tank.TANK_DIRECTION_RIGHT);	   //敌方坦克模型,显示在计分榜上

    private boolean createEnemyTankThreadRunning = false;	    //标识地方坦克线程是否运行

    private long lastCreateEnemyTankTime = System.currentTimeMillis();	    //记下上次投放时间,用来设置投放坦克最小时间间隔

    private List<Block> blockList = new ArrayList<>();	//块列表

    private List<Bomb> bombList = new ArrayList<>();	//爆炸列表

    private int grade = 1;		//游戏关卡

    private byte[][] gameGradeMap;		    //游戏某关地图

    private Camp camp = new Camp(12 * Block.BLOCK_WIDTH,24 * Block.BLOCK_HEIGHT);		//我方基地


    public GamePanel(){
        this.setSize(GAME_PANEL_WIDTH,GAME_PANEL_HEIGHT);        //设置面板大小

        //监听键盘事件
        this.setFocusable(true);           //让面板得到焦点
        this.addKeyListener(this);      //将监听键盘事件附加到面板上

        GameLogic.setInstance(new GameLogic(this));        //创建游戏逻辑实例
    }


    public void newGame(){		//开始新游戏方法

        gameReset();        //先调用游戏重置方法

        this.gameState = GAME_STATE_RUNNING;        //设置游戏状态为运行中

        loadGameMap();        //加载游戏地图方法

        camp.setState(Camp.CAMP_STATE_RUNNING);        //设置我方基地

        //创建我方坦克
        int heroX = 8 * Block.BLOCK_WIDTH;
        int heroY = (this.gameGradeMap.length - 2) * Block.BLOCK_HEIGHT;
        hero = new Hero(heroX,heroY,Tank.TANK_DIRECTION_UP);
        hero.work();

        //创建敌方坦克方法
        createEnemyTank();

        //启动线程来定时刷新画面
        refresh();

    }


    private void loadGameMap(){  		//加载游戏地图方法

        this.gameGradeMap = GameMap.getGameMap(this.grade);        // 得到本关地图

        int row = this.gameGradeMap.length;   	// 得到地图位置(几行几列)
        int column = this.gameGradeMap[0].length;

        // 开始循环
        for (int i = 0; i < row; i++){
            for (int j = 0; j < column; j++){
                int mapValue = this.gameGradeMap[i][j];
                switch (mapValue){
                    case Block.BLOCK_KIND_BRICK:
                        Brick brick = new Brick(Block.BLOCK_WIDTH * j,Block.BLOCK_HEIGHT * i);
                        this.blockList.add(brick);
                        break;
                    case Block.BLOCK_KIND_IRON:
                        Iron iron = new Iron(Block.BLOCK_WIDTH * j,Block.BLOCK_HEIGHT * i);
                        this.blockList.add(iron);
                        break;
                }
            }
        }

        this.enemyPoolMaxNum = GameMap.getEnemyTankNum(this.grade);     // 本关敌方坦克数量
    }

    private void gameReset(){		//游戏重置方法
        // 停止上局正在运行的线程
        if(this.gameState == GAME_STATE_RUNNING){this.gameState = GAME_STATE_READY;}
        while (true){
            if(this.createEnemyTankThreadRunning){
                try{
                    Thread.sleep(10);
                }
                catch (InterruptedException e){
                    throw new RuntimeException(e);
                }
            }
            else{
                break;
            }
        }

        // 清空敌方坦克池中的所有坦克及其子弹
        for (int i = 0; i < enemyPool.size(); i++) {       
        	Enemy enemy = enemyPool.get(i);
            enemy.reset();
            for (int j = 0; j < enemy.getBulletPool().size(); j++){
                Bullet bullet = enemy.getBulletPool().get(j);
                bullet.reset();
            }
            enemy.getBulletPool().clear();
        }
        enemyPool.clear();
        enemyDeadNum = 0;

		// 清空我方坦克及其子弹
        if(hero != null) {
            hero.reset();
            for (int i = 0; i < hero.getBulletPool().size(); i++)
            {
                Bullet bullet = hero.getBulletPool().get(i);
                bullet.reset();
            }
            hero.getBulletPool().clear();
        }

        // 清空块池中的所有块
        blockList.clear();

    }

    //创建地方坦克
    private void createEnemyTank(){
    	
        this.createEnemyTankThreadRunning = true;   // 线程运行中
        new Thread(()->{		
            // 记录已投放的坦克数量
            int createEnemyTankNum = 0;
            try{
                while (this.gameState == GAME_STATE_RUNNING){
                    // 休眠一会
                    try{
                        Thread.sleep(repaintInterval);      // 休眠时间短主要是考虑可以迅速退出本线程
                    }
                    catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    // 控制连续投放间隔
                    long curCreateEnemyTankTime = System.currentTimeMillis();
                    if((curCreateEnemyTankTime - this.lastCreateEnemyTankTime) >= 3000) {  // 3秒投放
                        this.lastCreateEnemyTankTime = curCreateEnemyTankTime;
                    }
                    else{
                        continue;
                    }
                    // 投放敌方坦克到达最大值后退出本线程
                    if(createEnemyTankNum >= enemyPoolMaxNum){break;}
                    // 在敌方坦克池中寻找空闲的坦克随机显示在左上角或右上角
                    Enemy enemy = null;
                    for (int i = 0; i < enemyPool.size(); i++) {
                        Enemy tmpEnemy = enemyPool.get(i);
                        if(tmpEnemy.getState() == Tank.TANK_STATE_FREE)
                        {
                            enemy = tmpEnemy;
                            break;
                        }
                    }
                    // 没有就增加一个
                    if(enemy == null) {
                        enemy = new Enemy(-100,-100,Tank.TANK_DIRECTION_DOWN);
                        enemyPool.add(enemy);
                    }
                    // 开始投放(随机投放到左上角与右上角,坦克不能重叠)
                    int enemyX;     // 坦克X坐标
                    int enemyDirection = Tank.TANK_DIRECTION_DOWN;  // 坦克方向默认向下
                    int randomPos = GameLogic.getRandomInt(0,1);    // 随机生成位置(0-左上角,1-右上角)
                    if(randomPos == 0){		// 左上角
                    	enemyX = 0;
                        if(GameLogic.getRandomInt(0,1) == 1){enemyDirection = Tank.TANK_DIRECTION_RIGHT;}
                    }
                    else {   // 右上角
                        enemyX = GAME_ACTION_WIDTH - Tank.TANK_WIDTH;
                        if(GameLogic.getRandomInt(0,1) == 1){enemyDirection = Tank.TANK_DIRECTION_LEFT;}
                    }
                    enemy.setX(enemyX);
                    enemy.setY(0);
                    enemy.setDirection(enemyDirection);
                    // 判断该范围内是否可以投放运行
                    boolean workFlag = true;
                    for (int i = 0; i < enemyPool.size(); i++){
                        Enemy tmpEnemy = enemyPool.get(i);
                        if(tmpEnemy.getState() == Tank.TANK_STATE_RUNNING && enemy != tmpEnemy) {
                            if(GameLogic.getInstance().tankCollideTank(enemy,tmpEnemy)) {  // 敌方坦克占位,不能投放

                                workFlag = false;
                                continue;
                            }
                        }
                    }
                    if(GameLogic.getInstance().tankCollideTank(enemy,hero)) {     // 我方坦克占位,不能投放
                        workFlag = false;
                    }
                    // 不能投放准备下一次
                    if(!workFlag){continue;}
                    // 可以投放了
                    enemy.work();   // 线程,启动!
                    createEnemyTankNum++;
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }
            finally{
                this.createEnemyTankThreadRunning = false;      // 线程结束
            }
        }).start();

    }

    //游戏结束方法
    private void gameOver(){

        // 设置游戏状态
        this.gameState = GAME_STATE_OVER;

        // 清空重置
        gameReset();

    }

    //y游戏胜利方法
    private void gameWin() {
        if(enemyPoolMaxNum - enemyDeadNum <= 0){
            this.grade++;
            newGame();
        }
    }

    //碰撞处理
    private void collide(){
        // 判断我方子弹碰撞
        for (int i = 0; i < hero.getBulletPool().size(); i++){
            Bullet bullet = hero.getBulletPool().get(i);
            if(bullet.getState() == Bullet.BULLET_STATE_RUNNING) { 
                // 判断是否与敌方坦克碰撞
                for (int j = 0; j < enemyPool.size(); j++){	//子弹
                    Enemy enemy = enemyPool.get(j);
                    //在这里判断子弹是否与敌方子弹碰撞
                    for (int k = 0; k < enemy.getBulletPool().size();k++) {
                    	Bullet bullet2 = enemy.getBulletPool().get(k);
                    	if(GameLogic.getInstance().bulletCollideBullet(bullet, bullet2)) {	//如果碰上了
                    		//记录子弹位置
                    		int bulletX = bullet.getX();
                    		int bulletY = bullet.getY();
                    		//子弹销毁
                    		bullet.reset();
                    		bullet2.reset();
                    		addBomb(bulletX,bulletY,bullet.getWidth(),bullet.getHeight());
                    	}
                    }
                    if(enemy.getState() == Tank.TANK_STATE_RUNNING) {     // 敌方坦克
                        if(GameLogic.getInstance().bulletCollideTank(bullet,enemy)) {   // 如果碰上了
                            // 记录坦克坐标,因为坦克销毁时会改变其坐标
                            int bombX = enemy.getX();
                            int bombY = enemy.getY();
                            // 子弹销毁,坦克受到伤害,判断坦克是否死亡
                            bullet.reset();
                            enemy.hurt(bullet);
                            if(enemy.isDead()){
                                // 坦克销毁,爆炸,每消灭一个敌人判断一次是否胜利
                                enemy.reset();
                                enemyDeadNum++;
                                addBomb(bombX,bombY,Tank.TANK_WIDTH,Tank.TANK_HEIGHT);
                                gameWin();
                            }
                        }
                    }
                }
                // 判断是否与块碰撞
                for (int m = blockList.size() - 1; m >= 0; m--) {
                    Block block = blockList.get(m);
                    if(GameLogic.getInstance().bulletCollideBlock(bullet,block)) {   //如果碰上了
                        // 记录块坐标
                        int bombX = block.getX();
                        int bombY = block.getY();
                        // 子弹销毁
                        bullet.reset();
                        if(block.getBlockKind() == Block.BLOCK_KIND_BRICK){
                            // 砖块销毁,爆炸
                            blockList.remove(m);
                            addBomb(bombX,bombY,Block.BLOCK_WIDTH,Block.BLOCK_HEIGHT);
                        }
                        else{
                            addBomb(bombX,bombY,Block.BLOCK_WIDTH,Block.BLOCK_HEIGHT);
                        }
                    }
                }
                // 判断是否与基地碰撞
                if(camp.getState() == Camp.CAMP_STATE_RUNNING){
                    if(GameLogic.getInstance().bulletCollideCamp(bullet,camp)) {   //基地GG
                        //子弹销毁,基地销毁,基地爆炸,游戏结束
                    	bullet.reset(); 
                        camp.setState(Camp.CAMP_STATE_FREE);
                        addBomb(camp.getX(),camp.getY(),camp.getWidth(),camp.getHeight()); 
                        gameOver(); 	//这样就可以自毁基地了
                    }
                }
            }
        }

        // 判断敌方子弹是否与我方坦克或块或大本营碰撞(不需要判断敌方坦克状态,因为即使坦克销毁子弹可能仍然在飞)
        for (int i = 0; i < enemyPool.size(); i++) {
            // 判断是否与我方坦克碰撞
            Enemy enemy = enemyPool.get(i);
            for (int j = 0; j < enemy.getBulletPool().size(); j++){
                Bullet bullet = enemy.getBulletPool().get(j);
                if(bullet.getState() == Bullet.BULLET_STATE_RUNNING) {
                    // 判断子弹是否与坦克碰撞
                    if(GameLogic.getInstance().bulletCollideTank(bullet,hero)) {   //如果碰上了
                        // 记录坦克坐标,因为坦克销毁时会改变其坐标
                        int bombX = hero.getX();
                        int bombY = hero.getY();
                        //子弹销毁、坦克受伤、判断是否死亡
                        bullet.reset();
                        hero.hurt(bullet);
                        if(hero.isDead()){
                            // 坦克销毁并爆炸,游戏结束
                            hero.reset();
                            addBomb(bombX,bombY,Tank.TANK_WIDTH,Tank.TANK_HEIGHT);
                            gameOver();
                        }
                    }
                    //判断子弹是否与块碰撞
                    for (int m = blockList.size() - 1; m >= 0; m--) {
                        Block block = blockList.get(m);
                        // 开始判断
                        if(GameLogic.getInstance().bulletCollideBlock(bullet,block)) {  // 如果碰上了
                            // 记录块坐标
                            int bombX = block.getX();
                            int bombY = block.getY();
                            bullet.reset();
                            if(block.getBlockKind() == Block.BLOCK_KIND_BRICK){
                                // 砖块销毁并爆炸
                                blockList.remove(m);
                                addBomb(bombX,bombY,Block.BLOCK_WIDTH,Block.BLOCK_HEIGHT);
                            }
                            else{
                                addBomb(bombX,bombY,Block.BLOCK_WIDTH,Block.BLOCK_HEIGHT);
                            }
                        }
                    }
                    // 判断子弹是否与基地碰撞
                    if(camp.getState() == Camp.CAMP_STATE_RUNNING){
                        if(GameLogic.getInstance().bulletCollideCamp(bullet,camp)) {   // 如果碰上
                            // 子弹销毁,基地销毁,基地爆炸,游戏结束
                            bullet.reset();
                            camp.setState(Camp.CAMP_STATE_FREE);
                            addBomb(camp.getX(),camp.getY(),camp.getWidth(),camp.getHeight());
                            gameOver();
                        }
                    }
                }
            }
        }

    }

    //添加爆炸效果
    private void addBomb(int x,int y,int w,int h){
        // 查找空闲的爆炸
        Bomb bomb = null;
        for (int i = 0; i < bombList.size(); i++) {
            Bomb tmpBomb = bombList.get(i);
            if(tmpBomb.getState() == Bomb.BOMB_STATE_FREE) {
                bomb = tmpBomb;
                break;
            }
        }
        // 没有就增加一个
        if(bomb == null){
            bomb = new Bomb(-100,-100);
            bombList.add(bomb);
        }
        bomb.setX(x);
        bomb.setY(y);
        bomb.setWidth(w);
        bomb.setHeight(h);
        bomb.work();
    }

    //字符被输入
    @Override
    public void keyTyped(KeyEvent e){}

    //某键被按下
    @Override
    public void keyPressed(KeyEvent e){
        // 游戏未开始或结束后禁止按键
        if(this.gameState != GAME_STATE_RUNNING){return;}

        int keyCode = e.getKeyCode();
        switch (keyCode){
            case KeyEvent.VK_W:
            case KeyEvent.VK_UP:	//两个case一个break
                hero.move(Tank.TANK_DIRECTION_UP);
                break;
            case KeyEvent.VK_D:
            case KeyEvent.VK_RIGHT:
                hero.move(Tank.TANK_DIRECTION_RIGHT);
                break;
            case KeyEvent.VK_S:
            case KeyEvent.VK_DOWN:
                hero.move(Tank.TANK_DIRECTION_DOWN);
                break;
            case KeyEvent.VK_A:
            case KeyEvent.VK_LEFT:
                hero.move(Tank.TANK_DIRECTION_LEFT);
                break;
            case KeyEvent.VK_SPACE:
                hero.shoot();
                break;
        }
    }

    //某键被释放
    @Override
    public void keyReleased(KeyEvent e){}

    //利用线程来定时刷新重绘游戏画面
    private void refresh(){
        new Thread(() ->{
            while (this.gameState == GAME_STATE_RUNNING) {
                collide();       // 碰撞处理
                repaint();       // 开始刷新

                try {		     // 延时睡眠
                    Thread.sleep(repaintInterval);
                }
                catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }).start();

    }

    //绘制游戏画面,利用双缓冲机制防止画面闪烁
    @Override
    public void paint(Graphics g){
        // 完成初始化工作
        super.paint(g);
        // 开始游戏时
        if(this.gameState == GAME_STATE_READY){
            // 清背景
            g.setColor(Color.GRAY);
            g.fillRect(0,0,this.getWidth(),this.getHeight());
            // 显示
            g.setColor(Color.ORANGE);
            g.setFont(new Font("微软雅黑",Font.BOLD,60));
            g.drawString("坦  克  大  战", 180,160);
            g.setColor(Color.BLUE);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("2023.6.15", 220,250);
            g.setColor(Color.WHITE);
            g.setFont(new Font("宋体",Font.PLAIN,20));
            g.drawString("面向对象程序设计答辩", 220,420);
            return;
        }

        // 游戏结束时
        if(this.gameState == GAME_STATE_OVER){
            g.setColor(Color.BLACK);
            g.fillRect(0,0,this.getWidth(),this.getHeight());
            g.setColor(Color.RED);
            g.setFont(new Font("宋体",Font.BOLD,60));
            g.drawString("游戏结束\n", 180,170);
            g.setColor(Color.GREEN);
            g.drawString("感谢游玩", 180,280);
            g.setColor(Color.WHITE);
            g.setFont(new Font("宋体",Font.PLAIN,20));
            g.drawString("面向对象程序设计答辩", 200,420);
        }

        // 游戏进行中
        if(this.gameState == GAME_STATE_RUNNING){
            // 设置游戏面板区域
            g.setColor(Color.LIGHT_GRAY);
            g.fillRect(0,0,this.getWidth(),this.getWidth());
            g.setColor(Color.WHITE);
            g.fill3DRect(GAME_ACTION_WIDTH,0,2,GAME_ACTION_HEIGHT,true);
            // 绘制分数
            // 敌方坦克信息
            enemyModel.draw(g);
            g.setColor(Tank.TANK_COLOR_ENEMY);
            g.setFont(new Font("微软雅黑",Font.BOLD,20));
            g.drawString("总数:" + enemyPoolMaxNum,enemyModel.getX() ,enemyModel.getY() + 70);
            g.drawString("死亡:" + enemyDeadNum,enemyModel.getX() ,enemyModel.getY() + 100);
            g.drawString("剩余:" + (enemyPoolMaxNum - enemyDeadNum),enemyModel.getX() ,enemyModel.getY() + 130);
            // 我方坦克信息
            heroModel.draw(g);
            g.setColor(Tank.TANK_COLOR_HERO);
            g.setFont(new Font("微软雅黑",Font.BOLD,20));
            g.drawString("歼敌:"+enemyDeadNum ,heroModel.getX() - 1 ,heroModel.getY() + 70);
            g.drawString("生命:" + hero.getHp() ,heroModel.getX() ,heroModel.getY() + 100);
            // 关口信息
            g.setColor(Color.BLACK);
            int gradeModelX = heroModel.getX();
            int gradeModelY = heroModel.getY() + 150;
            g.fillRect(gradeModelX,gradeModelY,3,40);
            Polygon triangle = new Polygon();
            triangle.addPoint(gradeModelX + 3, gradeModelY);
            triangle.addPoint(gradeModelX + 3, gradeModelY + 20);
            triangle.addPoint(gradeModelX  + 40, gradeModelY + 20);
            g.setColor(Color.RED);
            g.fillPolygon(triangle);
            g.setColor(Color.WHITE);
            g.setFont(new Font("微软雅黑",Font.BOLD,20));
            g.drawString("关数:" + this.grade ,gradeModelX ,gradeModelY + 70);

            //双缓冲机制来重绘画面,先把所有的元素绘制到缓冲图片上,再将该图片一次性绘制到画面上
            Graphics ig = bufferedImage.getGraphics();      //得到缓冲图片的画笔

            // 设置游戏面板区域
            ig.setColor(Color.BLACK);
            ig.fillRect(0,0,GAME_ACTION_WIDTH,GAME_ACTION_HEIGHT);

            // 绘制地图
            for (Block block : this.blockList){block.draw(ig);}

            // 绘制基地
            if(camp.getState() == Camp.CAMP_STATE_RUNNING){camp.draw(ig);}

            // 绘制我方坦克
            hero.draw(ig);

            // 绘制我方子弹
            for (Bullet bullet : hero.getBulletPool()){if(bullet.getState() == Bullet.BULLET_STATE_RUNNING){bullet.draw(ig);}}

            // 绘制敌方坦克、子弹
            for (int i = 0; i < enemyPool.size(); i++) {
                Enemy enemy = enemyPool.get(i);
                // 绘制坦克
                if(enemy.getState() == Tank.TANK_STATE_RUNNING){enemy.draw(ig);}
                // 绘制子弹
                for (Bullet bullet : enemy.getBulletPool()){if(bullet.getState() == Bullet.BULLET_STATE_RUNNING){bullet.draw(ig);}}
            }

            // 绘制爆炸
            for (Bomb bomb : bombList){if(bomb.getState() == Bomb.BOMB_STATE_RUNNING){bomb.draw(ig);}}

            // 将缓冲图片一次性显示到画面上
            g.drawImage(bufferedImage,0,0,null);
        }

    }

    public Hero getHero(){return hero;}

    public Vector<Enemy> getEnemyPool(){return enemyPool;}

    public List<Block> getBlockList(){return blockList;}

    public Camp getCamp(){return camp;}

    public void setGrade(int grade){this.grade = grade;}

}





————————————————————————————






package TankWarrrrrrr;

public class GameLogic{
    private static GameLogic instance;		//创建唯一实例
    private GamePanel gamePanel;    	//创建游戏面板


    public GameLogic(GamePanel gamePanel){
        this.gamePanel = gamePanel;
    }

    //得到唯一实例
    public static GameLogic getInstance(){
        return instance;
    }

    //设置唯一实例
    public static void setInstance(GameLogic gameLogic){
        instance = gameLogic;
    }

    //判断矩形1是否碰撞到矩形2
    public boolean rectCollideRect(int x1,int y1,int w1,int h1,int x2,int y2,int w2,int h2){
    	// 判断原理(1、矩形1的四个顶点是否落在矩形2里;2、矩形2的四个顶点是否落在矩形1里。若高度或宽阔相等时特殊判断)
        //挨着不算碰撞
    	// 判断矩形1的四个顶点是否落在矩形2里
        if((x1 > x2 && x1 < x2 + w2 && y1 > y2 && y1 < y2 + h2)
                || (x1 + w1 > x2 && x1 + w1 < x2 + w2 && y1 > y2 && y1 < y2 + h2)
                || (x1 > x2 && x1 < x2 + w2 && y1 + h1 > y2 && y1 + h1 < y2 + h2)
                || (x1 + w1 > x2 && x1 + w1 < x2 + w2 && y1 + h1 > y2 && y1 + h1 < y2 + h2))
        {return true;}

        // 判断矩形2的四个顶点是否落在矩形1里
        if((x2 > x1 && x2 < x1 + w1 && y2 > y1 && y2 < y1 + h1)
                || (x2 + w2 > x1 && x2 + w2 < x1 + w1 && y2 > y1 && y2 < y1 + h1)
                || (x2 > x1 && x2 < x1 + w1 && y2 + h2 > y1 && y2 + h2 < y1 + h1)
                || (x2 + w2 > x1 && x2 + w2 < x1 + w1 && y2 + h2 > y1 && y2 + h2 < y1 + h1))
        {return true;}

        // 特殊情况处理
        // 若2个矩形的宽度相等时
        if(w1 == w2){if(x1 == x2 && x1 + w1 == x2 + w2 && ((y1 > y2 && y1 < y2 + h2) || (y1 + h1 > y2 && y1 + h1 < y2 + h2))){return true;}}
        // 若2个矩形的高度相等时
        if(h1 == h2){if(y1 == y2 && y1 + h1 == y2 + h2 && ((x1 > x2 && x1 < x2 + w2) || (x1 + w1 > x2 && x1 + w1 < x2 + w2))){return true;}}
        // 2个矩形完全重合
        if(x1 == x2 && y1 == y2 && w1 == w2 && h1 == h2){return true;}
        return false;
    }

    //判断坦克移动时的下一个位置是否碰撞到任何对象
    public boolean tankMoveCollide(Tank tank){
        int newX = tank.getX();
        int newY = tank.getY();

        // 得到移动后的新坐标
        switch (tank.getDirection()){
            case Tank.TANK_DIRECTION_UP:
                newY = tank.getY() - tank.getSpeed();
                break;
            case Tank.TANK_DIRECTION_RIGHT:
                newX = tank.getX() + tank.getSpeed();
                break;
            case Tank.TANK_DIRECTION_DOWN:
                newY = tank.getY() + tank.getSpeed();
                break;
            case Tank.TANK_DIRECTION_LEFT:
                newX = tank.getX() - tank.getSpeed();
                break;
        }

        // 判断是否碰撞到边界
        switch (tank.getDirection()) {
            case Tank.TANK_DIRECTION_UP:
                if(newY < 0){return true;}
                break;
            case Tank.TANK_DIRECTION_RIGHT:
                if(newX + Tank.TANK_WIDTH > GamePanel.GAME_ACTION_WIDTH){return true;}
                break;
            case Tank.TANK_DIRECTION_DOWN:
                if(newY + Tank.TANK_HEIGHT > GamePanel.GAME_ACTION_HEIGHT){return true;}
                break;
            case Tank.TANK_DIRECTION_LEFT:
                if(newX < 0){return true;}
                break;
        }

        // 判断是否碰撞到敌方坦克
        for (int i = 0; i < gamePanel.getEnemyPool().size(); i++){
            Enemy enemy = gamePanel.getEnemyPool().get(i);
            if(enemy.getState() == Tank.TANK_STATE_RUNNING && tank != enemy)
            {
                if(rectCollideRect(newX,newY,Tank.TANK_WIDTH,Tank.TANK_HEIGHT,enemy.getX(),enemy.getY(),Tank.TANK_WIDTH,Tank.TANK_HEIGHT)){return true;}
            }
        }

        // 判断是否碰撞到我方坦克
        if(tank.getTankKind() == Tank.TANK_KIND_ENEMY) {
            if(rectCollideRect(newX,newY,Tank.TANK_WIDTH,Tank.TANK_HEIGHT,gamePanel.getHero().getX(),gamePanel.getHero().getY(),Tank.TANK_WIDTH,Tank.TANK_HEIGHT)){return true;}
        }

        // 判断是否碰撞到块
        for (Block block : gamePanel.getBlockList()){
            if(rectCollideRect(newX,newY,Tank.TANK_WIDTH,Tank.TANK_HEIGHT,block.getX(),block.getY(),Block.BLOCK_WIDTH,Block.BLOCK_HEIGHT)){return true;}
        }

        // 判断是否碰撞基地
        if(gamePanel.getCamp().getState() == Camp.CAMP_STATE_RUNNING){
            if(rectCollideRect(newX,newY,Tank.TANK_WIDTH,Tank.TANK_HEIGHT,gamePanel.getCamp().getX(),gamePanel.getCamp().getY(),gamePanel.getCamp().getWidth(),gamePanel.getCamp().getHeight())){return true;}
        }

        return false;
    }

    //判断坦克是否碰撞到坦克
    public boolean tankCollideTank(Tank tank1,Tank tank2){
        return rectCollideRect(tank1.getX(),tank1.getY(),Tank.TANK_WIDTH,Tank.TANK_HEIGHT,tank2.getX(),tank2.getY(),Tank.TANK_WIDTH,Tank.TANK_HEIGHT);
    }

    //判断子弹是否碰撞到坦克
    public boolean bulletCollideTank(Bullet bullet,Tank tank){
        return rectCollideRect(bullet.getX(),bullet.getY(),bullet.getWidth(),bullet.getHeight(),tank.getX(),tank.getY(),Tank.TANK_WIDTH,Tank.TANK_HEIGHT);
    }

    //判断子弹是否碰撞到块
    public boolean bulletCollideBlock(Bullet bullet,Block block){
        return rectCollideRect(bullet.getX(),bullet.getY(),bullet.getWidth(),bullet.getHeight(),block.getX(),block.getY(),Block.BLOCK_WIDTH,Block.BLOCK_HEIGHT);
    }

    //判断子弹是否碰撞到基地
    public boolean bulletCollideCamp(Bullet bullet,Camp camp){
        return rectCollideRect(bullet.getX(),bullet.getY(),bullet.getWidth(),bullet.getHeight(),camp.getX(),camp.getY(),camp.getWidth(),camp.getHeight());
    }
    
    //判断子弹是否碰撞到子弹
    public boolean bulletCollideBullet(Bullet bullet1,Bullet bullet2) {
    	return rectCollideRect(bullet1.getX(),bullet1.getY(),bullet1.getWidth(),bullet1.getHeight(),bullet2.getX(),bullet2.getY(),bullet2.getWidth(),bullet2.getHeight());
    }

    //得到某范围内的随机整数
    public static int getRandomInt(int min,int max) {
        return (int)(min + Math.random() * (max - min + 1));
    }

}

5.GameMap.java游戏地图

代码如下(示例)

package TankWarrrrrrr;


public class GameMap{
    //各关地图[26行26列](0-空地,1-砖块,2-铁块)
    private static byte[][][] gradeMap ={
    		{	//第一关地图
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,1,1,0,0,2,2,2,0,2,0,0,2,0,0,2,0,2,0,2,0,1,1,0,0},
    			{0,0,1,1,0,0,0,2,0,2,0,2,0,2,2,0,2,0,2,2,0,0,1,1,0,0},
    			{0,0,1,1,0,0,0,2,0,2,2,2,0,2,0,2,2,0,2,2,0,0,1,1,0,0},
    			{0,0,1,1,0,0,0,2,0,2,0,2,0,2,0,0,2,0,2,0,2,0,1,1,0,0},
    			{0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
    			{0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
    			{0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1},
    			{1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1},
       			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0}
    		},
    		//第二关地图
    		{
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,1,1,1,1,1,1,1,0,0,2,2,2,0,0,1,1,1,1,1,1,1,1,0,0},
    			{0,0,1,1,1,1,1,1,1,0,0,2,2,2,0,0,1,1,1,1,1,1,1,1,0,0},
    			{0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
    			{0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
    			{0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
    			{0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
    			{0,0,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0},
    			{0,0,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1},
    			{2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2},
    			{2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,1,1,0,0},
    			{0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,1,1,0,0},
    			{0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,1,1,0,0},
    			{0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,1,1,0,0},
    			{0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,1,1,0,0},
    			{0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,1,1,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
       			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
    			{2,2,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,2,2},
    			{2,2,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,2,2}
    		},
    		//第三关地图
    		{
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0},
    			{0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0},
    			{0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0},
    			{0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0},
    			{0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0},
    			{0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0},
    			{0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0},
    			{0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2},
    			{2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,2,2,0,0},
    			{0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,2,2,0,0},
    			{0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,2,2,0,0},
    			{0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,2,2,0,0},
    			{0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,2,2,0,0},
    			{0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,0,2,2,0,0,2,2,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
       			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
    			{2,2,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,2,2},
    			{2,2,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,2,2}
    		},
    		//第四关地图
    		{
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,0,0},
    			{0,0,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
     			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
       			{0,0,1,1,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,1,1,0,0},
    			{0,0,1,1,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,1,1,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1},
    			{2,2,0,0,0,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,0,0,2,2},
    			{0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,2,2,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,2,2,0,0},
    			{0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0},
    			{0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0},
    			{0,0,0,2,2,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,2,2,0,0},
    			{0,0,0,2,2,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,0,0,2,2,0,0},
    			{0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
       			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{2,2,2,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,2,2,2},
    			{1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,1},
    			{1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,1}
    		},
    		//第五关地图
    		{
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
     			{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,0,0,0,0,0,0,0,0},
    			{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,0,0,0,0,0,0,0,0},
       			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    			{0,0,0,0,0,0,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2},
    			{2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2},
    			{0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2},
       			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
    			{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
    		},
    		// 第六关地图
    		{
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,2,2,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,2,2,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
                {0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
                {1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1},
                {2,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2},
                {0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,0,0,2,2,0,0,0,0,1,1,0,0,1,1,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
            },
            // 第七关地图
            {
                {0,0,0,0,0,0,2,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,2,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0},
                {0,0,1,1,0,0,2,2,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,2,2,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1,2,2,1,1,0,0},
                {0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1,2,2,1,1,0,0},
                {0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0},
                {0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0},
                {0,0,0,0,0,0,1,1,0,0,0,0,2,2,0,0,0,0,1,1,0,0,1,1,2,2},
                {0,0,0,0,0,0,1,1,0,0,0,0,2,2,0,0,0,0,1,1,0,0,1,1,2,2},
                {0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,2,2,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,2,2,0,0,0,0,0,0,0,0},
                {0,0,1,1,1,1,1,1,0,0,0,0,0,0,2,2,0,0,0,0,0,0,1,1,0,0},
                {0,0,1,1,1,1,1,1,0,0,0,0,0,0,2,2,0,0,0,0,0,0,1,1,0,0},
                {0,0,0,0,0,0,2,2,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
                {0,0,0,0,0,0,2,2,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
                {2,2,1,1,0,0,2,2,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0},
                {2,2,1,1,0,0,2,2,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,2,2,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,2,2,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
                {0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
                {0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,0,0,0,0,0,0,2,2,0,0,0,0,1,1,0,0,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0},
                {0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0}
            }
        };

    private static int gradeCount = gradeMap.length;	//总关卡数

    private static int[] enemyTankNum = {5,10,15,20,25,25,25};	//各关敌方坦克数量
    
    //返回某关地图
    public static byte[][] getGameMap(int grade){
        // 由于数组是个对象,而原始地图是不允许被修改的,所以不能直接赋值(引用地址),得复制一个新的地图让游戏随便修改。
        byte[][] tempMap = null;
        if(grade > 0 && grade <= gradeCount){
            tempMap = gradeMap[grade - 1];
        }
        else{
            tempMap = gradeMap[0];
        }
        //开始复制
        int row = tempMap.length;
        int column = tempMap[0].length;
        byte[][] returnMap = new byte[row][column];
        for (int i = 0; i < row; i++){
            for (int j = 0; j < column; j++){
                returnMap[i][j] = tempMap[i][j];
            }
        }

        return returnMap;
    }

    //功能:返回总关卡数
    public static int getGradeCount(){return gradeCount;}

    //返回某关敌方坦克数量
    public static int getEnemyTankNum(int grade){
        if(grade < 1 || grade > gradeCount){grade = gradeCount;}
        return enemyTankNum[grade - 1];
    }

}

6.Tank.java坦克父类

设置坦克父类,创建各种常量,作为参数由我方坦克和敌方坦克继承,从而生成游戏内的坦克单位

 代码如下

package TankWarrrrrrr;
import java.awt.*;
import java.util.Vector;

public class Tank{
    //坦克类别常量
    public final static int TANK_KIND_HERO = 0;                 // 我方坦克
    public final static int TANK_KIND_ENEMY = 1;                // 敌方坦克

    //坦克颜色常量
    public final static Color TANK_COLOR_HERO = Color.YELLOW;   // 我方坦克颜色
    public final static Color TANK_COLOR_ENEMY = Color.CYAN;    // 敌方坦克颜色

    //坦克方向常量
    public final static int TANK_DIRECTION_UP = 0;              // 向上
    public final static int TANK_DIRECTION_RIGHT = 1;           // 向右
    public final static int TANK_DIRECTION_DOWN = 2;            // 向下
    public final static int TANK_DIRECTION_LEFT = 3;            // 向左

    //坦克状态常量
    public final static int TANK_STATE_FREE = 0;                // 空闲中
    public final static int TANK_STATE_RUNNING = 1;             // 运行中

    //坦克最大血量值
    public final static int TANK_MAX_BLOOD = 100;

    //坦克尺寸常量
    public final static int TANK_WIDTH = 40;
    public final static int TANK_HEIGHT = 40;

    private int x;    //坦克左上角X坐标 
    private int y;    //坦克左上角Y坐标
    private int speed = 8;    //坦克速度
    private int hp = TANK_MAX_BLOOD;    //坦克血量
    private int direction = TANK_DIRECTION_UP;    //坦克方向
    private int tankKind = TANK_KIND_HERO;    //坦克类别
    private int state = TANK_STATE_FREE;    //坦克状态

    //子弹池(考虑线程安全用Vector,没用ArrayList)
    private Vector<Bullet> bulletPool = new Vector<>();

    //上次射击时间(用来设置2次射击最小时间间隔,禁止连续射击)
    private long lastShootTime = System.currentTimeMillis();


    public Tank(int tankKind, int x, int y, int direction){
        this.tankKind = tankKind;
        this.x = x;
        this.y = y;
        this.direction = direction;
    }

    public void draw(Graphics g){
        // 绘制血条
        g.setColor(Color.YELLOW);
        g.fill3DRect(this.x,this.y,TANK_WIDTH,3,false);   // 底色
        g.setColor(Color.RED);
        g.fill3DRect(this.x,this.y,(hp * TANK_WIDTH)/TANK_MAX_BLOOD,3,false);   // 血量(计算宽度时由于都是int类型,因此除法是放到最后计算的,防止出现结果为0的问题【int取整了】)
        g.setColor(Color.WHITE);
        int tankToBloodHeight = 5;  // 坦克到血条的高度
        // 设置坦克颜色
        if(this.tankKind == TANK_KIND_HERO) {    // 我方坦克颜色
            g.setColor(TANK_COLOR_HERO);
        }
        else {    // 敌方坦克颜色
            g.setColor(TANK_COLOR_ENEMY);
        }

        // 根据方向开始绘制坦克
        switch (direction){
            case TANK_DIRECTION_UP:
                g.fill3DRect(this.x + tankToBloodHeight,this.y + tankToBloodHeight,7,30,false);            // 左边轮子
                g.fill3DRect(this.x + 23 + tankToBloodHeight,this.y + tankToBloodHeight,7,30,false);       // 右边轮子
                g.fill3DRect(this.x + 7 + tankToBloodHeight,this.y + 5 + tankToBloodHeight,16,20,false);   // 驾驶室
                g.fillOval(this.x + 9 + tankToBloodHeight,this.y + 9 + tankToBloodHeight,12,12);                  // 炮台
                g.fill3DRect(x + 14 + tankToBloodHeight,y + tankToBloodHeight,3,15,false);                 // 炮管
                break;
            case TANK_DIRECTION_RIGHT:
                g.fill3DRect(this.x + tankToBloodHeight,this.y + tankToBloodHeight,30,7,false);            // 上边轮子
                g.fill3DRect(this.x + tankToBloodHeight,this.y + 23 + tankToBloodHeight,30,7,false);       // 下边轮子
                g.fill3DRect(this.x + 5 + tankToBloodHeight,this.y + 7 + tankToBloodHeight,20,16,false);   // 驾驶室
                g.fillOval(this.x + 9 + tankToBloodHeight,this.y + 9 + tankToBloodHeight,12,12);                  // 炮台
                g.fill3DRect(x + 15 + tankToBloodHeight,y + 14 + tankToBloodHeight,15,3,false);            // 炮管
                break;
            case TANK_DIRECTION_DOWN:
                g.fill3DRect(this.x + tankToBloodHeight,this.y + tankToBloodHeight,7,30,false);            // 左边轮子
                g.fill3DRect(this.x + 23 + tankToBloodHeight,this.y + tankToBloodHeight,7,30,false);       // 右边轮子
                g.fill3DRect(this.x + 7 + tankToBloodHeight,this.y + 5 + tankToBloodHeight,16,20,false);   // 驾驶室
                g.fillOval(this.x + 9 + tankToBloodHeight,this.y + 9 + tankToBloodHeight,12,12);                  // 炮台
                g.fill3DRect(x + 14 + tankToBloodHeight,y + 15 + tankToBloodHeight,3,15,false);            // 炮管
                break;
            case TANK_DIRECTION_LEFT:
                g.fill3DRect(this.x + tankToBloodHeight,this.y + tankToBloodHeight,30,7,false);            // 上边轮子
                g.fill3DRect(this.x + tankToBloodHeight,this.y + 23 + tankToBloodHeight,30,7,false);       // 下边轮子
                g.fill3DRect(this.x + 5 + tankToBloodHeight,this.y + 7 + tankToBloodHeight,20,16,false);   // 驾驶室
                g.fillOval(this.x + 9 + tankToBloodHeight,this.y + 9 + tankToBloodHeight,12,12);                  // 炮台
                g.fill3DRect(x + tankToBloodHeight,y + 14 + tankToBloodHeight,15,3,false);                 // 炮管
                break;
        }

    }

    //坦克移动,direction为方向
    public void move(int direction){
        if(this.direction == direction) {     // 方向相同,加速前进(要判断边界及是否碰撞到别的对象)
            if(!GameLogic.getInstance().tankMoveCollide(this)) {   // 没有碰撞,可以移动
                switch (direction){
                    case TANK_DIRECTION_UP:
                        this.y -= this.speed;
                        break;
                    case TANK_DIRECTION_RIGHT:
                        this.x += this.speed;
                        break;
                    case TANK_DIRECTION_DOWN:
                        this.y += this.speed;
                        break;
                    case TANK_DIRECTION_LEFT:
                        this.x -= this.speed;
                        break;
                }
            }
        }
        else {    // 方向不同,仅调整方向不前进
            this.direction = direction;
        }
    }

    //坦克射击
    public void shoot(){
        // 禁止连续射击
        long curShootTime = System.currentTimeMillis();
        if((curShootTime - this.lastShootTime) >= 500) {  // 2发/秒
            this.lastShootTime = curShootTime;
        }
        else{
            return;
        }

        // 在子弹池中寻找空闲的子弹
        Bullet bullet = null;
        for (int i = 0; i < bulletPool.size(); i++){
            Bullet tmpBullet = bulletPool.get(i);
            if(tmpBullet.getState() == Bullet.BULLET_STATE_FREE) {
                bullet = tmpBullet;
                break;
            }
        }

        // 没有就增加一个
        if(bullet == null){
            bullet = new Bullet(this);
            bulletPool.add(bullet);
        }

        // 设置子弹位置
        switch (this.direction){
            case TANK_DIRECTION_UP:
                bullet.setPosition(this.x + TANK_WIDTH/2 - bullet.getWidth()/2,this.y - bullet.getHeight(),this.direction);
                break;
            case TANK_DIRECTION_RIGHT:
                bullet.setPosition(this.x + TANK_WIDTH,this.y + TANK_HEIGHT/2 - bullet.getHeight()/2,this.direction);
                break;
            case TANK_DIRECTION_DOWN:
                bullet.setPosition(this.x + TANK_WIDTH/2 - bullet.getWidth()/2,this.y + TANK_HEIGHT,this.direction);
                break;
            case TANK_DIRECTION_LEFT:
                bullet.setPosition(this.x - bullet.getWidth(),this.y + TANK_HEIGHT/2 - bullet.getHeight()/2,this.direction);
                break;
        }

        // 让子弹飞一会
        bullet.fly();
    }

    //坦克受到伤害
    public void hurt(Bullet bullet){
        this.hp -= bullet.getAtk();
        if(this.hp < 0){this.hp = 0;}
    }

    //坦克是否死亡
    public boolean isDead(){
        return this.hp <= 0;
    }

    //坦克开始工作
    public void work() {
        this.state = TANK_STATE_RUNNING;
    }

    //坦克重置
    public void reset(){
        this.setX(-100);
        this.setY(-100);
        this.setHp(Tank.TANK_MAX_BLOOD);
        this.setState(TANK_STATE_FREE);
    }

    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 int getSpeed(){return speed;}

    public void setSpeed(int speed){this.speed = speed;}

    public int getHp(){return hp;}

    public void setHp(int hp){this.hp = hp;}

    public int getDirection(){return direction;}

    public void setDirection(int direction){this.direction = direction;}

    public int getState(){return state;}

    public void setState(int state){this.state = state;}

    public int getTankKind(){return tankKind;}

    public Vector<Bullet> getBulletPool(){return bulletPool;}

}

7.我方的坦克代码

代码如下

package TankWarrrrrrr;

public class Hero extends Tank{
    public Hero(int x, int y, int direction){
        super(TANK_KIND_HERO, x, y, direction);
    }
}


8.敌方的坦克代码

在继承父类坦克常量参数的基础上,通过线程和判定语句实现敌方坦克的运行,移动,攻击的行为,与我方坦克博弈

代码如下


package TankWarrrrrrr;


public class Enemy extends Tank{
    public Enemy(int x, int y, int direction){
        super(TANK_KIND_ENEMY, x, y, direction);
    }

    @Override
    public void work(){
        super.work();
        // 启动线程让坦克跑
        new Thread(()->{
            //System.out.println("坦克线程启动...");
            while (this.getState() == TANK_STATE_RUNNING){
                try{
                    Thread.sleep(200);
                }
                catch (InterruptedException e){
                    e.printStackTrace();
                }
                // 随机确认是原地不动还是移动(0-不动,其它-移动)
                if(GameLogic.getRandomInt(0,8) != 0) {   // 移动(概率设大点)
                    // 随机确认是改变方向还是向前移动(0-改变方向,其它-向前移动)
                    if(GameLogic.getRandomInt(0,12) == 0) {  // 改变方向(概率设小点)
                        int newDirection = GameLogic.getRandomInt(TANK_DIRECTION_UP, TANK_DIRECTION_LEFT + 3);
                        if(newDirection > TANK_DIRECTION_LEFT){newDirection = TANK_DIRECTION_DOWN;}    // 向下概率设大点
                        this.setDirection(newDirection);
                    }
                    else {    // 向前移动
                        // 如果到边界了就换方向
                        boolean toBorder = false;     // 默认未到边界
                        switch (this.getDirection()){
                            case TANK_DIRECTION_UP:
                                if((this.getY() - this.getSpeed() < 0)){
                                    toBorder = true;
                                }
                                break;
                            case TANK_DIRECTION_RIGHT:
                                if((this.getX() + TANK_WIDTH + this.getSpeed() > GamePanel.GAME_ACTION_WIDTH)){
                                    toBorder = true;
                                }
                                break;
                            case TANK_DIRECTION_DOWN:
                                if((this.getY() + TANK_HEIGHT + this.getSpeed() > GamePanel.GAME_ACTION_HEIGHT)){
                                    toBorder = true;
                                }
                                break;
                            case TANK_DIRECTION_LEFT:
                                if((this.getX() - this.getSpeed() < 0)){
                                    toBorder = true;
                                }
                                break;
                        }
                        if(toBorder) {  // 到边界了换方向
                            int newDirection = GameLogic.getRandomInt(TANK_DIRECTION_UP, TANK_DIRECTION_LEFT);
                            this.setDirection(newDirection);
                        }
                        else {   // 继续前进
                            this.move(this.getDirection());
                        }
                    }
                }
                // 随机确认是发射子弹还是省子弹(1-发射,其它-不发射)
                if(GameLogic.getRandomInt(0,8) == 1){
                    this.shoot();
                }
            }
        }).start();
    }

}

9.Bullet.java子弹类

设置子弹常量和属性,确定子弹的基础参数,状态和攻击力上下限,通过线程完成子弹启动的运行,随机设定子弹的伤害,根据攻击力高低进行判定,从而确定子弹颜色

代码如下(示例)

package TankWarrrrrrr;

import java.awt.*;

public class Bullet{
    //子弹状态常量
    public final static int BULLET_STATE_FREE = 0;      // 空闲中
    public final static int BULLET_STATE_RUNNING = 1;   // 运行中

    //子弹攻击力常量
    public final static int BULLET_MAX_ATTACK = 100;    // 最大攻击力
    public final static int BULLET_MIN_ATTACK = 20;     // 最小攻击力

    private int x;    //子弹左上角X坐标
    private int y;    //子弹左上角Y坐标

    private int width = 10;    //子弹宽度
    private int height = 10;    //子弹高度

    private int direction;    //子弹方向
    private int speed = 16;    //子弹速度
    
    private int state = BULLET_STATE_FREE;    //子弹状态
    private Tank tank;    //所属坦克
    private int atk;    //子弹攻击力


    public Bullet(Tank tank){
        this.tank = tank;
        this.atk = GameLogic.getRandomInt(BULLET_MIN_ATTACK,BULLET_MAX_ATTACK);
    }

    //设置子弹位置
    public void setPosition(int x,int y,int direction){
        this.x = x;
        this.y = y;
        this.direction = direction;
    }

    //功能:子弹重置
    public void reset() {
        this.x = -100;
        this.y = -100;
        this.atk = GameLogic.getRandomInt(BULLET_MIN_ATTACK,BULLET_MAX_ATTACK);     // 重新随机生成攻击力
        this.state = BULLET_STATE_FREE;
    }

    //子弹飞行
    public void fly(){
        // 设置子弹状态为运行中
        this.state = BULLET_STATE_RUNNING;
        
        //启动子弹线程
        new Thread(()->{
            while (this.state == BULLET_STATE_RUNNING) {  //tank.getState() == Tank.TANK_STATE_RUNNING &&
                try{
                    Thread.sleep(50);
                }
                catch (InterruptedException e){
                    e.printStackTrace();
                }

                switch (direction){
                    case Tank.TANK_DIRECTION_UP:
                        if(this.y - this.speed >= 0){
                            this.y -= this.speed;
                        }
                        else{
                            this.reset();
                        }
                        break;
                    case Tank.TANK_DIRECTION_RIGHT:
                        if(this.x + this.width + this.speed <= GamePanel.GAME_ACTION_WIDTH){
                            this.x += this.speed;
                        }
                        else{
                            this.reset();
                        }
                        break;
                    case Tank.TANK_DIRECTION_DOWN:
                        if(this.y + this.height + this.speed <= GamePanel.GAME_ACTION_HEIGHT){
                            this.y += this.speed;
                        }
                        else{
                            this.reset();
                        }
                        break;
                    case Tank.TANK_DIRECTION_LEFT:
                        if(this.x >= this.speed) {
                            this.x -= this.speed;
                        }
                        else{
                            this.reset();
                        }
                        break;
                }
            }
        }).start();
    }

    // 画子弹
    public void draw(Graphics g){
        if(tank.getTankKind() == Tank.TANK_KIND_HERO) {    // 我方子弹
            g.setColor(Tank.TANK_COLOR_HERO);
        }
        else {    // 敌方子弹
            g.setColor(Tank.TANK_COLOR_ENEMY);
        }
        g.fillOval(this.x,this.y,this.width,this.height);
        // 根据攻击力画加强子弹
        g.setColor(Color.RED);
        if(this.atk == 100){
            g.fillOval(this.x,this.y,this.width,this.height);
        }
        else if(this.atk >= 90) {
            g.fillOval(this.x + 1,this.y + 1,this.width - 2,this.height - 2);
        }
        else if(this.atk >= 70){
            g.fillOval(this.x + 2,this.y + 2,this.width - 4,this.height - 4);
        }
        else if(this.atk >= 50){
            g.fillOval(this.x + 3,this.y + 3,this.width - 6,this.height - 6);
        }
    }

    public int getX(){return x;}

    public int getY(){return y;}

    public int getWidth(){return width;}

    public int getHeight(){return height;}

    public int getDirection(){return direction;}

    public int getSpeed(){return speed;}

    public int getState(){return state;}

    public int getAtk(){return atk;}

}

10. Bomb.java爆炸效果

设置爆炸参数,根据进度呈现爆炸效果,增添坦克消灭时的特效

代码如下(示例)

package TankWarrrrrrr;

import java.awt.*;

public class Bomb{
    //爆炸状态常量
    public final static int BOMB_STATE_FREE = 0;      // 空闲中
    public final static int BOMB_STATE_RUNNING = 1;   // 运行中

    private int x;    //爆炸左上角X坐标
    private int y;    //爆炸左上角Y坐标
    private int width = 20;    //爆炸宽度
    private int height = 20;    //爆炸高度

    private int state = BOMB_STATE_FREE;    //状态

    //爆炸进度,根据它来决定显示哪种爆炸形状,-1-不显示爆炸,0-准备显示,1-显示第一种爆炸形状,2-显示第二种爆炸形状,3-显示第三种爆炸形状
    public int bombProgress = -1;

    public Bomb(int x, int y){
        this.x = x;
        this.y = y;
    }

    public void work(){
        this.state = BOMB_STATE_RUNNING;        // 设置爆炸状态为运行中
        bombProgress = 0;        // 爆炸进度,准备显示
    }

    //重置爆炸
    public void reset(){
        this.setX(-100);
        this.setY(-100);
        this.state = BOMB_STATE_FREE;
        this.bombProgress = -1;
    }

    // 画爆炸,每帧显示一种形状,共三种,即3帧结束爆炸
    public void draw(Graphics g) {
        // 进度走起
        this.bombProgress++;

        // 根据进度显示某种爆炸形状
        switch (this.bombProgress){
            case 1:         // 第一种形状
                g.setColor(Color.WHITE);
                g.fillRoundRect(this.x + 5,this.y + 5,20,20,10,10);
                g.fillOval(this.x + 10,this.y,10,30);
                g.setColor(Color.YELLOW);
                g.drawOval(this.x + 10,this.y,10,30);
                g.setColor(Color.WHITE);
                g.fillOval(this.x,this.y + 10,30,10);
                g.setColor(Color.YELLOW);
                g.drawOval(this.x,this.y + 10,30,10);
                break;
            case 2:         // 第二种形状
                g.setColor(Color.WHITE);
                g.fillOval(this.x + 12,this.y + 5,6,20);
                g.setColor(Color.YELLOW);
                g.drawOval(this.x + 12,this.y + 5,6,20);
                g.setColor(Color.WHITE);
                g.fillOval(this.x + 5,this.y + 12,20,6);
                g.setColor(Color.YELLOW);
                g.drawOval(this.x + 5,this.y + 12,20,6);
                break;
            case 3:         // 第三种形状
                g.setColor(Color.WHITE);
                g.fillOval(this.x + 10,this.y + 10,10,10);
                g.setColor(Color.YELLOW);
                g.drawOval(this.x + 10,this.y + 10,10,10);
                break;
            default:
                this.reset();
                break;
        }
    }

    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 int getWidth(){return width;}

    public void setWidth(int width){this.width = width;}

    public int getHeight(){return height;}

    public void setHeight(int height){this.height = height;}

    public int getState(){return state;}

}

----------------------


package TankWarrrrrrr;

public class Brick extends Block{
    public Brick(int x, int y){
        super(BLOCK_KIND_BRICK, x, y);
    }

}

 11.Block.java砖块与铁块的父类

设置砖块和铁块的父类,设定不同的参数,确定砖块和铁块的外观和属性,使砖块可以通过攻击击破,铁块不可被击破

代码如下(示例)

package TankWarrrrrrr;

import java.awt.*;

	//块和铁块父类
public class Block{
    public final static int BLOCK_KIND_BRICK = 1;     // 砖块	//块类别常量
    public final static int BLOCK_KIND_IRON = 2;      // 铁块

    public final static int BLOCK_WIDTH = Tank.TANK_WIDTH/2;	    //块尺寸常量,和坦克等大
    public final static int BLOCK_HEIGHT = Tank.TANK_HEIGHT/2 ;

    private int x;    //块左上角X坐标

    private int y;    //块左上角Y坐标

    private int blockKind = BLOCK_KIND_BRICK;    //块类别


    public Block(int blockKind,int x, int y){
        this.blockKind = blockKind;
        this.x = x;
        this.y = y;
    }

    public void draw(Graphics g){		//画块
        if(this.blockKind == BLOCK_KIND_BRICK) {   // 画砖块
            g.setColor(new Color(210, 105, 30));
            g.fillRect(this.x,this.y,BLOCK_WIDTH,BLOCK_HEIGHT);
            g.setColor(new Color(244, 164, 96));
            g.drawLine(this.x,this.y,this.x + BLOCK_WIDTH - 1,this.y);
            g.drawLine(this.x,this.y + BLOCK_HEIGHT / 2,this.x + BLOCK_WIDTH - 1,this.y + BLOCK_HEIGHT / 2);
            g.drawLine(this.x,this.y,this.x,this.y + BLOCK_HEIGHT / 2);
            g.drawLine(this.x + BLOCK_WIDTH / 2,this.y + BLOCK_HEIGHT / 2, this.x + BLOCK_WIDTH / 2, this.y + BLOCK_HEIGHT - 1);
        }
        else if(this.blockKind == BLOCK_KIND_IRON) {      // 画铁块
            g.setColor(new Color(190, 190, 190));
            g.fillRect(this.x,this.y,BLOCK_WIDTH,BLOCK_HEIGHT);
            g.setColor(Color.WHITE);
            g.fillRect(this.x + 3,this.y + 3,BLOCK_WIDTH - 6,BLOCK_HEIGHT - 6);
            g.draw3DRect(this.x + 3,this.y + 3,BLOCK_WIDTH - 6,BLOCK_HEIGHT - 6,true);
            g.drawLine(this.x + 1,this.y + 1,this.x + 3,this.y + 3);
            g.drawLine(this.x + BLOCK_WIDTH - 1,this.y + 1,this.x + BLOCK_WIDTH - 3,this.y + 3);
            g.drawLine(this.x + 1,this.y + BLOCK_HEIGHT - 1,this.x + 3,this.y + BLOCK_HEIGHT - 3);
            g.drawLine(this.x + BLOCK_WIDTH - 1,this.y + BLOCK_HEIGHT - 1,this.x + BLOCK_WIDTH - 3,this.y + BLOCK_HEIGHT - 3);
        }
    }

    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 int getBlockKind(){return blockKind;}

}

12.Brick.java砖块

代码如下(示例)

package TankWarrrrrrr;

public class Brick extends Block{
    public Brick(int x, int y){
        super(BLOCK_KIND_BRIKCK, x, y);
    }
}

13.Iron.java铁块

代码如下(示例)

package TankWarrrrrrr;

public class Iron extends Block{
    public Iron(int x, int y){
        super(BLOCK_KIND_IRON, x, y);
    }
}

 14.Camp.java营地

代码如下(示例)

package TankWarrrrrrr;


import java.awt.*;

public class Camp{
    //基地状态常量
    public final static int CAMP_STATE_FREE = 0;                // 空闲中
    public final static int CAMP_STATE_RUNNING = 1;             // 运行中


    private int x;    // 基地左上角X坐标
    private int y;    //营地左上角Y坐标

    private int width = Tank.TANK_WIDTH;    //基地宽度
    private int height = Tank.TANK_HEIGHT;	//基地高度
    private int state = CAMP_STATE_FREE;	//基地状态

    private int elementWidth = 2;	//元素宽度
    private int elementHeight = 2;	//元素高度

    private static byte[][] campMap =	//基地地图
        {
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
            {0,0,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0},
            {1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,1,1,1,1},
            {0,2,1,1,1,0,0,0,1,0,0,1,1,0,0,1,1,1,2,0},
            {1,1,2,0,1,0,0,0,1,1,1,1,0,0,0,1,0,2,1,1},
            {0,0,1,2,1,1,0,0,1,1,1,1,0,0,1,1,2,1,0,0},
            {0,1,1,1,2,1,0,0,1,1,1,1,0,0,1,2,1,1,1,0},
            {0,0,1,1,1,2,1,1,1,1,1,1,1,1,2,1,1,1,0,0},
            {0,0,0,1,1,1,2,1,1,1,1,1,1,2,1,1,1,0,0,0},
            {0,0,1,1,1,1,1,1,2,1,1,1,2,1,1,1,1,1,0,0},
            {0,0,0,1,1,1,1,1,1,2,1,2,1,1,1,1,1,0,0,0},
            {0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0},
            {0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
            {0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0},
            {0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0},
            {0,0,0,0,0,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0},
            {0,0,0,0,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0},
            {0,0,0,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0},
            {0,0,0,0,0,1,1,0,1,0,1,0,1,1,0,0,0,0,0,0},
            {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
        };

    public Camp(int x, int y){
        this.x = x;
        this.y = y;
    }

    //画基地
    public void draw(Graphics g){
        int row = campMap.length;
        int column = campMap[0].length;
        for (int i = 0; i < row; i++){
            for (int j = 0; j < column; j++){
                int mapValue = campMap[i][j];
                if(mapValue == 1){
                    g.setColor(Color.WHITE);
                    drawElement(g,this.x + elementWidth * j,this.y + elementHeight * i);
                }
                else if(mapValue == 2){
                    g.setColor(Color.LIGHT_GRAY);
                    drawElement(g,this.x + elementWidth * j,this.y + elementHeight * i);
                }
            }
        }
    }

    //画元素
    private void drawElement(Graphics g,int x,int y){
        g.fillRect(x,y,elementWidth,elementHeight);
        g.setColor(Color.WHITE);
        g.draw3DRect(x,y,elementWidth,elementHeight,true);
    }

    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 int getWidth(){return width;}

    public int getHeight(){return height;}

    public int getState(){return state;}

    public void setState(int state){this.state = state;}

}

总结:

通过这次课程设计,感觉收获颇多,团队内两个人通过不断地学习查找,修改,更新,完成了最终的确定的代码。也切实感受到了自己不会的东西还有太多,思路的设计上反映出学习需要自己长期积累。由于能力有限,所以在整个课程设计的底层逻辑上对他人有所借鉴,最后才让整个程序完全运行起来。

 参考代码:(5条消息) Java游戏开发 —— 坦克大战_java游戏坦克_我是小木鱼的博客-CSDN博客

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值