Die Sokoban-Spielfigur , die mit den Cursortasten bewegt wird, kann die blauen Kisten verschieben. Ziel ist es, diese an die mit einem leeren blauen Quadrat markierten Stellen zu bringen. Es ist eine einfache Sokoban-Impementierung mit drei Levels, die bei der Erzeugung des SokobanGrids festgelegt werden.
Programmcode downloaden: Sokoban.zip |
Programmcode:
// Sokoban.java import ch.aplu.jgamegrid.*; import java.awt.event.KeyEvent; import java.awt.*; public class Sokoban extends GameGrid implements GGKeyListener { private class SokobanActor extends Actor { public SokobanActor() { super(true, "sprites/sokoban.gif"); // Rotatable } } private class SokobanTarget extends Actor { public SokobanTarget() { super("sprites/target.gif"); } } private class SokobanStone extends Actor { public SokobanStone() { super("sprites/stone.gif", 2); // Two sprites } } // ------------- End of inner classes ------ private final static SokobanGrid grid = new SokobanGrid(0); private final static int nbHorzCells = grid.getNbHorzCells(); private final static int nbVertCells = grid.getNbVertCells(); private final Color borderColor = new Color(130, 10, 50); private SokobanStone[] stones = new SokobanStone[grid.getNbStones()]; private SokobanTarget[] targets = new SokobanTarget[grid.getNbStones()]; private SokobanActor sok; private boolean isFinished = false; public Sokoban() { super(nbHorzCells, nbVertCells, 30, false); setTitle("Sokoban"); GGBackground bg = getBg(); drawBoard(bg); drawActors(); addKeyListener(this); show(); // Check if finished int nbTarget = 0; while (nbTarget < grid.getNbStones()) { nbTarget = 0; for (int i = 0; i < grid.getNbStones(); i++) { if (stones[i].isVisible(1)) nbTarget++; } setTitle("# Stones at Target: " + nbTarget); delay(500); } setTitle("Game over. Well done!"); isFinished = true; playSound(this, GGSound.NOTIFY); } private void drawActors() { int stoneIndex = 0; int targetIndex = 0; for (int y = 0; y < nbVertCells; y++) { for (int x = 0; x < nbHorzCells; x++) { Location location = new Location(x, y); int a = grid.getCell(location); if (a == 5) // Sokoban actor { sok = new SokobanActor(); addActor(sok, location); } if (a == 3) // Stones { stones[stoneIndex] = new SokobanStone(); addActor(stones[stoneIndex], location); stoneIndex++; } if (a == 4) // Targets { targets[targetIndex] = new SokobanTarget(); addActor(targets[targetIndex], location); targetIndex++; } } } setPaintOrder(SokobanTarget.class); } private void drawBoard(GGBackground bg) { bg.clear(new Color(230, 230, 230)); bg.setPaintColor(Color.darkGray); for (int y = 0; y < nbVertCells; y++) { for (int x = 0; x < nbHorzCells; x++) { Location location = new Location(x, y); int a = grid.getCell(location); if (a == 1 || a == 3 || a == 4 || a == 5) { bg.fillCell(location, Color.lightGray); Point center = toPoint(location); bg.drawLine(new Point(center.x - 15, center.y - 15), new Point(center.x + 15, center.y + 15)); bg.drawLine(new Point(center.x - 15, center.y + 15), new Point(center.x + 15, center.y - 15)); } if (a == 2) // Border bg.fillCell(location, borderColor); } } } public boolean keyPressed(KeyEvent evt) { if (isFinished) return true; Location next = null; switch (evt.getKeyCode()) { case KeyEvent.VK_LEFT: next = sok.getLocation().getNeighbourLocation(Location.WEST); sok.setDirection(Location.WEST); break; case KeyEvent.VK_UP: next = sok.getLocation().getNeighbourLocation(Location.NORTH); sok.setDirection(Location.NORTH); break; case KeyEvent.VK_RIGHT: next = sok.getLocation().getNeighbourLocation(Location.EAST); sok.setDirection(Location.EAST); break; case KeyEvent.VK_DOWN: next = sok.getLocation().getNeighbourLocation(Location.SOUTH); sok.setDirection(Location.SOUTH); break; } if (next != null && canMove(next)) { sok.setLocation(next); } refresh(); return true; } public boolean keyReleased(KeyEvent evt) { return true; } private boolean canMove(Location location) { // Test if try to move into border Color c = getBg().getColor(location); if (c.equals(borderColor)) return false; else // Test if there is a stone { SokobanStone stone = (SokobanStone)getOneActorAt(location, SokobanStone.class); if (stone != null) { // Try to move the stone stone.setDirection(sok.getDirection()); if (moveStone(stone)) return true; else return false; } } return true; } private boolean moveStone(SokobanStone stone) { Location next = stone.getNextMoveLocation(); // Test if try to move into border Color c = getBg().getColor(next); if (c.equals(borderColor)) return false; // Test if there is another stone SokobanStone neighbourStone = (SokobanStone)getOneActorAt(next, SokobanStone.class); if (neighbourStone != null) return false; // Move the stone stone.setLocation(next); // Check if we are at a target if (getOneActorAt(next, SokobanTarget.class) != null) stone.setVisible(1, true); else stone.setVisible(0, true); return true; } public static void main(String[] args) { new Sokoban(); } } class SokobanGr { private final static int nbHorzCells = 19; private final static int nbVertCells = 11; private static int[][] a = new int[nbHorzCells][nbVertCells]; private static int nbStones = 0; private final static String soko_0 = " xxxxx " + // 0 (19) " x...x " + // 1 " x*..x " + // 2 " xxx..*xx " + // 3 " x..*.*.x " + // 4 "xxx.x.xx.x xxxxxx" + // 5 "x...x.xx.xxxxx..oox" + // 6 "x.*..*..........oox" + // 7 "xxxxx.xxx.xAxx..oox" + // 8 " x.....xxxxxxxxx" + // 9 " xxxxxxx "; //10 private final static int nbHorzCells_0 = 19; private final static int nbVertCells_0 = 11; private final static String soko_1 = "xxxxxxxxxxxx " + // 0 (14) "xoo..x.....xxx" + // 1 "xoo..x.*..*..x" + // 2 "xoo..x*xxxx..x" + // 3 "xoo....A.xx..x" + // 4 "xoo..x.x..*.xx" + // 5 "xxxxxx.xx*.*.x" + // 6 " x.*..*.*.*.x" + // 7 " x....x.....x" + // 8 " xxxxxxxxxxxx"; // 9 private final static int nbHorzCells_1 = 14; private final static int nbVertCells_1 = 10; private final static String soko_2 = " xxxxxxxx " + // 0 (17) " x.....Ax " + // 1 " x.*x*.xx " + // 2 " x.*..*x " + // 3 " xx*.*.x " + // 4 "xxxxxxxxx.*.x.xxx" + // 5 "xoooo..xx.*..*..x" + // 6 "xxooo....*..*...x" + // 7 "xoooo..xxxxxxxxxx" + // 8 "xxxxxxxx "; // 9 private final static int nbHorzCells_2 = 17; private final static int nbVertCells_2 = 10; private final static String[] sokoModel = { soko_0, soko_1, soko_2 }; private final static int[] nbHorzCellsModel = { nbHorzCells_0, nbHorzCells_1, nbHorzCells_2 }; private final static int[] nbVertCellsModel = { nbVertCells_0, nbVertCells_1, nbVertCells_2 }; private static int model; public SokobanGrid(int model) { this.model = model; // Copy structure into integer array for (int k = 0; k < nbVertCellsModel[model]; k++) { for (int i = 0; i < nbHorzCellsModel[model]; i++) { switch (sokoModel[model].charAt(nbHorzCellsModel[model] * k + i)) { case ' ': a[i][k] = 0; // Empty outside break; case '.': a[i][k] = 1; // Empty inside break; case 'x': a[i][k] = 2; // Border break; case '*': a[i][k] = 3; // Stones nbStones++; break; case 'o': a[i][k] = 4; // Target positions break; case 'A': a[i][k] = 5; // Sokoban actor break; } } } } public static int getNbHorzCells() { return nbHorzCellsModel[model]; } public static int getNbVertCells() { return nbVertCellsModel[model]; } public static int getNbStones() { return nbStones; } public static int getCell(Location location) { return a[location.x][location.y]; } } |