引言:

坦克大战也是小时一个比较经典的游戏了,我在网上也是参考了韩顺平老师写的坦克大战,并做了一下完善,编写出来作为儿时的回忆吧!

思路:

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

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

利用线程固定刷新游戏界面。

处理各种碰撞问题

游戏结束。

代码:

本游戏用的是JDK1.8,编码UTF-8;

我这里用的IDE是Intellij Idea,新建了一个game的空项目,tankwar作为其中的一个模块(当然这个不重要,个人喜好罢了)。类比较多,TankWar.java是游戏入口类。GameFrame.java是主窗口类。GamePanel.java是游戏面板类。GameLogic.java是游戏逻辑类。先一口气把所有的代码贴上来再说。

TankWar.java 游戏入口类

package lag.game.tankwar;

/**

* 功能:坦克大战

* 作者:我是小木鱼(Lag)

*/

public class TankWar

{

public static void main(String[] args)

{

new GameFrame();

}

}

GameFrame.java游戏窗口

package lag.game.tankwar;

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 mb_main = new JMenuBar(); // 菜单栏

JMenu m_game = new JMenu("游戏"); // 游戏菜单

m_game.setFont(new Font("微软雅黑",Font.PLAIN,12)); // 游戏菜单字体

JMenuItem mi_new = new JMenuItem("新游戏"); // 游戏菜单中的新游戏子菜单

mi_new.setFont(new Font("微软雅黑",Font.PLAIN,12)); // 子菜单字体

mi_new.addActionListener(this); // 为窗口增加新游戏菜单的事件监听

mi_new.setActionCommand("new"); // 设置新游戏菜单的监听标识

m_game.add(mi_new); // 将新游戏子菜单附加到游戏菜单上

JMenuItem mi_grade = new JMenuItem("选关卡");

mi_grade.setFont(new Font("微软雅黑",Font.PLAIN,12));

mi_grade.addActionListener(this);

mi_grade.setActionCommand("grade");

m_game.add(mi_grade);

m_game.addSeparator(); // 菜单分隔符

JMenuItem mi_exit = new JMenuItem("退出");

mi_exit.setFont(new Font("微软雅黑",Font.PLAIN,12));

mi_exit.addActionListener(this);

mi_exit.setActionCommand("exit");

m_game.add(mi_exit);

mb_main.add(m_game);

JMenu m_help = new JMenu("帮助");

m_help.setFont(new Font("微软雅黑",Font.PLAIN,12));

JMenuItem mi_about = new JMenuItem("关于");

mi_about.setFont(new Font("微软雅黑",Font.PLAIN,12));

mi_about.addActionListener(this);

mi_about.setActionCommand("about");

m_help.add(mi_about);

mb_main.add(m_help);

this.setJMenuBar(mb_main);

// 定制面板

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); // 显示窗口

//音乐(用线程播放)

// new Thread(()->{

// GameMusic gameMusic = new GameMusic(this.getClass().getClassLoader().getResourceAsStream("audio/start.wav"));

// gameMusic.play(false);

// }).start();

}

catch (Exception e)

{

e.printStackTrace();

JOptionPane.showMessageDialog(this,"程序出现异常错误,即将退出!\r\n\r\n"+e.toString(),"提示",JOptionPane.ERROR_MESSAGE);

System.exit(0);

}

}

/**

* 事件监听

*/

@Override

public void actionPerformed(ActionEvent e)

{

// 监听事件的标识

String command = e.getActionCommand();

switch (command)

{

case "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;

case "about":

JOptionPane.showMessageDialog(this,"我是小木鱼(Lag)","提示",JOptionPane.INFORMATION_MESSAGE);

break;

}

}

}

GamePanel.java游戏面板

package lag.game.tankwar;

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 = 50; // 游戏每秒刷新(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);

/** 敌方坦克池(考虑线程安全用Vector,没用ArrayList) */

private Vector enemyPool = new Vector<>();

/** 敌方坦克池最大数量 */

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 blockList = new ArrayList<>();

/** 爆炸列表 */

private List 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(()->{

//System.out.println("创建敌方坦克线程开始启动...");

// 记录已投放的坦克数量

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;

//System.out.println("找到空闲的敌方坦克了..................");

break;

}

}

// 没有就增加一个

if(enemy == null)

{

enemy = new Enemy(-100,-100,Tank.TANK_DIRECTION_DOWN);

enemyPool.add(enemy);

//System.out.println("新建敌方坦克了.................");

}

// 开始投放(随机投放到左上角与右上角,坦克不能重叠)

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; // 线程结束

}

//System.out.println("创建敌方坦克线程退出历史舞台了......");

}).start();

}

/**

* 游戏结束

*/

private void gameOver()

