Worm.java

Denna kod är public domain. Om ni hittar fel eller vill ändra något i koden blir jag jätteglad om ni skickar dessa ändringar till jesper [at] fantasi [punkt] se.


/*
 * You may play this game and other on http://www.fantasi.se/jesper
 */

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.net.*;
import java.io.*;

public class Worm extends Applet
{
   public static final long serialVersionUID = 1L;
   int   score;
   Label sc;

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

      Panel control = new Panel();
      control.add(new Label("Score: "));
      control.add(sc = new Label("0"));

      setLayout(new BorderLayout());
      add("Center", new Field(this));
      add("South", control);
   }

   public void incScore( int i )
   {
      score += i;
      sc.setText("" + score);
   }

   public void resetScore()
   {
      score = 0;
      sc.setText("0");
   }
}

class Field extends Canvas
{
   public static final long serialVersionUID = 1L;
   public final int SIZE   = 10;
   public final int WIDTH  = 25;
   public final int HEIGHT = 25;
   public DemoWorm mirre;
   public LiveWorm murre;
   Coord  food;
   Worm   game;
   boolean notActive, info, textmode;
   Thread demo;
   String hiName[] = new String[8];
   String hiScore[] = new String[8];
   String textresult;

   public Field( Worm theApplet )
   {
      super();
      setFocusable(true);
      setBackground(Color.green);
      game  = theApplet;
      info  = notActive = true;
      mirre = new DemoWorm(0, 0, Color.blue, this, 20);
      murre = new LiveWorm((int)(WIDTH / 2), (int)(HEIGHT / 2),
                           Color.black, this, 10);
      food  = new Coord();
      textresult = new String();
      placeFood();
      this.addKeyListener(new Stearing());
      this.addMouseListener(new FocusOnMe());
      demo = new Thread(mirre);
      demo.start();
   }

   public void placeFood()
   {
      food.setX((int)(Math.random() * WIDTH));
      food.setY((int)(Math.random() * HEIGHT));
      while (!free(food))
      {
         food.setX((int)(Math.random() * WIDTH));
         food.setY((int)(Math.random() * HEIGHT));
      }
      if (!notActive)
      {
         Graphics g = getGraphics();
         g.setColor(Color.red);
         g.fillOval(food.getX() * SIZE + 2,
                    food.getY() * SIZE + 2, SIZE, SIZE);
      }
   }

   public boolean free( Coord c )
   {
      return !murre.occupies(c);
   }

   public boolean isFood( Coord c )
   {
      return c.equals(food);
   }

   public void eatFood()
   {
      game.incScore(1);
      placeFood();
   }

   public void start()
   {
      notActive    = false;
      mirre.active = false;
      murre.go     = false;
      game.resetScore();
      repaint();
   }

   class Stearing extends KeyAdapter
   {
      public void keyTyped( KeyEvent e )
      {
         if (notActive)
            return;

         if (textmode)
         {
            Graphics g = getGraphics();
            g.setColor(Color.black);
            g.setFont(new Font("Courier", Font.PLAIN, 14));
            char ch = e.getKeyChar();
            if (ch > 31)
            {
               g.drawString(ch + "", 20 + 12 * textresult.length(), 182);
               textresult = textresult.concat(new String(ch + ""));
               if (textresult.length() == 15)
                  textmode = false;
            }
         }
         else if (!murre.go)
         {
            switch(e.getKeyChar())
            {
               case '8': murre.goUp(); break;
               case '2': murre.goDown(); break;
               case '4': murre.goLeft(); break;
               case '6': murre.goRight(); break;
               default : return;
            }

            if (!murre.active)
            {
               Thread tr = new Thread(murre);
               tr.start();
            }
         }
      }

      public void keyPressed( KeyEvent e )
      {
         if (notActive)
            return;

         String str = KeyEvent.getKeyText(e.getKeyCode());
         if (textmode)
         {
            if (str.equalsIgnoreCase("enter"))
               textmode = false;
            else if (str.equalsIgnoreCase("backspace"))
            {
               textresult = textresult.substring(0, textresult.length() - 1);
               repaint();
            }
         }
         else if (!murre.go)
         {
            if (str.equalsIgnoreCase("up"))
               murre.goUp();
            else if (str.equalsIgnoreCase("down"))
               murre.goDown();
            else if (str.equalsIgnoreCase("left"))
               murre.goLeft();
            else if (str.equalsIgnoreCase("right"))
               murre.goRight();
            else return;

            if (!murre.active)
            {
               Thread tr = new Thread(murre);
               tr.start();
            }
         }
      }
   }

