vrijdag 16 maart 2012

a* (aStar) pathfinding example







I finally made the a* in Java. I spend the last two weeks typing the a* algorithm in Blitz basic. I typed it in about 13 times before I decided to type it into Java. I think I did it without creating errors.
The source code is below.

Anyone may use the code for their own. No credit is required.

Edit : there is a little problem with the code. The arraylist setup lacks the <Integer> parts. You need to add those to the code if you want to run it. It was removed becourse the < characters are HTML codes.

 


import java.awt.*;
import java.applet.*;
import java.util.ArrayList;

public class astarpathfindingexample01 extends Applet {

 int map[][] ={
     {0,0,0,0,0,0,0,0,0,0},
     {0,1,1,1,1,1,1,1,1,0},
     {0,0,0,1,0,1,0,1,0,0},
     {0,0,0,1,0,1,0,1,0,0},
     {0,1,1,1,0,0,0,1,0,0},
     {0,0,0,1,0,1,0,0,0,0},
     {0,0,0,1,0,1,0,1,0,0},
     {0,1,1,1,1,1,0,1,0,0},
     {0,0,0,0,0,1,0,1,1,0},
     {0,0,0,0,0,0,0,0,0,0}
     };
 int mapwidth = 9;
 int mapheight = 9;
 int cellwidth = 32;
 int cellheight = 24;

 int sx,sy,ex,ey;

 // Open list ( x, y, f, g, h, parentx, parenty )
 ArrayList olx = new ArrayList();
 ArrayList oly = new ArrayList();
 ArrayList olf = new ArrayList();
 ArrayList olg = new ArrayList();
 ArrayList olh = new ArrayList();
 ArrayList olpx = new ArrayList();
 ArrayList olpy = new ArrayList();
 // Closed list ( x, y, f, g, h, parentx, parenty )
 ArrayList clx = new ArrayList();
 ArrayList cly = new ArrayList();
 ArrayList clf = new ArrayList();
 ArrayList clg = new ArrayList();
 ArrayList clh = new ArrayList();
 ArrayList clpx = new ArrayList();
 ArrayList clpy = new ArrayList();
 // Path
 ArrayList px = new ArrayList();
 ArrayList py = new ArrayList();

 public void init() {
  setBackground(Color.black);

 }

 public void findpathback(){
  boolean exitloop = false;
  int x = ex;
  int y = ey;
  while ( exitloop == false ){
   for ( int i = 0 ; i < clx.size() ; i++ ){
    if ( clx.get( i ) == x && cly.get( i ) == y ){
     x = clpx.get( i );
     y = clpy.get( i );
     px.add( x );
     py.add( y );
    }
   }
   if ( x == sx && y == sy ) {
    exitloop = true;
   }
  }
 }

 public boolean removefromopenlist( int x , int y ){
  for ( int i = 0 ; i < olx.size() ; i++ ){
   if ( olx.get(i) == x && oly.get(i) == y ){
    olx.remove(i);
    oly.remove(i);
    olf.remove(i);
    olg.remove(i);
    olh.remove(i);
    olpx.remove(i);
    olpy.remove(i);
    return true;
   }
  }
  return false;
 }

 public boolean isonclosedlist( int x , int y ){
  for ( int i = 0 ; i < clx.size() ; i++ ){
   if ( clx.get(i) == x && cly.get(i) == y ) {
    return true;
   }
  }
  return false;
 }

 public boolean isonopenlist( int x , int y ){
  for ( int i = 0 ; i < olx.size() ; i++){
   if ( olx.get(i) == x && oly.get(i) == y ){
    return true;
   }
  }
  return false;
 }

 public boolean openlistisempty(){
  if ( olx.size() > 0 ) {
   return false;
  }
  return true;
 }

