Monday, April 4, 2011

Moving Objects and Sprite Manager - Part 7

This will be the end of the series. It is suggested to read the whole series from the beginning.


Extending the Sprite class


In the conclusion of the previous article, I said you could do really interesting thing if you understand the basic Sprite class well enough. Let's make a small sample on this. Up to now all bunnies look the same, we are going to add a "panic" bunny to the sprite list.

How does a "panic" bunny look like ? It face will turn red and it will be moving restlessly. Let make a reddish sprite first. How to make a sprite looks more reddish ? It is simple. For every pixel, we just reduce the green and blue component by half. This effectively increases the weighting of the red component in the image. And it will look reddish.

We don't have to rewrite the Sprite class. All we need is to extend it.
/******************************************************************************
* File : ReddishSprite.java
* Author : http://java.macteki.com/
* Description :
*   A sprite which is more "reddish" than normal
* Tested with : JDK 1.6
******************************************************************************/

import java.awt.image.BufferedImage;

class ReddishSprite extends Sprite
{
  public ReddishSprite(BufferedImage img)
  {
    super(img);
    this.image = makeReddishImage(this.image);
  }

  // make it reddish
  private BufferedImage makeReddishImage(BufferedImage tmpImage)
  {
    int h=tmpImage.getHeight(null);
    int w=tmpImage.getWidth(null);

    BufferedImage resultImage=new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
 
    for (int y=0;y<h;y++)
      for (int x=0;x<w;x++)
      {
        int color=tmpImage.getRGB(x,y);
        // get A,R,G,B value
        int A=color & 0xff000000;
        int R=(color & 0x00ff0000) >>> 16;
        int G=(color & 0x0000ff00) >>> 8;
        int B=color & 0x000000ff;
        // reduce the green and blue component by half
        G/=2;
        B/=2;
        // packed back to a color value
        color = A | (R<<16) | (G<<8) | B;
        
        resultImage.setRGB(x,y,color);
      }
 
 
    return resultImage;
  }
  
}
Next, we modify the method initSpriteList() in SpriteManager.java. Originally it just adds 50 bunnies to the list, now it adds one more "panic" bunny to the list.
// add 50 bunnies sprites to the sprite list  
  public void initSpriteList() throws Exception
  {
    BufferedImage image = javax.imageio.ImageIO.read(new java.io.File("bunny_sprite.png"));
 
    java.util.Random random=new java.util.Random();
    for (int i=0;i<50;i++)
    {
      Sprite sprite=new Sprite(image);
      sprite.x=50+16*random.nextInt(20);
      sprite.y=250+4*random.nextInt(20);
      sprite.relativeSpeed=1+(i%3);   // range from 1 to 4
      sprite.gestureWait=8;           // change it to 1 to see what happen
      spriteList.add(sprite);
    }

    // add a panic bunny
    ReddishSprite redSprite=new ReddishSprite(image);
    redSprite.x=0;
    redSprite.y=250;
    redSprite.relativeSpeed=1;   // full speed  (look more panic)
    redSprite.gestureWait=2;     // fast rhythm (look more restless)
    spriteList.add(redSprite);   // add to the sprite list just like the normal sprite
  }

Adding a Boss

To make thing more interesting, we extend the Sprite class again and make a "boss" bunny. It is double in size and it it moving slower. It also has the ability to fly in the sky.

/******************************************************************************
* File : BigSprite.java
* Author : http://java.macteki.com/
* Description :
*   A "Boss" Sprite
* Tested with : JDK 1.6
******************************************************************************/

import java.awt.image.BufferedImage;

class BigSprite extends Sprite
{

  // pre-defined source regions
  private int[][][] frameRect = // [direction][gesture][x,y,w,h]
    {
    {{ 0,  0,64,64}, {64,  0,64,64}, {128,  0,64,64}, {192,  0,64,64} },  // left
    {{ 0, 64,64,64}, {64, 64,64,64}, {128, 64,64,64}, {192, 64,64,64} },  // right
    {{ 0,128,64,64}, {64,128,64,64}, {128,128,64,64}, {192,128,64,64} },  // down
    {{ 0,192,64,64}, {64,192,64,64}, {128,192,64,64}, {192,192,64,64} }   // up
    };  

  public int[] getImageBound(int direction, int gesture)
  {
    return frameRect[direction][gesture];
  }

  public BigSprite(java.awt.image.BufferedImage img)
  {
    super(img);
    this.image = makeBlue(this.image);
    this.image = makeDoubleSizeImage(this.image);
  }

  // make it blue
  private BufferedImage makeBlue(BufferedImage tmpImage)
  {
    int h=tmpImage.getHeight(null);
    int w=tmpImage.getWidth(null);

    BufferedImage resultImage=new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
 
    for (int y=0;y<h;y++)
      for (int x=0;x<w;x++)
      {
        int color=tmpImage.getRGB(x,y);
        // get A,R,G,B value
        int A=color & 0xff000000;
        int R=(color & 0x00ff0000) >>> 16;
        int G=(color & 0x0000ff00) >>> 8;
        int B=color & 0x000000ff;
        // reduce the red and green component by half
        // double the blue component
        R/=2;  G/=2;  B*=2;
        // packed back to a color value
        color = A | (R<<16) | (G<<8) | B;
        
        resultImage.setRGB(x,y,color);
      }
 
 
    return resultImage;
  }

  // scale up the image by a factor of 2
  private BufferedImage makeDoubleSizeImage(BufferedImage tmpImage)
  {
    int h=tmpImage.getHeight(null);
    int w=tmpImage.getWidth(null);
 
    BufferedImage resultImage=new BufferedImage(w*2,h*2,BufferedImage.TYPE_INT_ARGB);

    java.awt.Graphics2D gr=(java.awt.Graphics2D) resultImage.getGraphics();
    java.awt.geom.AffineTransform transform=gr.getTransform();
    transform.scale(2,2);
    gr.setTransform(transform);
    gr.drawImage(tmpImage,0,0,null);
 
    return resultImage;
  }

  // Boss Sprite is flying in the sky
  public int[] getActiveRegion()
  {
    // upperLeft corner(x,y),  lowerRight corner(x,y)
    return new int[]{ 0,0,750,150};  // upper area of the screen.
  }
  
}

Of course we need to modify initSpriteList() again, add the boss sprite code just below the panic sprite code.

// add a panic bunny
    ReddishSprite redSprite=new ReddishSprite(image);
    redSprite.x=0;
    redSprite.y=250;
    redSprite.relativeSpeed=1;   // full speed (look more panic)
    redSprite.gestureWait=2;     // fast rhythm (look more restless)
    spriteList.add(redSprite);   // add to sprite list just like a normal sprite

    // add a Boss Bunny
    BigSprite bossSprite=new BigSprite(image);
    bossSprite.x=50;
    bossSprite.y=100;             // boss is flying in the sky
    bossSprite.relativeSpeed=8;   // boss move much slower due to its size
    bossSprite.gestureWait=16;    // boss is more reluctant to change gesture
    spriteList.add(bossSprite);   // add to sprite list just like a normal sprite

Result

If you are doing everything correctly, you should see a flying boss and a panic(red) bunny inside the crowd of the normal bunnies.

Acknowledgement

  1. bunny_sprite.png is provided by Moosader :
    http://moosader.deviantart.com/art/Public-domain-bunny-sprite-151156167

  2. background.jpg is provided by Jesccia Crabtree
    http://www.jessicacrabtree.com/journal1/public-domain-nature-photos

Next

This is the end of the series. If you like it, post a comment. If you don't like it, also post a comment. Right now I am thinking of the next programming topic. So I cannot tell what is going next. Anyway, I would try hard to update this site frequently. If you'd like to propose a topic, you can leave a comments in this blog under any articles. I may share something on it if I have the necessary skills and knowledges.

No comments:

Post a Comment