Java实现坦克大战小游戏

主要内容

使用Java面向对象思想设计并开发一个有GUI界面的小游戏坦克大战,允许玩家与电脑玩家进行对战,玩家使用键盘操控坦克,人机具有一定的移动和开火逻辑。

实现功能

1.有游戏图像界面,让玩家能看到游戏给出反馈;

2.有人机交互功能,完成能操控指定游戏元素;

3.不同阵营的坦克,具备不同外观,可分别敌我;

4.敌我坦克皆能移动和开关。

遇到的问题

屏幕闪烁问题

  1. 屏幕刷新时产生闪烁的原因

在MFC对话框上画图形,当需要显示新的图形或使原来的图形显示发生变化时,就需要刷新背景,也就是用背景颜色的画刷把背景重新刷一遍,这样就把原来的图形覆盖掉了,然后画上新图形,即可完成图形的刷新显示或动态显示。但是由于背景颜色(一般是白色)与图形颜色之间的反差,在不断的刷新、显示、刷新、显示过程中就会产生闪烁。这里要强调一下,闪烁本质上就是反差,反差越大,闪烁就越厉害。所以总结来说就是,当窗口由于任何原因需要重绘时,总是先用背景色将显示区清除,然后才调用OnPaint进行重绘,而背景色往往与绘图内容反差很大,这样在短时间内背景色与显示图形的交替出现,使得显示窗口看起来在闪。

  1. 双缓冲技术基本原理

我们知道在我们电脑中,屏幕中显示的东西都会被放在一个称为显示缓存的地方,在通常情况下我们只有一个这样的缓冲区,也就是单缓冲,在单缓冲中任何绘图的过程都会被立即显示在屏幕中,而所谓双缓冲就是再这个显示的缓冲区之外再建立一个不显示的缓冲区,我们所有的绘图都将在这个不显示的缓冲区中进行,只有当一帧都绘制完了之后才会被拷贝到真正的现实缓冲区显示出来,这样中间过程对于最终用户就是不可见的了,那即使是速度比较慢也只会出现停顿而不会有闪烁的现象出现。

  1. 解决思路
    定义一个与屏幕大小一致的图片
    获取图片的画笔
    使用图片画笔将元素绘制到图片中
    使用系统画笔将图片绘制到窗口中

长时间运行导致游戏卡顿的问题

  1. 导致游戏卡顿的原因
    子弹和爆炸效果绘制时会new一个Bullet对象和Explode对象保存在堆内存中,但是在子弹和爆炸效果消失时并没有从内存中销毁Bullet对象和Explode对象,导致随着游戏时间的增加堆内存中的垃圾数据越来越来,进而导致游戏卡顿。
  2. 解决思路
    设置子弹对象池和爆炸效果对象池,在类加载时将子弹对象和爆炸效果对象添加到容器中。需要用要绘制子弹时就从对象池中取出子弹,当子弹超出并不范围时,将该子弹归还到子弹对象池。爆炸效果对象池同理。

游戏界面

主菜单

游戏界面

项目结构

app包下的GameMain类是游戏的入口函数。img目录下存放游戏的静态资源。

tank包

该包下的类是tank的实体类,tank类分为我方坦克MyTank类、敌方坦克EnemyTank类。两个坦克类都继承了坦克父类tank类。

tank.class