 public void setcoordinates(){
  boolean exitloop = false;
  while ( exitloop == false ){
   sx = (int)( Math.random() * mapwidth );
   sy = (int)( Math.random() * mapheight );
   ex = (int)( Math.random() * mapwidth );
   ey = (int)( Math.random() * mapheight );
   if ( map[ sy ][ sx ] == 0 && map[ ey ][ ex ] == 0 ){
    if ( sx != ex && sy != ey ){
     exitloop = true;
    }
   }
  }
 }

 public void findpath(){
  // Clear all the pathfinding data
  olx.clear();
  oly.clear();
  olf.clear();
  olg.clear();
  olh.clear();
  olpx.clear();
  olpy.clear();
  //
  clx.clear();
  cly.clear();
  clf.clear();
  clg.clear();
  clh.clear();
  clpx.clear();
  clpy.clear();
  //
  px.clear();
  py.clear();
  //
  // Move the start position onto the open list
  olx.add( sx );
  oly.add( sy );
  olf.add( 0 );
  olg.add( 0 );
  olh.add( 0 );
  olpx.add( 0 );
  olpy.add( 0 );
  //
  boolean exitloop = false;
  int tx = 0;
  int ty = 0;
  int tf = 0;
  int tg = 0;
  int th = 0;
  int tpx = 0;
  int tpy = 0;
  int newx = 0;
  int newy = 0;
  int lowestf = 0;
  while ( exitloop == false ){
   // If the open list is empty then exit loop
   if ( openlistisempty() == true ){
    exitloop = true;
   }
   // Get the lowest f value position from the
   // open list and use that.
   lowestf = 100000;
   for ( int i = 0 ; i < olx.size() ; i++ ){
    if ( olf.get( i ) < lowestf ) {
     lowestf = olf.get( i );
     tx = olx.get( i );
     ty = oly.get( i );
     tf = olf.get( i );
     tg = olg.get( i );
     th = olh.get( i );
     tpx = olpx.get( i );
     tpy = olpy.get( i );
    }
   }
   // if the current position is the end position then
   // path was found.
   if ( tx == ex && ty == ey ){
    exitloop = true;
    clx.add( tx );
    cly.add( ty );
    clf.add( tf );
    clg.add( tg );
    clh.add( th );
    clpx.add( tpx );
    clpy.add( tpy );
    findpathback();
   }else{
    // Move the current position onto the closed list
    clx.add( tx );
    cly.add( ty );
    clf.add( tf );
    clg.add( tg );
    clh.add( th );
    clpx.add( tpx );
    clpy.add( tpy );
    // Remove the current position from the open is
    removefromopenlist( tx , ty );
    // Get the eight positions from around the current
    // position and move them onto the open list.
    //
    newx = tx - 1;
    newy = ty - 1;
    if ( newx > -1 && newy > -1 && newx < mapwidth + 1 && newy < mapheight + 1 ){
    if ( isonopenlist( newx , newy ) == false ){
    if ( isonclosedlist( newx , newy ) == false ){
    if ( map[ newy ][ newx ] == 0 ){
     olx.add( newx );
     oly.add( newy );
     olg.add( tg + 1 );
     olh.add( distance( newx , newy , ex , ey ));
     olf.add( ( tg + 1 ) + distance( newx , newy , ex , ey ) );
     olpx.add( tx );
     olpy.add( ty );
    }
    }
    }
    }
    //
    newx = tx;
    newy = ty - 1;
    if ( newx > -1 && newy > -1 && newx < mapwidth + 1 && newy < mapheight + 1 ){
    if ( isonopenlist( newx , newy ) == false ){
    if ( isonclosedlist( newx , newy ) == false ){
    if ( map[ newy ][ newx ] == 0 ){
     olx.add( newx );
     oly.add( newy );
     olg.add( tg + 1 );
     olh.add( distance( newx , newy , ex , ey ));
     olf.add( ( tg + 1 ) + distance( newx , newy , ex , ey ) );
     olpx.add( tx );
     olpy.add( ty );
    }
    }
    }
    }
    //
    newx = tx + 1;
    newy = ty - 1;
    if ( newx > -1 && newy > -1 && newx < mapwidth + 1 && newy < mapheight + 1 ){
    if ( isonopenlist( newx , newy ) == false ){
    if ( isonclosedlist( newx , newy ) == false ){
    if ( map[ newy ][ newx ] == 0 ){
     olx.add( newx );
     oly.add( newy );
     olg.add( tg + 1 );
     olh.add( distance( newx , newy , ex , ey ));
     olf.add( ( tg + 1 ) + distance( newx , newy , ex , ey ) );
     olpx.add( tx );
     olpy.add( ty );
    }
    }
    }
    }
    //
    newx = tx - 1;
    newy = ty;
    if ( newx > -1 && newy > -1 && newx < mapwidth + 1 && newy < mapheight + 1 ){
    if ( isonopenlist( newx , newy ) == false ){
    if ( isonclosedlist( newx , newy ) == false ){
    if ( map[ newy ][ newx ] == 0 ){
     olx.add( newx );
     oly.add( newy );
     olg.add( tg + 1 );
     olh.add( distance( newx , newy , ex , ey ));
     olf.add( ( tg + 1 ) + distance( newx , newy , ex , ey ) );
     olpx.add( tx );
     olpy.add( ty );
    }
    }
    }
    }
    //
    newx = tx + 1;
    newy = ty;
    if ( newx > -1 && newy > -1 && newx < mapwidth + 1 && newy < mapheight + 1 ){
    if ( isonopenlist( newx , newy ) == false ){
    if ( isonclosedlist( newx , newy ) == false ){
    if ( map[ newy ][ newx ] == 0 ){
     olx.add( newx );
     oly.add( newy );
     olg.add( tg + 1 );
     olh.add( distance( newx , newy , ex , ey ));
     olf.add( ( tg + 1 ) + distance( newx , newy , ex , ey ) );
     olpx.add( tx );
     olpy.add( ty );
    }
    }
    }
    }
    //
    newx = tx - 1;
    newy = ty + 1;
    if ( newx > -1 && newy > -1 && newx < mapwidth + 1 && newy < mapheight + 1 ){
    if ( isonopenlist( newx , newy ) == false ){
    if ( isonclosedlist( newx , newy ) == false ){
    if ( map[ newy ][ newx ] == 0 ){
     olx.add( newx );
     oly.add( newy );
     olg.add( tg + 1 );
     olh.add( distance( newx , newy , ex , ey ));
     olf.add( ( tg + 1 ) + distance( newx , newy , ex , ey ) );
     olpx.add( tx );
     olpy.add( ty );
    }
    }
    }
    }
    //
    newx = tx;
    newy = ty + 1;
    if ( newx > -1 && newy > -1 && newx < mapwidth + 1 && newy < mapheight + 1 ){
    if ( isonopenlist( newx , newy ) == false ){
    if ( isonclosedlist( newx , newy ) == false ){
    if ( map[ newy ][ newx ] == 0 ){
     olx.add( newx );
     oly.add( newy );
     olg.add( tg + 1 );
     olh.add( distance( newx , newy , ex , ey ));
     olf.add( ( tg + 1 ) + distance( newx , newy , ex , ey ) );
     olpx.add( tx );
     olpy.add( ty );
    }
    }
    }
    }
    //
    newx = tx + 1;
    newy = ty + 1;
    if ( newx > -1 && newy > -1 && newx < mapwidth + 1 && newy < mapheight + 1 ){
    if ( isonopenlist( newx , newy ) == false ){
    if ( isonclosedlist( newx , newy ) == false ){
    if ( map[ newy ][ newx ] == 0 ){
     olx.add( newx );
     oly.add( newy );
     olg.add( tg + 1 );
     olh.add( distance( newx , newy , ex , ey ));
     olf.add( ( tg + 1 ) + distance( newx , newy , ex , ey ) );
     olpx.add( tx );
     olpy.add( ty );
    }
    }
    }
    }

   }

  }
 }

