fastest method to make a parallax side-scrolling game using tiles

Hi, I just started making a Java 1.5 applet parallax side-scrolling adventure game using tiles. The game is going to be similar to Donkey Kong Country, Sonic the Hedgehog, and Super Mario World. However, I do not want to use any third-party game engines because of customization and speed issues. Third-party game engines are bloaty, unprofessional, and they are for novices. I want the fastest methods for making a game like that. I am using MemoryImageSource, but calling the drawImage(image, 0, 0, null) method on every frame is very slow. image.flush() is also slow, but not as slow as drawImage. The only thing that slows down the game is the drawImage method. How can I make the game run at 60 fps? I don’t know how to scroll it smoothly. How can I add sprites? Are there any faster methods for making games like this for Java 1.5 applets? The game is 512x512 pixels using 16x16 pixel tiles. Are there any faster methods to make this kind of game instead of memoryimagesource? If memoryimagesource is the fastest, how can I make it faster?

Here’s the code I’m using:



// the two-dimensional array of tiles

public byte tile[][];

static final int tilesX = 32;

static final int tilesY = 32;

static final int tileWidth = 16;

static final int tileHeight = 16;

static final int screenWidth = tileWidth * tilesX;

static final int screenHeight = tileHeight * tilesY;

protected int videoBuffer[] = new int[screenWidth * screenHeight];

private Image img;

img = createImage(new MemoryImageSource(screenWidth, screenHeight, videoBuffer, 0, screenWidth));

while (true)
{
	// modify the image

	img.flush();
	
	appletGraphics.drawImage(img, 0, 0, null);
}


If your goal is to make the game run fast then you better use hardware acceleration. It’s unlikely you’ll get 60 fps with that resolution using a software renderer. Transfering the image to the gfx card just takes to long. But if you still want to try, then BufferedImage might be slightly faster than MemoryImageSource. How to access the image buffer is shown in the Java2D faq.

Java2D can give you hw acceleration if you follow some rules. But then Java2D is your “Third-party game engine”. The alternative is to access the hardware directly using one of the OpenGL wrappers, like JOGL or LWJGL.

Unless Chet has added some hadrware support for BufferedImage sicne last I looked at it, id stay away from it as it by definition means you are holding and modifying your image data in Java heap space whcih is abotua s far from the graphics card as you can get.

Beyoind that it depends on what your target palktforms are, to some degree. AWT has very nice support for hardware buffer flipping and video-memory resident images in the API using FullScreen Exclusive mode, BufferStrategy and VolatileImage. Together those three thinsg give you the classic DirectDraw way of doing fast 2D BLT and show in a somehwat more convenient form.

UNFORTUNATELY last I looekd the only good implemntation of this is under WIn32. Linux unfrotunately does all its AWT through X which by definition prevents you from doing true buffer flipping. The Linux JDK from Sun will fake it ina full screen undecorated X window and pul lsome eprformance tricks but ist nowhere near the WIndows performance.

Apple COULD do it as fast as WIndows but last time I looked, they had thatopart of their JDK throgoughly screwed up and it was dirt slow. They may have fixed it since then, I stopped tracking Appl,e’s JDK about a year ago.

In the end, the best way to get hardware support across the alrgest numerb of paltforms is to use OGL through either LWJGL or JOGL. However doing 2D with OGL isn’t the simplest or msot obvious thing in the world. There may be some libraries out there to do it, Im not sure on that.

Above it all… if yo uwant speed… PROFILE. You may find the reasons yo uarent getting the eprformance you are wanting has nothign whatsoever to do with your render method. You can’t know until you profile your code.

Good luck.

OH a few odd notes…

(1) Here’s the classic article on how to use Full Screen Exclusive mdoe and byuffer flippign if you decide to go that route…

http://java.sun.com/docs/books/tutorial/extra/fullscreen/

(2) I actually wrote a little demo Isometric scroller using FSE when it was first released. Its called “Scroller”.
If someone knwos where a copy is these days and can post a poinetr Il lsee about getting it added to the 2D demos project

Two ways

i) Load your tiles as images & copy into VolatileImages. Then draw the VolatileImages on the screen (checking to make sure they haven’t been trashed). If the VolatileImages get hardware accelerated then fine. If not the poor performance.