   class FocusOnMe extends MouseAdapter
   {
      public void mousePressed( MouseEvent e )
      {
         requestFocus();
         if (!(textmode || murre.active)) start();
      }
   }

   public void checkScore()
   {
      loadHiScore();
      if (game.score > Integer.parseInt(hiScore[7]))
      {
         textresult = "";
         textmode   = true;
         repaint();
         while (textmode)
         {
            try { Thread.sleep(10); }
            catch (InterruptedException e)
            {
               System.err.println(e.getMessage());
            }
         }
         saveHiScore();
      }
   }

   public void loadHiScore()
   {
      int ok = 0;

      for (int i = 0; i < 8; i++)
      {
         hiName[i]  = "Worm          ";
         hiScore[i] = "" + (40 - i * 5);
      }
      try
      {
         URL url = new URL(game.getCodeBase(), "Worm.hi");
         BufferedReader indata =
            new BufferedReader(new InputStreamReader(url.openStream()));

         for (int i = 0; i < 8; i++)
         {
            hiName[i] = indata.readLine();
            if (hiName[i].length() > 14)
               hiName[i] = hiName[i].substring(0, 14);
            hiScore[i] = indata.readLine();
            ok = i;
         }
      }
      catch (MalformedURLException e)
      {
         System.err.println(e.getMessage());
      }
      catch (IOException e)
      {
         System.err.println(e.getMessage());
         try
         {
            for (int i = ok; i < 8; i++)
            {
               URL url = new URL("http://url.to.server/worm.pl?" +
                                 "name=Worm&score=" + (40 - 5 * i));
               BufferedReader indata =
                  new BufferedReader(new InputStreamReader(url.openStream()));
               indata.readLine();
            }
         }
         catch (MalformedURLException ex)
         {
            System.err.println(ex.getMessage());
         }
         catch (IOException ex)
         {
            System.err.println(ex.getMessage());
         }
      }
   }

   public void saveHiScore()
   {
      int i;

      while ((i = textresult.indexOf(' ')) != -1)
      {
         textresult = textresult.substring(0, i) + "+" +
            textresult.substring(i + 1);
      }
      try
      {
         URL url = new URL("http://url.to.server/worm.pl?" +
                           "name=" + textresult + "&score=" + game.score);
         BufferedReader indata =
            new BufferedReader(new InputStreamReader(url.openStream()));
         indata.readLine();
      }
      catch (MalformedURLException e)
      {
         System.err.println(e.getMessage());
      }
      catch (IOException e)
      {
         System.err.println(e.getMessage());
      }
   }

   public void paint( Graphics g )
   {
      g.drawRect(0,0,(WIDTH + 1) * SIZE + 3,(HEIGHT + 1) * SIZE + 3);
      g.drawRect(1,1,(WIDTH + 1) * SIZE + 1,(HEIGHT + 1) * SIZE + 1);

      if (notActive)
      {
         if (info)
         {
            mirre.paint(g);
            g.setColor(Color.black);
            g.setFont(new Font("Helvetica", Font.BOLD, 40));
            g.drawString("the Worm", 20, 60);
            g.setFont(new Font("Helvetica", Font.BOLD, 18));
            g.drawString("Key control:", 20, 100);
            g.drawString("8 - Up", 150, 100);
            g.drawString("2 - Down", 150, 125);
            g.drawString("4 - Left", 150, 150);
            g.drawString("6 - Right", 150, 175);
            g.drawString("or use the arrow keys", 20, 200);
            g.drawString("Click in window to start", 20, 250);
         }
         else
         {
            mirre.paint(g);
            g.setColor(Color.black);
            g.setFont(new Font("Helvetica", Font.BOLD, 20));
            g.drawString("HiScore:", 90, 40);
            loadHiScore();
            g.setFont(new Font("Helvetica", Font.BOLD, 16));
            for (int i = 0; i < 8; i++)
            {
               g.drawString(hiName[i], 20, 65 + i * 25);
               g.drawString(hiScore[i], 200, 65 + i * 25);
            }
         }
      }
      else
      {
         murre.paint(g);
         g.setColor(Color.red);
         g.fillOval(food.getX() * SIZE + 2, food.getY() * SIZE + 2, SIZE, SIZE);
         if (textmode)
         {
            g.setColor(new Color(100, 100, 200));
            g.setFont(new Font("Helvetica", Font.BOLD, 30));
            g.drawString("WoOoW!", 73, 100);
            g.setFont(new Font("Helvetica", Font.BOLD, 20));
            g.drawString("A new HiScore!", 55, 125);
            g.drawString("Enter your name", 50, 150);
            g.drawRect(12, 162, 239, 25);
            g.setColor(Color.green);
            g.fillRect(13, 163, 238, 24);
            g.setColor(Color.black);
            g.setFont(new Font("Courier", Font.PLAIN, 20));
            g.drawString(textresult, 20, 182);
         }
      }
   }
}