 public int distance( int x1 , int y1 , int x2 , int y2 ){
  int distance=(int)Math.sqrt( ( x1 - x2 ) * ( x1 - x2 ) + ( y1 - y2 ) * ( y1 - y2 ) ) ;
  return distance;
 }

 public void paint(Graphics g) {

  setcoordinates();
  findpath();
  // Draw the map on the applet window
  g.setColor( Color.blue );
  for ( int y = 0 ; y < mapheight ; y++ ){
  for ( int x = 0 ; x < mapwidth ; x++ ){
   if ( map[ y ][ x ] == 1 ){
    g.fillRect( x * cellwidth , y * cellheight , cellwidth , cellheight );
   }
  }
  }
  // Draw the start position on the applet window
  g.setColor( Color.green );
  g.fillOval( sx * cellwidth + 4 , sy * cellheight + 4 , 8 , 8 );
  g.setColor( Color.red );
  g.fillOval( ex * cellwidth + 4 , ey * cellheight + 4 , 8 , 8 );

  // Draw the path
  g.setColor( Color.yellow );
  for ( int i = 0 ; i < px.size() ; i++ ){
   g.fillOval( px.get( i ) * cellwidth + 8 , py.get( i ) * cellheight + 8 , 8 , 8 );
  }

 }
}


