这是上篇飞机大战全部思路及源码的链接
——————————————————————————————————————
这篇东西主要是补充说明上一篇中我画布类中的方法,以及我在做的时候碰到的一些bug。
public class GamePanel extends JPanel {
BufferedImage bg = null;
// new英雄机对象
hero hero = new hero();
// new敌机对象
// Ep ep = new Ep();
// 建立敌机集合 不使用数组做容器是因为敌机数量未知,建立数组先要定义数组长度
List<Ep> eps = new ArrayList<Ep>();
// 建立子弹的弹药库
List<Fire> fs = new ArrayList<Fire>();
// 定义分数
int socre;
boolean gameover;// 设置开关
int power = 1;// 火力值
/*
* 开始游戏的方法 建立一个线程
*/
public void action() {
new Thread() {
public void run() {
while (true) {
// if语句判断是否gameover
if (!gameover) {
epEnter();// 敌机进场
epMove();
// 发射子弹
shoot();
// 子弹移动
fireMove();
shootEp();
hit();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
repaint();// 刷新界面
}
}
/*
* 检测子弹是否打到敌机
*/
public void shootEp() {
// 遍历所有子弹
for (int i = 0; i < fs.size(); i++) {
Fire f = fs.get(i);
bang(f);
}
}
/*
* 判断子弹是否击中敌机
*/
private void bang(Fire f) {
for (int i = 0; i < eps.size(); i++) {
Ep e = eps.get(i);
if (e.shootBy(f)) {
e.hp--;
// 当敌机没hp,死亡
if (e.hp <= 0) {
if (e.type == 12) {
power++;
if (power > 3) {
hero.hp++;
power = 3;
}
}
eps.remove(e);// 移除敌机
fs.remove(f);// 移除子弹
}
// 增加分数
socre += 10;
if(socre%1000==0) {
Random rd = new Random();
int index = rd.nextInt(5) + 1;
bg = ImageUtil.getImage("/img/bg" + index + ".jpg");
repaint();// 刷新界面
hero.hp++;
}
}
}
}
}.start();
}
/**
* 检测敌机是否撞到了英雄机
*/
protected void hit() {
// 遍历敌机
for (int i = 0; i < eps.size(); i++) {
// 获取一个敌机
Ep e = eps.get(i);
// 如果敌机被英雄机撞上了
if (e.hitBy(hero)) {
// 1.删除敌机
eps.remove(e);
// 2.英雄机的血量减少
hero.hp--;
// 英雄机的火力恢复为1
power = 1;
// 3.增加分数
socre += 10;
// 4.当英雄机的血量减少到0时,游戏结束
if (hero.hp <= 0) {
// 游戏结束
gameover = true;
}
}
}
}
public void fireMove() {
for (int i = 0; i < fs.size(); i++) {
Fire f = fs.get(i);
f.move();
}
}
// 发射子弹
int fireindax = 0;// 记录执行的次数
public void shoot() {
fireindax++;
if (fireindax >= 10) {
if (power == 1) {
// 创建子弹
Fire fire3 = new Fire(hero.x + 45, hero.y - 20, 1);
// 将子弹加入到弹药库
fs.add(fire3);
} else if (power == 2) {
// 创建子弹
Fire fire1 = new Fire(hero.x + 15, hero.y, 1);
// 将子弹加入到弹药库
fs.add(fire1);
// 创建子弹
Fire fire2 = new Fire(hero.x + 75, hero.y, 1);
// 将子弹加入到弹药库
fs.add(fire2);
} else if (power == 3) {
// 创建子弹
Fire fire1 = new Fire(hero.x + 15, hero.y, 0);
// 将子弹加入到弹药库
fs.add(fire1);
// 创建子弹
Fire fire2 = new Fire(hero.x + 75, hero.y, 2);
// 将子弹加入到弹药库
fs.add(fire2);
// 创建子弹
Fire fire3 = new Fire(hero.x + 45, hero.y - 20, 1);
// 将子弹加入到弹药库
fs.add(fire3);
}
fireindax = 0;// 计算器
}
}
public void epMove() {
for (int i = 0; i < eps.size(); i++) {
Ep e = eps.get(i);
e.move();
}
}
/*
* 敌机入场方法 该方法在死循环中一直调用
*/
int indax = 0;
public void epEnter() {
indax++;
if (indax >= 20) {
Ep e = new Ep();
eps.add(e);// 把敌机不断加入到集合里面
indax = 0;
}
}
public GamePanel(GameFrame frame) {
setBackground(Color.BLACK);
bg = ImageUtil.getImage("/img/bg2.jpg");
// 使用鼠标监听器
// 1创建鼠标监听器
MouseAdapter md = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// 点击鼠标时,会执行的代码
// 如果游戏结束了,点击屏幕时重新开始游戏
if (gameover) {
// 重新开始游戏
// 需要做些什么事情?
// 重新创建一个英雄机
hero = new hero();
// 重置游戏开关
gameover = false;
// 分数清0
socre = 0;
eps.clear();// 清空敌机集合
fs.clear();// 清空子弹集合
// 随机背景图
Random rd = new Random();
int index = rd.nextInt(5) + 1;
bg = ImageUtil.getImage("/img/bg" + index + ".jpg");
repaint();
}
}
// 2确定鼠标监听事件
@Override
public void mouseMoved(MouseEvent e) {
int mX = e.getX();
int mY = e.getY();
// 判断游戏是否结束,结束则不能移动
if (!gameover) {
hero.MovetoMouse(mX, mY);
}
repaint();// 刷新界面
}
};
// 将适配器加到监听器中
addMouseListener(md);
addMouseMotionListener(md);
// ------------------------------------------
// 使用键盘监听器
// KeyAdapter kd = new KeyAdapter() {
// @Override
// public void keyPressed(KeyEvent e) {
// int KeyCode = e.getKeyCode();
// if (KeyCode == KeyEvent.VK_UP || KeyCode == KeyEvent.VK_W) {
// hero.MoveUp();
// repaint();// 刷新界面
// } else if (KeyCode == KeyEvent.VK_DOWN || KeyCode == KeyEvent.VK_S) {
// hero.MoveDown();
// repaint();// 刷新界面
// } else if (KeyCode == KeyEvent.VK_LEFT || KeyCode == KeyEvent.VK_A) {
// hero.MoveLeft();
// repaint();// 刷新界面
// } else if (KeyCode == KeyEvent.VK_RIGHT || KeyCode == KeyEvent.VK_D) {
// hero.MoveRight();
// repaint();// 刷新界面
// }
// }
// };
// frame.addKeyListener(kd);// 键盘适配器要加到窗体监听器
}
@Override
public void paint(Graphics g) {
super.paint(g);
// draw有先后顺序,先画会被后画覆盖
g.drawImage(bg, 0, 0, null);
g.drawImage(hero.img, hero.x, hero.y, hero.w, hero.h, null);
// 遍历集合里面的所有敌机并显示出来
for (int i = 0; i < eps.size(); i++) {
Ep ep = eps.get(i);
g.drawImage(ep.img, ep.x, ep.y, ep.w, ep.h, null);
}
// 遍历集合里面的所有子弹并显示出来
for (int i = 0; i < fs.size(); i++) {
Fire fire = fs.get(i);
g.drawImage(fire.img, fire.x, fire.y, fire.w, fire.h, null);
}
// 画分数
g.setColor(Color.white);
g.setFont(new Font("楷体", Font.BOLD, 20));
g.drawString("分数: " + socre, 10, 30);
// 画英雄机的血量
for (int i = 0; i < hero.hp; i++) {
g.drawImage(hero.img, 470, 5+ i * 30, 30, 30, null);
}
// 当游戏结束时,显示Gameover
if (gameover) {
g.setColor(Color.red);
g.setFont(new Font("楷体", Font.BOLD, 35));
g.drawString("GAMEOVER!", 35, 300);
g.setColor(Color.green);
g.setFont(new Font("楷体", Font.BOLD, 20));
g.drawString("提醒你点击屏幕重新开始游戏", 40, 350);
}
}
}
代码从上而下说明
开启线程,让多个敌机多个子弹得以同时进场,用死循环让方法能一直被调用。
public void action() {
new Thread() {
public void run() {
while (true) {
// if语句判断是否gameover
if (!gameover) {
epEnter();// 敌机进场
epMove();
// 发射子弹
shoot();
// 子弹移动
fireMove();
shootEp();
hit();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
repaint();// 刷新界面
}
}
————————————————————————————————
射击方法,从集合中遍历所有子弹,再执行bang()方法判断子弹是否击中敌机并执行血量减少,分数增加等操作。
public void shootEp() {
// 遍历所有子弹
for (int i = 0; i < fs.size(); i++) {
Fire f = fs.get(i);
bang(f);
}
}
/*
* 判断子弹是否击中敌机
*/
private void bang(Fire f) {
for (int i = 0; i < eps.size(); i++) {
Ep e = eps.get(i);
if (e.shootBy(f)) {
e.hp--;
// 当敌机没hp,死亡
if (e.hp <= 0) {
if (e.type == 12) {
power++;
if (power > 3) {
hero.hp++;
power = 3;
}
}
eps.remove(e);// 移除敌机
fs.remove(f);// 移除子弹
}
// 增加分数
socre += 10;
if(socre%1000==0) {
Random rd = new Random();
int index = rd.nextInt(5) + 1;
bg = ImageUtil.getImage("/img/bg" + index + ".jpg");
repaint();// 刷新界面
hero.hp++;
}
}
}
}
————————————————————————————————
该方法用于判断敌机是否撞到战机,碰撞后敌机与战机属性的一系列变化。
/**
* 检测敌机是否撞到了英雄机
*/
protected void hit() {
// 遍历敌机
for (int i = 0; i < eps.size(); i++) {
// 获取一个敌机
Ep e = eps.get(i);
// 如果敌机被英雄机撞上了
if (e.hitBy(hero)) {
// 1.删除敌机
eps.remove(e);
// 2.英雄机的血量减少
hero.hp--;
// 英雄机的火力恢复为1
power = 1;
// 3.增加分数
socre += 10;
// 4.当英雄机的血量减少到0时,游戏结束
if (hero.hp <= 0) {
// 游戏结束
gameover = true;
}
}
}
}
————————————————————————————————
该方法遍历集合中的所有子弹,并调用Fire类的move()方法进行子弹的移动。
public void fireMove() {
for (int i = 0; i < fs.size(); i++) {
Fire f = fs.get(i);
f.move();
}
}
该方法遍历集合中的所有敌机,并调用Ep类中的move()方法进行移动
public void epMove() {
for (int i = 0; i < eps.size(); i++) {
Ep e = eps.get(i);
e.move();
}
}
————————————————————————————————
这是一个定义射击的方法,定义战机不同火力的子弹情况,计数器减缓子弹的出现速度,将子弹加入到集合中。
// 发射子弹
int fireindax = 0;// 记录执行的次数
public void shoot() {
fireindax++;
if (fireindax >= 10) {
if (power == 1) {
// 创建子弹
Fire fire3 = new Fire(hero.x + 45, hero.y - 20, 1);
// 将子弹加入到弹药库
fs.add(fire3);
} else if (power == 2) {
// 创建子弹
Fire fire1 = new Fire(hero.x + 15, hero.y, 1);
// 将子弹加入到弹药库
fs.add(fire1);
// 创建子弹
Fire fire2 = new Fire(hero.x + 75, hero.y, 1);
// 将子弹加入到弹药库
fs.add(fire2);
} else if (power == 3) {
// 创建子弹
Fire fire1 = new Fire(hero.x + 15, hero.y, 0);
// 将子弹加入到弹药库
fs.add(fire1);
// 创建子弹
Fire fire2 = new Fire(hero.x + 75, hero.y, 2);
// 将子弹加入到弹药库
fs.add(fire2);
// 创建子弹
Fire fire3 = new Fire(hero.x + 45, hero.y - 20, 1);
// 将子弹加入到弹药库
fs.add(fire3);
}
fireindax = 0;// 计数器
}
}
————————————————————————————————
该方法与上一个方法作用一致,
/*
* 敌机入场方法 该方法在死循环中一直调用
*/
int indax = 0;
public void epEnter() {
indax++;
if (indax >= 20) {
Ep e = new Ep();
eps.add(e);// 把敌机不断加入到集合里面
indax = 0;
}
}
————————————————————————————————
该方法用于定义背景,清空背景等操作
public GamePanel(GameFrame frame) {
setBackground(Color.BLACK);
bg = ImageUtil.getImage("/img/bg2.jpg");
// 使用鼠标监听器
// 1创建鼠标监听器
MouseAdapter md = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// 点击鼠标时,会执行的代码
// 如果游戏结束了,点击屏幕时重新开始游戏
if (gameover) {
// 重新开始游戏
// 需要做些什么事情?
// 重新创建一个英雄机
hero = new hero();
// 重置游戏开关
gameover = false;
// 分数清0
socre = 0;
eps.clear();// 清空敌机集合
fs.clear();// 清空子弹集合
// 随机背景图
Random rd = new Random();
int index = rd.nextInt(5) + 1;
bg = ImageUtil.getImage("/img/bg" + index + ".jpg");
repaint();
}
}
————————————————————————————————
这是定义鼠标或者键盘监听的方法
// 2确定鼠标监听事件
@Override
public void mouseMoved(MouseEvent e) {
int mX = e.getX();
int mY = e.getY();
// 判断游戏是否结束,结束则不能移动
if (!gameover) {
hero.MovetoMouse(mX, mY);
}
repaint();// 刷新界面
}
};
// 将适配器加到监听器中
addMouseListener(md);
addMouseMotionListener(md);
// ------------------------------------------
// 使用键盘监听器
// KeyAdapter kd = new KeyAdapter() {
// @Override
// public void keyPressed(KeyEvent e) {
// int KeyCode = e.getKeyCode();
// if (KeyCode == KeyEvent.VK_UP || KeyCode == KeyEvent.VK_W) {
// hero.MoveUp();
// repaint();// 刷新界面
// } else if (KeyCode == KeyEvent.VK_DOWN || KeyCode == KeyEvent.VK_S) {
// hero.MoveDown();
// repaint();// 刷新界面
// } else if (KeyCode == KeyEvent.VK_LEFT || KeyCode == KeyEvent.VK_A) {
// hero.MoveLeft();
// repaint();// 刷新界面
// } else if (KeyCode == KeyEvent.VK_RIGHT || KeyCode == KeyEvent.VK_D) {
// hero.MoveRight();
// repaint();// 刷新界面
// }
// }
// };
// frame.addKeyListener(kd);// 键盘适配器要加到窗体监听器
}
————————————————————————————————
该方法用于在背景上显示出飞行物和一些其他内容
@Override
public void paint(Graphics g) {
super.paint(g);
// draw有先后顺序,先画会被后画覆盖
g.drawImage(bg, 0, 0, null);
g.drawImage(hero.img, hero.x, hero.y, hero.w, hero.h, null);
// 遍历集合里面的所有敌机并显示出来
for (int i = 0; i < eps.size(); i++) {
Ep ep = eps.get(i);
g.drawImage(ep.img, ep.x, ep.y, ep.w, ep.h, null);
}
// 遍历集合里面的所有子弹并显示出来
for (int i = 0; i < fs.size(); i++) {
Fire fire = fs.get(i);
g.drawImage(fire.img, fire.x, fire.y, fire.w, fire.h, null);
}
// 画分数
g.setColor(Color.white);
g.setFont(new Font("楷体", Font.BOLD, 20));
g.drawString("分数: " + socre, 10, 30);
// 画英雄机的血量
for (int i = 0; i < hero.hp; i++) {
g.drawImage(hero.img, 470, 5+ i * 30, 30, 30, null);
}
// 当游戏结束时,显示Gameover
if (gameover) {
g.setColor(Color.red);
g.setFont(new Font("楷体", Font.BOLD, 35));
g.drawString("GAMEOVER!", 35, 300);
g.setColor(Color.green);
g.setFont(new Font("楷体", Font.BOLD, 20));
g.drawString("提醒你点击屏幕重新开始游戏", 40, 350);
}
}
————————————————————————————————