推箱子游戏的基本思路:
1、添加背景,创建人物和箱子,以及障碍物,目标;
2、利用二维数组布置障碍物;
3、添加键盘监听,控制人物移动;
4、碰撞检测;
5、通关判定。
程序源代码:
1、添加背景,创建人物和箱子,以及障碍物,目标
//添加背景
private void backgroundInit() {
//添加背景图片
ImageIcon icon = new ImageIcon("background.png");
JLabel lab_bg = new JLabel(icon);
lab_bg.setBounds(0, 0, 800, 600);
this.add(lab_bg);
}
JLabel lab_man;
JLabel lab_box1;
JLabel lab_box2;
JLabel lab_box3;
JLabel target1;
JLabel target2;
JLabel target3;
// 新建一个数组存放JLabel组件
JLabel[][] boxs = new JLabel[12][16];
//8代表目标
private void targetInit() {
ImageIcon icon = new ImageIcon("8.png");
target1 = new JLabel(icon);
target1.setBounds(600, 300, 50, 50);
this.add(target1);
datas[6][12] = 8;
target2 = new JLabel(icon);
target2.setBounds(600, 250, 50, 50);
this.add(target2);
datas[5][12] = 8;
target3 = new JLabel(icon);
target3.setBounds(600, 200, 50, 50);
this.add(target3);
datas[4][12] = 8;
}
// 4代表箱子
private void boxInit() {
ImageIcon icon1 = new ImageIcon("4.png");
lab_box1 = new JLabel(icon1);
lab_box1.setBounds(6 * 50, 6 * 50, 50, 50);
this.add(lab_box1);
// 修改箱子对应位置上的数据为4(数据初始化)
datas[6][6] = 4;
// 把JLabel组件放入boxs中
boxs[6][6] = lab_box1;
ImageIcon icon2 = new ImageIcon("4.png");
lab_box2 = new JLabel(icon2);
lab_box2.setBounds(8 * 50, 6 * 50, 50, 50);
this.add(lab_box2);
//现实中的行列跟游戏里的行列恰恰相反
datas[6][8] = 4;
boxs[6][8] = lab_box2;
ImageIcon icon3 = new ImageIcon("4.png");
lab_box3 = new JLabel(icon3);
lab_box3.setBounds(6 * 50, 8 * 50, 50, 50);
this.add(lab_box3);
datas[8][6] = 4;
boxs[8][6] = lab_box3;
}
//人物的坐标
int mx;
int my;
//人物
private void manInit() {
//人物的初始坐标(行列)
mx = 1;
my = 1;
ImageIcon icon = new ImageIcon("-10.png");
lab_man = new JLabel(icon);
//人物在窗体中的实际坐标=人物所在行列 x 人物图片尺寸
lab_man.setBounds(mx * 50, my * 50, 50, 50);
this.add(lab_man);
}
//1代表障碍
private void treeInit() {
ImageIcon imageIcon = new ImageIcon("1.png");
for (int i = 0; i < datas.length; i++) {
for (int j = 0; j < datas[i].length; j++) {
if (datas[i][j] == 1) {
// 创建障碍物
JLabel lab_tree = new JLabel(imageIcon);
lab_tree.setBounds(50 * j, 50 * i, 50, 50);
this.add(lab_tree);
}
}
}
}
2、利用二维数组布置障碍物
根据背景图片的大小,把背景分成12行16列的50 x 50大小的组件,每个组件都填充一张图片(人物、箱子、障碍物、目标),并用一个数字标识(1是障碍;4是箱子;8是目标;12是有箱子的目标);因此,推箱子游戏的本质是数字之间的移动和判定。
// 使用二维数组模拟地图场景数据;
int[][] datas = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } };
3、添加键盘监听,控制人物移动; + 碰撞检测;
人物跟箱子、跟障碍、跟目标之间的关系一共有13种(笨办法就像以下一样一一列出):
-----人物 障碍
-----人物 箱子 障碍
-----人物 箱子 箱子
-----人物 箱子 目标箱子
-----人物 目标箱子 障碍
-----人物 目标箱子 箱子
-----人物 目标箱子 目标箱子
-----人物 空地
-----人物 空目标
-----人物 箱子 空地
-----人物 箱子 空目标
-----人物 目标箱子 空地
-----人物 目标箱子 空目标
public void keyReleased(KeyEvent e) {
// 获取按键号
int key = e.getKeyCode();
// 向上移动
if (key == 38) {
// 人 空
if (datas[my - 1][mx] == 0) {
//人物移动一格(行列)
my = my - 1;
//获取人物当前位置坐标
int x = (int) lab_man.getLocation().getX();
int y = (int) lab_man.getLocation().getY();
//人物坐标移动50
lab_man.setLocation(x, y - 50);
//插入人物向上移动时的图片
ImageIcon icon = new ImageIcon("10.png");
lab_man.setIcon(icon);
return;
}
// 人 障碍
if (datas[my - 1][mx] == 1) {
//此种情况下,什么事都不做,直接返回
return;
}
// 人 箱 障碍
if (datas[my - 1][mx] == 4 && datas[my - 2][mx] == 1) {
//此种情况下,什么事都不做,直接返回
return;
}
// 人 箱 箱
if (datas[my - 1][mx] == 4 && datas[my - 2][mx] == 4) {
//此种情况下,什么事都不做,直接返回
return;
}
// 人 箱 箱笼
if (datas[my - 1][mx] == 4 && datas[my - 2][mx] == 12) {
//此种情况下,什么事都不做,直接返回
return;
}
// 人 箱笼 障碍
if (datas[my - 1][mx] == 12 && datas[my - 2][mx] == 1) {
//此种情况下,什么事都不做,直接返回
return;
}
// 人 箱笼 箱
if (datas[my - 1][mx] == 12 && datas[my - 2][mx] == 4) {
//此种情况下,什么事都不做,直接返回
return;
}
// 人 箱笼 箱笼
if (datas[my - 1][mx] == 12 && datas[my - 2][mx] == 12) {
//此种情况下,什么事都不做,直接返回
return;
}
// 人 笼
if (datas[my - 1][mx] == 8) {
//人物移动一格
my = my - 1;
//获取人物当前位置坐标
int x = (int) lab_man.getLocation().getX();
int y = (int) lab_man.getLocation().getY();
//人物坐标移动50
lab_man.setLocation(x, y - 50);
//插入此状态图片
ImageIcon icon = new ImageIcon("10.png");
lab_man.setIcon(icon);
return;
}
// 人 箱 空地 4-0 0-4
if (datas[my - 1][mx] == 4 && datas[my - 2][mx] == 0) {
//此种情况下,箱子标识与空地互换
datas[my - 1][mx] = 0;
datas[my - 2][mx] = 4;
}
// 人 箱 笼 4-0 8-12
if (datas[my - 1][mx] == 4 && datas[my - 2][mx] == 8) {
//此种情况下,箱子原来位置的标识变成0,箱子移动后的位置标识变成12(箱子到达目标)
datas[my - 1][mx] = 0;
datas[my - 2][mx] = 12;
//箱子到达目标的个数加1
num++;
}
// 人 箱笼 空 12-8 0-4
if (datas[my - 1][mx] == 12 && datas[my - 2][mx] == 0) {
//此种情况下,箱子原来位置的标识变成8,箱子移动后的位置标识变成4
datas[my - 1][mx] = 8;
datas[my - 2][mx] = 4;
num--;
}
// 人 箱笼 空笼 12-8 8-12
if (datas[my - 1][mx] == 12 && datas[my - 2][mx] == 8) {
//此种情况下,箱子原来位置的标识变成8,箱子移动后的位置标识变成12
datas[my - 1][mx] = 8;
datas[my - 2][mx] = 12;
}
//箱子的坐标改变
boxs[my - 1][mx].setLocation(mx * 50, my * 50 - 100);
boxs[my - 2][mx] = boxs[my - 1][mx];
boxs[my - 1][mx] = null;
//人物移动一格
my = my - 1;
int x = (int) lab_man.getLocation().getX();
int y = (int) lab_man.getLocation().getY();
//人物坐标移动50
lab_man.setLocation(x, y - 50);
ImageIcon icon = new ImageIcon("10.png");
lab_man.setIcon(icon);
//每移动一下就通关判定一次
victory();
return;
}
键盘监听的其他几个方向为:
上:38;下:40;左:37;右:39;
因为都是重复的,此处就不再赘述。
5、通关判定
int num = 0;
int total = 3;
private void victory() {
//箱子全部到达目标即为胜利
if (num == total) {
System.out.println("胜利");
}
}
只要每按一下按键,就调用一次 victory() 即可。
项目总结:
这个项目一开始看觉得不难,但是中间仍然出现了一些小问题,比如num老是没有进行相应的加减,后来检查了几遍才发现是目标忘记添加标识了,导致通关判定一直没有成功(还是粗心了啊!)。总的来说,这个项目的新点难点在于障碍物的设置,初次运用二维数组来对地图配置,这种思维的亮点在于对地图进行分割成一个个小组件,然后对每个组件填充不同的内容,进而配置地图。只要通过初始设定数组的内容,然后遍历数组,就可以很方便地对地图进行修改。
最后,写程序一定要一步一个脚印,否则思路乱了就会容易出错。