dinsdag 6 maart 2012

finally did it. a* working

I finally have a working a* function working on my computer and made it myself. I had bought the book "ai for game developers" and read through the chapter on pathfinding. I had a few mistypes that caused bugs but I was able to repair those. The code is in another language at the moment. In blitz basic 3d. This since I have more experience with that language. I will code the a* in Java in the future.

I will make a applet with a* pathfinding I think this weekend.

zondag 4 maart 2012

Random Obstacle Avoidance Example






From the book ai for game developers. Random Obstacle Avoidance. The white block moves through the map and avoids the green trees. Below the code that shows how it is done.


 

import java.awt.*;
import java.applet.*;
public class RandomObstacleAvoidanceExample001 extends Applet implements Runnable{
 Graphics bufferGraphics;
    Image offscreen;
 int sx , sy , ex , ey; // start and end position
 int px , py; // player position
 long delay;
 private int map[][] =  new int[][]{
 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
 {0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0},
 {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0},
 {0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0},
 {0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0},
 {0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0},
 {0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0},
 {0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0},
 {0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
 };
 public void init(){
  setBackground( Color.black );
     offscreen = createImage(getSize().width,getSize().height);
     bufferGraphics = offscreen.getGraphics();
  setstartposition();
  setendposition();
  px = sx;
  py = sy;
  new Thread(this).start();
 }
    public void run() {
     for(;;) { // animation loop never ends
         moveplayer();
         repaint();
         try {
             Thread.sleep(16);
            }
             catch (InterruptedException e) {
             }
     }
    }
 public void update (Graphics g)
  {
  bufferGraphics.clearRect( 0 , 0 , getSize().width , getSize().height );
     bufferGraphics.setColor ( Color.white );
     bufferGraphics.drawString( "Random Obstacle Avoidance." , 10 , 10 );
  bufferGraphics.setColor( Color.green );
  // draw map
  for ( int y = 0 ; y < 15 ; y++ ){
   for ( int x = 0 ; x < 20 ; x++ ){
    if ( map[ y ][ x ] == 1 ){
     bufferGraphics.fillOval( x * 16 , y * 16 , 16 , 16 );
    }
   }
  }
  // draw end and start position
  bufferGraphics.setColor( Color.red );
  bufferGraphics.fillRect( sx * 16 , sy * 16 , 16 , 16 );
  bufferGraphics.setColor( Color.yellow );
  bufferGraphics.fillRect( ex * 16 , ey * 16 , 16 , 16 );
  // draw player
  bufferGraphics.setColor( Color.white );
  bufferGraphics.fillRect( px * 16 , py * 16 , 16 , 16 );

     g.drawImage(offscreen,0,0,this);

  }
  public void moveplayer(){
   if ( delay < System.currentTimeMillis() ){
    int newx = px;
    int newy = py;
    if ( px < ex ){
     newx++;
    }
    if ( px > ex ){
     newx--;
    }
    if ( py < ey ){
     newy++;
    }
    if ( py > ey ){
     newy--;
    }
    if ( map[ newy ][ newx ] == 1 ){
     boolean newposfound = false;
     newx = px;
     newy = py;
     while ( newposfound == false ){
      if ( (int)(Math.random() * 2 ) == 0 ){
       newx--;
      }else{
       newx++;
      }
      if ( (int)(Math.random() * 2 ) == 0 ){
       newy--;
      }else{
       newy++;
      }
      if ( map[ newy ][ newx ] == 0 ){
       newposfound = true;
      }
     }
    }
    px = newx;
    py = newy;
    if ( px == ex && py == ey ){
    setstartposition();
    setendposition();
    px = sx;
    py = sy;
    }
    delay = System.currentTimeMillis() + 200;
   }
  }
 public void setstartposition(){
  if (  (int)( Math.random() * 2 ) == 0 ){
   sx = ( int )( Math.random() * 6 );
   sy = 0;
  }else{
   sx = 0;
   sy = ( int )( Math.random() * 6 );
  }
 }
 public void setendposition(){
  if (  (int)( Math.random() * 2 ) == 0 ){
   ex = 20 - ( int )( Math.random() * 6 );
   ey = 14;
  }else{
   ex = 19;
   ey = 14 - ( int )( Math.random() * 6 );
  }

 }
}


woensdag 29 februari 2012

I received a new book - Ai for game developers.

I ordered a book yesterday. Today I got it. It is a book about Artificial Intelligence. It is for Novice programmers. There is a whole chapter on a* in it. I think I will be making more artificial intelligence examples for the weblog in the future.

On google books you can read through a large part of the book. Last year I made a random obstacle avoidance example in another language from this book. This method is great for moving ai through forrest map parts.

woensdag 22 februari 2012

The Gimp - investing time in art creation.

It has been years ago that I last draw art for games. Sometimes I get the idea to spend time in drawing programs. I now downloaded the latest version of Gimp after looking around for drawing programs. I could find nothing better then the Gimp. I already found my favourite brush, the Smudge brush. This one can be used to smear the pixels around. It is easy to make clouds with the smudge brush for instance.
I want to spend time in the future drawing. I want to get good at it. This means getting to the 10.000 hours of experience with it. This means it will probably be old before I am good enough.

In blogger you can upload png files so I will be placing example drawings and step by step drawings in posts in the future. I hope that I will be productive. I also still think of things that I want to code.

zaterdag 18 februari 2012

Copperbar Example



In the code below you can see how the copperbar shown above is made. Copperbars were used in games to create a filled background. The effect looks quite nice.


 

import java.awt.*;
import java.applet.*;

public class CopperBarExample001 extends Applet {

