分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
推(搬)箱子,又名Sokoban,仓库番等,是一款堪称古玩级的电脑游戏。
提起它,笔者相信没什么人会感觉到陌生,更没什么生物会连听都没听说过。它的发展历史之久远,甚至超越了俄罗斯方块(1988年电脑游戏化)。
这款游戏最初起源于日本,是个很难争辩的事实(我知道有人反对,但笔者确实找不到什么有力的反对证据)。他由日本人(哎……)今川宏行在1981年创立游戏规则,并于1982年经日本软件公司Thinking Rabbit正式发布。比较遗憾的是,早期的推箱子并没有PC版,笔者在网络上搜索到的老版游戏也大多为90年以前的Mac OS下程式。
但说起真正令推箱子风靡于PC机的,却该感谢我们的台湾同胞李果兆先生。是他在1994年开发的仓库世家,才真正令推箱子游戏在世界各地大受推崇;仔细说来,推箱子这款小游戏之所以能有今时今日的声望与地位,固然有今川宏行的开创之功,但若说到贡献最大,承前启后的,则非中国台湾的李果兆先生莫属。
推箱子游戏的规则非常简单,就是用尽量少的推动或移动把所有箱子都推到目标点上。箱子只能推动而不能拉动;一次只能推动一个箱子。然而,尽管它的规则是很简单的,但对于不同难度的关卡,所需要的脑力却是截然不同的,有些关卡可能会花费您几个小时、几天甚至几个月的时间,也正是这种简单性和复杂性的结合,最终令推箱子类游戏风靡全球!
本回笔者在Blog中提供的,就是一款Java版推箱子游戏的简单实现。
笔者设定[上、下、左、右]为方向控制 ,[S]键为后退到上一步操作,[ESC]为重新开始当前关卡,点击键盘上对应关卡的数字键可以直接选关,需要注意的是笔者以HP限制了角色的移动次数,HP归0则挑战失败。
目前版本仅提供有5关,有需要者可参考同类游戏自行扩充,游戏源码在jar内。
下载地址1(由于google code维护,需要等此文发表的隔天才能开放下载):http://code.google.com/p/loon-simple/downloads/list
下载地址2:http://download.csdn.net/source/1397545
游戏截图:
核心代码:
Sokoban.java
- package 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 = "按下 [Enter] 开始进行游戏";
- 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[4];
- this.sprite = new RpgSprite("image/role1.gif");
- this.maxX = 16;
- this.maxY = 13;
- this.comps = 0;
- this.complete = new boolean[stage.getMaxStageNo()];
- this.boxMove = new boolean[stage.getMaxStageNo()][1500];
- this.ons = new int[stage.getMaxStageNo()][1500];
- this.hp = new int[stage.getMaxStageNo()];
- this.stageStates = new int[stage.getMaxStageNo()][maxY][maxX];
- this.role = new int[stage.getMaxStageNo()];
- this.rolex = new int[stage.getMaxStageNo()];
- this.roley = new int[stage.getMaxStageNo()];
- this.mapx = new int[stage.getMaxStageNo()];
- this.mapy = new int[stage.getMaxStageNo()];
- for (int j = 0; j < 4; j++) {
- floorImage[j] = 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()[stageNo] = 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[stageNo]; i++) {
- for (int j = 0; j < mapx[stageNo];) {
- switch (stageStates[stageNo][i][j]) {
- case 2:
- case 3:
- case 4:
- case 5:
- screen.drawImage(floorImage[1], moveX(j), moveY(i), null);
- default:
- j++;
- break;
- }
- }
- }
- for (int n = 0; n < mapy[stageNo]; n++) {
- for (int l = 0; l < mapx[stageNo]; l++)
- switch (stageStates[stageNo][n][l]) {
- case 1:
- screen.drawImage(floorImage[0], 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[stageNo][n][l - 1] != 1) {
- screen.setColor(new Color(160, 128, 96));
- screen.drawLine(moveX(l), moveY(n) + 1, moveX(l),
- moveY(n) + CS - 2);
- }
- if (l == mapx[stageNo] - 1 || l < mapx[stageNo] - 1
- && stageStates[stageNo][n][l + 1] != 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[stageNo][n][l]) {
- default:
- break;
- case 2:
- case 3:
- screen.drawImage(floorImage[3], moveX(l), moveY(n),
- null);
- break;
- case 4:
- break;
- }
- if (stageStates[stageNo][n][l] != 3)
- screen.drawImage(floorImage[2], moveX(l), moveY(n),
- null);
- break;
- default:
- break;
- }
- }
- // System.out.println(role[stageNo]);
- screen.drawImage(sprite.getOnlyMove(role[stageNo]),
- moveX(rolex[stageNo]), moveY(roley[stageNo]), null);
- if (stageStates[stageNo][roley[stageNo]][rolex[stageNo]] == 4) {
- screen.drawImage(floorImage[2], moveX(rolex[stageNo]),
- moveY(roley[stageNo]), null);
- }
- setupDisplay();
- }
- /**
- * 定位到实际的X座标
- *
- * @param i
- * @return
- */
- public int moveX(int i) {
- return (CS * ((maxX - mapx[stageNo]) + 1)) / 2 + CS * i;
- }
- /**
- * 定位到实际的Y座标
- *
- * @param i
- * @return
- */
- public int moveY(int i) {
- return (CS * ((maxY - mapy[stageNo]) + 1)) / 2 + CS * i;
- }
- /**
- * 执行操作
- *
- */
- public synchronized void execute() {
- boolean flag = true;
- for (int i = 0; i < mapy[stageNo]; i++) {
- for (int j = 0; j < mapx[stageNo]; j++) {
- if (stageStates[stageNo][i][j] == 4) {
- flag = false;
- }
- }
- }
- if (flag) {
- stage.getMode()[stageNo] = 3;
- complete[stageNo] = true;
- } else if (hp[stageNo] == 0) {
- stage.getMode()[stageNo] = 2;
- }
- comps = 0;
- for (int n = 0; n < stage.getMaxStageNo(); n++) {
- if (complete[n]) {
- 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()[stageNo] == 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[stageNo][hp[stageNo] - 1] = false;
- switch (i) {
- case 0:
- if (stageStates[stageNo][roley[stageNo] + 1][rolex[stageNo]] < 2) {
- return;
- }
- if (stageStates[stageNo][roley[stageNo] + 1][rolex[stageNo]] < 4) {
- if (stageStates[stageNo][roley[stageNo] + 2][rolex[stageNo]] < 4) {
- return;
- }
- stageStates[stageNo][roley[stageNo] + 1][rolex[stageNo]] += 2;
- stageStates[stageNo][roley[stageNo] + 2][rolex[stageNo]] -= 2;
- boxMove[stageNo][hp[stageNo] - 1] = true;
- }
- roley[stageNo]++;
- break;
- case 1:
- if (stageStates[stageNo][roley[stageNo]][rolex[stageNo] - 1] < 2) {
- return;
- }
- if (stageStates[stageNo][roley[stageNo]][rolex[stageNo] - 1] < 4) {
- if (stageStates[stageNo][roley[stageNo]][rolex[stageNo] - 2] < 4) {
- return;
- }
- stageStates[stageNo][roley[stageNo]][rolex[stageNo] - 1] += 2;
- stageStates[stageNo][roley[stageNo]][rolex[stageNo] - 2] -= 2;
- boxMove[stageNo][hp[stageNo] - 1] = true;
- }
- rolex[stageNo]--;
- break;
- case 2:
- if (stageStates[stageNo][roley[stageNo]][rolex[stageNo] + 1] < 2) {
- return;
- }
- if (stageStates[stageNo][roley[stageNo]][rolex[stageNo] + 1] < 4) {
- if (stageStates[stageNo][roley[stageNo]][rolex[stageNo] + 2] < 4) {
- return;
- }
- stageStates[stageNo][roley[stageNo]][rolex[stageNo] + 1] += 2;
- stageStates[stageNo][roley[stageNo]][rolex[stageNo] + 2] -= 2;
- boxMove[stageNo][hp[stageNo] - 1] = true;
- }
- rolex[stageNo]++;
- break;
- case 3:
- if (stageStates[stageNo][roley[stageNo] - 1][rolex[stageNo]] < 2) {
- return;
- }
- if (stageStates[stageNo][roley[stageNo] - 1][rolex[stageNo]] < 4) {
- if (stageStates[stageNo][roley[stageNo] - 2][rolex[stageNo]] < 4) {
- return;
- }
- stageStates[stageNo][roley[stageNo] - 1][rolex[stageNo]] += 2;
- stageStates[stageNo][roley[stageNo] - 2][rolex[stageNo]] -= 2;
- boxMove[stageNo][hp[stageNo] - 1] = true;
- }
- roley[stageNo]--;
- break;
- default:
- if (hp[stageNo] == stage.getMaxHp()[stageNo]) {
- return;
- }
- switch (ons[stageNo][hp[stageNo]]) {
- case 0:
- if (boxMove[stageNo][hp[stageNo]]) {
- stageStates[stageNo][roley[stageNo] + 1][rolex[stageNo]] += 2;
- stageStates[stageNo][roley[stageNo]][rolex[stageNo]] -= 2;
- }
- roley[stageNo]--;
- break;
- case 1:
- if (boxMove[stageNo][hp[stageNo]]) {
- stageStates[stageNo][roley[stageNo]][rolex[stageNo] - 1] += 2;
- stageStates[stageNo][roley[stageNo]][rolex[stageNo]] -= 2;
- }
- rolex[stageNo]++;
- break;
- case 2:
- if (boxMove[stageNo][hp[stageNo]]) {
- stageStates[stageNo][roley[stageNo]][rolex[stageNo] + 1] += 2;
- stageStates[stageNo][roley[stageNo]][rolex[stageNo]] -= 2;
- }
- rolex[stageNo]--;
- break;
- default:
- if (boxMove[stageNo][hp[stageNo]]) {
- stageStates[stageNo][roley[stageNo] - 1][rolex[stageNo]] += 2;
- stageStates[stageNo][roley[stageNo]][rolex[stageNo]] -= 2;
- }
- roley[stageNo]++;
- break;
- }
- break;
- }
- if (i != -1) {
- hp[stageNo]--;
- ons[stageNo][hp[stageNo]] = i;
- }
- role[stageNo] = ons[stageNo][hp[stageNo]];
- if (i == -1) {
- hp[stageNo]++;
- }
- execute();
- }
- /**
- * 开场画面
- *
- */
- public synchronized void openDraw() {
- background();
- for (int i = 0; i < 5; i++) {
- for (int j = 0; j < maxX + 1; j++) {
- screen.drawImage(floorImage[0], 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[stageNo][i][j] = 0;
- }
- }
- mapx[stageNo] = stage.getConf()[stageNo][0];
- mapy[stageNo] = stage.getConf()[stageNo][1];
- rolex[stageNo] = stage.getConf()[stageNo][2];
- roley[stageNo] = stage.getConf()[stageNo][3];
- for (int n = 0; n < mapy[stageNo]; n++) {
- for (int l = 0; l < mapx[stageNo]; l++) {
- stageStates[stageNo][n][l] = stage.getMapData()[stageNo][n][l];
- }
- }
- hp[stageNo] = stage.getMaxHp()[stageNo];
- role[stageNo] = 0;
- for (int i1 = 0; i1 < stage.getMaxHp()[stageNo]; i1++) {
- ons[stageNo][i1] = 0;
- }
- for (int j1 = 0; j1 < stage.getMaxHp()[stageNo]; j1++) {
- boxMove[stageNo][j1] = 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[j]) {
- screen.setColor(Color.gray);
- } else {
- screen.setColor(Color.white);
- }
- if (j == stageNo) {
- if (complete[j]) {
- screen.setColor(Color.magenta);
- } else {
- screen.setColor(Color.cyan);
- }
- }
- screen.drawString(m_stageName[j], size = (10 + (screen
- .getFontMetrics().stringWidth("关卡0") + 20)
- * j), LSystem.HEIGHT - 50);
- }
- screen.setColor(Color.white);
- if (stageNo == -1) {
- // 初始画面,无数据
- } else {
- // 显示状态
- if (hp[stageNo] == 0) {
- screen.setColor(Color.red);
- } else if (hp[stageNo] <= stage.getMaxHp()[stageNo] / 4) {
- screen.setColor(Color.orange);
- } else