Aegidius
 Plüss   Aplulogo
     
 www.aplu.ch      Print Text 
© 2021, V10.4
 
  JGameGrid
 
 

The source code of all applications is included in the JGameGrid distribution.

 

Battleship (Schiffe versenken)

The game Battleship (in German "Schiffe versenken", famous in former days to survive boring lessons) is a guessing game played by two people. It is known throughout the world as a pencil and paper game and predates World War I in this form. The game is played in a grid of usually 10x10 cells. Both players arranges some predefined "ships", having a rectangular shape of one cell width and 2, 3, 4, or 5 cells long. The ships cannot overlap, with some game rules they cannot touch each other. The deployment of each player's ships is hidden to the other.

After the ships are deployed, the game proceeds in a series of rounds. Each player announces a cell coordinate where he drops a bomb. The other player replies "miss" or "hit" depending if the cell is occupied by a part of a ship. He marks a part hit by the bomb. If all parts are hit, the player announces "sunk" and the ship is considered to be removed from the grid. After all of one player's ships are sunk, the game is over and the other player wins.

[Ref. http://en.wikipedia.org/wiki/Battleship_(game)]

The game may be implemented in a solitaire version, where the player fights again a virtual enemy, e.g. a computer program. Unlike this, our implementation is close to the original game design, but paper and pencil are replaced by two computers linked via Bluetooth, providing a pretty example of computer communication. A similar approach using TCP/IP could be implemented following the same design principles.

The game has two phases: The deployment phase, where each player arranges his ships freely in the grid by moving/rotating them using the mouse and the keyboard, and the playing phase, where each player clicks on the grid to select the cell coordinates of the bomb. The cell location is transferred via Bluetooth and the reply ("miss", "hit", "sunk") is automatically transferred back to the player and announced by a particular sprite image. No verbal interaction between the players is necessary.

The ships are modeled by the class Ship that is abstract, because each special type of ship is represented by a derived class Carrier, Battleship, Destroyer, Submarine and PatrolBoat. E.g.

// Destroyer.java

public
 class Destroyer extends Ship
{
  
public Destroyer()
  
{
    
super("sprites/destroyer.gif", 4);
  
}
}

The constructor takes the sprite image file and the length of the ship (in cell width). Each ship implements a GGMouseListener. Its mouseEvent() method is responsible for the dragging operation during the deployment phase.

 public boolean mouseEvent(GGMouse mouse)
  
{
    
if (!isMouseEnabled)
      
return false;
    Location location 
= gameGrid.toLocationInGrid(mouse.getX(), mouse.getY());
    
switch (mouse.getEvent())
    
{
      
case GGMouse.lPress:
        lastLocation 
= location.clone();
        
if (gameGrid.getOneActorAt(location) == this)
          isDragging 
= true;
        
break;
      
case GGMouse.lDrag:
        
if (isDragging && advance(location, 0))
        
{
          
setLocation(location);
          lastLocation 
= location.clone();
        
}
        
break;
      
case GGMouse.lRelease:
        
if (isDragging)
        
{
          
setLocation(lastLocation);
          isDragging 
= false;
        
}
        
break;
    
}
    
updateCells(getLocation());
    
return false;
  
}

While dragging, the method advance() checks if the move is valid (whole ship inside grid, no overlap with other ships). The ship contains an array cells of the locations that are currently occupied by the ship. updateCells() updates this array depending on the current location and direction (the stern of the boat determines the ship location). The ship actors are rotatable, so the rotated images are generated automatically. To avoid a Java heap overflow due to the big size of the ship images, we must limit the number of rotated images to the 4 compass directions by the special GameGrid constructor.

GameGrid(10, 10, 25, Color.black, null, false, 4);

that sets the following properties of the game window:

10x10 grid, 25 pixel wide
grid color black
no background image
no navigation area
only 4 rotated sprites (default is 60
)

For the Bluetooth communication, the package ch.aplu.bluetooth is used that is based on the Bluecove implementation of JSR-82. In this package the client-server model is implemented through the class BluetoothPeer. The constructors takes the Bluetooth friendly name of the partner PC and tries to connect as client. If it fails, a Bluetooth server is automatically started waiting for an incoming client to connect. The transfer of an integer array data block is performed by calling sendDataBlock(). On the receiver side a notification method receiveDataBlock() is triggered when the data block is received. This simple implementation avoids the construction of Input-/Output streams and of internal threads that control the transfer (see the Bluetooth package site for more information).

We want to animate the fires (growing bigger and bigger) when a bomb hits a part of a ship. After the actor is created, the dynamical behaviour of an actor is completely decoupled from the rest of the program by overriding act(). We use 4 sprite images for the growing fire and slow down the change from one image to the next by increasing the simulation period by a factor of 10. After the last image (with spriteId = 3) is shown, act() is disabled. This is a very nice example of encapsulating behaviour, state and properties in OOP.

// Fire.java

import
 ch.aplu.jgamegrid.*;

public
 class Fire extends Actor
{
  
public Fire()
  
{
    
super("sprites/fire.gif", 4);
    
setSlowDown(10);
  
}
  
  
public void act()
  
{
    
if (getIdVisible() == 2)
      
setActEnabled(false);
    
showNextSprite();
  
}
}

You may study all implementation details by downloading the full source code included in the JGameGrid distribution.

battleship1 battleship2

Player 1

   
Player 2
 

Execute the program locally using WebStart (two Bluetooth enabled computers needed)