游戏是有背景音乐和打击音效的,十分炫酷。那么接下来,我将编写此游戏的全过程做一遍详细介绍,解释部分核心效果实现代码,只要读者此时具备基础的java语法知识,我相信一定可以非常轻松的编写出一款属于自己的雷霆战机游戏。(大神可跳过,直接看源代码)
话不多说,我们直接开始:
一、首先理清编写思路,利用javaOOP面对对象思想分析游戏:
游戏界面组成部分无非是:玩家飞机、敌方飞机、子弹、背景、爆炸效果等。利用OOP思想创建 Class
二、需要将对象一一添加到面板中:
首先将背景图片绘制到面板中:代码如下
package com.my.plane;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import util.ImageUtil;
public class Background {
BufferedImage bg=ImageUtil.img.get("bg.jpg");
BufferedImage bg1=ImageUtil.img.get("bg_meitu_1.jpg");
int by=0;
public void drawbg(Graphics g) {
if(GameJPanel.gameover) {
g.drawImage(bg1,0,0,null);
}
else {
g.drawImage(bg,0,by,null);
g.drawImage(bg,0,by-ImageUtil.img.get("bg.jpg").getHeight(),null);
}
}
public void move() {
this.by+=2;
if(by>=ImageUtil.img.get("bg.jpg").getHeight())
by=0;
}
}
【每次重绘将背景图片向下移动2个像素,即可实现飞机移动效果,绘制两张,以免出现面板空白】
重写JPanel paint()方法将各个元素添加到面板中 核心代码如下:
public void paint(Graphics g) {
bgck.drawbg(g);//绘制背景
plane.drawplane(g);//绘制玩家飞机
for(int i=0;i
【希望读者编写程序时,也将代码注释标写清楚,否则在程序出错时没有头绪将是很糟糕的事情,本人初期就深受其害】
paint()方法中创建元素对象,并调用对象类中的绘制方法实现 将元素添加到面板中。我以玩家飞机类为例,介绍元素对象类的编写:
我这里玩家飞机类为Plane
定义对象类十分简单且易于理解: 只需要定义 Plane 的 x,y坐标,并通过drawImage将对象元素绘制到面板中即可,代码如下:
package com.my.plane;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import util.ImageUtil;
public class Plane {
int px;
int py;
int pw;
int ph;
int count=0;
BufferedImage []pimage= {ImageUtil.img.get("success.png"),ImageUtil.img.get("success1.png")};
Plane() {
this.pw=pimage[0].getWidth();
this.ph=pimage[0].getHeight();
this.px=GameJFrame.jx/2-pw/2;//飞机的坐标定义面板的正下方
this.py=GameJFrame.jy-ph+50;
}
public void drawplane(Graphics g) {
if(GameJPanel.gameover) { //这里我是用来判断游戏结束时绘制死亡效果的 ,读者可以暂时忽略
g.drawImage(ImageUtil.img.get("die2.png"),px,py,null);}
else {
g.drawImage(pimage[count], px, py, null);
count++;
if(count>1) count=0;
}
}
}
【我这里定义了一个ImageUtil类,此类作为API工具类将所有需要使用的图片读取到内存中,方便读取,提高游戏性能,代码如下:】
package util;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
public final class ImageUtil {
public static Mapimg=new HashMap();//BufferedImage:内存中的图片对象
static{
File file=new File("img");
File [] fs=file.listFiles();
for(File f:fs) {
//通过当前的文件名作为HashMap的key
String s=f.getName();
//将读取到的文件对象 作为BufferedImage存储
try {
BufferedImage i=ImageIO.read(f);
img.put(s, i);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
你可能注意到,Plane 类中元素的图片有两张,这两张图片在线程中反复重绘,可使飞机更加立体生动。若你有更好的方法实现这个效果,可以忽略。或可忽略立体效果,即只认定飞机元素只有一张图片,将图片绘制于面板中即可。
至于 Enemy(敌方飞机) Boom Bullet 等 类实现方法大同小异,基本一致,代码如下:
Enemy类
package com.my.plane;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
import util.ImageUtil;
public class Enemy {
int []ex=new int[4];
int []ey=new int[4];
int []ew=new int[4];
int []eh=new int[4];
int count=0;
BufferedImage []enemy= {ImageUtil.img.get("s2_1.png"),
ImageUtil.img.get("s2_2.png"),
ImageUtil.img.get("s2_2.png"),ImageUtil.img.get("airplane.png")};
Enemy(int x,int x1,int x2,int x3,int y,int y1,int y2,int y3){
this.ex[0]=x;
this.ex[1]=x1;
this.ex[2]=x2;
this.ex[3]=x3;
this.ey[0]=y;
this.ey[1]=y1;
this.ey[2]=y2;
this.ey[3]=y2;
this.ew[0]=ImageUtil.img.get("s2_1.png").getWidth();
this.ew[1]=ImageUtil.img.get("s2_2.png").getWidth();
this.ew[2]=ImageUtil.img.get("s2_2.png").getWidth();
this.ew[3]=ImageUtil.img.get("airplane.png").getWidth();
this.eh[0]=ImageUtil.img.get("s2_1.png").getHeight();
this.eh[1]=ImageUtil.img.get("s2_2.png").getHeight();
this.eh[2]=ImageUtil.img.get("s2_1.png").getHeight();
this.eh[3]=ImageUtil.img.get("airplane.png").getHeight();
}
public void drawEnemy(Graphics g) {
if(GameJPanel.gameover) {for(int i=0;i<4;i++) {
g.drawImage(ImageUtil.img.get("07.png"),ex[i],ey[i],null);}}
else {
for(int i=0;i<4;i++)
g.drawImage(enemy[i],ex[i],ey[i],null);
}
}
public void move(int y,int y1,int y2,int y3) {
this.ey[0]=y;
this.ey[1]=y1;
this.ey[2]=y2;
this.ey[3]=y3;
}
}
Bullet类
package com.my.plane;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import util.ImageUtil;
public class Bullet {
int []bx=new int[2];
int []by=new int[2];
int []bw=new int[2];
int []bh=new int[2];
boolean bullet1=false; //这里我设置一个bullet1绑定到键盘事件中,当按下“J”键可切换子弹
boolean bullet2=false;
BufferedImage []bullet={ImageUtil.img.get("myb_3.png"),
ImageUtil.img.get("feidan.png")};
Bullet(int x,int x1,int y,int y1){
this.bx[0]=x;
this.bx[1]=x1;
this.by[0]=y;
this.by[1]=y1;
}
public void drawBullet(Graphics g) {
if(bullet1) g.drawImage(bullet[1],bx[0],by[0],null);
else g.drawImage(bullet[0],bx[1],by[1],null);
}
public void move() {
by[0]-=5;
by[1]-=5;
}
}
Boom 类
package com.my.plane;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import util.ImageUtil;
public class Boom {
int ox;
int oy;
int count=0;
BufferedImage [] boom= {ImageUtil.img.get("01.png"),ImageUtil.img.get("02.png"),ImageUtil.img.get("03.png"),
ImageUtil.img.get("04.png"),ImageUtil.img.get("05.png"),
ImageUtil.img.get("06.png"),ImageUtil.img.get("07.png")};
Boom(int x,int y){
this.ox=x;
this.oy=y;
}
public void drawBoom(Graphics g) {
g.drawImage(boom[count], ox, oy, null);
count++;
if(count>7) count=0;
}
}
【boom 类定义了七张图片,这七张图片反复重绘即可实现动态的爆炸视觉效果】
Music类 代码如下
package com.my.plane;
import java.applet.Applet;
import java.applet.AudioClip;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
public class Music {
File file1=new File("music\\game_music.wav");
File file2=new File("music\\bullet.wav");
File file3=new File("music\\enemy1_down.wav");
AudioClip bgmusic=null;
AudioClip bulletmusic=null;
AudioClip boommusic=null;
Music(){
try {
bgmusic=Applet.newAudioClip(file1.toURI().toURL());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
bulletmusic=Applet.newAudioClip(file2.toURI().toURL());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
boommusic=Applet.newAudioClip(file3.toURI().toURL());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这里我设置了三种音乐,分别为背景音乐,子弹发射音效,爆炸音效。
3、设置调用线程,完成所有对象类元素的重绘,实现动态效果画面
我这里直接用面板实现Runnable接口, 在面板中添加线程。
面板类的全部代码如下:
package com.my.plane;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import java.util.Random;
import javax.swing.JPanel;
import util.ImageUtil;
public class GameJPanel extends JPanel implements Runnable,KeyListener{
Plane plane=new Plane();//这是玩家飞机
Background bgck=new Background();
Music music=new Music();
LinkedList allEnemy=new LinkedList();//这是敌方飞机
LinkedList allBoss=new LinkedList();
LinkedList allBullet=new LinkedList();
LinkedList allBoom=new LinkedList();
//用这个四个bool类型来判断 plane(我方飞机)是否移动
boolean left=false;
boolean right=false;
boolean up=false;
boolean down=false;
boolean bullet1=false;//用来选择子弹
public static boolean gameover=false;
//*******************
int count=0; //计数器
int count1=0;
int count2=0;
int over=0;
Random rand=new Random();//用来产生随机数
GameJPanel(){
this.setFocusable(true);
this.addKeyListener(this);
music.bgmusic.loop();
}
public void paint(Graphics g) {
bgck.drawbg(g);//绘制背景
plane.drawplane(g);//绘制玩家飞机
for(int i=0;i= GameJFrame.jx) plane.px=20;
if(plane.px<=0) plane.px=GameJFrame.jx;
if(plane.py>=GameJFrame.jy-55) plane.py=GameJFrame.jy-55;
if(plane.py<=0) plane.py=0;
//***************玩家飞机设置到此结束***************************
//***************************下面是增加敌方的飞机**********
if(count>=20) {
allEnemy.add(new Enemy(rand.nextInt(GameJFrame.jx-20),
rand.nextInt(GameJFrame.jx-20),
rand.nextInt(GameJFrame.jx-20),rand.nextInt(GameJFrame.jx-20),
-40,-10,-15,-400));
count=0;
}
//********************************************
//*******************设置敌方飞机的移动**********
for(int i=0;iGameJFrame.jy&&now.eh[1]>GameJFrame.jy&&now.eh[2]>GameJFrame.jy&&
now.eh[3]>GameJFrame.jy) {
allEnemy.remove(i);
}
}
//********************敌方飞机设置到此结束*************
//**********************下方是添加boss**********
if(count1>=400) {
allBoss.add(new Boss(rand.nextInt(GameJFrame.jx-500),-20));
count1=0;}
//********************************************
for(int i=0;iGameJFrame.jy) {
allBoss.remove(i);
//*****************************BOSS类设置到此结束************
}
}
//*****************************BOSS类设置到此结束************
//*********下面是子弹类设置*****
int v=90;
if(bullet1) {
v=20;
}
if(count2>=v) {
allBullet.add(new Bullet(plane.px+plane.pimage[0].getWidth()/2-10,
plane.px+plane.pimage[0].getWidth()/2-45,
plane.py, plane.py ));
music.bulletmusic.play();
count2=0;
}
for(int i=0;i=7) {
allBoom.remove(i);
}
}
over++;
//这里当敌方飞机与玩家飞机相撞则宣布 gameover
if(over>500) { for(int i=0;ir2x+r2w||r1x+r1wr2y+r2h||r1y+r1h
【面板中无非实现两个效果一:使用线程改变各类对象元素的坐标,调用repaint实现元素坐标重绘,二:将飞机类 X Y 坐标的移动绑定到键盘事件上,实现键盘 wasd 控制上下左右。 代码虽长,但很容易理解。】
此时只需要创建一个窗口类将面板添加进去即可,窗口代码如下
package com.my.plane;
import java.applet.Applet;
import java.applet.AudioClip;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import javax.swing.JFrame;
import util.ImageUtil;
public class GameJFrame extends JFrame{
GameJPanel gamePanelnew =new GameJPanel();
Thread move=new Thread(gamePanelnew);
public static int jx=ImageUtil.img.get("bg.jpg").getWidth();
public static int jy=ImageUtil.img.get("bg.jpg").getHeight();
@SuppressWarnings("deprecation")
GameJFrame(){
this.setTitle("--雷霆战机--(自写原创源码,作者See:QQ:3492625357)");
this.setSize(jx, jy+90);
this.setLocationRelativeTo(null);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(gamePanelnew);
}
}
这时候随便创建一个游戏入口类即主类,创建这个窗口即可
package com.my.plane;
import javax.swing.JFrame;
import util.ImageUtil;
public class Game_Main {
public static void main(String[] args) {
JFrame game=new GameJFrame();
}
}
到这里,所有的项目就大功告成了!!这时候运行你的主类,就可以玩属于你自己雷霆战机啦!是不是有 原来如此的感受呢。
看似华丽的背后,仅仅只是一行行简单的代码实现的。加油!!!
最后我已经将有所有源代码和游戏所需要的素材全部打包了,这些素材是我在网络上找了很多的素材的合集,内容非常丰富,如果有需要的,可以添加我的 QQ3492625357
原创不易,你阅读我文章亦如你与我交谈一般,交谈即为交友,朋友,离别之际请给予你的朋友一个赞,好吗! 后会有期!