 public void init() {
  // Set the applet background color to black.
  setBackground(Color.black);
 }

 public void paint(Graphics g) {
  g.setColor( Color.white );
  g.drawString( "Copperbar Example" , 10, 10 );
  int y = 50;
  double col = 0;
  while ( y < 100 ){ // draw the first 50 lines of the copperbar , dark to light
   g.setColor( new Color( 0 , 0 , (int)col ) );
   col += 255 / 50;
   g.drawLine( 0 , y , getSize().width , y );
   y++;
  }
  while ( y < 150 ){ // draw the last 50 lines of the copperbar, light to dark.
   g.setColor( new Color( 0 , 0 , (int)col ) );
   col -= 255 / 50;
   g.drawLine( 0 , y , getSize().width , y );
   y++;
  }

 }


}


Sidescrolling Shooter Shooting Example



In this example you can control a block that shoots 3 types of blocks. The control instructions are on the applet screen.


 

import java.awt.*;
import java.applet.*;

public class ShooterShootingExample001 extends Applet implements Runnable {
 Graphics bufferGraphics;
    Image offscreen;
 int px; // player x coordinate.
 int py; // player y coordinate.
 int pw = 16; // player width.
 int ph = 16; // player height.
 boolean pmoveup = false; // player move up.
 boolean pmovedown = false; // player move down.
 int shoottype = 0; // shooting , 0 = no shot, 1 = type 1, 2 = type 2, 3 = type 3
 long lastshottime = 0;
 int numshots = 32;
 double shots[][] = new double[ numshots ][ 5 ]; //active, x, y, mx, my
 int shotw = 3; // shot width.
 int shoth = 3; // shot height.

