JavaSwing实现的推箱子项目源码
推(搬)箱子,又名Sokoban,仓库番等,是一款堪称古玩级的电脑游戏。提起它,笔者相信没什么人会感觉到陌生,更没什么生物会连听都没听说过。它的发展历史之久远,甚至超越了俄罗斯方块(1988年电脑游戏化)。
这款游戏最初起源于日本,是个很难争辩的事实(我知道有人反对,但笔者确实找不到什么有力的反对证据)。他由日本人(哎……)今川宏行在1981年创立游戏规则,并于1982年经日本软件公司Thinking Rabbit正式发布。比较遗憾的是,早期的推箱子并没有PC版,笔者在网络上搜索到的老版游戏也大多为90年以前的Mac OS下程式。
但说起真正令推箱子风靡于PC机的,却该感谢我们的台湾同胞李果兆先生。是他在1994年开发的仓库世家,才真正令推箱子游戏在世界各地大受推崇;仔细说来,推箱子这款小游戏之所以能有今时今日的声望与地位,固然有今川宏行的开创之功,但若说到贡献最大,承前启后的,则非中国台湾的李果兆先生莫属。
推箱子游戏的规则非常简单,就是用尽量少的推动或移动把所有箱子都推到目标点上。箱子只能推动而不能拉动;一次只能推动一个箱子。然而,尽管它的规则是很简单的,但对于不同难度的关卡,所需要的脑力却是截然不同的,有些关卡可能会花费您几个小时、几天甚至几个月的时间,也正是这种简单性和复杂性的结合,最终令推箱子类游戏风靡全球!
本回笔者在Blog中提供的,就是一款Java版推箱子游戏的简单实现。
笔者设定[上、下、左、右]为方向控制 ,键为后退到上一步操作,为重新开始当前关卡,点击键盘上对应关卡的数字键可以直接选关,需要注意的是笔者以HP限制了角色的移动次数,HP归0则挑战失败。
目前版本仅提供有5关,有需要者可参考同类游戏自行扩充,游戏源码在jar内。
游戏截图:
核心代码:
Sokoban.javapackage org.loon.game.simple.sokoban.control;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import org.loon.game.simple.sokoban.GraphicsUtils;
import org.loon.game.simple.sokoban.LSystem;
import org.loon.game.simple.sokoban.SimpleControl;
/**
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email <a title="" href="http://hi.baidu.com/ceponline" mce_href="http://hi.baidu.com/ceponline" target="_blank">ceponline</a>@yahoo.com.cn
* @version 0.1
*/
public class Sokoban extends SimpleControl {
/**
*
*/
private static final long serialVersionUID = 1L;
private Image backImage = GraphicsUtils.loadImage("image/back1.jpg");
private Image screenImage;
// 墙壁图
private Image floorImage[];
// 角色精灵
private RpgSprite sprite;
// 窗体显示图
private Graphics screen;
private String message = "按下 开始进行游戏";
private String m_stageName[] = { "关卡1", "关卡2", "关卡3", "关卡4", "关卡5", "关卡6",
"关卡7" };
private int CS = 32;
private int maxX, maxY, comps;
private int stageNo;
private boolean complete[];
private boolean boxMove[][];
private int hp[];
private int stageStates[][][];
private int ons[][];
private int role[];
private int rolex[];
private int roley[];
private int mapx[];
private int mapy[];
private int sleep = 0;
private boolean succeed = false;
private Stage stage;
public Sokoban(Stage stage) {
this.stage = stage;
this.floorImage = new Image;
this.sprite = new RpgSprite("image/role1.gif");
this.maxX = 16;
this.maxY = 13;
this.comps = 0;
this.complete = new boolean;
this.boxMove = new boolean;
this.ons = new int;
this.hp = new int;
this.stageStates = new int;
this.role = new int;
this.rolex = new int;
this.roley = new int;
this.mapx = new int;
this.mapy = new int;
for (int j = 0; j < 4; j++) {
floorImage = GraphicsUtils.loadImage("image/back" + (j + 1)
+ ".gif");
}
this.screenImage = GraphicsUtils.createImage(CS * maxX + CS, CS
* (maxY + 1) + 32, true);
this.screen = screenImage.getGraphics();
for (stageNo = 0; stageNo < stage.getMaxStageNo(); stageNo++) {
this.setupStage();
}
this.stageNo = -1;
// 开场界面
this.openDraw();
}
/**
* 刷新关卡
*
*/
public synchronized void reset(int stageNo) {
this.stageNo = stageNo;
this.stage.getMode() = 1;
this.message = null;
// 设定关卡
this.setupStage();
// 重绘背景
this.background();
// 重绘游戏屏幕
this.drawScreen();
}
/**
* 绘制屏幕背景
*
*/
public synchronized void background() {
screen.drawImage(backImage, 0, 0, null);
screen.setColor(Color.black);
screen.fillRect(0, LSystem.HEIGHT - 40, LSystem.WIDTH, 40);
}
/**
* 绘制屏幕图像
*
*/
public synchronized void drawScreen() {
if (stageNo >= stage.getMaxStageNo()) {
stageNo = 0;
}
for (int i = 0; i < mapy; i++) {
for (int j = 0; j < mapx;) {
switch (stageStates) {
case 2:
case 3:
case 4:
case 5:
screen.drawImage(floorImage, moveX(j), moveY(i), null);
default:
j++;
break;
}
}
}
for (int n = 0; n < mapy; n++) {
for (int l = 0; l < mapx; l++)
switch (stageStates) {
case 1:
screen.drawImage(floorImage, moveX(l), moveY(n), null);
screen.setColor(new Color(32, 0, 0));
screen.drawLine(moveX(l), moveY(n + 1), moveX(l) + CS - 1,
moveY(n + 1));
if (l == 0 || l > 0 && stageStates != 1) {
screen.setColor(new Color(160, 128, 96));
screen.drawLine(moveX(l), moveY(n) + 1, moveX(l),
moveY(n) + CS - 2);
}
if (l == mapx - 1 || l < mapx - 1
&& stageStates != 1) {
screen.setColor(new Color(72, 64, 64));
screen.drawLine(moveX(l) + CS - 1, moveY(n), moveX(l)
+ CS - 1, moveY(n) + CS - 2);
}
break;
case 2:
case 3:
case 4:
switch (stageStates) {
default:
break;
case 2:
case 3:
screen.drawImage(floorImage, moveX(l), moveY(n),
null);
break;
case 4:
break;
}
if (stageStates != 3)
screen.drawImage(floorImage, moveX(l), moveY(n),
null);
break;
default:
break;
}
}
// System.out.println(role);
screen.drawImage(sprite.getOnlyMove(role),
moveX(rolex), moveY(roley), null);
if (stageStates]] == 4) {
screen.drawImage(floorImage, moveX(rolex),
moveY(roley), null);
}
setupDisplay();
}
/**
* 定位到实际的X座标
*
* @param i
* @return
*/
public int moveX(int i) {
return (CS * ((maxX - mapx) + 1)) / 2 + CS * i;
}
/**
* 定位到实际的Y座标
*
* @param i
* @return
*/
public int moveY(int i) {
return (CS * ((maxY - mapy) + 1)) / 2 + CS * i;
}
/**
* 执行操作
*
*/
public synchronized void execute() {
boolean flag = true;
for (int i = 0; i < mapy; i++) {
for (int j = 0; j < mapx; j++) {
if (stageStates == 4) {
flag = false;
}
}
}
if (flag) {
stage.getMode() = 3;
complete = true;
} else if (hp == 0) {
stage.getMode() = 2;
}
comps = 0;
for (int n = 0; n < stage.getMaxStageNo(); n++) {
if (complete) {
comps++;
}
}
}
/**
* 键盘事件处理
*/
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 10 && stageNo == -1) {
// 开始关卡1
reset(0);
} else if (stageNo < 0) {
return;
}
// 选关(默认为最大支持7关,更多请自行设定)
if (e.getKeyCode() == 97 || e.getKeyCode() == 49) {
stageNo = 0;
} else if (e.getKeyCode() == 98 || e.getKeyCode() == 50) {
stageNo = 1;
} else if (e.getKeyCode() == 99 || e.getKeyCode() == 51) {
stageNo = 2;
} else if (e.getKeyCode() == 100 || e.getKeyCode() == 52) {
stageNo = 3;
} else if (e.getKeyCode() == 101 || e.getKeyCode() == 53) {
stageNo = 4;
} else if (e.getKeyCode() == 102 || e.getKeyCode() == 54) {
stageNo = 5;
} else if (e.getKeyCode() == 103 || e.getKeyCode() == 55) {
stageNo = 6;
// ESC,重新开始
} else if (e.getKeyCode() == 27) {
reset(stageNo);
} else if (stage.getMode() == 1) {
// 退步
if (e.getKeyCode() == 83) {
nextStep(-1);
}
// 移动角色
else if (e.getKeyCode() == 40) {
nextStep(0);
} else if (e.getKeyCode() == 37) {
nextStep(1);
} else if (e.getKeyCode() == 39) {
nextStep(2);
} else if (e.getKeyCode() == 38) {
nextStep(3);
} else {
return;
}
} else {
return;
}
// 绘制背景
background();
// 绘制游戏画面
drawScreen();
}
/**
* 切换动作
*
* @param i
*/
public synchronized void nextStep(final int i) {
boxMove - 1] = false;
switch (i) {
case 0:
if (stageStates + 1]] < 2) {
return;
}
if (stageStates + 1]] < 4) {
if (stageStates + 2]] < 4) {
return;
}
stageStates + 1]] += 2;
stageStates + 2]] -= 2;
boxMove - 1] = true;
}
roley++;
break;
case 1:
if (stageStates] - 1] < 2) {
return;
}
if (stageStates] - 1] < 4) {
if (stageStates] - 2] < 4) {
return;
}
stageStates] - 1] += 2;
stageStates] - 2] -= 2;
boxMove - 1] = true;
}
rolex--;
break;
case 2:
if (stageStates] + 1] < 2) {
return;
}
if (stageStates] + 1] < 4) {
if (stageStates] + 2] < 4) {
return;
}
stageStates] + 1] += 2;
stageStates] + 2] -= 2;
boxMove - 1] = true;
}
rolex++;
break;
case 3:
if (stageStates - 1]] < 2) {
return;
}
if (stageStates - 1]] < 4) {
if (stageStates - 2]] < 4) {
return;
}
stageStates - 1]] += 2;
stageStates - 2]] -= 2;
boxMove - 1] = true;
}
roley--;
break;
default:
if (hp == stage.getMaxHp()) {
return;
}
switch (ons]) {
case 0:
if (boxMove]) {
stageStates + 1]] += 2;
stageStates]] -= 2;
}
roley--;
break;
case 1:
if (boxMove]) {
stageStates] - 1] += 2;
stageStates]] -= 2;
}
rolex++;
break;
case 2:
if (boxMove]) {
stageStates] + 1] += 2;
stageStates]] -= 2;
}
rolex--;
break;
default:
if (boxMove]) {
stageStates - 1]] += 2;
stageStates]] -= 2;
}
roley++;
break;
}
break;
}
if (i != -1) {
hp--;
ons] = i;
}
role = ons];
if (i == -1) {
hp++;
}
execute();
}
/**
* 开场画面
*
*/
public synchronized void openDraw() {
background();
for (int i = 0; i < 5; i++) {
for (int j = 0; j < maxX + 1; j++) {
screen.drawImage(floorImage, CS * j,
(CS * i + CS / 2 * maxY) - CS * 2, null);
}
}
GraphicsUtils.setAntialias(screen, true);
String mes = "怪蜀黍传说 - 勇者推魔王";
screen.setFont(new Font("华文新魏", 1, 35));
GraphicsUtils.drawStyleString(screen, mes, (CS * maxX - screen
.getFontMetrics().stringWidth(mes)) / 2 + 13,
(CS * maxY) / 2 + 25, Color.black, Color.orange);
mes = "Java版搬箱子游戏开发入门示例 - 0.1.0";
screen.setFont(new Font("华文新魏", 0, 30));
GraphicsUtils.drawStyleString(screen, mes, (CS * maxX - screen
.getFontMetrics().stringWidth(mes)) / 2 + 13,
(CS * (maxY + 2)) / 2 - 55, Color.black, Color.white);
GraphicsUtils.setAntialias(screen, false);
setupDisplay();
}
/**
* 绘图接口实现
*/
public synchronized void draw(Graphics g) {
g.drawImage(screenImage, 0, 0, null);
if (succeed) {
if (sleep == 100) {
// 进入下一关
reset(++stageNo);
succeed = false;
sleep = 0;
}
sleep++;
}
}
/**
* 设置基本数据
*
*/
public void setupStage() {
for (int i = 0; i < maxY; i++) {
for (int j = 0; j < maxX; j++) {
stageStates = 0;
}
}
mapx = stage.getConf();
mapy = stage.getConf();
rolex = stage.getConf();
roley = stage.getConf();
for (int n = 0; n < mapy; n++) {
for (int l = 0; l < mapx; l++) {
stageStates = stage.getMapData();
}
}
hp = stage.getMaxHp();
role = 0;
for (int i1 = 0; i1 < stage.getMaxHp(); i1++) {
ons = 0;
}
for (int j1 = 0; j1 < stage.getMaxHp(); j1++) {
boxMove = false;
}
}
/**
* 设置显示
*
*/
public void setupDisplay() {
if (message == null) {
screen.setFont(new Font(LSystem.FONT, 0, 12));
int size = 0;
for (int j = 0; j < stage.getMaxStageNo(); j++) {
if (complete) {
screen.setColor(Color.gray);
} else {
screen.setColor(Color.white);
}
if (j == stageNo) {
if (complete) {
screen.setColor(Color.magenta);
} else {
screen.setColor(Color.cyan);
}
}
screen.drawString(m_stageName, size = (10 + (screen
.getFontMetrics().stringWidth("关卡0") + 20)
* j), LSystem.HEIGHT - 50);
}
screen.setColor(Color.white);
if (stageNo == -1) {
// 初始画面,无数据
} else {
// 显示状态
if (hp == 0) {
screen.setColor(Color.red);
} else if (hp <= stage.getMaxHp() / 4) {
screen.setColor(Color.orange);
} else if (hp <= stage.getMaxHp() / 2) {
screen.setColor(Color.yellow);
}
screen.drawString("主角 HP " + hp + "/"
+ stage.getMaxHp(), size + 50,
LSystem.HEIGHT - 50);
switch (stage.getMode()) {
// 生命耗尽
case 2:
screen.setFont(new Font(LSystem.FONT, 1, 30));
screen.setColor(Color.red);
GraphicsUtils.setAntialias(screen, true);
screen.drawString("The End!",
(CS * maxX - screen.getFontMetrics().stringWidth(
"The End!")) / 2 + 14,
((CS * (maxY + 1) + screen.getFontMetrics()
.getAscent()) - screen.getFontMetrics()
.getDescent()) / 2);
GraphicsUtils.setAntialias(screen, false);
break;
// 胜利
case 3:
screen.setFont(new Font(LSystem.FONT, 2, 40));
screen.setColor(Color.darkGray);
GraphicsUtils.drawStyleString(screen, "Good job!", (CS
* maxX - screen.getFontMetrics().stringWidth(
"Good job!")) / 2 + 14, ((CS * (maxY + 1) + screen
.getFontMetrics().getAscent()) - screen
.getFontMetrics().getDescent()) / 2, Color.black,
Color.white);
// 胜利标记
succeed = true;
break;
}
}
}
// 存在信息时
else {
screen.setFont(new Font(LSystem.FONT, 0, 12));
int n = screen.getFontMetrics().stringWidth(message) + 16;
int l = screen.getFontMetrics().getAscent()
+ screen.getFontMetrics().getDescent() + 8;
int i1 = (CS * (maxX + 1) - n) / 2;
int j1 = (CS * maxY + 1) - l / 2;
int k1 = i1 + 8;
int l1 = CS
* maxY
+ 1
+ (screen.getFontMetrics().getAscent() - screen
.getFontMetrics().getDescent()) / 2;
screen.setColor(Color.black);
screen.fillRect(i1, j1, n, l);
screen.setColor(Color.white);
screen.drawString(message, k1, l1);
}
}
}
启动类:
Main.javapackage org.loon.game.simple.sokoban.main;
import org.loon.game.simple.sokoban.GameCursor;
import org.loon.game.simple.sokoban.GameFrame;
import org.loon.game.simple.sokoban.control.Sokoban;
import org.loon.game.simple.sokoban.control.Stage;
import org.loon.game.simple.sokoban.control.Stage1;
/**
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email <a title="" href="http://hi.baidu.com/ceponline" mce_href="http://hi.baidu.com/ceponline" target="_blank">ceponline</a>@yahoo.com.cn
* @version 0.1
*/
public class Main {
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
GameFrame frame = new GameFrame("Java版搬箱子游戏入门示例及源码-0.1.0", 540, 480);
frame.setCursor(GameCursor.getCursor("image/cursor.png"));
// 获得搬箱子关卡接口
Stage stage = new Stage1();
// 设定游戏控制器
frame.getGame().setControl(new Sokoban(stage));
// 游戏全屏
// frame.updateFullScreen();
// 是否显示fps
frame.setFPS(true);
// 允许的最大刷新率
frame.setMaxFrames(60);
frame.mainLoop();
frame.showFrame();
}
});
}
}
楼主好屌啊!!!!!!!!!!!!!!!!!!!!! 学习一下。谢谢:victory: 不错不错不错不错 谢谢 最近在研究Swing
页:
[1]