/***********************PlaneCilent***************************/
package plane;

import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* 游戏的控制端,整合控制所有的对象
*
* @author Administrator
*
*/
public class PlaneCilent extends JPanel {
int index;
int EnemyChance = 15;// 敌机出现的概率
int totalEnemy = 0;// 总共出现的敌机
static int times = 0;// 双倍火力剩余的×××数
static boolean doubleBullets = false;// 双倍火力的开关
boolean hasufo = false;// 是否出现ufo
boolean gameOver = false;// 游戏是否结束
public static final int Fram_width = 480; // 静态全局窗口大小
public static final int Fram_length = 800;
Random r = new Random();
List<Enemy> enemy = new Vector<Enemy>();// 敌机的对象集合,因为涉及到线程,所以用线程安全的Vector
List<Shoot> shoot = new Vector<Shoot>();// ×××的对象集合
Hero hero;
Music music = new Music();// 音乐对象,如果只定义一个对象,会特别卡
Music music1 = new Music();
Music music2 = new Music();
Ufo ufo = Ufo.getUfo();// 工厂模式获取ufo对象
Background bg = new Background();// 背景
Shoot st = new Shoot();
public static void main(String[] args) {
PlaneCilent pc = new PlaneCilent();// 创建一个窗口
JFrame frame = new JFrame(" 飞机大战");
frame.add(pc);
frame.setSize(Fram_width, Fram_length);
frame.setLocationRelativeTo(null);
frame.setVisible(true);// 显示窗口
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private class Mouse extends MouseAdapter {// 内部类,实现鼠标的监听
public void mouseMoved(MouseEvent e) {// 鼠标移动事件
hero.mouseMoved(e);// 调用hero里面的鼠标移动方法
}
public void mousePressed(MouseEvent e) {// 按下鼠标键事件
if (Ufo.hasbomb > 0) {// 如果有×××,就爆炸
Ufo.hasbomb--;
for (int i = 0; i < enemy.size(); i++) {
Enemy em = enemy.get(i);
em.addScore();
}
enemy.clear();// 爆炸实际上是清空了enemy集合
}
}
}
public PlaneCilent() {
hero = new Hero(300, 700);// 初始化hero的位置
this.addMouseListener(new Mouse());// 监听鼠标事件
this.addMouseMotionListener(new Mouse());// 监听鼠标移动事件
new Thread(new PaintThread()).start(); // 启动绘图线程
music.backMusic();// 启动背景音乐
}
public void getUfo() {// 获取ufo的方法
int i = r.nextInt(1000);// 概率1/1000
if (i == 5) {
ufo = Ufo.getUfo();
hasufo = true;
}
}
public void getEnemy() {// 获取敌机方法
int i = r.nextInt(EnemyChance);// 概率为1/EnemyChance
if (i == 1) {
enemy.add(Enemy.getEnemy());// 将获取到的敌机add到enemy集合中
totalEnemy++;// 总敌机加1
if (totalEnemy % 50 == 0) {// 每出现50架敌机,敌机出现的概率增大
System.out.println("敌机出现几率增加");
EnemyChance--;
if (EnemyChance <= 3) {// 最大概率为1/3
EnemyChance = 3;
}
}
}
}
public void shoot() {// 处理射击的方法
index++;
if (doubleBullets && index % 7 == 0) {// 如果为双倍火力,就执行{}里面的方法
times--;
System.out.println("剩余×××数:" + times);
if (times <= 0) {
// times=0;
doubleBullets = false;
Shoot.doubleBullets = false;
}
shoot.add(new Shoot(hero.x - 7, hero.y - 50));// 将×××添加到shoot集合中
shoot.add(new Shoot(hero.x + 7, hero.y - 50));
music2.shootMusic();// 发×××的声音
} else if (index % 7 == 0) {// 普通射击
shoot.add(new Shoot(hero.x, hero.y - 50));
music2.shootMusic();
}
}
private class PaintThread implements Runnable {// 主要用来画图的线程
public void run() {
while (!gameOver) {
repaint();
shoot();
getEnemy();
getUfo();
try {
Thread.sleep(1000 / 24);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void paint(final Graphics g) {// 画图的方法
bg.draw(g);// 画背景
hero.draw(g);// 画我的飞机
st.draw(g);// 画×××
if (ufo != null) {// 画面板里面的字符
ufo.drawString(g);
}
if ((ufo != null) && hasufo) {// 画ufo
ufo.draw(g);
ufo.getUfo(hero);// 判断我的飞机是否撞到ufo
}
Iterator<Shoot> itst = shoot.iterator();// ×××的迭代器
while (!(shoot == null) && itst.hasNext()) {
Shoot st = itst.next();// 取得一个Shoot的对象
if (!st.live) {// 如果×××死了,continue
itst.remove();
continue;
}
Iterator<Enemy> itet = enemy.iterator();// 敌机的迭代器
while (!(enemy == null) && itet.hasNext()) {
final Enemy em = itet.next();// 取得一个Enemy对象
if (!(em == null) && !em.live) {// 如果敌机死亡,活着是空的,continue
continue;
}
if (!(st == null) && !(em == null) && st.hitPlane(em)) {// 对于每一个×××,判断是否打到敌机上
if (em.dead()) {// 如果敌机死亡
em.boom(g);// 画爆炸效果
music1.boomMusic();// 播放爆炸音效
itet.remove();// 移除这个对象
}
st.live = false;// ×××死亡
}
}
st.draw(g);// 画×××
if (st.y < 0) {
st.live = false;
}
}
Iterator<Enemy> it = enemy.iterator();// 敌机的迭代器
while (it.hasNext()) {// 如果有敌机
Enemy em = it.next();// 获取一个Enemy的对象
if (em != null) {// 对象不空,就画这个敌机
em.draw(g);
}
if (hero.heroDead(em)) {// 对于每一个敌机,判断是否撞到了hero
gameOver = true;// 撞到游戏结束
}
if (em != null && em.y > Fram_length) {// 跑到面板外面
it.remove();// 移除敌机
}
}
}
}
/***********************PlaneCilent End***************************/


/***********************Enemy***************************/
package plane;

import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.p_w_picpath.BufferedImage;
import java.util.Random;

/**
* 处理敌机的类.父类Enemy为抽象类,提供抽象方法
*
* @author Administrator
*
*/
public abstract class Enemy {
private static PlaneImage pi = PlaneImage.getPlaneImage();// 单例模式,获取PlaneImage类中的图片资源
BufferedImage enemy3 = pi.bufferedImage.get(1);// 获取敌机图片
BufferedImage[] enemy3_down = { pi.bufferedImage.get(4),
pi.bufferedImage.get(5), pi.bufferedImage.get(7),
pi.bufferedImage.get(8) };// 获取敌机爆炸图片

BufferedImage enemy2 = pi.bufferedImage.get(15);
BufferedImage[] enemy2_down = { pi.bufferedImage.get(18),
pi.bufferedImage.get(19), pi.bufferedImage.get(20),
pi.bufferedImage.get(21) };

BufferedImage enemy1 = pi.bufferedImage.get(30);
BufferedImage[] enemy1_down = { pi.bufferedImage.get(24),
pi.bufferedImage.get(25), pi.bufferedImage.get(26),
pi.bufferedImage.get(27) };
int speed;// 敌机的移动速度,会随着游戏时间改变
int blood;// 敌机的血量
int x, y;// 敌机的坐标
static Random r = new Random();// 静态随机数发生器
static int score;// 游戏的分数
static int step = 4;// 敌机的基础速度
static int index = 0;// 产生序号
boolean live = true;// 敌机是否活着
public Enemy() {// 无参构造方法
}
public static Enemy getEnemy() {// 产生敌机的工厂方法
index++;// 每产生一架敌机index加1
if (index == 50) {// 每产生50架,敌机的基础速度加1
System.out.println("敌机速度变快了" + step);
index = 0;
step++;
}
int i = r.nextInt(100) + 1;
if (i > 21) {// 小飞机产生的概率78%
return new Enemy1();
} else if (i < 19) {// 中等飞机18%
return new Enemy2();
} else if (i == 20 || i == 19 || i == 21) {
return new Enemy3();// 3%
}
return null;
}
public void move() {// 敌机的移动方法
y += speed;
}
public boolean dead() {// 判断敌机是否被击爆了
if (blood <= 0) {
live = false;
addScore();// 如果被击爆,加分
return true;// 被击爆了返回true
}
return false;// 没有被击爆
}
/** 以下是抽象方法,子类重写抽象方法,实现多态 */
public void draw(Graphics g) {
}
public void addScore() {
}
public void boom(Graphics g) {
}
public Rectangle getRect() { // 构造指定参数的长方形实例
return null;
}
}

class Enemy1 extends Enemy {
public Enemy1() {
super();
x = r.nextInt(PlaneCilent.Fram_width - enemy1.getWidth());// y坐标保证不出边界
blood = 1;
speed = r.nextInt(5) + step;// 飞机的移动速度
y = 0 - enemy1.getHeight();
}
public void draw(Graphics g) {// 画飞机,每次repaint调用move()方法
if (live) {
g.drawImage(enemy1, x, y, null);
move();
}
}
public void boom(Graphics g) {// 画爆炸效果
for (int i = 0; i < 4; i++) {
g.drawImage(enemy1_down[0], x, y, null);
}
}
public Rectangle getRect() { // 构造指定参数的长方形实例
return new Rectangle(x, y, enemy1.getWidth(), enemy1.getHeight());
}
public void addScore() {
score += 90;
}
}

class Enemy2 extends Enemy {
public Enemy2() {
super();
x = r.nextInt(PlaneCilent.Fram_width - enemy2.getWidth());
blood = 5;
speed = r.nextInt(5) + step;
y = 0 - enemy2.getHeight();
}
public void draw(Graphics g) {
if (live) {
g.drawImage(enemy2, x, y, null);
move();
}
}
public void boom(Graphics g) {
for (int i = 0; i < enemy2_down.length; i++) {
g.drawImage(enemy2_down[0], x, y, null);
}
}
public Rectangle getRect() { // 构造指定参数的长方形实例
return new Rectangle(x, y, enemy2.getWidth(), enemy2.getHeight());
}
public void addScore() {
score += 490;
}
}

class Enemy3 extends Enemy {
public Enemy3() {
super();
x = r.nextInt(PlaneCilent.Fram_width - enemy3.getWidth());
y = 0 - enemy3.getHeight();
blood = 15;
speed = r.nextInt(3) + step;
}
public void draw(Graphics g) {
if (live) {
g.drawImage(enemy3, x, y, null);
move();
}
}
public void boom(Graphics g) {
for (int i = 0; i < enemy3_down.length; i++) {
g.drawImage(enemy3_down[i], x, y, null);
}
}
public Rectangle getRect() { // 构造指定参数的长方形实例
return new Rectangle(x, y, enemy3.getWidth(), enemy3.getHeight());
}
public void addScore() {
score += 2000;
}
}
/***********************Enemy End***************************/


/***********************Hero***************************/

package plane;

import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.p_w_picpath.BufferedImage;

public class Hero {
int x, y;// 飞机的坐标
static PlaneImage pi = PlaneImage.getPlaneImage();// 单例模式,获取PlaneImage类中的图片资源
BufferedImage her = pi.bufferedImage.get(9);// 取得飞机的图片
private boolean live = true; // 飞机是否活着

public Hero(int x, int y) {
this.x = x;
this.y = y;
}
public void mouseMoved(MouseEvent e) {// 鼠标事件,获取鼠标指针当前位置
x = e.getX();// 设置飞机的位置为鼠标指针的位置
y = e.getY();
}
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
public void draw(Graphics g) {
g.drawImage(her, x - 48, y - 50, null);// 因为获取的坐标表示图片的左上角,所以要调整图片的位置
}
public Rectangle getRect() { // 构造指定参数的长方形实例.返回的宽度为飞机宽度的1/3
return new Rectangle(x - 48 + her.getWidth() / 3, y - 50, her
.getWidth() / 3, her.getHeight() - 20);
}
public boolean heroDead(Enemy enemy) {// 判断是否撞到敌机了
if (this.getRect() != null && enemy.getRect() != null
&& this.getRect().intersects(enemy.getRect())) {
return true;
}
return false;
}
}
/***********************Hero End***************************/


/***********************Music*************************/
package plane;

import java.applet.Applet;
import java.applet.AudioClip;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

public class Music {// 处理音乐的类,这个了解即可
URL bm = null;
URL bt = null;
URL boom = null;
AudioClip aau;
public Music() {
File backgroundMusic = new File("shoot/sound/game_music.mp3");
File bullet = new File("shoot/sound/bullet.mp3");
File enemyBoom = new File("shoot/sound/enemy1_down.mp3");
try {
bm = backgroundMusic.toURL();
bt = bullet.toURL();
boom = enemyBoom.toURL();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void shootMusic() {
Thread thread = new Thread(new Runnable() {
public void run() {
aau = Applet.newAudioClip(bt);
aau.play();
}
});
thread.start();
}
public void backMusic() {
Thread thread = new Thread(new Runnable() {
public void run() {
aau = Applet.newAudioClip(bm);
aau.loop();
}
});
thread.start();
}
public void boomMusic() {
Thread thread = new Thread(new Runnable() {
public void run() {
aau = Applet.newAudioClip(boom);
aau.play();
}
});
thread.start();
}
}
/***********************Music End*************************/


/***********************PlaneImage*************************/
package plane;

import java.awt.p_w_picpath.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
import javax.p_w_picpathio.ImageIO;
/**
* 从一张大图根据配置文件从里面截取出所有图片,存放在Vector集合里面
*
* @author Administrator
*
*/
public class PlaneImage {
private static PlaneImage pi = new PlaneImage();// 单例模式
private String planeName;// 飞机的名称,会输出到控制台,和图片对应
private BufferedImage planes;// 读取出来的图片
private int i = -1;// 序号
List<BufferedImage> bufferedImage = new Vector<BufferedImage>();// 线程安全的Vector用来储存截取出来的图片
// static Map<String, BufferedImage> plane = new HashMap<String,
// BufferedImage>();
int x, y, width, height;// 要截取的每张图片坐标

private PlaneImage() {// 单例模式,定义为权限为private
try {
planes = ImageIO.read(new File("shoot/shoot.png"));// 读取大图片
BufferedReader in = new BufferedReader(new InputStreamReader(
new BufferedInputStream(new FileInputStream(
"shoot/shoot.pack")), "GBK"));// 读取配置文件
String row;
while ((row = in.readLine()) != null && !row.equals("over")) {// 读取一行
row = row.trim();// 去掉字符串前后的空格
String[] str = row.split(":|,");// 用正则表达式拆分字符串,结果存放在String数组里面
if (str.length == 1) {// 如果str的长度为1,表示的是飞机对应的名称
planeName = Arrays.toString(str);// 将字符数组里面的字符转换为字符赋值给.
System.out.println(i++ + planeName);
} else if (str.length == 3 && str[0].equals("xy")) {// 表示读取到飞机图片的x,y坐标了
x = Integer.parseInt(str[1].trim(), 10);// 得到的坐标是字符,去掉左右空格转换为int型
y = Integer.parseInt(str[2].trim(), 10);
row = in.readLine();// 下一行是要截取图片的宽高
str = row.split(":|,");
width = Integer.parseInt(str[1].trim(), 10);
height = Integer.parseInt(str[2].trim(), 10);
bufferedImage.add(planes.getSubp_w_picpath(x, y, width, height));// 截取图片后add到plane集合中
}
}
in.close();// 关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
public static PlaneImage getPlaneImage() {// 单例模式,获取对象
return pi;
}
}


/***********************PlaneImage End*************************/


/***********************Shoot*************************/
package plane;

import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.p_w_picpath.BufferedImage;

public class Shoot {
int x, y;
boolean live = true;// ×××是否活着
static boolean doubleBullets = false;// 是否为双倍火力
static PlaneImage pi = PlaneImage.getPlaneImage();// 单例模式,获取图片
BufferedImage bullet1 = pi.bufferedImage.get(31);// 两种不同的×××
BufferedImage bullet2 = pi.bufferedImage.get(32);
public Shoot() {
}
public Shoot(int x, int y) {
this.x = x;
this.y = y;
}
public boolean hitPlane(Enemy enemy) {// 检测×××是否打到飞机了
if (this.getRect() != null && enemy.getRect() != null
&& this.getRect().intersects(enemy.getRect())) {
enemy.blood--;// 飞机血减少
this.live = false;// ×××死亡
return true;
}
return false;
}
public void draw(Graphics g) {
if (doubleBullets) {
g.drawImage(bullet2, x, y, null);
} else {
g.drawImage(bullet1, x, y, null);
}
y -= 25;
}
public Rectangle getRect() { // 构造指定参数的长方形实例
return new Rectangle(x, y, bullet2.getWidth(), bullet2.getHeight());
}
}
/***********************PlaneImage End*************************/


/***********************Ufo*************************/
package plane;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.p_w_picpath.BufferedImage;
import java.util.Random;

/**
* 抽象类Ufo,提供基本方法和抽象方法
*
* @author Administrator
*
*/
public abstract class Ufo {
int x, y;// ufo的x,y坐标
int index;// 用来控制ufo
int step;// ufo移动的速度
static Random r = new Random();
static boolean thisUfo = false;// 是否有ufo
static int hasbomb = 0;// 拥有的×××数目
static PlaneImage pi = PlaneImage.getPlaneImage();// 单例模式,获取图片
BufferedImage ufo1 = pi.bufferedImage.get(22);
BufferedImage ufo2 = pi.bufferedImage.get(17);
BufferedImage bomb = pi.bufferedImage.get(23);
public Ufo() {
this.thisUfo = true;
x = r.nextInt(PlaneCilent.Fram_width - ufo1.getWidth());
y = 0;
}
public boolean getUfo(Hero hero) {// 获得ufo的方法
return false;
}
public void draw(Graphics g) {// 画ufo的方法
}
public void drawString(Graphics g) {// 画字符,以及界面上的文字
g.drawImage(bomb, 5, PlaneCilent.Fram_length - 90, null);
g.setColor(Color.black);
g.setFont(new Font("TimesRoman", Font.BOLD, 20));
String str = "x" + hasbomb + " 提示:鼠标右键引爆×××";
g.drawString(str, 80, PlaneCilent.Fram_length - 40);
str = "SCORE:" + Enemy.score;
g.drawString(str, 10, 40);
}
public static Ufo getUfo() {// 工厂方法,获得ufo的对象
int i = r.nextInt(2);
if (i == 0) {
System.out.println("UFO--火力加倍");
return new Ufo1();
} else if (i == 1) {
System.out.println("UFO--×××");
return new Ufo2();
}
return null;
}
public void move() {// ufo的移动方法
index++;
if (index < 20) {
y += step++;
} else if (index >= 20 && index <= 40) {
y -= step--;
} else {
y += step++;
}
if (y > PlaneCilent.Fram_length) {
this.thisUfo = false;
}
}
public Rectangle getRect() { // 构造指定参数的长方形实例
return new Rectangle(x, y, ufo1.getWidth(), ufo1.getHeight());
}
}
class Ufo1 extends Ufo {// 双倍火力的ufo
public Ufo1() {
super();
// TODO Auto-generated constructor stub
}
public boolean getUfo(Hero hero) {
if (thisUfo && this.getRect().intersects(hero.getRect())) {
thisUfo = false;
PlaneCilent.doubleBullets = true;
Shoot.doubleBullets = true;
System.out.println("super bullets");
PlaneCilent.times = 50;
return true;
}
return false;
}
public void draw(Graphics g) {
if (thisUfo) {
g.drawImage(ufo1, x, y, null);
move();
}
}
}

class Ufo2 extends Ufo {// ×××ufo
public Ufo2() {
super();
// TODO Auto-generated constructor stub
}
public boolean getUfo(Hero hero) {
if (thisUfo && this.getRect().intersects(hero.getRect())) {
thisUfo = false;
hasbomb++;
return true;
}
return false;
}
public void draw(Graphics g) {
if (thisUfo) {
g.drawImage(ufo2, x, y, null);
move();
}
}
}

/***********************Ufo End*************************/


/***********************Background*************************/
package plane;

import java.awt.Graphics;
import java.awt.p_w_picpath.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.p_w_picpathio.ImageIO;

public class Background {
private int y = 0;
private int speed = 5;// 背景移动的速度
private BufferedImage shoot_background;
private BufferedImage background;
public Background() {
try {
shoot_ ImageIO.read(new File(
"shoot/shoot_background.png"));// 读取图片
shoot_background.getSubp_w_picpath(0, 75, 480, 825);// 截取读取出来图片中的一部分
} catch (IOException e) {
e.printStackTrace();
}
}
public void draw(Graphics g) {
g.drawImage(background, 0, y, null);
g.drawImage(background, 0, y - background.getHeight(), null);// 画2张图,实现背景无缝移动
move();// 每画一次,调用move()方法改变y的值
}
private void move() {
if (y >= background.getHeight()) {
y = 0;
}
y += speed;
}
}

/***********************Background End*************************/