一、项目目录结构 二、关于游戏窗体和游戏面板这是一个Java小游戏,带背景音乐的飞机大战,简单易上手,一共九个代码段,具体代码和游戏制作如下:
Gameframe.Java
package ui;
import javax.swing.Jframe;
public class Gameframe extends Jframe {
public Gameframe() {
//设置标题 方法来源于Jframe类
setTitle("全民飞机大战");
//设置大小 setSize(宽度,高度);
setSize(512,768);
//设置位置居中显示
//快捷键:Alt+? 开启代码提示
//null相对于屏幕左上角居中
setLocationRelativeTo(null);
//设置不允许玩家改变界面大小
setResizable(false);
//设置默认的关闭选项
//关闭窗体的时候退出程序
setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE);
}
public static void main(String arg[]) {
//创建窗体对象:调用窗体的构造方法,制作窗体
Gameframe frame=new Gameframe();
//创建面板对象:调用面板的构造方法,制作面板
GamePanel panel = new GamePanel(frame);//方便在面板中添加键盘监听器
//调用开始游戏的方法,启动游戏
panel.action();
//将面板加入到窗体中
frame.add(panel);
//显示窗体 true显示 false隐藏
frame.setVisible(true);
//Music music=new Music();
//music.player();
String filepath="src/img/game_music.wav";
musicStuff musicObject=new musicStuff();
musicObject.playMusic(filepath);
}
}
package ui;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
//import java.awt.List;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JPanel;
public class GamePanel extends JPanel{
//1.定义背景图
BufferedImage bg;//背景图
//创建英雄机对象
Hero hero=new Hero();
//创建敌机对象
//Ep ep=new Ep();
//创建敌机的大本营(所有的敌机都放在这里)
//使用集合不使用数组,是因为数组必须指定长度,而此游戏中,敌机数量不确定。
List eps = new ArrayList();
//英雄机的弹药库
List fs = new ArrayList();
//定义分数
int score;
//设置游戏开关
boolean gameover;//游戏开始时,gameover为false,游戏结束时,gameover为true。
//设置英雄机的活力
int power=1;
public void action() {
//创建并启动一个线程,线程作用控制游戏场景中物体的移动
//固定格式
//new Thread(){public void run(){线程需要做的事情}}.start();
new Thread(){
public void run(){
//写一个死循环,让游戏一直运行
while(true) {
if(!gameover) {
//调用敌机入场的方法
epEnter();
//调用让敌机移动的方法
epMove();
//发射子弹
shoot();
//让子弹移动
fireMove();
//判断子弹是否打到敌机
shootEp();
//判断敌机是否撞到英雄机
hit();
}
//每执行一次,休息一会
//线程休眠 sleep(毫秒数)
try {
//每隔10毫秒,执行一次epEnter方法
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//重绘,刷新界面
repaint();
}
}
}.start();
}
protected void hit() {
//遍历敌机
for(int i=0;i3) {
hero.hp++;
power=3;
}
}
//1.敌机死亡,从敌机大本营中删掉
eps.remove(e);
//增加分数
score+=10;
//当英雄机的血量减少到0时,游戏结束
if(hero.hp<=0) {
//游戏结束
gameover=true;
}
}
}
//2.子弹消失,从弹药库中删除子弹
fs.remove(f);
}
}
}
protected void fireMove() {
//遍历所有子弹
for(int i=0;i=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,0);
//将子弹加入到弹药库中
fs.add(fire1);
//创建第二排子弹
Fire fire2=new Fire(hero.x+75,hero.y,2);
//将子弹加入到弹药库中
fs.add(fire2);
}else {
//创建第一排子弹
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);
}
//将计数器归零
findex=0;
}
}
protected void epMove() {
//遍历所有的敌机
for(int i=0; i=8) {
//创建敌机
Ep e=new Ep();
//将敌机加入到敌机大本营中
eps.add(e);
//将index重新设置为0
index=0;
}
}
public GamePanel(Gameframe frame){
//设置背景
setBackground(Color.blue);
//初始化图片
//如果工具类中没有加static,则要加App app=new App();
bg=App.getImg("/img/bg2.jpg");
//使用鼠标监听器(固定格式)
//1.创建鼠标适配器
MouseAdapter adapter= new MouseAdapter() {
//确定需要监听的鼠标事件
@Override
public void mouseClicked(MouseEvent e) {
//点击鼠标时会执行的代码
//如果游戏结束了,点击屏幕重新开始游戏
if(gameover) {
//重新开始游戏,重新创建一个英雄机
hero=new Hero();
//重置游戏开关
gameover=false;
//分数清0
score=0;
//清空敌机集合
eps.clear();
//清空子弹集合
fs.clear();
//随机背景图
Random rd=new Random();
int index=rd.nextInt(5)+1;
bg=App.getImg("/img/bg"+index+".jpg");
//刷新界面
repaint();
}
}
@Override
public void mouseMoved(MouseEvent e) {
//当鼠标在游戏界面中移动时,会触发的方法
//当写入如下代码时,鼠标每移动一次就会触发一次“移动了鼠标~~”
//System.out.println("移动了鼠标~~");
//让英雄机跟着鼠标一起移动,让英雄机的横纵坐标等于鼠标的横纵坐标
//获取鼠标的横纵坐标
int mx=e.getX();//鼠标的横坐标
int my=e.getY();//鼠标的纵坐标
if(!gameover) {
//让英雄机移动到鼠标的位置上(英雄机的行为,可以在英雄机中定义移动到鼠标的方法)
hero.moveToMouse(mx, my);
}
//刷新界面,将英雄机绘制到新的位置上
//重新调用paint方法
repaint();
}
};
//3.将适配器加入到监听器中(固定格式)
addMouseListener(adapter);
addMouseMotionListener(adapter);
//使用键盘监听器(固定格式)
//1.创建键盘适配器
KeyAdapter kd=new KeyAdapter() {
//2.确定需要监听的键盘事件
public void keyPressed(KeyEvent e) {
//当按下键盘按键时,会触发的方法
//监听键盘的按键
//每一个按键都会对应一个数字
//获取键盘上按键的数字
int keyCode=e.getKeyCode();
System.out.println(keyCode);
if(keyCode==KeyEvent.VK_W) {
//英雄机向上移动
hero.moveUp();
}else if(keyCode==KeyEvent.VK_A) {
//英雄机向左移动
hero.moveLeft();
}else if(keyCode==KeyEvent.VK_D) {
//英雄机向右移动
hero.moveRight();
}else if(keyCode==KeyEvent.VK_S) {
//英雄机向下移动
hero.moveDown();
}
//重绘,将飞机画到新的位置上
repaint();
}
};
//3.将适配器加入到窗体的监听器中
frame.addKeyListener(kd);
}
@Override
public void paint(Graphics g) {
super.paint(g);
//画图片
//g.drawImage(图片,图片的横坐标,图片的纵坐标,null);
//横纵坐标,是设置图片左上角的坐标
g.drawImage(bg,0,0,null);
//画图片时,如果不加宽度,高度,画的就是原图的大小
//如果想要改变图片的大小,可以使用如下的格式
//g.drawImage(图片,图片的横坐标,图片的纵坐标,图片的宽度,图片的高度,null);
//在paint中画图是有顺序的,先画的会被后画的覆盖,向栈一样
//画英雄机
g.drawImage(hero.img,hero.x,hero.y,hero.w,hero.h,null);
//画敌机
//遍历敌机大本营集合,画出所有的敌机
for(int i=0;i
三、编写游戏中的飞行物
Ep.java
package ui;
import java.awt.image.BufferedImage;
import java.util.Random;
public class Ep extends FlyObject {
int sp;//敌机的速度
public int hp;//敌机的血量
int type;//敌机的类型
//BufferedImage img;
//int x;//敌机的横坐标
//int y;//敌机的纵坐标
//int w;//敌机的宽度
//int h;//敌机的高度
public Ep() {
//确定随机数的类
Random rd=new Random();
//生成一个随机数,用来选取图片,随机数为1,则为第一张图片以此类推
int index=rd.nextInt(15)+1;
//设置敌机的类型
type=index;
//三目运算符
//格式:条件表达式?值1:值2
//表达式为true,取值1,否则值2
String path="/img/ep"+(index<10?"0":"")+index+".png";
//常见笔试题
//加号可以用来做加法运算,也可以用连接内容
//加号遇到双引号之前,都做加法运算
//加号遇到双引号开始及之后,都只能做连接,连接之后的结果为字符串
//确定敌机显示的图片
img=App.getImg(path);
y=-h;
//确定敌机的大小
w=img.getWidth();
//确定敌机的位置
//nextInt(num) 表示会在[0,num)之间随机生成一个整数
x=rd.nextInt(512-w);
h=img.getHeight();
//设置敌机的速度,序号越大,速度越慢
sp=17-index;
}
public void move() {
if(type==1||type==7||type==12) {
x-=1;
y+=sp;
}else if(type==2||type==6||type==11) {
x+=2;
y+=sp;
}else if(type==3||type==8||type==13){
x+=1;
y+=sp;
}else if(type==4||type==9||type==14){
x-=2;
y+=sp;
}else if(type==15) {
//敌机导弹速度快
y+=20;
}else if(type==5||type==10) {
y+=sp;
}
}
public boolean shootBy(Fire f) {
boolean hit=x<=f.x+f.w &&
x>=f.x-w &&
y<=f.y+f.h &&
y>=f.y-h;
return hit;
}
//将英雄机看成子弹,复制上面的代码
public boolean hitBy(Hero f) {
boolean hit=x<=f.x+f.w &&
x>=f.x-w &&
y<=f.y+f.h &&
y>=f.y-h;
return hit;
}
}
FlyObject.java
package ui;
import java.awt.image.BufferedImage;
public class FlyObject {
//飞行物的图片
BufferedImage img;
int x;//飞行物的横坐标
int y;//飞行物的纵坐标
int w;//飞行物的宽度
int h;//飞行物的高度
}
package ui;
public class Fire extends FlyObject {
//子弹当前移动的方向
int dir;//dir 为0:左上角 为1:垂直向上 为2:右上角
public Fire(int hx,int hy,int dir) {
//确定子弹的图片
img=App.getImg("/img/fire.png");
//确定子弹的大小
w=img.getWidth()/4;
h=img.getHeight()/4;
//确定子弹的位置(初始位置在英雄机的上方)
x=hx;
y=hy;
//属性的名字和参数的名字相同时,要加this
this.dir=dir;
}
public void move(){
if(dir==0) {
//左上角飞
x-=1;
y-=10;
}else if(dir==1){
//垂直飞
y-=10;
}else {
//右上角飞
x+=1;
y-=10;
}
}
}
Hero.java
package ui;
import java.awt.image.BufferedImage;
public class Hero extends FlyObject {
int hp;//确定英雄机的血量
//英雄机的图片
//BufferedImage img;
//英雄机的横坐标
//int x;
//英雄机的纵坐标
//int y;
//英雄机的宽度
//int w;
//英雄机的高度
//int h;
public Hero() {
//确定游戏开始时,英雄机显示的图片
img=App.getImg("/img/hero.png");
//使用横纵坐标,确定英雄机的初始位置
x=200;
y=500;
//确定英雄机的大小,使用图片的大小作为飞机的大小
w=img.getWidth();
h=img.getHeight();
//确定游戏开始时,英雄机的初始血量
hp=3;
}
public void moveToMouse(int mx,int my) {
x=mx-w/2;
y=my-h/2;
//x,y各减1/2,让鼠标作用在英雄机的中心位置
//System.out.println(x+","+y);
}
public void moveUp() {
//英雄机向上移动
y-=100;
}
public void moveDown() {
//英雄机向下移动
y+=100;
}
public void moveLeft() {
//英雄机向左移动
x-=100;
}
public void moveRight() {
//英雄机向右移动
x+=100;
}
}
四、插入背景音乐
Music.java
package ui;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
public class Music {
private int t = 0; // 音乐播放时间
AudioInputStream bgm;
private boolean playing = false;
public boolean isPlaying() {
return playing;
}
public void setPlaying(boolean playing) {
this.playing = playing;
}
public int getT() {
return t;
}
public void setT(int t) {
this.t = t;
}
public Music() {
try {
bgm = AudioSystem.getAudioInputStream(new File("src/img/game_music.wav"));
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} // 获得音频输入流
}
public void player() {
AudioInputStream ais;
AudioFormat baseFormat;
DataLine.Info info;
ais = bgm;
baseFormat = ais.getFormat(); // 指定声音流中特定数据安排
info = new DataLine.Info(SourceDataLine.class, baseFormat);
SourceDataLine line = null; //该数据线处理字节的缓冲并将其传递到混频器
try {
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(baseFormat);
// 打开具有指定格式的行,这样可使行获得所有所需的系统资源并变得可操作。
line.start();// 允许数据行执行数据 I/O
int BUFFER_SIZE = 4000 * 4;
int intBytes = 0;
byte[] audioData = new byte[BUFFER_SIZE]; // 音频数据数组
while (intBytes != -1 && (playing == false)) {
intBytes = ais.read(audioData, 0, BUFFER_SIZE);
// 从音频流读取指定的最大数量的数据字节,并将其放入给定的字节数组中。
if (intBytes >= 0) {
line.write(audioData, 0, intBytes);// 通过此源数据行将音频数据写入混频器。
t += 1;
}
//System.out.println(t);
}
} catch (LineUnavailableException | IOException e1) {
e1.printStackTrace();
}
}
}
五、 处理图片的工具类
App.java
package ui;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class App {
public static BufferedImage getImg(String path) {
//加载图片
//java中的IO流,输送数据的管道
//输入输出流
//App.class找到App类的路径
//getResource()获取资源
try {
BufferedImage img=ImageIO.read(App.class.getResource(path));
//如果找到图片就将图片返回
return img;
} catch (IOException e) {
//catch如果找不到图片,就会捕获找不到图片的原因
e.printStackTrace();
}
return null;
}
}
六、运行截图
需要游戏素材的小伙伴点赞加关注私聊哈~~~
瑞斯拜~~~



