推箱子游戏是一个比较古老的游戏,深受广大游戏爱好者的欢迎,它在带来乐趣的同时也能培养我们的反应力以及严谨的思维能力。
游戏规则是要求角色将地图中所有放置的箱子推到指定目标位置,只有合理安排移动次序和位置 ,才能顺利完成任务。
项目任务是用java语言设计并实现一个推箱子游戏,旨在培养学生面向对象编程思维方式,开发小型桌面应用程序的能力。
系统功能模块设计
其中系统可以分为初始化模块,绘制地图模块,移动箱子模块、移动小人模块,音乐播放模块,功能控制模块。
程序设计
主要分为四个类:BattleField类,Music类,Window类和Gameload类。
1. Battlefield类:内含BattleField构造方法,paint方法。其中paint方法重写了Graphics类中的paint方法,承载了绘制地图的作用,对内置的box、field、hero、target和wall等图片进行图像绘制。BattleField方法承载着初始化图片的作用,从相应的位置提取图片并存储到相应的图片存储单元中。
2. Music类:内置run方法和play方法。其中run方法调用了play方法使得其能够在调用run方法的时候进行音乐的播放。Play方法读取文件、存储到相应的存储单元中,最后通过player对象实现音乐文件的播放。
3. Window类:作为主方法,其中包含了了GUI界面的设计。建立了多个JPanel作为容器存储相关的JButton、JTextField和JLabel,以及相应的监视器,来确定在组件响应的时候所执行的操作,包括按钮监听,键盘监听等监视器。
4. Gameload类:初始化地图,通过读取地图文件来绘制地图。包含了moveLeft、moveRight、moveUp和moveDown等方法,以及判断游戏是否结束的isEnd方法。
项目文件位于GitHub上,在此处仅粘贴相关代码。
GitHub仓库链接
Music.java
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.*;
class Play0 extends Thread {
Player player;
String music;
public Play0(String file) {
this.music = file;
}
public void run() {
try {
play();
} catch (FileNotFoundException | JavaLayerException e) {
e.printStackTrace();
}
}
public void play() throws FileNotFoundException, JavaLayerException {
BufferedInputStream buffer = new BufferedInputStream(new FileInputStream(music));
player = new Player(buffer);
player.play();
}
}
Window.java
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
public class Window extends JFrame {
private Gameload Gameload;
private BattleField canvas;int sum=1;//设置关卡数目
JFrame frame=new JFrame();
public Window()
{
Play0 pl=new Play0("music.mp3");
pl.start();//打开时就开始播放音乐
Gameload=new Gameload(sum);
canvas=new BattleField(Gameload);
frame.setLayout(new BorderLayout());
frame.add(canvas,BorderLayout.CENTER);
frame.setSize(700,690);//设置窗口大小
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton exit=new JButton("退出");//设置退出游戏按钮
exit.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
pl.stop();
exit.setFocusable(false);
}
});//设置窗口关闭
JButton next=new JButton("下一关");//设置下一关按钮
JButton refresh=new JButton("重新开始");//设置重新开始按钮
refresh.addActionListener(new ActionListener() {//按下”重新开始“按钮的监视器
@Override
public void actionPerformed(ActionEvent e) {
Gameload.init(sum);
canvas.repaint();
refresh.setFocusable(false);
}
});
JButton musicstop=new JButton("关闭音乐");//设置关闭音乐的按钮
JPanel buttons=new JPanel();//新建一个JPanel 容纳所有的按钮
JPanel lbadtxt=new JPanel(new BorderLayout());//显示相关字体和文本框
JPanel txtandfield=new JPanel();//新建
JTextField mission=new JTextField(2);
mission.setEditable(false);
JLabel missions=new JLabel("关卡数");
mission.setText(String.valueOf(sum));//显示相关的关卡数
txtandfield.add(missions);
txtandfield.add(mission);
JLabel titles=new JLabel("狼
狼
追
羊
羊
",JLabel.CENTER);//设置标题按钮
Font f=new Font("微软雅黑",Font.BOLD,40);//设置字体
titles.setFont(f);
titles.setForeground(Color.red);
lbadtxt.add(titles,BorderLayout.CENTER);
lbadtxt.add(txtandfield,BorderLayout.NORTH);
buttons.add(exit);//设置按钮控件,并放置在button panel里
buttons.add(next);
buttons.add(refresh);
buttons.add(musicstop);
next.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
sum++;//关卡数控件
if(sum<=2){
mission.setText(String.valueOf(sum));//显示相关的关卡数
Gameload.init(sum);
canvas.repaint();
next.setFocusable(false);
}
else{
JOptionPane.showMessageDialog(null, "关卡数超出,程序退出", "ERROR",
JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
next.setFocusable(false);
}
});//控件
musicstop.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
pl.stop();
musicstop.setFocusable(false);
}
});
frame.add(buttons,BorderLayout.SOUTH);//放在界面的南部(即下部)
frame.add(lbadtxt,BorderLayout.EAST);//放在界面的东部(即右部)
frame.addKeyListener(new KeyListener(){//创建监视器
public void keyPressed(KeyEvent event) {
if(event.getKeyCode()==KeyEvent.VK_UP)
{
Gameload.moveUp();//监控键盘,如果按下方向上键,则执行向上走的方法
}else if(event.getKeyCode()==KeyEvent.VK_DOWN)
{
Gameload.moveDown();
}else if(event.getKeyCode()==KeyEvent.VK_LEFT)
{
Gameload.moveLeft();
}else if(event.getKeyCode()==KeyEvent.VK_RIGHT)
{
Gameload.moveRight();
}
canvas.repaint();
if(Gameload.isEnd()) {
JOptionPane.showMessageDialog(null, "游戏结束");
System.exit(0);
}
}
public void keyReleased(KeyEvent event) {
}
public void keyTyped(KeyEvent event) {
}
});
frame.setVisible(true);
frame.setFocusable(true);
}
public static void main(String[] args) {
Window show=new Window();
}
}
Gameload.Java
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class Gameload {
private boolean exist=true;
// 游戏角色的坐标位置
private int x;
private int y;
// 游戏为20x20的地图
private String field[][] = new String[20][20];
// 记录推箱子的目标位置
private String target[][] = new String[20][20];
public void init(int num) {
try {
BufferedReader reader = new BufferedReader(new FileReader("field" + String.valueOf(num) + ".txt"));
// 读取文件的一行
String line = reader.readLine();
int j = 0;
while (line != null) {
// 以空格为分隔符号,分割一行数据;
String strs[] = line.split(" ");
for (int i = 0; i < 20; i++) {//初次设计的是20*20矩阵 以后根据要求重新编辑文件
field[i][j] = strs[i];
if (strs[i].equals("T")) {
// 记录目标位置
target[i][j] = "T";
} else {
// 非目标位置记为O
target[i][j] = "O";
}
// 记录角色的初始位置
if (strs[i].equals("H")) {
this.x = i;
this.y = j;
}
}
line = reader.readLine();
j++;
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public Gameload(int num) {
// 从field文件加载地图信息
try {
BufferedReader reader = new BufferedReader(new FileReader("field" + String.valueOf(num) + ".txt"));
// 读取文件的一行
String line = reader.readLine();
int j = 0;
while (line != null) {
// 以空格为分隔符号,分割一行数据;
String strs[] = line.split(" ");
for (int i = 0; i < 20; i++) {//初次设计的是20*20矩阵 以后根据要求重新编辑文件
field[i][j] = strs[i];
if (strs[i].equals("T")) {
// 记录目标位置
target[i][j] = "T";
} else {
// 非目标位置记为O
target[i][j] = "O";
}
// 记录角色的初始位置
if (strs[i].equals("H")) {
this.x = i;
this.y = j;
}
}
line = reader.readLine();
j++;
}
reader.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
//角色向左移动
public void moveLeft() {
int a = x;
int b = y;
if (!field[a - 1][b].equals("W")) {//判断二维数组前一位是否为墙壁
if (field[a - 1][b].equals("B")) {
if (!field[a - 2][b].equals("B") && !field[a - 2][b].equals("W")) {
if (target[a][b].equals("T")) {//如果任务位置为目标位置
field[a - 1][b] = "H";//将人物向左平移一格
field[a][b] = "T";//将目标位置定在原来人物位置上
field[a - 2][b] = "B";
x = a - 1;//将人物位置x坐标平移一位
} else {//否则将人物向左平移
field[a - 1][b] = "H";
field[a][b] = "E";//将背景赋值为
field[a - 2][b] = "B";//将箱子向左平移两个
x = a - 1;
}
}
} else {//如果人物位置的左边不为墙壁位置
if (target[a][b].equals("T")) {
field[a - 1][b] = "H";//当位置为目标位置时,将H向左移动
field[a][b] = "T";//将位置设置为T
x = a - 1;//向左位置设置
} else {
field[a - 1][b] = "H";//不为目标位置时,将H向左移动
field[a][b] = "E";//将位置设置为背景
x = a - 1;//向左位置设置
}
}
}
}
//角色向右移动
public void moveRight() {
int a = x;
int b = y;
if (!field[a + 1][b].equals("W")) {
if (field[a + 1][b].equals("B")) {
if (!field[a + 2][b].equals("B") && !field[a + 2][b].equals("W")) {
if (target[a][b].equals("T")) {
field[a + 1][b] = "H";
field[a][b] = "T";
field[a + 2][b] = "B";
x = a + 1;
} else {
field[a + 1][b] = "H";
field[a][b] = "E";
field[a + 2][b] = "B";
x = a + 1;
}
}
} else {
if (target[a][b].equals("T")) {
field[a + 1][b] = "H";
field[a][b] = "T";
x = a + 1;
} else {
field[a + 1][b] = "H";
field[a][b] = "E";
x = a + 1;
}
}
}
}
//角色向上移动
public void moveUp() {
int a = x;
int b = y;
if (!field[a][b - 1].equals("W")) {
if (field[a][b - 1].equals("B")) {
if (!field[a][b - 2].equals("B") && !field[a][b - 2].equals("W")) {
if (target[a][b].equals("T")) {
field[a][b - 1] = "H";
field[a][b] = "T";
field[a][b - 2] = "B";
y = b - 1;
} else {
field[a][b - 1] = "H";
field[a][b] = "E";
field[a][b - 2] = "B";
y = b - 1;
}
}
} else {
if (target[a][b].equals("T")) {
field[a][b - 1] = "H";
field[a][b] = "T";
y = b - 1;
} else {
field[a][b - 1] = "H";
field[a][b] = "E";
y = b - 1;
}
}
}
}
//角色向下移动
public void moveDown() {
int a = x;
int b = y;
if (!field[a][b + 1].equals("W")) {
if (field[a][b + 1].equals("B")) {
if (!field[a][b + 2].equals("B") && !field[a][b + 2].equals("W")) {
if (target[a][b].equals("T")) {
field[a][b + 1] = "H";
field[a][b] = "T";
field[a][b + 2] = "B";
y = b - 1;
} else {
field[a][b + 1] = "H";
field[a][b] = "E";
field[a][b + 2] = "B";
y = b + 1;
}
}
} else {
if (target[a][b].equals("T")) {
field[a][b + 1] = "H";
field[a][b] = "T";
y = b + 1;
} else {
field[a][b + 1] = "H";
field[a][b] = "E";
y = b + 1;
}
}
}
}
//判断游戏是否结束
public boolean isEnd() {
for (int i = 0; i < 20; i++)
for (int j = 0; j < 20; j++) {
if (field[i][j].equals("T"))
return false;
}
return true;
}
public String[][] getfield() {
return field;
}
}
Battlefield.java
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
//游戏使用的场地初始化,即战场
public class BattleField extends JPanel {
private BufferedImage box;
private BufferedImage field;
private BufferedImage hero;
private BufferedImage target;
private BufferedImage wall;
private Gameload gl;
public Graphics g;
public BattleField(Gameload gl){
this.gl=gl;
try{
box= ImageIO.read(new File("box.png"));
field=ImageIO.read(new File("field.png"));
hero=ImageIO.read(new File("hero.png"));
target=ImageIO.read(new File("target.png"));
wall=ImageIO.read(new File("wall.png"));
}catch(IOException e){
e.printStackTrace();
}
}
public void paint(Graphics g){
this.g=g;
BufferedImage image=null;
for(int j=0;j<20;j++)
for(int i=0;i<20;i++)
{
if(gl.getfield()[i][j].equals("B"))
{
image=box;//将图像设置为box
}else if(gl.getfield()[i][j].equals("E"))
{
image=field;//将图像设置为底图
}else if(gl.getfield()[i][j].equals("H")) {
image = hero;//将图像设置为人物
}
else if(gl.getfield()[i][j].equals("W")) {
image = wall;//将图像设置为墙面
}
else if (gl.getfield()[i][j].equals("T")){
image=target;//将图像设置为目标位置
}
g.drawImage(image, 0+i*image.getWidth(), 0+j*image.getHeight(),null);
}
}
}
学习不易,请勿随意转载。