{

// 设置游戏状态

this.gameState = GAME_STATE_OVER;

// 游戏清空重置

gameReset();

}

/**

* 游戏胜利

*/

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)) // 完蛋了啊

{

// 子弹销毁

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;

//System.out.println("找到空闲的爆炸了..................");

break;

}

}

// 没有就增加一个

if(bomb == null)

{

bomb = new Bomb(-100,-100);

bombList.add(bomb);

//System.out.println("新建爆炸了.................");

}

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:

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){}

/**

* 利用线程来定时刷新重绘游戏画面,适用于飞机类刷新频率较高的游戏。

* 动画原理就是在极短时间内连续显示多个图片,给人眼一种画面动起来的错觉(人眼的识别静态图时间为0.1秒)。

* 屏幕刷新频率(FPS->帧/每秒),单位赫兹(Hz)。

* 20Hz ->每秒刷新画面20次,即每隔(1000/20)毫秒刷新一次画面。

*/

private void refresh()

{

// 利用Lambda表达式替代内部类更方便

new Thread(() ->

{

//System.out.println("游戏自动刷新线程开始启动...");

while (this.gameState == GAME_STATE_RUNNING)

{

// 碰撞处理

collide();

// 开始刷新

repaint();

// 延时睡眠

try

{

Thread.sleep(repaintInterval);

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

//System.out.println("游戏自动刷新线程退出历史舞台了......");

}).start();

}

/**

* 绘制游戏画面(利用双缓冲机制防止画面闪烁)

*/

@Override

public void paint(Graphics g)

{

// 完成初始化工作,该语句千万不要动

super.paint(g);

// 准备开始游戏

if(this.gameState == GAME_STATE_READY)

{

// 清一下背景

g.setColor(Color.BLACK);

g.fillRect(0,0,this.getWidth(),this.getHeight());

// 显示Logo

g.setColor(Color.ORANGE);

g.setFont(new Font("微软雅黑",Font.BOLD,60));

g.drawString("坦 克 大 战", 160,170);

g.setColor(Color.CYAN);

g.setFont(new Font("微软雅黑",Font.BOLD,40));

g.drawString("2023", 280,280);

g.setColor(Color.WHITE);

g.setFont(new Font("宋体",Font.PLAIN,20));

g.drawString("我是小木鱼(Lag)制作", 240,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("游戏结束", 200,170);

g.drawString("大虾请重新来过吧!", 70,280);

}

// 游戏进行中

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("总数:1" ,heroModel.getX() ,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 getEnemyPool(){return enemyPool;}

public List getBlockList(){return blockList;}

public Camp getCamp(){return camp;}

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

}

GameLogic.java游戏逻辑

package lag.game.tankwar;

/**

* 游戏逻辑(牛逼类)

*/

public class GameLogic

{

/** 唯一实例 */

private static GameLogic instance;

/** 游戏面板 */

private GamePanel gamePanel;

/**

* 构造函数

* @param gamePanel 游戏面板

*/

public GameLogic(GamePanel gamePanel)

{

this.gamePanel = gamePanel;

}

/**

* 得到唯一实例

*/

public static GameLogic getInstance()

{

return instance;

}

/**

* 设置唯一实例

* @param gameLogic 游戏逻辑

*/

public static void setInstance(GameLogic gameLogic)

{

instance = gameLogic;

}

/**

* 判断矩形1是否碰撞到矩形2

* @param x1 矩形1左上角X坐标

* @param y1 矩形1左上角Y坐标

* @param w1 矩形1宽度

* @param h1 矩形1高度

* @param x2 矩形2左上角X坐标

* @param y2 矩形2左上角Y坐标

* @param w2 矩形2宽度

* @param h2 矩形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;

}

/**

* 判断坦克是否碰撞到坦克

* @param tank1 坦克1

* @param tank2 坦克2

*/

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());

}

/**

* 得到某范围内的随机整数

* @param min 最小值

* @param max 最大值

*/

public static int getRandomInt(int min,int max)

{

return (int)(min + Math.random() * (max - min + 1));

}

}

GameMap.java游戏地图

package lag.game.tankwar;

/**

* 游戏地图

*/

public class GameMap

{

/** 各关地图[26行26列](0-空地,1-砖块,2-铁块) */

private static byte[][][] gradeMap =

{

// 第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,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,1,1,1,1,0,0,0,1,1,0,0,1,1,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}

},

// 第2关地图

{

{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,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0},

{0,0,1,1,0,0,1,1,0,0,0,1,0,0,1,0,0,0,1,1,1,1,1,1,0,0},

{0,0,1,1,0,0,1,1,0,0,0,1,0,0,1,0,0,0,1,1,1,1,1,1,0,0}

}

// 其他关地图...

};

/** 总关卡数 */

private static int gradeCount = gradeMap.length;

/** 各关敌方坦克数量 */

private static int[] enemyTankNum = {10,20};

/**

* 返回某关地图

* @param grade 关数

*/

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;}

/**

* 返回某关敌方坦克数量

* @param grade 关数

*/

public static int getEnemyTankNum(int grade)

{

if(grade < 1 || grade > gradeCount){grade = gradeCount;}

return enemyTankNum[grade - 1];

}

}

