Spielprogrammierung mit Java
HomeAufgabenDruckenJava-Online

Bubbleshooter


Bubble Shooter ist eines der bekanntesten Computerspiele. Unten erscheinen farbige Kugeln in zufälliger Reihenfolge. Mit Mausbewegen kann der Pfeil ausgerichtet werden, mit einem Mausklick wird die Kugel in die entsprechende Richtung abgeschossen. Trifft sie auf zwei oder mehr Kugeln der gleichen Farbe, werden alle diese Kugeln entfernt. Ziel des Spiels ist es, alle Kugeln zum Verschwinden zu bringen. Bei unserer Version dürfen noch 5 Kugeln übrig bleiben.




Programmcode Downloaden: BubbleShooter.zip

 

Programmcode:

// BubbleShoter.java

import ch.aplu.jgamegrid.*;
import java.awt.Point;
import java.util.*;

public class BubbleShooter extends GameGrid implements GGMouseListener
{
  int nbOfBubbleColors = 5; // Zahl zwischen 1 - 5
  Location shootLoc = new Location(18, 36);
  ArrayList<Location> bubblePreviewLocations = new ArrayList<Location>();
  private boolean previousBubbleArrived = true;

  public BubbleShooter()
  {
    super(37, 38, 20, false);
    addMouseListener(thisGGMouse.lPress);
    initializeActors();
    show();
    setSimulationPeriod(30); // => 33 refreshes per second
    doRun();
  }

  private void initializeActors()
  {
    bubblePreviewLocations.add(shootLoc);
    for (int = 27; x < 37; x += 2)
      bubblePreviewLocations.add(new Location(x, 36));
    for (Location loc : bubblePreviewLocations)
      addRandomBubble(loc);
// initialize Bubblefield:
    for (int = 1; y < 6; y++)
    {
      for (int = y; x < 37 - y; x += 2)
        addRandomBubble(new Location(x, 2 * - 1));
    }
    addActor(new Pointer(), shootLoc);
    setPaintOrder(Bubble.classPointer.class);
  }

  public boolean mouseEvent(GGMouse mouse)
  {
    if (previousBubbleArrived)
    {
      Bubble shootBubble = (Bubble)getOneActorAt(shootLoc, Bubble.class);
      shootBubble.addCollisionActors(getFieldBubbles());
      shootBubble.addActorCollisionListener(shootBubble);
      shootBubble.shoot(new Point(mouse.getX(), mouse.getY()));
      reloadPreviewBubbles();
      checkForGameOver();
      previousBubbleArrived = false;
    }
    return true;
  }

  public void setReadyForNextBubble()
  {
    previousBubbleArrived = true;
  }

  private ArrayList<Actor> getFieldBubbles()
  {
    ArrayList<Actor> fieldBubbles = getActors(Bubble.class);
    for (Location loc : bubblePreviewLocations)
      fieldBubbles.remove(getOneActorAt(loc, Bubble.class));
    return fieldBubbles;
  }

  private void addRandomBubble(Location loc)
  {
    int rN = (int)(Math.random() * nbOfBubbleColors);
    addActor(new Bubble(rN, this), loc);
  }

  /*
   * Reloads the shooter, advances the preview bubbles &
   * adds a new preview bubble at the end of the preview list.
   */
  private void reloadPreviewBubbles()
  {
    for (int = 1; b < bubblePreviewLocations.size(); b++)
      getOneActorAt(bubblePreviewLocations.get(b)).setLocation(
        bubblePreviewLocations.get(b - 1));
    addRandomBubble(bubblePreviewLocations.get(bubblePreviewLocations.size() - 1));
  }

  // The game is over if only the shooter & the preview Bubbles are left.
  private void checkForGameOver()
  {
    if (getNumberOfActors() <= 11)
    {
      addActor(new Actor("sprites/gameover.png")new Location(18, 15));
      stopGameThread();
    }
  }

  public static void main(String[] args)
  {
    new BubbleShooter();
  }
}

// ------------ class Bubble ---------------------------
class Bubble extends Actor
{
  private BubbleShooter gg;
  private double vy, vx, x, y;
  private final double acceleration = 10, bubbleRadius = 19;