 public void init() {
  setBackground(Color.black);
     offscreen = createImage(getSize().width,getSize().height);
     bufferGraphics = offscreen.getGraphics();
     px = 16;
     py = getSize().height / 2 - ph / 2;
     // Start the runnable thread.
  new Thread(this).start();
 }
    public void run() {
     for(;;) { // animation loop never ends
   moveplayer();
   playershoot();
   updateshots();
         repaint();
         try {
             Thread.sleep(16);
            }
             catch (InterruptedException e) {
             }
     }
    }
 public void update (Graphics g)
  {
  bufferGraphics.clearRect( 0 , 0 , getSize().width , getSize().height );
     bufferGraphics.setColor ( Color.white );
     bufferGraphics.drawString( "Sidescroller Shooter Shooting Example." , 10 , 10 );
  bufferGraphics.drawString( "use : w and s to move up and down." , 10 , 20 );
  bufferGraphics.drawString( "use : i , o and p to shoot." , 10 , 30 );
  bufferGraphics.setColor( Color.red );
  // draw shots.
  for ( int i = 0 ; i < numshots ; i++ ){
   if ( shots[ i ][ 0 ] == 1 ){
    bufferGraphics.fillOval( (int)shots[ i ][ 1 ] , (int)shots[ i ][ 2 ] , shotw , shoth );
   }
  }
  // draw player.
  bufferGraphics.fillRect( px , py , pw , ph );
     g.drawImage(offscreen,0,0,this);
  }
  public boolean keyUp (Event e, int key){
  if ( key == 119 ){ // w key, up
   pmoveup = false;
  }
  if ( key == 115 ){ // s key, down
   pmovedown = false;
  }
  if ( key == 105 ){ // i key, fire 1
   shoottype = 0;
  }
  if ( key == 111 ){ // o key, fire 2
   shoottype = 0;
  }
  if ( key == 112 ){ // p key, fire 3
   shoottype = 0;
  }
    return true;
  }

   public boolean keyDown (Event e, int key){
  if ( key == 119 ){ // w key, up
   pmoveup = true;
  }
  if ( key == 115 ){ // s key, down
   pmovedown = true;
  }
  if ( key == 105 ){ // i key, fire 1
   shoottype = 1;
  }
  if ( key == 111 ){ // o key, fire 2
   shoottype = 2;
  }
  if ( key == 112 ){ // p key, fire 3
   shoottype = 3;
  }
        System.out.println ("Charakter: " + (char)key + " Integer Value: " + key);
        return true;
  }

 public void moveplayer(){
  if ( pmoveup ){
   if ( py > 30 ){
    py--;
   }
  }
  if ( pmovedown ){
   if ( py < getSize().height - ph ){
    py++;
   }
  }
 }