GameMusic.java

package lag.game.tankwar;

import java.io.File;

import java.io.InputStream;

import javax.sound.sampled.Clip;

import javax.sound.sampled.DataLine;

import javax.sound.sampled.AudioFormat;

import javax.sound.sampled.AudioSystem;

import javax.sound.sampled.AudioInputStream;

/**

* 游戏音乐

* 支持音乐格式(AITF、AU、WAV),就是加载有点慢啊。

*/

public class GameMusic

{

/** 音频输入流 */

private AudioInputStream stream;

/** 音频格式 */

private AudioFormat format;

/** 音频剪辑 */

private Clip clip;

/**

* 功能:构造函数

*/

public GameMusic(String fileName)

{

try

{

File file = new File(fileName);

//将音乐文件转为音频输入流

this.stream = AudioSystem.getAudioInputStream(file);

//得到音频格式

this.format = stream.getFormat();

}

catch(Exception e)

{

e.printStackTrace();

}

}

/**

* 构造函数

* @param fileName URL文件名

*/

public GameMusic(InputStream fileName)

{

try

{

//将音乐文件转为音频输入流

this.stream = AudioSystem.getAudioInputStream(fileName);

//得到音频格式

this.format = stream.getFormat();

}

catch(Exception e)

{

e.printStackTrace();

}

}

/**

* 功能:播放音乐

* 参数:boolean _loop -> 是否循环(True-无限循环,False-不循环)

*/

public void play(boolean _loop)

{

try

{

//设置音频行信息

DataLine.Info info = new DataLine.Info(Clip.class,this.format);

//建立音频行信息

this.clip = (Clip)AudioSystem.getLine(info);

this.clip.open(this.stream);

if(_loop) //无限循环

{

this.clip.loop(Clip.LOOP_CONTINUOUSLY);

}

else

{

this.clip.loop(0);

}

this.clip.start();

}

catch(Exception e)

{

e.printStackTrace();

}

}

/**

* 功能:停止音乐

*/

public void stop()

{

try

{

if(this.clip.isRunning())

{

this.clip.stop();

this.clip.close();

}

}

catch(Exception e)

{

e.printStackTrace();

}

}

}

Tank.java坦克父类

package lag.game.tankwar;

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;

/** 坦克左上角X坐标 */

private int x;

/** 坦克左上角Y坐标 */

private int 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 bulletPool = new Vector<>();

/** 上次射击时间(用来设置2次射击最小时间间隔,禁止连续射击) */

private long lastShootTime = System.currentTimeMillis();

/**

* 构造函数

* @param tankKind 坦克类别

* @param x 坦克左上角X坐标

* @param y 坦克左上角Y坐标

* @param direction 坦克方向

*/

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);

g.draw3DRect(this.x,this.y,TANK_WIDTH,3,false); // 边框

int tankToBloodHeight = 5; // 坦克到血条的高度

// 设置坦克颜色

if(this.tankKind == TANK_KIND_HERO) // 我方坦克颜色

{

g.setColor(TANK_COLOR_HERO);

}

else // 敌方坦克颜色

{

g.setColor(TANK_COLOR_ENEMY);

}

// 绘制四周虚线

for (int i = 0; i <= 10; i++)

{

g.drawOval(x - 1,y + 4 * i - 1, 1,1);

g.drawOval(x + TANK_WIDTH - 1,y + 4 * i - 1, 1,1);

if(i < 10){g.drawOval(x + 4 * i - 1,y + TANK_HEIGHT - 1, 1,1);}

}

// 根据方向开始绘制坦克

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;

}

}

/**

* 坦克移动

* @param 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;

//System.out.println("找到空闲的子弹了..................");

break;

}

}

// 没有就增加一个

if(bullet == null)

{

bullet = new Bullet(this);

//System.out.println("新建子弹了.................");

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 getBulletPool(){return bulletPool;}

}

Hero.java我方的坦克

package lag.game.tankwar;

/**

* 我方的坦克

*/

public class Hero extends Tank

{

/**

* 构造函数

* @param x 坦克左上角X坐标

* @param y 坦克左上角Y坐标

* @param direction 坦克方向

*/

public Hero(int x, int y, int direction)

{

super(TANK_KIND_HERO, x, y, direction);

}

}

Enemy.java敌方的坦克

package lag.game.tankwar;

/**

* 敌方的坦克

*/