  public Bubble(int imgId, BubbleShooter gg)
  {
    super("sprites/peg.png"6);
    this.gg = gg;
    show(imgId);
    setActEnabled(false);
    setCollisionCircle(new Point(0, 0), (int)bubbleRadius);
  }

  public void shoot(Point mousePos)
  {
    x = getPixelLocation().x;
    = getPixelLocation().y;
    int vx = mousePos.x - getPixelLocation().x;
    int vy = mousePos.y - getPixelLocation().y;
    double vectorLength = getPixelLocation().distance(mousePos);
    this.vx = vx / vectorLength;
    this.vy = vy / vectorLength;
    setActEnabled(true);
  }

  // Handles the arriving of the bubble at the bubblefield.
  public int collide(Actor shootActor, Actor hitActor)
  {
    setActEnabled(false);
    setLocation(setOnValidLocation(shootActor.getLocation()));
    addActorCollisionListener(null);
    this.setLocationOffset(new Point(0, 0)); // centers sprite
    removeSameColorNeighbours(this);
    gg.setReadyForNextBubble();
    return 100;
  }

  public void act()
  {
// collision with wall:
    if (x - bubbleRadius < || + bubbleRadius > gg.getPgWidth())
      vx = -vx;
    else if (y - bubbleRadius < || + bubbleRadius > gg.getPgHeight())
      vy = -vy;
// movement:
    = vx * acceleration + x;
    y = vy * acceleration + y;
    setPixelLocation(new Point((int)x, (int)y));
  }

  /**
   * Transforms the given Location into a valid location of the
   * Bubble-Grid. Means: an even row is not allowed, and
   * every second row starting with 1 changes behaviour on the column-grid
   * To see more: Change the GameGrid Constructor so it shows the grid.
   */
  private Location setOnValidLocation(Location loc)
  {
    if (loc.y % == 0)
      return setOnValidLocation(new Location(loc.x, loc.y + 1));
    else if ((loc.y % == && loc.x % == 1)
      || (loc.y % == && loc.x % == 0))
      return loc;
    else
      return fixX(loc, x);
  }

  private Location fixX(Location loc, double x)
  {
    int fix;
    if ((x / gg.cellSize) % > 0.5)
      fix = 1;
    else
      fix = -1;
    return new Location(loc.x + fix, loc.y);
  }

  public ArrayList<Bubble> getSameColorNeighbours(Bubble initialBubble)
  {
    ArrayList<Bubble> sameColorNeighbours = new ArrayList<Bubble>();
    Stack<Bubble> uncheckedNeighbours = new Stack<Bubble>();
    uncheckedNeighbours.push(initialBubble);
    while (!uncheckedNeighbours.isEmpty())
    {
      Bubble checkBubble = uncheckedNeighbours.pop();
      for (Actor a : checkBubble.getNeighbours(2, Bubble.class))
      {
        Bubble = (Bubble)a;
        if (b.hasSameColorAs(initialBubble)
          && !uncheckedNeighbours.contains(b)
          && !sameColorNeighbours.contains(b))
          uncheckedNeighbours.push(b);
      }
      sameColorNeighbours.add(checkBubble);
    }
    return sameColorNeighbours;
  }

  private boolean hasSameColorAs(Bubble compareBubble)
  {
    return this.getIdVisible() == compareBubble.getIdVisible();
  }

  private void removeSameColorNeighbours(Bubble initialBubble)
  {
    ArrayList<Bubble> sameColorNeighbours = getSameColorNeighbours(initialBubble);
    if (sameColorNeighbours.size() > 2)
      for (Bubble b : sameColorNeighbours)
        b.removeSelf();
  }
}

 // -------- class Pointer -----------------
class Pointer extends Actor
{
  public Pointer()
  {
    super(true"sprites/pointer.png");
  }

  public void act()
  {
    Location mousePos = gameGrid.getMouseLocation();
    if (mousePos != null)
    { // is null if mouse is outside of grid
      double dirToMouse = getLocation().getDirectionTo(mousePos);
      setDirection(dirToMouse);
    }
  }
}