 public void playershoot(){
  int n = -1;
  if ( lastshottime < System.currentTimeMillis() ){
   if ( shoottype == 1 ){
    n = getemptyshot();
    if ( n > -1 ){
     shots[ n ][ 0 ] = 1;
     shots[ n ][ 1 ] = px + pw;
     shots[ n ][ 2 ] = py + ph / 2;
     shots[ n ][ 3 ] = 3;
     shots[ n ][ 4 ] = 0;
    }
   }
   if ( shoottype == 2 ){
    n = getemptyshot();
    if ( n > -1 ){
     shots[ n ][ 0 ] = 1;
     shots[ n ][ 1 ] = px + pw;
     shots[ n ][ 2 ] = py + ph / 2;
     shots[ n ][ 3 ] = 3;
     shots[ n ][ 4 ] = 0;
    }
    n = getemptyshot();
    if ( n > -1 ){
     shots[ n ][ 0 ] = 1;
     shots[ n ][ 1 ] = px + pw;
     shots[ n ][ 2 ] = py + ph / 2;
     shots[ n ][ 3 ] = 3;
     shots[ n ][ 4 ] = -2;
    }
    n = getemptyshot();
    if ( n > -1 ){
     shots[ n ][ 0 ] = 1;
     shots[ n ][ 1 ] = px + pw;
     shots[ n ][ 2 ] = py + ph / 2;
     shots[ n ][ 3 ] = 3;
     shots[ n ][ 4 ] = 2;
    }
   }
   if ( shoottype == 3 ){
    n = getemptyshot();
    if ( n > -1 ){
     shots[ n ][ 0 ] = 1;
     shots[ n ][ 1 ] = px + pw;
     shots[ n ][ 2 ] = py + ph / 2;
     shots[ n ][ 3 ] = 3;
     shots[ n ][ 4 ] = 0;
    }
    n = getemptyshot();
    if ( n > -1 ){
     shots[ n ][ 0 ] = 1;
     shots[ n ][ 1 ] = px + pw;
     shots[ n ][ 2 ] = py + ph / 2;
     shots[ n ][ 3 ] = 3;
     shots[ n ][ 4 ] = -2;
    }
    n = getemptyshot();
    if ( n > -1 ){
     shots[ n ][ 0 ] = 1;
     shots[ n ][ 1 ] = px + pw;
     shots[ n ][ 2 ] = py + ph / 2;
     shots[ n ][ 3 ] = 3;
     shots[ n ][ 4 ] = 2;
    }
    n = getemptyshot();
    if ( n > -1 ){
     shots[ n ][ 0 ] = 1;
     shots[ n ][ 1 ] = px + pw;
     shots[ n ][ 2 ] = py + ph / 2;
     shots[ n ][ 3 ] = 0;
     shots[ n ][ 4 ] = -3;
    }
    n = getemptyshot();
    if ( n > -1 ){
     shots[ n ][ 0 ] = 1;
     shots[ n ][ 1 ] = px + pw;
     shots[ n ][ 2 ] = py + ph / 2;
     shots[ n ][ 3 ] = 0;
     shots[ n ][ 4 ] = 3;
    }

   }
   lastshottime = System.currentTimeMillis() + 300;
  }

 }

 public int getemptyshot(){
  for ( int i = 0 ; i < numshots ; i++ ){
   if ( shots[ i ][ 0 ] == 0 ){
    return i;
   }
  }
  return -1;
 }

 public void updateshots(){
  for ( int i = 0 ; i < numshots ; i++ ){
   if ( shots[ i ][ 0 ] == 1 ){
    // Update the shots location on the screen.
    shots[ i ][ 1 ] += shots[ i ][ 3 ];
    shots[ i ][ 2 ] += shots[ i ][ 4 ];
    // If the shots get outside of the screen then disable them.
    if ( shots[ i ][ 1 ] > getSize().width ){
     shots[ i ][ 0 ] = 0;
    }
    if ( shots[ i ][ 2 ] < 0 - shoth ){
     shots[ i ][ 0 ] = 0;
    }
    if ( shots[ i ][ 2 ] > getSize().height ){
     shots[ i ][ 0 ] = 0;
    }

   }
  }
 }

}