public class Enemy extends Tank

{

/**

* 构造函数

* @param x 坦克左上角X坐标

* @param y 坦克左上角Y坐标

* @param direction 坦克方向

*/

public Enemy(int x, int y, int direction)

{

super(TANK_KIND_ENEMY, x, y, direction);

}

/**

* 起来干活了

*/

@Override

public void work()

{

super.work();

// 启动线程让坦克跑(看看敌方坦克的AI)

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();

}

}

//System.out.println("坦克线程退出历史舞台了...");

}).start();

}

}

Bullet.java子弹类

package lag.game.tankwar;

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; // 最小攻击力

/** 子弹左上角X坐标 */

private int x;

/** 子弹左上角Y坐标 */

private int 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;

/**

* 构造函数

* @param tank 所属坦克

*/

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(()->{

//System.out.println(tank.getTankKind() + "子弹线程启动...");

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;

}

}

//System.out.println("子弹线程退出历史舞台了......");

}).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;}

}

Bomb.java爆炸效果

package lag.game.tankwar;

import java.awt.*;

/**

* 爆炸效果

*/

public class Bomb

{

/** 爆炸状态常量 */

public final static int BOMB_STATE_FREE = 0; // 空闲中

public final static int BOMB_STATE_RUNNING = 1; // 运行中

/** 爆炸左上角X坐标 */

private int x;

/** 爆炸左上角Y坐标 */

private int y;

/** 爆炸宽度 */

private int width = 20;

/** 爆炸高度 */

private int height = 20;

/** 状态 */

private int state = BOMB_STATE_FREE;

/** 爆炸进度,根据它来决定显示哪种爆炸形状(-1-不显示任何爆炸形状,0-准备显示,1-显示第一种爆炸形状,2-显示第二种爆炸形状,3-显示第三种爆炸形状) */

public int bombProgress = -1;

/**

* 构造函数

* @param x 爆炸左上角X坐标

* @param y 爆炸左上角Y坐标

*/

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;}

}

Block.java砖块与铁块的父类

package lag.game.tankwar;

import java.awt.*;

/**

* 砖块与铁块的父类

*/

public class Block

{

/** 块类别常量 */

public final static int BLOCK_KIND_BRICK = 1; // 砖块

public final static int BLOCK_KIND_IRON = 2; // 铁块

/** 块尺寸常量(默认4个块=1坦克大小) */

public final static int BLOCK_WIDTH = Tank.TANK_WIDTH / 2;

public final static int BLOCK_HEIGHT = Tank.TANK_HEIGHT / 2;

/** 块左上角X坐标 */

private int x;

/** 块左上角Y坐标 */

private int y;

/** 块类别 */

private int blockKind = BLOCK_KIND_BRICK;

/**

* 构造函数

* @param blockKind 块类别

* @param x 块左上角X坐标

* @param y 块左上角Y坐标

*/

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;}

}

Brick.java砖块

package lag.game.tankwar;

/**

* 砖块

*/

public class Brick extends Block

{

/**

* 构造函数

* @param x 砖块左上角X坐标

* @param y 砖块左上角Y坐标

*/

public Brick(int x, int y)

{

super(BLOCK_KIND_BRICK, x, y);

}

}

Iron.java铁块

package lag.game.tankwar;

/**

* 铁块

*/

public class Iron extends Block

{

/**

* 构造函数

* @param x 铁块左上角X坐标

* @param y 铁块左上角Y坐标

*/

public Iron(int x, int y)

{

super(BLOCK_KIND_IRON, x, y);

}

}

Camp.java营地

package lag.game.tankwar;

import java.awt.*;

/**

* 营地

*/

public class Camp

{

/** 营地状态常量 */

public final static int CAMP_STATE_FREE = 0; // 空闲中

public final static int CAMP_STATE_RUNNING = 1; // 运行中

/** 营地左上角X坐标 */

private int x;

/** 营地左上角Y坐标 */

private int 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;

/** 营地地图(20 * 20) */

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);

}

}

}

}

/**

* 画元素

* @param x 元素左上角X坐标

* @param y 元素左上角Y坐标

*/

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;}

}

下载:

链接:https://pan.baidu.com/s/1aqNjqATCjteiAdv90YDByw?pwd=mylx

提取码:mylx

感言:

本游戏并没有使用图片,都是用Java画的,有兴趣的朋友可以自己改用图片,图片素材我已经打包了。使用图片的朋友要注意一个问题,就是图片加载是需要时间的,第一次可能还未加载成功就直接刷新下一次界面了,这也是韩顺平老师那个第一次射击坦克不出现爆炸效果的原因。Toolkit.getDefaultToolkit().createImage这个方法有BUG,改用new ImageIcon(图片路径)).getImage()就可以了。

文章链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: