在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学完J2SE的小伙伴们一点启示!
坦克大战效果图:
坦克大战V0.7图片版实现功能:
1、将方向定义为一个Enum类写在一个文件里,修正坦克子弹的颜色
2、加入坦克、子弹、爆炸的图片
3、添加配置文件,并导出可运行的jar包
注意事项:
1、ProperMrg类中props.load(ProperMgr.class.getClassLoader().getResourceAsStream("config/tank.properties"));的解释:
(1)得到ProperMgr这个类编译后的class文件(ProperMgr.class)
(2)得到类装载器(getClassLoader())
(3)通过装载器得到源文件("config/tank.properties")的Stream(getResourceAsStream())
(4)加载(load)源文件
2、Tank类中获取图片tk.getImage(Tank.class.getClassLoader().getResource("images/tankL.gif"))的解释:
(1)Tank.class.getClassLoader()得到某个类(Tank)的装载器
(2)再获取文件getResource("文件路径")
(3)这样既不是绝对路径也不是相对路径,文件路径是根据装载器来获取相应的路径的。不用担心文件被移动后的路径问题(所有的文件最终会被编译到bin目录下)
坦克大战V0.7图片版源代码:
包com.exjava.tankWar中含有的类
TankClient类:
package com.exjava.tankWar;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.List; //java.awt包中也有个List,所以此处要导包明确
import java.util.ArrayList;
import java.util.Properties;
/**
* 主要的类
* @ClassName: TankClient
* @Description: 坦克,子弹,爆炸,血块都在这里实例化
* @author oldinaction
* @date 2014年9月2日 下午4:15:44
*/
public class TankClient extends Frame {
public static final int GAME_WIDTH = 800;
public static final int GAME_HEIGHT = 600;
Tank myTank = new Tank(350, 520, true, Direction.STOP, this); //我方坦克
Wall w1 = new Wall(100, 300, 20, 100, this), w2 = new Wall(300, 250, 150, 20, this);
Blood b = new Blood(this);
List missiles = new ArrayList(); //定义一个集合来装子弹
List explodes = new ArrayList();
List tanks = new ArrayList();
Image offScreenImage = null; //定义一个屏幕后的虚拟图片
@Override
public void paint(Graphics g) {
if (tanks.size() <= 0) {
for(int i = 0; i < Integer.parseInt(ProperMgr.getProperty("reProduceTank")); i++) {
tanks.add(new Tank(50 + 40*(i+1), 50, false, Direction.D, this));
}
}
g.drawString("missiles Count: " + missiles.size(), 10, 50); //用来记录missiles中子弹的个数
g.drawString("explodes Count: " + explodes.size(), 10, 70);
g.drawString("tanks Count: " + tanks.size(), 10, 90);
g.drawString("myTank life: " + myTank.getLife(), 10, 110);
for (int i = 0; i < missiles.size(); i++) { //遍历集合,把其中的子弹画出来
Missile m = missiles.get(i);
m.hitTanks(tanks);
m.hitTank(myTank);
m.hitWall(w1); //检测子弹是否撞墙
m.hitWall(w2);
m.drawMissile(g);
}
for (int i = 0; i < explodes.size(); i++) {
Explode e = explodes.get(i);
e.draw(g);
}
for (int i = 0; i < tanks.size(); i++) {
Tank t = tanks.get(i);
t.collidesWithWall(w1); //检测敌方坦克是否撞墙
t.collidesWithWall(w2);
t.collidesWithTanks(tanks);
t.drawTank(g);
}
myTank.drawTank(g);
myTank.eat(b);
w1.draw(g);
w2.draw(g);
b.draw(g);
}
//利用双缓冲消除圆圈移动时屏幕的闪动
@Override
public void update(Graphics g) {
if (offScreenImage == null) {
offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT); //判断是为了避免每次重画时都给offScreenImage赋值
}
Graphics gOffScreen = offScreenImage.getGraphics(); //定义虚拟图片上的画笔gOffScreen
Color c = gOffScreen.getColor();
gOffScreen.setColor(Color.BLACK);
gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT); //重画背景,如果没有这句则在屏幕上会保留圆圈的移动路径
gOffScreen.setColor(c);
paint(gOffScreen); //把圆圈画到虚拟图片上
g.drawImage(offScreenImage, 0, 0, null); //再一次性把虚拟图片画到真实屏幕上,在真实屏幕上画则要用真实屏幕的画笔g
}
public void luanchFrame() {
int initTankCount = Integer.parseInt(ProperMgr.getProperty("initTankCount"));
for(int i = 0; i < initTankCount; i++) {
tanks.add(new Tank(50 + 40*(i+1), 50, false, Direction.D, this));
}
this.setLocation(300, 50);
this.setSize(GAME_WIDTH, GAME_HEIGHT);
this.setTitle("坦克大战 - 游戏还存在Bug,欢迎大家试玩! - 帮助(复活:F2;放弹:1键;超级炮弹:空格) - By:小易 - QQ:381740148");
this.setResizable(false); //不允许改变窗口大小
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}); //添加关闭功能,此处使用匿名类比较合适
this.setBackground(Color.BLACK);
this.addKeyListener(new KeyMonitor());
setVisible(true);
new Thread(new PaintThread()).start(); //启动线程,实例化线程对象时不要忘了new Thread(Runnable对象);
}
public static void main(String[] args) {
TankClient tc = new TankClient();
tc.luanchFrame();
}
//PaintThread只为TankClient服务,所以写成内部类好些
public class PaintThread implements Runnable {
public void run()