class Coord
{
   private int x, y;

   public Coord()
   {
      x = 0;
      y = 0;
   }

   public Coord( int ix, int iy )
   {
      x = ix;
      y = iy;
   }

   public int  getX() { return x; }
   public int  getY() { return y; }
   public void setX( int ix ) { x = ix; }
   public void setY( int iy ) { y = iy; }

   public boolean equals( Coord c )
   {
      return (( x == c.getX() ) && ( y == c.getY() ));
   }
}

class LiveWorm implements Runnable
{
   static final int MAXLEN = 200;
   static final int UP     = 0;
   static final int DOWN   = 1;
   static final int LEFT   = 2;
   static final int RIGHT  = 3;
   static final int STOP   = 4;
   Coord   pos[] = new Coord[MAXLEN];
   int     ix,iy;            // Where shall we begin?
   int     dx,dy;            // the Worms direction
   int     start,end;        // Beginning and end of the worm in the array
   int     length;
   boolean active,go;        // Is the worm alive?
   Color   col;
   Field   battlefield;
   int     direction;

   public LiveWorm( int x, int y, Color c, Field p, int l )
   {
      battlefield = p;
      col         = c;
      length      = l;
      ix          = x;
      iy          = y;
      go          = false;
      active      = false;
      start       = length;
      end         = 0;
      dx          = 0;
      dy          = 0;
      direction   = STOP;
      for (int i = 0; i < MAXLEN; i++)
         pos[i] = new Coord();
      place(ix,iy);
   }

   public void goUp()    { if (direction != DOWN  ) { dx = 0; dy = -1; }}
   public void goDown()  { if (direction != UP    ) { dx = 0; dy =  1; }}
   public void goLeft()  { if (direction != RIGHT ) { dy = 0; dx = -1; }}
   public void goRight() { if (direction != LEFT  ) { dy = 0; dx =  1; }}

   public void place( int x, int y )
   {
      int i = end;

      while ( i != start)
      {
         pos[i].setX(x);
         pos[i].setY(y);
         i++;
         if (i == MAXLEN) i = 0;
      }
      pos[i].setX(x);
      pos[i].setY(y);
   }

   public void setDirection()
   {
      if (dx == 1) direction = RIGHT;
      else if (dx == -1) direction = LEFT;
      else if (dy == 1) direction = DOWN;
      else direction = UP;
   }

