Game-Apps für Smartphones und Tablets |
|
Bern University oh Teacher Education |
|
![]() |
// BoxGame.java package app.boxgame; import java.util.Hashtable; import java.util.LinkedList; import android.graphics.*; import ch.aplu.android.*; public class BoxGame extends GameGrid implements GGActorTouchListener { private static final boolean customizableGrid = false; Hashtable<Location, LinkedList<Stroke>> BoxMap = new Hashtable<Location, LinkedList<Stroke>>(); private Player currentPlayer; private Player[] players = new Player[2]; private GGStatusBar status; private static int playerCounter = 0; public static final int INIT_CELL_SIZE = 75; public BoxGame() { super(3 + 2, 3 + 2, cellZoom(INIT_CELL_SIZE), Color.WHITE); status = addStatusBar(30); } public void main() { players[0] = new Player(Color.BLUE, "Blue"); players[1] = new Player(Color.RED, "Red"); currentPlayer = players[0]; //blue begins; getBg().clear(Color.WHITE); refresh(); //so user doesn't sit in front of black screen for (int x = 1; x < getNbHorzCells(); x++) { for (int y = 1; y < getNbVertCells(); y++) { Location loc = new Location(x, y); BoxMap.put(loc, new LinkedList<Stroke>()); for (StrokeDirection d : StrokeDirection.values()) { //prevent loop from drawing unnecessary strokes if (y == getNbVertCells() - 1 && d == StrokeDirection.VERTICAL || x == getNbHorzCells() - 1 && d == StrokeDirection.HORIZONTAL) continue; Stroke s = new Stroke(this, d); addActorNoRefresh(s, new Location(x, y)); s.addActorTouchListener(this, GGTouch.click); for (Location l : s.getPossibleFillLocations()) BoxMap.get(l).add(s); } } } status.setText("Click on an edge to start"); setTitle("The box game -- www.java-online.ch"); refresh(); } @Override public void actorTouched(Actor actor, GGTouch mouse, Point spot) { Stroke s = (Stroke) actor; if (s.isDrawn()) return; switch (mouse.getEvent()) { case GGTouch.click: s.draw(currentPlayer.id); boolean nextPlayer = true; for (Location loc : s.getPossibleFillLocations()) { if (players[currentPlayer.id].tryToFillBoxes(loc)) nextPlayer = false; } if (nextPlayer) currentPlayer = currentPlayer.nextPlayer(); updateStatusText(); break; } refresh(); } private void updateStatusText() { String msg = players[0].getLabelledScore() + " vs " + players[1].getLabelledScore(); if (Stroke.allDrawn()) msg = "Final Score -- " + msg; else msg = msg + ", current Player is " + currentPlayer; status.setText(msg); } private boolean outOfValidGrid(Location loc) { return loc.y >= getNbVertCells() - 1 || loc.x >= getNbHorzCells() - 1 || loc.y < 1 || loc.x < 1; } class Player { private int id; private int color; private int score; private String name; public Player(int blue, String name) { this.name = name; this.id = playerCounter++; this.color = blue; this.score = 0; } public String toString() { return name; } public Player nextPlayer() { return players[(id + 1) % playerCounter]; } public String getLabelledScore() { return name + ": " + score; } private boolean tryToFillBoxes(Location loc) { if (outOfValidGrid(loc)) return false; for (Stroke s : BoxMap.get(loc)) if (!s.isDrawn()) return false; getPanel().fillCell(loc, color); score++; return true; } } } // class Stroke extends Actor { private BoxGame gg; private StrokeDirection direction; private boolean drawn; private static int drawnStrokes; private static int strokeCounter = 0; public Stroke(BoxGame gg, StrokeDirection d) { super(true, "strokeboarder", 3); strokeCounter++; this.gg = gg; this.direction = d; this.drawn = false; } public void reset() { this.turn(direction.ordinal() * 90); this.setLocationOffset(scaleOffset(direction.getOffset())); L.d("Cell size: " + gg.getCellSize()); this.setActorTouchCircle(new Point(0, 0), BoxGame.INIT_CELL_SIZE / 3); } private Point scaleOffset(GGVector offset) { int scaleFactor = gg.getCellSize() / 2; return new Point((int) (offset.x * scaleFactor), (int) (offset.y * scaleFactor)); } public LinkedList<Location> getPossibleFillLocations() { LinkedList<Location> fillLocs = new LinkedList<Location>(); Location loc = getLocation(); fillLocs.add(loc); if (loc.y != 1 && direction == StrokeDirection.HORIZONTAL) fillLocs.add(new Location(loc.x, loc.y - 1)); if (loc.x != 1 && direction == StrokeDirection.VERTICAL) fillLocs.add(new Location(loc.x - 1, loc.y)); return fillLocs; } public StrokeDirection getStrokeDirection() { return direction; } public void draw(int playerId) { drawnStrokes++; drawn = true; show(1 + playerId); } public boolean isDrawn() { return drawn; } public static boolean allDrawn() { return strokeCounter == drawnStrokes; } } // --------- class StrokeDirection --------------- enum StrokeDirection { HORIZONTAL(new GGVector(0, -1)), VERTICAL(new GGVector(-1, 0)); private GGVector offset; StrokeDirection(GGVector offset) { this.offset = offset; } public GGVector getOffset() { return offset; } } |
Hashtable<Location, LinkedList<Stroke>> BoxMap | Wir möchten für jede Location die umgebenden Striche einfach abrufen können. Deshalb speichern wir sie in einer Hashtable. |
BoxMap.put(loc, new LinkedList<Stroke>()); | Initialisiert eine leere Liste von Strokes für eine Location, in die später die dazugehörigen Striche abgefüllt werden. |
BoxMap.get(loc) | Gibt eine Liste mit den vier umgebenden Striche dieser Location zurück. Falls die Location ungültig ist, wird eine Exception geworfen. |