目录
一、需求
- 窗体、面板、背景图的绘制
- 英雄机的出现及移动
- 敌机的出现及移动
- 英雄机子弹的出现及移动
- 敌机子弹的出现及移动
- 英雄机子弹打中敌机
- 敌机子弹打中英雄机
- 敌机与英雄机相撞
- 游戏的开始与结束界面
- 增加背景音乐和爆炸音效
二、窗体、面板、背景图的绘制
2.1 工具类
/**
* 这是工具类,用于获取图片
* @author Administrator
*
*/
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Tool {
public static BufferedImage getImage(String path) {
try {
BufferedImage img = ImageIO.read(Tool.class.getResource(path));
return img;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
2.2 面板类
/**
* 这是面板类,继承JPanel
*/
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
public class GamePanel extends JPanel {
// 定义背景图
private BufferedImage bg;
// 构造方法
public GamePanel() {
bg = Tool.getImage("../img/bg3.jpg");
}
// paint方法
@Override
public void paint(Graphics g) {
g.drawImage(bg, 0, 0, null);
}
}
2.3 窗体类
import javax.swing.JFrame;
/**
* 这个类是窗体类,继承JFrame类
*
* @author Administrator
*
*/
public class GameFrame extends JFrame {
public GameFrame() {
setSize(512, 768);
setLocationRelativeTo(null);// 居中
setIconImage(Tool.getImage("../img/hero.png"));// 图标
setTitle("飞机大战");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 关闭停止运行
}
public static void main(String[] args) {
GameFrame frame = new GameFrame();
GamePanel panel = new GamePanel();
frame.add(panel);
frame.setVisible(true);//窗体可见
}
}
2.4 效果图
三、英雄机的出现及移动
3.1 定义飞行父类
import java.awt.image.BufferedImage;
/**
* 这是飞行类,作为飞机及子弹的父类
* @author Administrator
*
*/
abstract class FlyObject {
//图片
BufferedImage img;
//坐标
int x;
int y;
//宽高
int w;
int h;
}
3.2 英雄机的出现
/**
* 这是英雄机类
* @author Administrator
*
*/
public class Hero extends FlyObject {
public Hero() {
img = Tool.getImage("../img/hero.png");
x = 190;
y = 550;
w = img.getWidth();
h = img.getHeight();
}
}
3.3 加入鼠标监听器
// 构造方法
public GamePanel() {
bg = Tool.getImage("../img/bg3.jpg");
//创建鼠标适配器
MouseAdapter adapter = new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
int mx = e.getX();
int my = e.getY();
hero.moveToMouse(mx,my);
repaint();
}
};
//将适配器加入到监听器
addMouseListener(adapter);
addMouseMotionListener(adapter);
}
3.4 英雄机的移动
/**
* 英雄机跟随鼠标移动
* @param mx
* @param my
*/
public void moveToMouse(int mx, int my) {
x = mx - w/2;
y = my - h/2;
}
四、敌机的出现及移动
4.1 敌机类
import java.util.Random;
/**
* 这是敌机类
* @author Administrator
*/
public class Enemy extends FlyObject{
//敌机速度
int sp;
public Enemy() {
Random num = new Random();
int index = num.nextInt(11)+1;//生成1~11的随机数
img = Tool.getImage("../img/ep"+index+".png");
w = img.getWidth();
h = img.getHeight();
x = num.nextInt(512 - w);
y = -h;
sp = 11 - index;
}
//敌机移动
public void move() {
y += sp;
}
}
4.2 敌机入场
// 敌机入场
public void epEnter() {
epcount++;
if (epcount > 10) {
Enemy ep = new Enemy();
eps.add(ep);
epcount = 0;
}
}
4.3 敌机移动
//敌机移动
public void epMove() {
for(int i = 0; i < eps.size(); i++) {
Enemy ep = eps.get(i);
ep.move();
}
}
4.4 启动一个线程
//游戏启动方法
public void action() {
new Thread() {
public void run() {
while(true) {
epEnter();
epMove();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
repaint();
}
}
}.start();
}
4.5 效果图
五、英雄机子弹的出现及移动
5.1 英雄机子弹类
/**
* 这是英雄机子弹类
* @author Administrator
*
*/
public class HeroFire extends FlyObject{
public HeroFire(int hx,int hy) {
img = Tool.getImage("../img/herofire.png");
x = hx;
y = hy;
w = img.getWidth()/3;
h = img.getHeight()/3;
}
//英雄机子弹的移动
public void move() {
y -= 10;
}
}
5.2 英雄机发射子弹
//英雄机发射子弹
public void heroShoot() {
hero_fire_count++;
if(hero_fire_count > 5) {
HeroFire hf = new HeroFire(hero.x+43,hero.y);
hfs.add(hf);
hero_fire_count = 0;
}
}
5.3 英雄机子弹移动
//英雄机子弹移动
public void heroFireMove() {
for(int i = 0; i < hfs.size(); i++) {
HeroFire hf = hfs.get(i);
hf.move();
}
}
5.4 效果图
六、敌机子弹的出现及移动
6.1 敌机子弹类
/**
* 这是敌机子弹类
* @author Administrator
*
*/
public class EnemyFire extends FlyObject{
int sp;
public EnemyFire(int ex,int ey) {
img = Tool.getImage("../img/fire.png");
x = ex;
y = ey;
w = img.getWidth()/5;
h = img.getHeight()/5;
}
//敌机子弹移动
public void move() {
y += sp+5;
}
}
6.2 敌机发射子弹
//敌机发射子弹
public void enemyShoot() {
enemy_fire_count++;
if (enemy_fire_count > 10) {
for (int i = 0; i < eps.size(); i++) {
Enemy ep = eps.get(i);
EnemyFire ef = new EnemyFire(ep.x+55, ep.y+120);
ef.sp = ep.sp;
efs.add(ef);
}
enemy_fire_count = 0;
}
}
6.3 敌机子弹移动
//敌机子弹移动
public void enemyFireMove() {
for(int i = 0; i < efs.size(); i++) {
EnemyFire ef = efs.get(i);
ef.move();
}
}
6.4 效果图
七、击中问题
7.1 英雄机子弹击中敌机
//英雄机子弹击中敌机
public void heroFireHitEnemy() {
for(int i = 0; i < hfs.size(); i++) {
HeroFire hf = hfs.get(i);
enemyBang(hf);
}
}
//敌机被击中后消失
public void enemyBang(HeroFire hf) {
for(int i = 0; i < eps.size(); i++) {
Enemy ep = eps.get(i);
if(ep.enemyshootBy(hf)) {
ep.hp--;
if(ep.hp <= 0) {
eps.remove(ep);
}
hfs.remove(hf);
}
}
}
7.2 敌机子弹击中英雄机
//3.敌机子弹击中英雄机
public void enemyFireHitHero() {
for(int i = 0; i < efs.size(); i++) {
EnemyFire ef = efs.get(i);
heroBang(ef);
}
}
//4.英雄机被敌机击中后,游戏结束
public void heroBang(EnemyFire ef) {
if(hero.heroshootBy(ef)) {
hero.hp--;
if(hero.hp <= 0) {
gameover = true;
}
efs.remove(ef);
}
}
7.3 敌机与英雄机相撞
//7.敌机与英雄机相撞
public void enemyBumpHero() {
for(int i = 0; i < eps.size(); i++) {
Enemy ep = eps.get(i);
if(ep.bumpByHero(hero)) {
eps.remove(ep);
//hero.hp--;
if(hero.hp <= 0) {
gameover = true;
}
}
}
}
7.4 效果图
八、游戏的开始与结束
8.1 鼠标点击监听事件
//鼠标点击监听
@Override
public void mouseClicked(MouseEvent e) {
if (!start) {
hero = new Hero();
gameover = false;
start = true;
score = 0;
eps.clear();
hfs.clear();
efs.clear();
repaint();
}
if (gameover) {
start = false;
repaint();
}
}
8.2 开始与结束界面
//绘制结束界面
if(gameover) {
g.drawImage(over, 60, 200, over.getWidth() * 2, over.getHeight() * 2, null);
g.drawImage(again_img,190,450,null);
}
//绘制开始界面
if(!start) {
g.drawImage(begin_img,0,0,null);
g.drawImage(title_img,-30,10,title_img.getWidth(),title_img.getHeight(),null);
g.drawImage(start_img,180,400,null);
}
8.3 效果图
九、加入音效
9.1 音乐类
/**
* 这是音乐类,用于播放音乐
* @author Administrator
*
*/
public class Sound {
private AudioClip bang;
private AudioClip music;
public Sound() {
String fileName = "E:\\learning\\Program\\img\\bang.wav";
String fileName2 = "E:\\learning\\Program\\img\\bgm.wav";
try {
bang = JApplet.newAudioClip(new URL("file:"+fileName));
music = JApplet.newAudioClip(new URL("file:"+fileName2));
} catch (Exception e) {
e.printStackTrace();
}
}
//播放飞机爆炸的声音
public void bangVoice() {
new Thread() {
public void run() {
bang.play();;
}
}.start();
}
//播放背景音乐
public void bgm() {
new Thread() {
public void run() {
music.loop();
}
}.start();
}
//停止播放背景音乐
public void stop() {
music.stop();
}
}
十、遇到的问题
1. 明明没有敌机出现,可是子弹却一直不停的从上方发出,一开始我总把注意力放在敌机和子弹的出现频率上,后来更改敌机的
初始贴图位置后,发现敌机速度为0,所以一直在发射子弹。不同的敌机拥有不同的速度,其中有一种设为0了。
2. 关于鼠标点击监听,游戏结束后,点击后应该重新开始游戏,结果游戏并未运行,只贴出了背景图和英雄机,于是又把注意
力放在了gameover上,因为游戏不运行,就是某个地方gameover=true了,找了很久发现action函数中if把异常中的睡眠也包
括进去了,包括睡眠与不包括睡眠这两者的区别我还不明白。
3. 关于加入敌机爆炸特效,不知道怎么加。
4. 关于背景图的循环滚动,不知道怎么加。
十一、学习地址
----------------------------------------------------------------------更新bug及功能-------------------------------------------------------------------------------
- 关于开始界面,简介界面,结束界面之间存在bug,更正监听代码如下
//鼠标点击监听
@Override
public void mouseClicked(MouseEvent e) {
boolean clickstartgame = e.getX() >= 160 && e.getX() <= 349 && e.getY() >= 400 && e.getY() <= 462;
boolean clickregame = e.getX() >= 190 && e.getX() <= 332 && e.getY() >= 450 && e.getY() <= 501;
boolean clickbrief = e.getX() >= 160 && e.getX() <= 349 && e.getY() >= 480 && e.getY() <= 542;
boolean clickreturn = e.getX() >= 160 && e.getX() <= 349 && e.getY() >= 620 && e.getY() <= 682;
if(clickbrief && !gameover) {
playbrief = true;
}
if(playbrief && clickreturn) {
start = false;
playbrief = false;
}
if (!start && clickstartgame) {
hero = new Hero();
gameover = false;
start = true;
score = 0;
eps.clear();
hfs.clear();
efs.clear();
sound.bgm();
repaint();
}
if (gameover && clickregame) {
start = false;
gameover = false;
repaint();
}
}
- 关于背景的循环滚动
//背景图的移动,画两张相同的背景图
public void bgMove() {
y1++;
y2++;
if(y1 == 0) {
y2 = -game_bg.getHeight();
}
if(y2 == 0) {
y1 = -game_bg.getHeight();
}
}