/*** 坦克类的属性*/
public abstract class Tank {//坦克前进的四个方向public static final int DIR_UP = 0;public static final int DIR_DOWN = 1;public static final int DIR_LEFT = 2;public static final int DIR_RIGHT = 3;//坦克的半径public static final int RADIUS = 30;//默认速度public static final int DEFAULT_SPEED = 10;//坦克状态public static final int STATE_STAND = 0;public static final int STATE_MOVE = 1;public static final int STATE_DIE = 2;//坦克的初始生命值public static final int DEFAULT_HP = 1000;private int x, y;private int hp = DEFAULT_HP;private int atk;//攻击力private int speed = DEFAULT_SPEED;private int dir;//标识坦克的方向private int state = STATE_STAND;//标识坦克的状态private Color color;private boolean isEnemy = false;//标识是否是敌人get/set...}

tank类的方法

//使用ArrayList容器管理子弹private List<Bullet> bullets = new ArrayList();//使用ArrayList容器管理爆炸效果private List<Explode> explodes = new ArrayList<>();public Tank(int x, int y, int dir) {this.x = x;this.y = y;this.dir = dir;color = MyUtil.getRandomColor();}/*** 绘制坦克** @param g*/public void draw(Graphics g) {logic();//调用坦克逻辑处理方法,包括move方法drawTankImg(g);drawBullet(g);//调用绘制子弹的方法}/*** 使用图片的方法绘制坦克** @param g*/public abstract void drawTankImg(Graphics g);/*** 使用系统的方法绘制坦克** @param g*/private void drawTank(Graphics g) {g.setColor(color);//绘制坦克圆g.fillOval(x - RADIUS, y - RADIUS, RADIUS << 1, RADIUS << 1);//绘制坦克炮管//炮管的坐标int endX = x;int endY = y;switch (dir) {case DIR_UP:endY = y - RADIUS * 2;break;case DIR_DOWN:endY = y + RADIUS * 2;break;case DIR_LEFT:endX = x - RADIUS * 2;break;case DIR_RIGHT:endX = x + RADIUS * 2;break;}g.drawLine(x, y, endX, endY);}//坦克逻辑处理private void logic() {switch (state) {case STATE_STAND:break;case STATE_MOVE:move();break;case STATE_DIE:break;}}//坦克移动的功能private void move() {switch (dir) {case DIR_UP:y -= speed;if (y < RADIUS + GameFrame.titleBarH) {y = RADIUS + GameFrame.titleBarH;}break;case DIR_DOWN:y += speed;if (y > Constant.FRAME_HEIGHT - RADIUS - GameFrame.titleBarH) {y = Constant.FRAME_HEIGHT - RADIUS - GameFrame.titleBarH;}break;case DIR_LEFT:x -= speed;if (x < RADIUS) {x = RADIUS;}break;case DIR_RIGHT:x += speed;if (x > Constant.FRAME_WIDTH - RADIUS - GameFrame.titleBarH) {x = Constant.FRAME_WIDTH - RADIUS - GameFrame.titleBarH;}break;}}/*** 坦克发射炮弹的方法* 创建一个子弹实例,并将子弹加入到子弹容器中*/public void fire() {int bulletX = x;int bulletY = y;switch (dir) {case DIR_UP:bulletY -= RADIUS;break;case DIR_DOWN:bulletY += RADIUS;break;case DIR_LEFT:bulletX -= RADIUS;break;case DIR_RIGHT:bulletX += RADIUS;break;}
//        Bullet bullet = new Bullet(bulletX, bulletY, dir, atk, color);Bullet bullet = BulletPool.get();//从池塘中获取子弹bullet.setX(bulletX);bullet.setY(bulletY);bullet.setDir(dir);bullet.setAtk(atk);bullet.setColor(color);bullet.setVisible(true);bullets.add(bullet);}/*** 绘制出容器里的子弹** @param g*/private void drawBullet(Graphics g) {for (Bullet bullet : bullets) {bullet.draw(g);}//遍历所有子弹,并将超出frame的子弹还原到对象池for (int i = 0; i < bullets.size(); i++) {Bullet bullet = bullets.get(i);if (!bullet.isVisible()) {//如果当前子弹超出frame,则还原到对象池Bullet remove = bullets.remove(i);BulletPool.theReturn(remove);i--;}}}/*** 坦克与敌方子弹的碰撞检测** @param bullets*/public void collideBullet(List<Bullet> bullets) {//遍历集合的所有的子弹,依次进行碰撞检测for (Bullet bullet : bullets) {int bulletX = bullet.getX();int bulletY = bullet.getY();if (MyUtil.isCollide(x, y, RADIUS, bulletX, bulletY)) {//子弹消失bullet.setVisible(false);//添加爆炸效果Explode explode = ExplodePool.get();explode.setX(x + RADIUS * 2);explode.setY(y + RADIUS / 2);explode.setVisible(true);explode.setIndex(0);explodes.add(explode);}}}/*** 绘制当前坦克的爆炸效果** @param g*/public void drawExplodes(Graphics g) {for (Explode explode : explodes) {explode.draw(g);}for (int i = 0; i < explodes.size(); i++) {Explode explode = explodes.get(i);if (!explode.isVisible()) {Explode remove = explodes.remove(i);ExplodePool.theReturn(remove);i--;}}}

我方坦克MyTank.class

public class MyTank extends Tank {private static Image[] tankImg;static {tankImg = new Image[4];tankImg[0] = getImage("img/p1tankU.gif");tankImg[1] = getImage("img/p1tankD.gif");tankImg[2] = getImage("img/p1tankL.gif");tankImg[3] = getImage("img/p1tankR.gif");}public MyTank(int x, int y, int dir) {super(x, y, dir);}@Overridepublic void drawTankImg(Graphics g) {g.drawImage(tankImg[getDir()], getX() - RADIUS, getY() - RADIUS, null);}
}

敌方坦克EnemyTank.class

敌方坦克为电脑控制,有简单的AI,可自动移动开火。

public class EnemyTank extends Tank {private static Image[] enemyImg;static {enemyImg = new Image[4];enemyImg[0] = getImage("img/p2tankU.gif");enemyImg[1] = getImage("img/p2tankD.gif");enemyImg[2] = getImage("img/p2tankL.gif");enemyImg[3] = getImage("img/p2tankR.gif");}//记录ai开始运行的时间private long aiTime;public EnemyTank(int x, int y, int dir) {super(x, y, dir);//敌人一旦开始创建就计时aiTime = System.currentTimeMillis();}//创建一个敌人的坦克public static Tank createEnemy() {int x = MyUtil.getRandomNumber(0, 2) == 0 ? RADIUS : Constant.FRAME_WIDTH - GameFrame.titleBarH;int y = GameFrame.titleBarH + RADIUS;int dir = DIR_DOWN;Tank enemy = new EnemyTank(x, y, dir);enemy.setEnemy(true);enemy.setState(STATE_MOVE);return enemy;}public void drawTankImg(Graphics g) {ai();g.drawImage(enemyImg[getDir()], getX() - RADIUS, getY() - RADIUS, null);}/*** 敌人的AI*/private void ai() {//间隔五秒切换一个状态if (System.currentTimeMillis() - aiTime > Constant.ENEMY_AI_INTERVAL) {//五秒随机一个方向setDir(MyUtil.getRandomNumber(DIR_UP, DIR_RIGHT + 1));//五秒随机一个状态setState(MyUtil.getRandomNumber(0, 2) == 0 ? STATE_STAND : STATE_MOVE);//重新计时aiTime = System.currentTimeMillis();}//设置开火逻辑if (Math.random() < Constant.ENEMY_AI_PERCENT) {fire();}}
}

game包

game包下的类是关于绘制可视化图像,使用Graphics类绘制游戏窗口。

控制子弹效果 Bullet.class

/**** 控制子弹效果 */
public class Bullet {//子弹的默认速度是坦克的两倍private static final int DEFAULT_SPEED = Tank.DEFAULT_SPEED << 1;//子弹的半径private static final int RADIUS = 4;private int x, y;private int speed = DEFAULT_SPEED;private int dir;private int atk;private Color color;private boolean visible = true;//子弹是否可见,默认可见public Bullet(int x, int y, int dir, int atk, Color color) {this.x = x;this.y = y;this.dir = dir;this.atk = atk;this.color = color;}/*** 默认无参的构造方法,给对象池使用*/public Bullet() {}/*** 绘制炮弹的方法** @param g*/public void draw(Graphics g) {if (!visible) {return;}logic();g.setColor(color);g.fillOval(x - RADIUS, y - RADIUS, RADIUS << 1, RADIUS << 1);}/*** 炮弹的逻辑处理方法*/private void logic() {move();}/*** 炮弹的运动方法** @return*/private void move() {switch (dir) {case Tank.DIR_UP:y -= speed;if (y < 0) {visible = false;}break;case Tank.DIR_DOWN:y += speed;if (y > Constant.FRAME_HEIGHT) {visible = false;}break;case Tank.DIR_LEFT:x -= speed;if (x < 0) {visible = false;}break;case Tank.DIR_RIGHT:x += speed;if (x > Constant.FRAME_WIDTH) {visible = false;}break;}}
}

控制爆炸效果Explode.class

/*** 用于控制爆炸效果的类*/
public class Explode {//爆炸帧数的个数private static final int EXPLODE_FRAME_COUNT = 4;//爆炸图片private static Image[] boom_img;private static int explodeWidth;//爆炸图片的宽private static int explodeHeight;//爆炸图片的宽static {boom_img = new Image[EXPLODE_FRAME_COUNT];boom_img[0] = getImage("img/blast1.gif");boom_img[1] = getImage("img/blast2.gif");boom_img[2] = getImage("img/blast3.gif");boom_img[3] = getImage("img/blast4.gif");}//爆炸属性private int x, y;//坐标private int index;//当前图片帧数下标【0-3】private boolean visible = true;//是否可见public Explode(int x, int y) {this.x = x;this.y = y;index = 0;}public Explode() {index = 0;}//绘制爆炸效果public void draw(Graphics g) {if (explodeHeight <= 0) {explodeWidth = boom_img[0].getWidth(null);explodeHeight = boom_img[0].getHeight(null) >> 1;}if (!visible) {return;}g.drawImage(boom_img[index], x - explodeWidth, y - explodeHeight, null);index++;//播放到最后一帧,设置为不可见if (index >= EXPLODE_FRAME_COUNT) {visible = false;}}
}

游戏主窗口GameFrame.class

/*** 游戏主窗口*/
public class GameFrame extends Frame implements Runnable {/*** 双缓冲技术解决屏幕闪烁问题* 1.定义一个与屏幕大小一致的图片* 2.获取图片的画笔* 3.使用图片画笔将元素绘制到图片中* 4.使用系统画笔将图片绘制到窗口中*/private BufferedImage bufImg = new BufferedImage(FRAME_WIDTH, FRAME_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR);//游戏状态public static int gameState;//菜单指向private static int menuIndex;//定义坦克对象private Tank myTank;//定义敌人坦克private List<Tank> enemies = new ArrayList<>();//标题栏的高度public static int titleBarH;//对窗口进行初始化public GameFrame() {initFrame();initEventListener();//启动刷新窗口的线程new Thread(this).start();}//对游戏进行初始化public void initGame() {gameState = STATE_MENU;}//对窗口属性进行初始化private void initFrame() {setTitle(GAME_TITLE);//设置窗口可见setVisible(true);setSize(FRAME_WIDTH, FRAME_HEIGHT);setLocation(FRAME_X, FRAME_Y);setResizable(false);titleBarH = getInsets().top;}/*** 该方法负责绘制所有在屏幕中显示的内容,继承Frame类* 该方法不能主动调用,只能通过repaint方法回调该方法** @param graphics*/@Overridepublic void update(Graphics graphics) {//实例化图片画笔gGraphics g = bufImg.getGraphics();//使用画笔g绘制元素g.setFont(GAME_FONT);switch (gameState) {case STATE_MENU:drawMenu(g);break;case STATE_HELP:drawHelp(g);break;case STATE_ABOUT:drawAbout(g);break;case STATE_RUN:drawRun(g);break;case STATE_OVER:drawOver(g);break;}//使用系统画笔将bufImg绘制到frame中graphics.drawImage(bufImg, 0, 0, null);}private void drawOver(Graphics g) {}private void drawAbout(Graphics g) {}/*** 绘制游戏状态的内容** @param g*/private void drawRun(Graphics g) {//绘制背景g.setColor(Color.WHITE);g.fillRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT);//绘制敌方坦克drawEnemy(g);//绘制我方坦克myTank.draw(g);//绘制爆炸效果drawExplodes(g);//子弹与坦克的碰撞检测bulletCollideTank();}/*** 绘制敌人** @param g*/private void drawEnemy(Graphics g) {for (int i = 0; i < enemies.size(); i++) {Tank enemy = enemies.get(i);enemy.draw(g);}}private void drawHelp(Graphics g) {}/*** 绘制菜单的方法** @param g*/private void drawMenu(Graphics g) {//绘制背景g.setColor(Color.BLACK);g.fillRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT);//菜单栏行间距和选项宽度final int DIS = 50;final int STR_WIDTH = 76;//菜单栏坐标int x = FRAME_WIDTH - STR_WIDTH >> 1;int y = FRAME_HEIGHT / 3;for (int i = 0; i < MENUS.length; i++) {if (i == menuIndex) {g.setColor(Color.RED);} else {g.setColor(Color.WHITE);}g.drawString(MENUS[i], x, y + DIS * i);}}//初始化窗口事件监听private void initEventListener() {//注册窗口监听事件addWindowListener(new WindowAdapter() {//点击关闭按钮时该方法会被自动调用@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);//结束虚拟机}});//注册窗口监听事件addKeyListener(new KeyAdapter() {//监听按键被按下的事件@Overridepublic void keyPressed(KeyEvent e) {//捕获按下的键值int keyCode = e.getKeyCode();//不同的游戏状态给出不同的处理switch (gameState) {case STATE_MENU:keyPressedEventMenu(keyCode);break;case STATE_HELP:keyPressedEventHelp(keyCode);break;case STATE_ABOUT:keyPressedEventAbout(keyCode);break;case STATE_RUN:keyPressedEventRun(keyCode);break;case STATE_OVER:keyPressedEventOver(keyCode);break;}}//监听按键被松开的事件@Overridepublic void keyReleased(KeyEvent e) {//捕获按下的键值int keyCode = e.getKeyCode();if (gameState == STATE_RUN) {keyReleasedEventRun(keyCode);}}});}//按键松开时,游戏处理的方法private void keyReleasedEventRun(int keyCode) {switch (keyCode) {case KeyEvent.VK_UP:case KeyEvent.VK_W:case KeyEvent.VK_DOWN:case KeyEvent.VK_S:case KeyEvent.VK_LEFT:case KeyEvent.VK_A:case KeyEvent.VK_RIGHT:case KeyEvent.VK_D:myTank.setState(Tank.STATE_STAND);break;}}private void keyPressedEventOver(int keyCode) {}private void keyPressedEventHelp(int keyCode) {}/*** 游戏进行中的按键处理** @param keyCode*/private void keyPressedEventRun(int keyCode) {switch (keyCode) {case KeyEvent.VK_UP:case KeyEvent.VK_W:myTank.setDir(Tank.DIR_UP);myTank.setState(Tank.STATE_MOVE);break;case KeyEvent.VK_DOWN:case KeyEvent.VK_S:myTank.setDir(Tank.DIR_DOWN);myTank.setState(Tank.STATE_MOVE);break;case KeyEvent.VK_LEFT:case KeyEvent.VK_A:myTank.setDir(Tank.DIR_LEFT);myTank.setState(Tank.STATE_MOVE);break;case KeyEvent.VK_RIGHT:case KeyEvent.VK_D:myTank.setDir(Tank.DIR_RIGHT);myTank.setState(Tank.STATE_MOVE);break;case KeyEvent.VK_SPACE:myTank.fire();break;}}private void keyPressedEventAbout(int keyCode) {}//菜单状态下的按键处理private void keyPressedEventMenu(int keyCode) {switch (keyCode) {case KeyEvent.VK_UP:case KeyEvent.VK_W:menuIndex--;if (menuIndex < 0) {menuIndex = MENUS.length - 1;}break;case KeyEvent.VK_DOWN:case KeyEvent.VK_S:menuIndex++;if (menuIndex > MENUS.length - 1) {menuIndex = 0;}break;case KeyEvent.VK_ENTER://TODOnewGame();break;}}private void newGame() {gameState = STATE_RUN;//创建坦克对象myTank = new MyTank(400, 200, Tank.DIR_DOWN);//生产敌方坦克的线程new Thread() {@Overridepublic void run() {while (true) {if (enemies.size() < ENEMY_MAX_COUNT) {Tank enemy = EnemyTank.createEnemy();enemies.add(enemy);}try {Thread.sleep(ENEMY_BORN_INTERVAL);} catch (InterruptedException e) {e.printStackTrace();}}}}.start();}@Overridepublic void run() {while (true) {repaint();try {Thread.sleep(REPAINT_INTERVAL);} catch (InterruptedException e) {e.printStackTrace();}}}/*** 碰撞检测*/private void bulletCollideTank() {//我方子弹与所有敌人的碰撞检测for (Tank enemy : enemies) {enemy.collideBullet(myTank.getBullets());}//敌坦克与我方子弹碰撞for (Tank enemy : enemies) {myTank.collideBullet(enemy.getBullets());}}/*** 绘制坦克效果** @param g*/private void drawExplodes(Graphics g) {//绘制敌方坦克for (Tank enemy : enemies) {enemy.drawExplodes(g);}//绘制我方坦克myTank.drawExplodes(g);}
}

utils包

该包下有工具类、爆炸对象池、子弹对象池、游戏常量对象

工具类MyUtil.class

/*
* 工具类
* */
public class MyUtil {private MyUtil() {}//构造方法私有化,将该类进行封装/*** 得到指定区间的随机数** @param min* @param max* @return*/public static final int getRandomNumber(int min, int max) {return (int) (Math.random() * (max - min) + min);}/*** 获取随机颜色** @return*/public static final Color getRandomColor() {int red = getRandomNumber(0, 256);int green = getRandomNumber(0, 256);int blue = getRandomNumber(0, 256);return new Color(red, green, blue);}/*** 获取图片对象** @param image_path* @return*/public static Image getImage(String image_path) {ImageIcon imageIcon = new ImageIcon(MyUtil.class.getClassLoader().getResource(image_path));return imageIcon.getImage();}/*** 求坦克和子弹是否碰撞** @param rectX  坦克的坐标* @param rectY* @param radius 坦克的边长* @param pointX 子弹的坐标* @param pointY* @return*/public static final boolean isCollide(int rectX, int rectY, int radius, int pointX, int pointY) {//坦克中心点和子弹的xy轴距离int disX = Math.abs(rectX - pointX);int disY = Math.abs(rectY - pointY);if (disX < radius && disY < radius) {return true;}return false;}}

爆炸效果对象池

/***爆炸效果对象池*/
public class ExplodePool {//默认的爆炸效果数量public static final int DEFAULT_POOL_SIZE = 200;//最大爆炸效果容量public static final int POOL_MAX_SIZE = 300;//用于保存所有爆炸的对象池private static List<Explode> pool = new ArrayList<>();//在类加载时将爆炸效果对象添加到容器中static {for (int i = 0; i < DEFAULT_POOL_SIZE; i++) {pool.add(new Explode());}}/*** 从爆炸效果对象池中取出一颗爆炸效果** @return*/public static Explode get() {Explode explode = null;//当对对象池中无爆炸效果时,new一个新的爆炸效果对象if (pool.size() == 0) {explode = new Explode();} else {explode = pool.remove(0);}return explode;}/*** 当爆炸效果被销毁时,归还爆炸效果** @param*/public static void theReturn(Explode explode) {if (pool.size() == POOL_MAX_SIZE) {return;}pool.add(explode);}
}

子弹对象池

/*** 子弹对象池*/
public class BulletPool {//默认的子弹数量public static final int DEFAULT_POOL_SIZE = 200;//最大子弹容量public static final int POOL_MAX_SIZE = 300;//用于保存所有子弹的对象池private static List<Bullet> pool = new ArrayList<>();//在类加载时将子弹对象添加到容器中static {for (int i = 0; i < DEFAULT_POOL_SIZE; i++) {pool.add(new Bullet());}}/*** 从子弹对象池中取出一颗子弹** @return*/public static Bullet get() {Bullet bullet = null;//当对对象池中无子弹时,new一个新的子弹对象if (pool.size() == 0) {bullet = new Bullet();} else {bullet = pool.remove(0);}return bullet;}/*** 当子弹被销毁时,归还子弹** @param bullet*/public static void theReturn(Bullet bullet) {if (pool.size() == POOL_MAX_SIZE) {return;}pool.add(bullet);}
}

游戏常量类

/*** 游戏常量类*/
public class Constant {/****************游戏窗口相关属性*********************/public static final String GAME_TITLE = "坦克大战";public static final int FRAME_WIDTH = 1000;public static final int FRAME_HEIGHT = 900;//获取系统屏幕的宽高public static final int SCREEN_W = Toolkit.getDefaultToolkit().getScreenSize().width;public static final int SCREEN_H = Toolkit.getDefaultToolkit().getScreenSize().height;//游戏窗口顶点坐标public static final int FRAME_X = SCREEN_W - FRAME_WIDTH >> 1;public static final int FRAME_Y = SCREEN_H - FRAME_HEIGHT >> 1;/****************游戏菜单相关属性********************************/public static final int STATE_MENU = 0;public static final int STATE_HELP = 1;public static final int STATE_ABOUT = 2;public static final int STATE_RUN = 3;public static final int STATE_OVER = 4;public static final String[] MENUS = {"开始游戏","继续游戏","游戏帮助","游戏相关","退出游戏"};public static final Font GAME_FONT = new Font("宋体", Font.BOLD, 24);//窗口刷新间隔public static final int REPAINT_INTERVAL = 30;//最大敌人数量public static final int ENEMY_MAX_COUNT = 10;//敌方坦克生产间隔public static final int ENEMY_BORN_INTERVAL = 5000;//敌方坦克状态切换的间隔public static final int ENEMY_AI_INTERVAL = 1000;//敌方坦克每帧发射子弹的概率public static final double ENEMY_AI_PERCENT = 0.10;
}
Size().width;public static final int SCREEN_H = Toolkit.getDefaultToolkit().getScreenSize().height;//游戏窗口顶点坐标public static final int FRAME_X = SCREEN_W - FRAME_WIDTH >> 1;public static final int FRAME_Y = SCREEN_H - FRAME_HEIGHT >> 1;/****************游戏菜单相关属性********************************/public static final int STATE_MENU = 0;public static final int STATE_HELP = 1;public static final int STATE_ABOUT = 2;public static final int STATE_RUN = 3;public static final int STATE_OVER = 4;public static final String[] MENUS = {"开始游戏","继续游戏","游戏帮助","游戏相关","退出游戏"};public static final Font GAME_FONT = new Font("宋体", Font.BOLD, 24);//窗口刷新间隔public static final int REPAINT_INTERVAL = 30;//最大敌人数量public static final int ENEMY_MAX_COUNT = 10;//敌方坦克生产间隔public static final int ENEMY_BORN_INTERVAL = 5000;//敌方坦克状态切换的间隔public static final int ENEMY_AI_INTERVAL = 1000;//敌方坦克每帧发射子弹的概率public static final double ENEMY_AI_PERCENT = 0.10;
}

Java实现坦克大战小游戏相关推荐

