import java.awt.*; import java.awt.image.ImageObserver; import java.io.*; import java.util.Vector; public class Level { public static final int ELEMENT_SIZE = 16; public static final int ELEMENT_SHIFT = 4; public static final int GRID_WIDTH = 16; public static final int GRID_HEIGHT = 15; private final boolean[][] grid = new boolean[ GRID_HEIGHT ][ GRID_WIDTH ]; private final byte[][] smells = new byte[ GRID_HEIGHT ][ GRID_WIDTH ]; private Vector jewels = new Vector(); private Vector dogs = new Vector(); private Sprite doorSprite = null; private Sprite exitSprite = null; public boolean isSpace( int x, int y ) { x >>= ELEMENT_SHIFT; y >>= ELEMENT_SHIFT; if ( x < 0 || x >= GRID_WIDTH ) return false; if ( y < 0 || y >= GRID_HEIGHT ) return false; return grid[ y ][ x ]; } /** Returns the value of the jewel the sprite has collided with. * Removes the jewel from the level if a collision has occured. **/ public int checkJewelCollisions( Sprite sprite ) { for ( int i = jewels.size()-1; i >= 0; --i ) { Sprite s = (Sprite)jewels.elementAt( i ); if ( sprite.onTop( s ) ) { jewels.removeElementAt( i ); return 1; } } return 0; } public boolean checkDogCollisions( Sprite sprite ) { calcSmells( sprite ); for ( int i = dogs.size()-1; i >= 0; --i ) { Sprite s = (Sprite)dogs.elementAt( i ); if ( sprite.isColliding( s ) ) { return true; } } return false; } public void calcSmells( Sprite sprite ) { int x = sprite.getX(); int y = sprite.getY(); x >>= ELEMENT_SHIFT; y >>= ELEMENT_SHIFT; for ( int i = 0; i < GRID_HEIGHT; i++ ) { for ( int j = 0; j < GRID_WIDTH; j++ ) { smells[ i ][ j ] = -1; } } smells[ y ][ x ] = 0; for ( byte n = 1; n <= 7; n++ ) { for ( int i = 0; i < GRID_HEIGHT; i++ ) { for ( int j = 0; j < GRID_WIDTH; j++ ) { if ( grid[ i ][ j ] && smells[ i ][ j ] == -1 ) { if ( near( j, i, n-1 ) ) smells[ i ][ j ] = n; } } } } } private boolean near( int i, int j, int n ) { if ( i != 0 && smells[ j ][ i-1 ] == n ) return true; if ( i != GRID_WIDTH-1 && smells[ j ][ i+1 ] == n ) return true; if ( j != 0 && smells[ j-1 ][ i ] == n ) return true; if ( j != GRID_HEIGHT-1 && smells[ j+1 ][ i ] == n ) return true; return false; } /** Returns direction which is nearest to the cat via smell. **/ public int sniff( int x, int y ) { x >>= ELEMENT_SHIFT; y >>= ELEMENT_SHIFT; int l = 255, r = 255, u = 255, d = 255; if ( x != 0 ) l = smells[ y ][ x-1 ]; if ( x != GRID_WIDTH-1 ) r = smells[ y ][ x+1 ]; if ( y != 0 ) u = smells[ y-1 ][ x ]; if ( y != GRID_HEIGHT-1 ) d = smells[ y+1 ][ x ]; if ( l == -1 ) l = 255; if ( r == -1 ) r = 255; if ( u == -1 ) u = 255; if ( d == -1 ) d = 255; int closest = Math.min( l, r ); closest = Math.min( u, Math.min( d, closest ) ); if ( closest == 255 ) return -1; if ( l == closest ) return Sprite.LEFT; if ( r == closest ) return Sprite.RIGHT; if ( u == closest ) return Sprite.UP; return Sprite.DOWN; } public boolean levelDone( Sprite sprite ) { return jewels.size() == 0 && sprite.onTop( exitSprite ); } public void tick() { for ( int i = dogs.size()-1; i >= 0; --i ) { Sprite s = (Sprite)dogs.elementAt( i ); s.tick( this ); } } public void paintStatic( Graphics g, ImageObserver o ) { Image floorImage = SpriteImages.get().getFloorImage(); Image wallImage = SpriteImages.get().getWallImage(); for ( int i = 0; i < GRID_HEIGHT; i++ ) { boolean[] row = grid[ i ]; for ( int j = 0; j < GRID_WIDTH; j++ ) { if ( !row[ j ] ) g.drawImage( wallImage, j << ELEMENT_SHIFT, i << ELEMENT_SHIFT, o ); else g.drawImage( floorImage, j << ELEMENT_SHIFT, i << ELEMENT_SHIFT, o ); } } } public void paint( Graphics g, ImageObserver o ) { /*for ( int i = 0; i < GRID_HEIGHT; i++ ) { byte[] row = smells[ i ]; for ( int j = 0; j < GRID_WIDTH; j++ ) { byte b = row[ j ]; float f = b/10.0f; if ( b == -1 ) f = 0.0f; else f = 1.0f - f; f = Math.min( f, 1.0f ); f = Math.max( f, 0.0f ); g.setColor( new Color( f, f, f ) ); g.fillRect( j << ELEMENT_SHIFT, i << ELEMENT_SHIFT, ELEMENT_SIZE, ELEMENT_SIZE ); } }*/ for ( int i = jewels.size()-1; i >= 0; --i ) { Sprite s = (Sprite)jewels.elementAt( i ); s.paint( g, o ); } if ( jewels.size() != 0 ) doorSprite.paint( g, o ); else exitSprite.paint( g, o ); for ( int i = dogs.size()-1; i >= 0; --i ) { Sprite s = (Sprite)dogs.elementAt( i ); s.paint( g, o ); } } public void load( Reader r, Sprite sprite ) throws IOException { jewels.removeAllElements(); dogs.removeAllElements(); doorSprite = null; StreamTokenizer st = new StreamTokenizer( r ); st.ordinaryChar( '_' ); st.ordinaryChar( '*' ); st.ordinaryChar( '%' ); st.ordinaryChar( '@' ); st.ordinaryChar( '<' ); st.ordinaryChar( '>' ); st.ordinaryChar( '^' ); st.ordinaryChar( 'v' ); Image jewel = SpriteImages.get().getJewelImage(); Image door = SpriteImages.get().getDoorImage(); Image exit = SpriteImages.get().getExitImage(); Image dog = SpriteImages.get().getDogImage(); for ( int i = 0; i < GRID_HEIGHT; i++ ) { for ( int j = 0; j < GRID_WIDTH; j++ ) { int ttype = st.nextToken(); switch( ttype ) { case '*': grid[ i ][ j ] = false; break; case '_': grid[ i ][ j ] = true; break; case '%': grid[ i ][ j ] = true; jewels.addElement( new Sprite( jewel, j << Level.ELEMENT_SHIFT, i << Level.ELEMENT_SHIFT ) ); break; case '@': grid[ i ][ j ] = true; sprite.setPosition( j << Level.ELEMENT_SHIFT, i << Level.ELEMENT_SHIFT ); doorSprite = new Sprite( door, j << Level.ELEMENT_SHIFT, i << Level.ELEMENT_SHIFT ); exitSprite = new Sprite( exit, j << Level.ELEMENT_SHIFT, i << Level.ELEMENT_SHIFT ); break; case '<': grid[ i ][ j ] = true; dogs.addElement( new DogSprite( Sprite.LEFT, dog, j << Level.ELEMENT_SHIFT, i << Level.ELEMENT_SHIFT ) ); break; case '>': grid[ i ][ j ] = true; dogs.addElement( new DogSprite( Sprite.RIGHT, dog, j << Level.ELEMENT_SHIFT, i << Level.ELEMENT_SHIFT ) ); break; case '^': grid[ i ][ j ] = true; dogs.addElement( new DogSprite( Sprite.UP, dog, j << Level.ELEMENT_SHIFT, i << Level.ELEMENT_SHIFT ) ); break; case 'v': grid[ i ][ j ] = true; dogs.addElement( new DogSprite( Sprite.DOWN, dog, j << Level.ELEMENT_SHIFT, i << Level.ELEMENT_SHIFT ) ); break; default: throw new IOException( "Error line " + st.lineno() ); } } } if ( doorSprite == null ) throw new IOException( "Level does not have a door!" ); } }