ii) Create a BufferedImage the same size as your screen. Do all your drawing onto that and then, once per frame, draw that onto the screen. That last op is slow, but at least you are only doing it once per frame.

For option ii) if memory is no object, consider pre-tiling each layer into a big BufferedImage before starting each level. This works well if the background layers are not animated. I tried this a couple of months ago for two layers (no tiling) & it worked fine).

Experiment with writing code to manually copy a section from the underlying byte array of one bitmap to the other and compare the speed to that when using the built in drawImage(). Surprised? I was too.

You shouldnt be.

The slowest part of the draw-chain in WIntel architecture is pushing data across the bus to the video card. PCI-Express may finnaly chnage that, we’ll see…

Every draw of a non-accelerated image means a cross of that barrier. AWT will try to cache some kinds of images for you in video memory. Thats called a “managed image”. BUT there are a number of things you can do to force it to drop that cache. A key one is changing the contents of the image.

An array copy in Java is simply copying data between two places on the Java Heap. Thats very quick. About the quickest kind of memory move you can do in Java. But it doesnt get it down to the video card, and that final operation will cost you twice… once to move the data from Java Heap to C memory and then again to push that data across the bus to the graphics card.

The way fast 2D has always been done in DirectDraw is to pre-download everything you can to the video card and do all your BLTing in video memory. You then flip that assembled video buffer to the screen,
which takles the move of one pointer in the video system (as free as it gets). Thats what Fullscreen Exclusive mode, Buffer Strategies, and VolatileImage make possible in Java.

The big limit is that you cant have more graphics then you can fit in video memory. ofcourse video memory is getting pretty big these days…

Now with 3D becoming ubiquitous, this entire approach may get superceeded by doing 2D in 3D (OGL and D3D). In fact, DirectDraw no longer even exists in the latest DirectX. In preperation for this Microsoft has merged their 2D API into Direct3D. The equivalent of that today in Java is using OGL to do your drawing.

Hello guys,

I am experimenting the exact same issue with my animation.

My “engine” renders frames pixel by pixel (actually, i am implementing an “old school effect”, “Tunnel”, you can find some pictures of the effect here:http://www.student.kuleuven.ac.be/~m0216922/CG/tunnel.html).

Right now, i am rendering into a int[] (wrapped in a MemoryImageSource) and then i draw this MemoryImageSource into a JFrame.
Performances are acceptable at 640480 (30 fps on a 2 Ghz G5, PCI-Express bus), but drop dramatically at 800600 and 1024*768.

The reason is that it takes 100 ms+, to draw the MemoryImageSource in the JFrame (namely, copy data from jvm memory to vram).

After some reading, i found the VolatileImage type, with which datas reside in vram. But it seems there is no way to access pixel in an accelerated way.

I tried to use VolatileImage.getGraphics.fillRec(x,y,1,1) , but none of the methods in Graphics seems to work efficiently :frowning: !

Is there ANY way to access pixels directly in VRAM ?
Is it planned for java 1.6 ?
If i switch to FullScreen with awt, what kind of object should i use to have my generated int[’] in vram ?

Thxs :slight_smile: !

If you want per pixel access, MemoryImageSource’s and BufferedImage’s are for you. Like explained above, these need to transfer all ints to the videocard which is slow. What I can add is that when you create a managed image (BufferedImage using component.createCompatibleImage) you’re likely to sqeeze more fps out as when using a MemoryImageSource (on my config I get about 30-50fps more). Like Alan said, do all your rendering in int[] and use 1 BufferedImage as big as your screen, then when all per pixel operations are done on those int[] copy them into the BufferedImage which represents your screen.

VolatileImages are stored in vram and are probably suffcient for most tile engine’s. Same for using opengl. There is one way to have your textures stored in vram and still do per pixel effects; using opengl and pixelshaders. You can do all these oldskool effects on the GPU that way.

Thijs

EDIT:
I just remembered a 2d sidescroller which also did this (accelerated 2d graphics but with nice per pixel effects):
http://www.facewound.com/
http://www.facewound.com/tutorials/shader1/

Working with such small primitives (1x1 pixel) is very inefficient.
Why not use sprites? Opaque and 1bit transparent images are hw accelerated
in 1.4+.

In 1.5 with OpenGL pipeline translucent images (and a lot of other stuff)
is accelerated as well. Look for OpenGL pipeline info in Java2D forum.

There’s currently no way to access pixels directly in vram - this is not the best
way anyway - access to vram (reading from) is extremely slow.

You should work with images and other higher level primitives, and let Java2D sort it out and find the
best way to render them.

Also consider using java.awt.image.BufferStrategy for double-buffering.

Thanks,
Dmitri
Java2D Team

So true… and even more with 1.6. My little gamechmark runs at 100fps under 1.6 where it used to run at 60 under 1.5, without modifications and using plain java2d.

Pixel access is needed to implement the tunnel effect he is doing. This can’t be done with sprites, lines or any other operation.

Then I’d suggest to work with pixels on a Bufferedimage (by getting the array from the
DataBuffer) and then copy the image to the back-buffer. It works fine if the image is not huge.

Check out the background effect here:
https://ping.dev.java.net/

Thanks,
Dmitri

You should check out this guy:
http://www.mandrixx.net/javasimple.html

I get about 300 fps on his small tunnel effect, 150 fps on the big one. Crazy effects too.

Over at
http://www.mandrixx.net/javaadv.html
he manages to keep >60 fps with a bump-mapped tunnel. No idea how he does all this in java2d.

[quote]You should check out this guy:
http://www.mandrixx.net/javasimple.html

I get about 300 fps on his small tunnel effect, 150 fps on the big one. Crazy effects too.

Over at
http://www.mandrixx.net/javaadv.html
he manages to keep >60 fps with a bump-mapped tunnel. No idea how he does all this in java2d.
[/quote]
Actually I work together with him on a project. He uses int arrays for all the pixel operations and hooks it up to a MemoryImageSource. Like mentioned before, using a BufferedImage instead of a MemoryImageSource gives sligthly better perormance. He used a MemoryImageSource because of 1.1 compatibility.

GPU accelerated pixel effects are possible, use JOGL and pixelshaders.

It’s also now finally possible to embed JOGL into applets. Check out the JOGL Applet Test. This works on every browser on all of JOGL’s supported platforms with no manual installation of software. I used to be a skeptic about applets but am personally finding this deployment technique more and more compelling.

I know, i jaded this guys applets sources…he get’s such a huge frame rate because he renders a 256256 pictures…and then display it as 512512…

I’ve been trying to push the limit for a month now, but move a raster from system memory to VRAM is like a wall. No way to beat it.

I tried to implement this effect in c++ using SDL ( which allows direct VRAM access) and performance were much better but still no way to make it in 1024*768.

My conclusion ( please correct me if i am wrong):

It is impossible to work directly with a raster from the main CPU and create an animation to an acceptable rate with resolution above 640*480. If this is true this is really sad…

Althrought, i remember Quake I was software renderer and had a 1024*768 resolution available so i must be wrong…

In order to get fast writes to VRAM you’ve actually got to go via AGP RAM, and that’s not possible with the standard Java APIs. You need some DirectX lovin’. I seem to recall Quake 1 running OK at 320x200 on a P166 or so but the majority of the rasteriser was written in some quite ingenious assembly language and was (is!) extremely cutting edge. It also hit a brick wall at higher resolutions than 640x480 because in those days PCI was the norm and that was about as much data as it could pump. Not forgetting it was 8 bit palletised as well, not hi-colour or true colour.

Cas :slight_smile:

Its true that the bus transfer from system memory to VRAM in the PC has always been the slowest part of the system.

Sofwtare renderer doesnt encessarily mean it was all in system memory. In general the trick to speed on thinsg like thatw as to get your textures down to VRAM and keep them there then draw using BLTs from those textures. Withotu knowing any of the inertnals I would guess Quake used such tricks,

(QUake also, btw was dark as hell and that hid a WHOLE lot of render flaws.)

Quake did the lot in system RAM but was able to use AGP RAM where available because it had no blending effects and therefore needed no reads. There was a system RAM depth buffer ISTR but that never needed to be blitted to VRAM so it was quite efficient. None of the textures went to VRAM as a result of this whole architecture. Quite nifty stuff!

Cas :slight_smile:

Hm nodoby has carmack’s phone number ?? :slight_smile: !