Java Water Simulation

Description

You can create a fairly realistic water simulation in only a few lines of code. I've seen the algorithm implemented here discussed on many sites. A good explanation of why this works can be found here. The basic approach is:-

Demonstration

alt="Your browser can handle applet's, but isn't for some reason!" Your browser cannot handle the applet tag!
Move your mouse over the pool balls


Main code

The code for the main loop is as follows:-
    public void newframe() {
      //Toggle maps each frame
      i=oldind;
      oldind=newind;
      newind=i;

      i=0;
      mapind=oldind;
      for (int y=0;y<height;y++) {
        for (int x=0;x<width;x++) {
	      short data = (short)((ripplemap[mapind-width]+ripplemap[mapind+width]+
				ripplemap[mapind-1]+ripplemap[mapind+1])>>1);
          data -= ripplemap[newind+i];
          data -= data >> 5;
          ripplemap[newind+i]=data;

	      //where data=0 then still, where data>0 then wave
	      data = (short)(1024-data);

          //offsets
  	      a=((x-hwidth)*data/1024)+hwidth;
          b=((y-hheight)*data/1024)+hheight;

 	      //bounds check
          if (a>=width) a=width-1;
          if (a<0) a=0;
          if (b>=height) b=height-1;
          if (b<0) b=0;

          ripple[i]=texture[a+(b*width)];
          mapind++;
	      i++;
        }
      }
    }

Future Improvements

You may have noticed that when you create a ripple at the left or right edge of the applet the water is also disturbed at the opposite edge. Not very realistic huh? This is simply because the ripplemap element corresponding to the right-hand edge pixel on one row is adjacent to the element of the left-hand pixel in the next row. This create a wraparound effect. You could get around this by ensuring that the extreme right/left elements are always zero. I've done something similar to separate the two state maps. Remember earlier when I described the size of the ripple map as being two rows larger than necessary in both states. This was so that the ripples could reach the top and bottom without crossing over into the opposite state map.

You'll notice that many of the values that would alter the behaviour of the water are hard-coded, e.g. magnitude of the ripple, radius of ripple, rate of decay, etc. A wider range of effects could be acheived if these were runtime parameters.


Download

water.java
water.class