使用到的素材文件夹:
素材说明:bg0.jpg是背景图片。bomb_enemy是敌机爆炸时按顺序播放的四帧图片,bullet_0.png是子弹图片,enemy_alive.png是敌机图片,player.png是主角图片;
素材及完整源码链接:https://pan.baidu.com/s/1mwFNPrnNed5jbVZSSrtaUg 提取码: db6h
场景分析:玩家可以通过上下左右控制主角飞机的移动,主角每隔一段时间发射子弹,后台随机位置生成敌机,敌机如果碰到子弹,敌机死亡并播放爆炸效果,同时击中敌机的子弹失效;场景画布滚动播放。
设计子弹Bullet类:
package 雷电飞机射击游戏;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.ImageObserver;
import javax.swing.JPanel;
public class Bullet {
static final int BULLET_STEP_X = 3;
static final int BULLET_STEP_Y = 15;
static final int BULLET_WIDTH = 30;
public int m_posX = 0;
public int m_posY = -20;
boolean mFacus = true;
private Image pic[] = null;
private int mPlayID = 0;
public Bullet(){
pic = new Image[1];
// System.out.println(pic.length);
for(int i=0;i=pic.length)
mPlayID = 0;
}
public void UpdateBullet(){
m_posY -= BULLET_STEP_Y;
}
}
子弹类分析:pic数组用于存放子弹的帧数,由于这里子弹帧数只有一张,所以数组长度设为1;UpdateBullet()用于更新子弹位置;m_posX,m_posY存放子弹坐标;
设计敌机Enemy类:
package 雷电飞机射击游戏;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.ImageObserver;
import javax.swing.JPanel;
public class Enemy {
public static final int ENEMY_ALIVE_STATE = 0;
public static final int ENEMY_DEATH_STATE = 1;
static final int ENEMY_STEP_Y = 5;
public int m_posX = 0;
public int m_posY = 0;
public int mAnimState = ENEMY_ALIVE_STATE;
private Image enemyExplorePic[] = new Image[4];
public int mPlayID = 0;
public Enemy(){
for(int i=0;i
敌机类分析:m_posX,m_posY存放敌机坐标;enemyExplorePic数组存放敌机爆炸时顺序播放的帧数图片;mAnimState存放敌机状态;UpdateEnemy()控制敌机位置的移动;
设计游戏面板GamePanel类:
package 雷电飞机射击游戏;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Iterator;
import java.util.Random;
import java.util.Vector;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable,KeyListener{
private int mScreenWidth = 320;//屏宽
private int mScreenHeight = 480;//屏高
private static final int STATE_GAME = 0;
private int mState = STATE_GAME;
private Image mBitMenuBG0 = null;//背景图1
private Image mBitMenuBG1 = null;//背景图2
private int mBitposY0 = 0;//背景1的y轴起点
private int mBitposY1 = 0;//背景2的y轴起点
private Sound sound = new Sound();
private long createEnemyTime = System.currentTimeMillis();//用来监控敌机创建时间
final static int BULLET_POOL_COUNT = 15;//最多同时存在的子弹数
final static int PLAN_STEP = 10;//主角移动步长
final static int PLAN_TIME = 500;//隔500ms发射子弹
final static int ENEMY_POOL_COUNT = 5;//敌机最多同时存在个数
final static int ENEMY_POS_OFF = 65;//敌机偏移量
final static int BULLET_LEFT_OFFSET = 0;//子弹左偏移量
final static int BULLET_UP_OFFSET = 10;//子弹上偏移量
private Thread mThread = null;//主线程
private boolean mIsRunning = false;//初始游戏状态未运行
public int mAirPosX = 0;//主角x位置
public int mAirPosY = 0;//主角y位置
Vector mEnemy = new Vector();//存储敌机
Vector mBullet = new Vector();//存储子弹
public int mSendId = 0;
public long mSendTime = 0L;
Image myPlanePic[];
public int myPlaneID = 0;
public GamePanel(){
setPreferredSize(new Dimension(mScreenWidth,mScreenHeight));
setFocusable(true);
addKeyListener(this);
sound.loadSound();
init();
setGameState(STATE_GAME);
mIsRunning = true;
mThread = new Thread(this);
mThread.start();
setVisible(true);
}
public void init(){
try{
mBitMenuBG0 = Toolkit.getDefaultToolkit().getImage("D:/Game/bg0.jpg");
mBitMenuBG1 = Toolkit.getDefaultToolkit().getImage("D:/Game/bg0.jpg");
}catch(Exception e){
e.printStackTrace();
}
mBitposY0 = 0;
mBitposY1 = -mScreenHeight;
mAirPosX = 150;
mAirPosY = 400;
myPlanePic = new Image[1];
for(int i=0;i=mScreenHeight){
mEnemy.remove(i);
}
}
long nowTime = System.currentTimeMillis();
if(mEnemy.size()<5&&nowTime-createEnemyTime>=1000)//至少要间隔1秒才生成飞机
{
createEnemyTime = nowTime;
Enemy tempEnemy = new Enemy();
tempEnemy.init(UtilRandom(0,mScreenWidth-30),0);
mEnemy.add(tempEnemy);
}
if(mSendId=PLAN_TIME){
Bullet tempBullet = new Bullet();
tempBullet.init(mAirPosX-BULLET_LEFT_OFFSET, mAirPosY-BULLET_UP_OFFSET);
mBullet.add(tempBullet);
mSendTime = now;
mSendId++;
}
}else{
mSendId= 0;
}
Collision();
}
public void Collision(){
for(int i=0;imEnemy.get(j).m_posX-30&&mBullet.get(i).m_posX=mEnemy.get(j).m_posY&&mBullet.get(i).m_posY<=mEnemy.get(j).m_posY+30){
mEnemy.get(j).mAnimState = Enemy.ENEMY_DEATH_STATE;
mBullet.get(i).mFacus = false;//如果子弹撞上敌机,敌机状态修改为死亡,子弹状态修改为失效
}
}
}
}
//返回的敌机x坐标
private int UtilRandom(int bottom,int top){
return ((Math.abs(new Random().nextInt()) % (top - bottom)) + bottom);
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
//System.out.println(key);
if(key == KeyEvent.VK_UP){
mAirPosY -= PLAN_STEP;
}
if(key == KeyEvent.VK_DOWN){
mAirPosY += PLAN_STEP;
}
if(key == KeyEvent.VK_LEFT){
mAirPosX -= PLAN_STEP;
if(mAirPosX<0){
mAirPosX = 0;
}
}
if(key == KeyEvent.VK_RIGHT){
mAirPosX += PLAN_STEP;
if(mAirPosX > mScreenWidth-30){
mAirPosX = mScreenWidth - 30;
}
}
// System.out.println("飞机当前坐标是("+mAirPosX+","+mAirPosY+")");
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void run() {
while(mIsRunning){
draw();
try{
Thread.sleep(100);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
游戏面板类分析:
①mThread线程用于定时生成子弹,如果当前生效的子弹数没有超过15个,每隔500ms生成子弹,子弹位于主角飞机上方一个子弹上偏移量的位置;
②image0和image1是背景图片,初始化背景图片2位于背景图片1上方,随着游戏的进行,背景图片逐渐下移,当背景图片1到屏幕外时,将背景图片1放到背景图片2上方;
③碰撞检测:循环子弹数组和敌机数组,如果当前子弹生效,当前敌机状态存活,子弹的x值>敌机的x值-子弹宽度&&子弹的x值<敌机的x值+敌机宽度&&子弹的y值>=敌机的y值&&子弹的y值<=敌机的y值+敌机高度,那么修改当前敌机的状态为死亡并播放爆炸动画,修改当前子弹状态为失效;
④如果敌机死亡并且爆炸动画播放完毕,或者敌机超出屏幕显示范围,删除敌机;
⑤如果子弹失效或者超过屏幕范围,删除子弹;
⑥敌机后台随机生成,位于屏幕上方,控制至少每隔1秒才能生成新的敌机,并且当前屏幕上的敌机数量最多不能超过五个;
最后还剩游戏窗口类和背景音乐类代码:
package 雷电飞机射击游戏;
import java.awt.Container;
import javax.swing.JFrame;
public class planeFrame extends JFrame{
public planeFrame(){
setTitle("飞行射击类游戏");
GamePanel panel = new GamePanel();
Container contentPane = getContentPane();
contentPane.add(panel);
pack();
}
public static void main(String[] args) {
planeFrame e1 = new planeFrame();
e1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
e1.setVisible(true);
}
}
package 雷电飞机射击游戏;
import javax.sound.midi.*;
import java.io.File;
import java.io.IOException;
public class Sound {
String path = new String("D:/Music/");
String file = new String("nor.mid");
Sequence seq;
Sequencer midi;
boolean sign;
void loadSound(){
try {
seq = MidiSystem.getSequence(new File(path+file));
midi = MidiSystem.getSequencer();
midi.open();
midi.setSequence(seq);
midi.start();
midi.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
} catch (InvalidMidiDataException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MidiUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sign = true;
}
public Sound(String file,String path){
this.file = file;
this.path = path;
}
public Sound() {
// TODO Auto-generated constructor stub
}
void mystop(){midi.stop();midi.close();sign=false;}
boolean isplay(){return sign;}
void setMusic(String e){file=e;}
}
至此,游戏开发已经完毕,运行效果如下: