Efficient Subimages (Newbie)
I've been writing java stuff for a while, but I've only just started looking at gaming.
Basically, the game is a tile based map with a little guy that runs around it. The way I draw the map is as follows:
1) On start of game, generate image of the whole map.
2) When the map needs to scroll, calculate the portion of the map the needs to be displayed
3) Grab that portion of the map, and slap it on the screen.
4) Draw the character.
The problem I'm having is in part 3). I can't get the map portion to display quickly. It takes a signigicant amounr of tme to get it up. Ive tried a number of ways to grab a portion of an image (BufferedImage.getSubimage(), PixelGrabber/ImageProducer), but neither manage it very quickly.
Is there a glaring error in my logic here that I'm not noticing? Or an efficient method for getting part of an image?
First of all, you don't want to load the entire map into memory as images, you want only a portion of the map slightly larger than that you're displaying stored in volatile memory (Or as an automatic image). If you store the entire map into memory, you're going to run into limitations when you decide you want to load a larger map (Eventually you'll run out of memory. It's best to make a tile-based map, and have the tiles reprisented in some kind of integer array only as numbers. Remember, volatile memory is only an itermediate place to store the images in a back-buffer before page-flipping.
Now, you want all of your tiles stored into one image, one right next to the other, and you want every tile a size that can be displayed eficiently on the chosen screen resolution, and making it absolutely square helps too. For 640x480 (Great for video games), 32x32 tiles are the best, and you can divide your map up into 20x15 squares.
Now for loading them as subimages.
Image myTileImage = new ImageIcon("MyImage.gif").getImage();
BufferedImage myBufferedTileImage = toBufferedImage(myImage);
BufferedImage[] myTiles = new BufferedImage[NumTilesWidth*NumTilesHeight];
for(int i = 0; i < 24*15; i ++)
{
myTiles = toBufferedImage(myBufferedTileImage.getSubimage(((i+NumTilesWidth)%NumTilesWidth)*32,32,32));
}
myBufferedImage = null;
myImage = null;
System.gc();
Now, the above first reads the image in using ImageIcon's getImage() method. This is the best method (Far better than MediaTracker), it insures that the entire image is loaded. Then it uses the "toBufferedImage()" method, which I will show at the end of this document, to convert this Image to a BufferedImage. This WILL create a duplicate image in memory temporarily, but don't worry about it, the end result will be much more efficient. Now that you have a BufferedImage, you can now break it up into tiles using BufferedImage's getSubimage method. This is an extremely quick process, it takes less than half a second on my 500mhz machine. Now, this is the real magic here, the "toAutomaticImage" method is what will make this baby really fly.
There isn't an Automatic Image object, but the Java virtual machine does create a special cross between a BufferedImage, and a Volatile Image known as a "Automatic Image" when possible; and it will handle everything pretty much transparently for you. Pretty much it will store the image in video memory when possible, but it will allow direct pixel manipulation, and all of the powerful manipulation routines of a Buffered Image. The secret is using the GraphicsConfiguration object you used to achieve fullscreen mode to create the BufferedImage. I do this with the regular BufferedImage routine too, but I'm not certain if when you call "getSubimage" if it's creating a duplicate of that subportion of the BufferedImage that is no longer volatile, so I convert it again, just to be safe.
//Generates an "Automatic" Image.
private BufferedImage toBufferedImage(Image image)
{
BufferedImage bufferedImage = myConfiguration.createCompatibleImage(image);
Graphics g = bufferedImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return bufferedImage;
}
-Jason Thomas.