  1. 【JAVA程序设计】基于JAVA的坦克大战小游戏--入门级小游戏

    基于JAVA的坦克大战小游戏--入门级小游戏 零.项目获取 一.项目简介 二.开发环境 三.游戏玩法 四.运行截图 零.项目获取 获取方式(点击下载):是云猿实战 项目经过多人测试运行,可以确保100 ...

  2. JAVA开发坦克大战小游戏个人实战笔记

    1.认识frame类 a.这是一个窗口类 b.常用方法 setSize();## 标题//设置大小 setVisible();//显示窗口 setTitle();//设置标题 setResizable ...

  3. Java实现的经典坦克大战小游戏

    Java实现的经典坦克大战小游戏 先看一下游戏结构: 有点多,没有耐心的可以不用看,这里先给出链接吧! 云链接:经典坦克大战 提取码:s9ai 这里就不介绍功能了,贴了一张游戏运行的截图,具体的功能自 ...

  4. 【Java】Java基础飞机大战小游戏完整代码

    Java基础飞机大战小游戏完整代码 先来展示一下代码实现结果图 主函数ShootGame 初始化游戏原始背景图片,游戏人物图片,游戏开始结束图片:构建产生敌人算法:产生英雄机算法:发射子弹算法:判断是 ...

  5. html实现经典坦克大战小游戏

