经典的推箱子是一个来自日本的古老游戏,目的是在训练你的逻辑思考能力。在一个狭小的仓库中,要求把木箱放到指定的位置,稍不小心就会出现箱子无法移动或者通道被堵住的情况,所以需要巧妙的利用有限的空间和通道,合理安排移动的次序和位置,才能顺利的完成任务。
推箱子游戏界面
性能测试:
程序设计的思路
我们把地图想象成一个网格,每个格子就是工人每次移动的步长(这里为30像素),也是箱子移动的距离,这样问题就简化多了。首先我们设计一个mapRow *mapColumn的二维数组map。按照这样的框架来思考。对于格子的(X,Y)两个屏幕像素坐标,可以由二维数组下标(i,j)换算。
换算公式为:leftX + j * 30, leftY + i* 30
每个格子状态值分别用枚举类型值:
// 定义一些常量,对应地图的元素
final byte WALL = 1, BOX = 2, BOXONEND = 3, END = 4, MANDOWN = 5,
MANLEFT = 6, MANRIGHT = 7, MANUP = 8, GRASS = 9,
MANDOWNONEND = 10,MANLEFTONEND = 11,
MANRIGHTONEND = 12, MANUPONEND = 13;
每个格子状态值分别用枚举类型值:
// 定义一些常量,对应地图的元素
final byte WALL = 1, BOX = 2, BOXONEND = 3, END = 4, MANDOWN = 5,
MANLEFT = 6, MANRIGHT = 7, MANUP = 8, GRASS = 9,
MANDOWNONEND = 10,MANLEFTONEND = 11,
MANRIGHTONEND = 12, MANUPONEND = 13;
Wall(1)代表墙,Box(2)代表箱子,BOXONEND(3)代表放到目的地的箱子,
END(4)代表目的地;
MANDOWN(5)向下的人,MANLEFT(6)向左的人MANRIGHT(7)向右的人, MANUP(8)向上的人;GRASS(9)代表通道。
MANDOWNONEND(10)站在目的地向下的人,MANLEFTONEND(11)站在目的地向左的人,MANRIGHTONEND(12)站在目的地向右的人,MANUPONEND(13)站在目的地向上的人。
存储的原始地图中格子的状态值数组采用相应的整数形式存放。
游戏规则
可以假设工人移动趋势方向向右,其他方向原理是一致的。P1,P2分别代表工人移动趋势方向前两个方格。
1.前方P1是围墙
如果工人前方是围墙(即阻挡工人的路线)
{
退出规则判断,布局不做任何改变;
}
2.前方P1是通道(GRASS)或目的地(END)
如果工人前方是通道或目的地
{
工人可以进到P1方格;修改相关位置格子的状态值。
}
程序设计的步骤:
1.设计地图数据类(MapFactory.java)地图数据类保存所有关卡的原始地图数据,每关数据类保存所有关卡的原始地图数据,每关数据为一个二维数组。所以此处map是三维数组。
2.设计地图类(Map.java)由于每移动一步,需要保存当前的游戏状态,所以此处定义此地图类,保存人的位置和游戏地图的当前状态。撤销移动时,恢复地图是通过此类获取需要人的位置,地图当前状态,关卡数。
3.设计游戏面板类(GameFrame.java)
游戏面板类完成游戏的界面刷新显示,以及相应鼠标键盘相关事件。
事后总结:在这次与黄臻的合作中,我体会到了团队合作的重要性。同时,也对Java游戏编程有了更深的了解,此次编程借鉴的是其他人的代码,由于刚刚接触游戏编程,还没有能力在此基础上进行创新(仅仅做到看懂并运行测试),望老师谅解。
提出过程改进计划:在下一次团队合作中,一定要注意分工明确这一点。同时,应提高自身的编程能力,及思考视野。
整个游戏的源文件说明:
GameFrame.java:游戏界面视图。
//6-18完成
//推箱子带音乐版
//右键单击--悔棋功能
//用时1:40分钟
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.ArrayList;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class GameFrame extends JFrame implements ActionListener, MouseListener// 主面板类
, KeyListener {
private int grade = 0;
// row,column记载人的行号 列号
// leftX,leftY 记载左上角图片的位置 避免图片从(0,0)坐标开始
private int row = 7, column = 7, leftX = 0, leftY = 0;
// 记载地图的行列数
private int mapRow = 0, mapColumn = 0;
// width,height 记载屏幕的大小
private int width = 0, height = 0;
private boolean acceptKey = true;
// 程序所用到的图片
private Image pic[] = null;
// 定义一些常量,对应地图的元素
final byte WALL = 1, BOX = 2, BOXONEND = 3, END = 4, MANDOWN = 5,
MANLEFT = 6, MANRIGHT = 7, MANUP = 8, GRASS = 9, MANDOWNONEND = 10,
MANLEFTONEND = 11, MANRIGHTONEND = 12, MANUPONEND = 13;
private byte[][] map = null;
private ArrayList list = new ArrayList();
Sound sound;
public void getManPosition() {
for (int i = 0; i < map.length; i++)
for (int j = 0; j < map[0].length; j++)
if (map[i][j] == MANDOWN || map[i][j] == MANDOWNONEND
|| map[i][j] == MANUP || map[i][j] == MANUPONEND
|| map[i][j] == MANLEFT || map[i][j] == MANLEFTONEND
|| map[i][j] == MANRIGHT || map[i][j] == MANRIGHTONEND) {
row = i;
column = j;
break;
}
}
public void DisplayToast(String str) {
JOptionPane.showMessageDialog(null, str, "提示",
JOptionPane.ERROR_MESSAGE);
}
// 撤销移动
public void undo() {
if (acceptKey) {
// 撤销
if (list.size() > 0) {
// 若要撤销 必须走过
Map priorMap = (Map) list.get(list.size() - 1);
map = priorMap.getMap();
row = priorMap.getManX();
column = priorMap.getManY();
repaint();
list.remove(list.size() - 1);
} else
DisplayToast("不能再撤销!");
} else {
DisplayToast("此关已完成,不能撤销!");
}
}
public void nextGrade() {