   public void run()
   {
      Graphics g = battlefield.getGraphics();

      active = true;
      go = false;
      while (active)
      {
         int next = start + 1;

         if (next == MAXLEN) next = 0;
         pos[next].setX(pos[start].getX() + dx);
         pos[next].setY(pos[start].getY() + dy);
         setDirection();

         if ( (pos[next].getX() > battlefield.WIDTH)  ||
              (pos[next].getX() < 0) ||
              (pos[next].getY() > battlefield.HEIGHT) ||
              (pos[next].getY() < 0) )
         {
            active = false;
         }
         else
         {
            if (battlefield.isFood(pos[next]))
            {
               battlefield.eatFood();
               length++;
               if (length == MAXLEN)
                  length--;
            }
            else
            {
               if (occupies(pos[next]))
               {
                  active = false;
               }
               else
               {
                  end++;
                  if (end == MAXLEN) end = 0;
               }
            }
         }

         if (active)
         {
            int last = end + 1;

            start = next;
            if (last == MAXLEN) last = 0;
            if (!pos[last].equals(pos[end]))
            {
               g.setColor(Color.green);
               g.fillOval(pos[end].getX() * battlefield.SIZE + 2,
                          pos[end].getY() * battlefield.SIZE + 2,
                          battlefield.SIZE, battlefield.SIZE);
            }
            g.setColor(col);
            g.fillOval(pos[start].getX() * battlefield.SIZE + 2,
                       pos[start].getY() * battlefield.SIZE + 2,
                       battlefield.SIZE, battlefield.SIZE);
            try { Thread.sleep(Math.max(200 - (length * 2), 0)); }
            catch (InterruptedException e)
            {
               System.err.println(e.getMessage());
            }
         }
      }
      go = true;
      battlefield.repaint();
      battlefield.checkScore();
      battlefield.notActive = true;
      battlefield.info = false;
      battlefield.demo = new Thread(battlefield.mirre);
      battlefield.demo.start();
      length = 10;
      start = length;
      end = 0;
      dx = 0;
      dy = 0;
      direction = STOP;
      place(ix, iy);
   }

   public void kill() { active = false; }

   public boolean occupies( Coord c )
   {
      int i = end;

      while ( i != start)
      {
         if (c.equals(pos[i]))
            return true;
         i++;
         if (i == MAXLEN) i = 0;
      }
      if (c.equals(pos[start]))
         return true;
      return false;
   }

   public void paint( Graphics g )
   {
      g.setColor(Color.green);
      g.fillOval(pos[end].getX() * battlefield.SIZE + 2,
                 pos[end].getY() * battlefield.SIZE + 2,
                 battlefield.SIZE, battlefield.SIZE);
      g.setColor(col);

      int i = end;
      while ( i != start)
      {
         i++;
         if (i == MAXLEN) i = 0;
         g.fillOval(pos[i].getX() * battlefield.SIZE + 2,
                    pos[i].getY() * battlefield.SIZE + 2,
                    battlefield.SIZE, battlefield.SIZE);
      }

      if (go)
      {
         g.setColor(new Color(100, 100, 255));
         g.setFont(new Font("Helvetica", Font.BOLD, 40));
         g.drawString("Game Over!", 20, 42);
      }
   }
}

class DemoWorm extends LiveWorm
{
   int lap;

   public DemoWorm( int x, int y, Color c, Field f, int l )
   {
      super(x, y, c, f, l);
      goRight();
   }

   public void turn()
   {
      if (dx == 1) goDown();
      else if (dx == -1) goUp();
      else if (dy == 1) goLeft();
      else { goRight(); lap++; }
   }

   public void run()
   {
      try { Thread.sleep(500); }
      catch (InterruptedException e)
      {
         System.err.println(e.getMessage());
      }

      Graphics g = battlefield.getGraphics();
      active = true;
      lap = 1;
      while (active)
      {
         int next = start + 1;
         if (next == MAXLEN)
            next = 0;
         pos[next].setX(pos[start].getX() + dx);
         pos[next].setY(pos[start].getY() + dy);

         if ( (pos[next].getX() > battlefield.WIDTH)  ||
              (pos[next].getX() < 0) ||
              (pos[next].getY() > battlefield.HEIGHT) ||
              (pos[next].getY() < 0) )
         {
            turn();
            pos[next].setX(pos[start].getX() + dx);
            pos[next].setY(pos[start].getY() + dy);
         }

         end++;
         if (end == MAXLEN)
            end = 0;

         start = next;

         int last = end + 1;
         if (last == MAXLEN)
            last = 0;

         g.setColor(Color.green);
         g.fillOval(pos[end].getX() * battlefield.SIZE + 2,
                    pos[end].getY() * battlefield.SIZE + 2,
                    battlefield.SIZE, battlefield.SIZE);

         g.setColor(col);
         g.fillOval(pos[start].getX() * battlefield.SIZE + 2,
                    pos[start].getY() * battlefield.SIZE + 2,
                    battlefield.SIZE, battlefield.SIZE);

         if (lap == 2)
         {
            lap = 0;
            battlefield.info = !battlefield.info;
            battlefield.repaint();
         }
         try { Thread.sleep(130); }
         catch (InterruptedException e)
         {
            System.err.println(e.getMessage());
         }
      }
   }
}