    文章目录 1.设计来源 1.1 游戏主界面 1.2 游戏界面 2.效果和源码 2.1 动态效果 2.2 源代码 源码下载 作者:xcLeigh 文章地址:https://blog.csdn.net/w ...

  6. C++实用编程——坦克大战小游戏

    C++实用编程--坦克大战小游戏 Warning: 转载类 原文地址:*HTML https://yq.aliyun.com/articles/683666 改变速度的玩意坏了 我们直接看代码吧,适于 ...

  7. 【180930】坦克大战小游戏源码

    坦克大战小游戏源码程序实现了小霸王游戏机上坦克大战的功能,主要功能是开火.移动.3种不同的敌方坦克.用户自制地图等,缺点是有些小细节还处理的不好,感觉画面不够好,还没实现自动的下一关功能(主要是嫌做默 ...

  8. canvas+js实现简单的坦克大战小游戏

    使用canvas和js实现经典的坦克大战并不难,坦克和炮弹的绘制可以使用canvas的里API画出,而坦克的移动和炮弹的发射可以依赖于键盘事件和定时器来实现. 在这里我要实现的坦克大战是双人模式,有木 ...

  9. 一小时制作java坦克大战小游戏

    <坦克大战>是由日本南梦宫Namco游戏公司开发的一款平面射击游戏,于1985年发售.游戏以坦克战斗及保卫基地为主题,属于策略型联机类. 同时也是FC平台上少有的内建关卡编辑器的几个游戏之 ...

  10. java实现飞机大战小游戏——————【附素材、源码、逐行注释讲解】

    java飞机小游戏,实现了以下功能: 1.我方小飞机可以通过鼠标移动来控制. 2.蜜蜂(必须打死而不是碰到,并且碰到蜜蜂会失去生命值)分为两种奖励 获得生命值或者子弹翻3倍. 3.当鼠标移动到界面外可 ...

最新文章

  1. Css的filter常用滤波器属性及语句大全
  2. [YTU]_2440( C++习题 复数类--重载运算符+,-,*,/)
  3. 【Chocolatey】查找包
  4. ubuntu查看node的安装目录_ubuntu安装nfs服务实现共享目录
  5. 进程间通信————无名管道
  6. 院士发言:有高校博士后待遇比国际平均水平高出一倍,这不正常!
  7. JavaScript模态对话框类(拖拽时动画)
  8. hdl四位二进制计数器_四位二进制加法计数器
  9. JavaScript性能优化【下】--性能优化的具体方式
  10. NB-IoT---(0) NB-IoT技术
  11. python单链表实现具体例子_python中单链表的实现
  12. jQuery按键监听(模拟QQ聊天:按下回车键发送消息)
  13. 橘子皮巧治咳嗽痰多 泡茶喝-转
  14. Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.8.2:deploy
  15. 小学身高体重测试软件,学生测量身高体重秤,小学体检秤
  16. 笔趣看小说Python3爬虫抓取
  17. 多台显示器图像拼接组成大屏幕是怎么实现的?
  18. English improvement of IT Test(2014)
  19. 【selenium-python】显式等待和隐式等待的使用和区别
  20. 工作一周随笔记———一个即将踏入编程的少年

热门文章

  1. python自学篇——PyGame模块的所有功能函数详解
  2. 在指定字符串后面插入字符串
  3. 手把手教你开发App(HelloWorld)
  4. 山西大同大学教务处教师端——可在PC端,手机端操作
  5. php cookie 注入,LiveZilla 'setCookieValue()'函数PHP对象注入漏洞
  6. 递归解决卖桃子问题java
  7. word2010中设置页码起始页从任意一页开始
  8. 好看简约加速器官网源码
  9. 三重积分平均值_质心计算
  10. Discuz发帖如何设置默认回帖仅作者可见回帖