Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » Effective Parallax Coding or tutorial

Credits go to gnolam and Neil Walker for helping out!
This thread is locked; no one can reply to it. rss feed Print
Effective Parallax Coding or tutorial
Kevin Epps
Member #5,856
May 2005
avatar

Hey Guys,

My parallax scrolling code for my 2D game uses up too much memory and I'm trying to learn an effective way to code it.

Here's the logic code:

1 if((player.scroll_left) && (player.mapxoff < (mapwidth * mapblockwidth - WIDTH)) && (player.mapxoff > 0))
2 {
3 if(player.is_state(STATE_RUNNING))
4 {
5 bg_x-=player.x_vel + 3 + 1;
6 foreground_x-=player.x_vel + 2;
7 grass_x[3]-=player.x_vel + 1;
8 grass_x[0]-=player.x_vel;
9 grass_x[1]-=player.x_vel - 1 - 1;
10 grass_x[2]-=player.x_vel - 2 - 1;
11 front_x-=player.x_vel - 3 - 2;
12 }
13 else
14 { bg_x-=player.x_vel + 3;
15 foreground_x-=player.x_vel + 2;
16 grass_x[3]-=player.x_vel + 1;
17 grass_x[0]-=player.x_vel;
18 grass_x[1]-=player.x_vel - 1;
19 grass_x[2]-=player.x_vel - 2;
20 front_x-=player.x_vel - 3;
21 }
22 }
23 if((player.scroll_right) && (player.mapxoff > 0) && (player.mapxoff < (mapwidth * mapblockwidth - WIDTH)))
24 {
25 if(player.is_state(STATE_RUNNING))
26 {
27 bg_x-=player.x_vel - 3 - 1;
28 foreground_x-=player.x_vel - 2;
29 grass_x[3]-=player.x_vel - 1;
30 grass_x[0]-=player.x_vel;
31 grass_x[1]-=player.x_vel + 1 + 1;
32 grass_x[2]-=player.x_vel + 2 + 1;
33 front_x-=player.x_vel + 3 + 2;
34 }
35 else
36 {
37 bg_x-=player.x_vel - 3;
38 foreground_x-=player.x_vel - 2;
39 grass_x[3]-=player.x_vel - 1;
40 grass_x[0]-=player.x_vel;
41 grass_x[1]-=player.x_vel + 1;
42 grass_x[2]-=player.x_vel + 2;
43 front_x-=player.x_vel + 3;
44 }
45 }

Here's the drawing code:

1draw_sprite(buffer, bg, bg_x, 0);
2 draw_sprite(buffer, foreground, foreground_x, 0);
3 masked_blit(foreground, buffer, 0, 0, foreground_x + foreground->w, 0, foreground->w, foreground->h);
4 masked_blit(foreground, buffer, 0, 0, foreground_x + foreground->w + foreground->w, 0, foreground->w, foreground->h);
5 masked_blit(grass[3], buffer, 0, 0, grass_x[3], 335, grass[3]->w, grass[3]->h);
6 masked_blit(grass[0], buffer, 0, 0, grass_x[0], 355, grass[0]->w, grass[0]->h);
7 masked_blit(grass[3], buffer, 0, 0, grass_x[3] + grass[3]->w, 335, grass[3]->w, grass[3]->h);
8 masked_blit(grass[0], buffer, 0, 0, grass_x[0] + grass[0]->w, 355, grass[0]->w, grass[0]->h);
9 masked_blit(grass[0], buffer, 0, 0, grass_x[0] + grass[0]->w + grass[0]->w, 355, grass[0]->w, grass[0]->h);
10 //draw the background tiles
11 MapDrawBGT(buffer, player.mapxoff, player.mapyoff, 0, 0, WIDTH-1, HEIGHT-1);
12 //draw foreground tiles
13 MapDrawFG(buffer, player.mapxoff, player.mapyoff, 0, 0, WIDTH-1, HEIGHT-1, 0);
14 masked_blit(grass[0], buffer, 0, 0, grass_x[0], 419, grass[0]->w, grass[0]->h);
15 masked_blit(grass[1], buffer, 0, 0, grass_x[1], 429, grass[1]->w, grass[1]->h);
16 masked_blit(grass[2], buffer, 0, 0, grass_x[2], 439, grass[2]->w, grass[2]->h);
17 masked_blit(grass[0], buffer, 0, 0, grass_x[0] + grass[0]->w, 419, grass[0]->w, grass[0]->h);
18 masked_blit(grass[0], buffer, 0, 0, grass_x[0] + grass[0]->w + grass[0]->w, 419, grass[0]->w, grass[0]->h);
19 masked_blit(grass[1], buffer, 0, 0, grass_x[1] + grass[1]->w, 429, grass[1]->w, grass[1]->h);
20 masked_blit(grass[1], buffer, 0, 0, grass_x[1] + grass[1]->w + grass[1]->w, 429, grass[1]->w, grass[1]->h);
21 masked_blit(grass[2], buffer, 0, 0, grass_x[2] + grass[2]->w, 439, grass[2]->w, grass[2]->h);
22 masked_blit(grass[2], buffer, 0, 0, grass_x[2] + grass[2]->w + grass[2]->w, 439, grass[2]->w, grass[2]->h);
23 masked_blit(grass[2], buffer, 0, 0, grass_x[2] + grass[2]->w + grass[2]->w + grass[2]->w, 439, grass[2]->w, grass[2]->h);
24 player.draw(buffer);
25 masked_blit(front_trees, buffer, 0, 0, front_x, 0, front_trees->w, front_trees->h);
26 masked_blit(front_trees, buffer, 0, 0, front_x + front_trees->w, 0, front_trees->w, front_trees->h);
27 masked_blit(front_trees, buffer, 0, 0, front_x + front_trees->w + front_trees->w, 0, front_trees->w, front_trees->h);
28 masked_blit(front_trees, buffer, 0, 0, front_x + front_trees->w + front_trees->w + front_trees->w, 0, front_trees->w, front_trees->h);
29 masked_blit(front_trees, buffer, 0, 0, front_x + front_trees->w + front_trees->w + front_trees->w + front_trees->w, 0, front_trees->w, front_trees->h);

Obviously there's some stuff that I need to change with this. I've heard using a camera is good, but I want to implement one for a 9 layer background with the middle layer a tile map that's drawn by mappy.

What's the best course of action? If it's the camera method, could someone help me or at least get me started past the point where I've created a class?

Thanks guys!

gnolam
Member #2,030
March 2002
avatar

Gah! For the love of Chernobog and all that is unholy, use loops!

Something like (typed directly into the reply box, so caveat lector):

1typedef struct layer {
2 BITMAP *sprite;
3 int y;
4 float speed;
5} layer;
6 
7layer[NUM_LAYERS];
8 
9void draw_frame(void)
10{
11 int t;
12 
13 for (t = 0; t < NUM_LAYERS; t++) {
14 
15 //assuming each background is at least one screen width long
16 masked_blit(layer[t].sprite, buffer, 0, 0, -((int)(camera.x*layer[t].speed)%layer[t].sprite->w), layer[t].y - camera.y*layer[t].speed, layer[t].sprite->w, layer[t].sprite->h);
17 masked_blit(layer[t].sprite, buffer, 0, 0, layer[t].sprite->w - ((int)(camera.x*layer[t].speed)%layer[t].sprite->w), layer[t].y - camera.y*layer[t].speed, layer[t].sprite->w, layer[t].sprite->h);
18 }
19 
20 draw_sprite(buffer, player.sprite, player.x-camera.x, player.y-camera.y);
21}

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Kevin Epps
Member #5,856
May 2005
avatar

hey gnolam,

I already have a for loop in there. I just didn't post it. It's ok........

As far as the camera code, I'll try that out and let you know.

Neil Walker
Member #210
April 2000
avatar

You do know mappy has a parallax layer and set of functions don't you?

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Kevin Epps
Member #5,856
May 2005
avatar

What?

Really?

I was looking at that tutorial and it mention parallax but really didn't elaborate on it.

I'll look into that!

Neil Walker
Member #210
April 2000
avatar

It is only for the bottom most single background though and you have to read it carefully as it is easy to not do it right and end up streaking your parallax graphic.

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Kevin Epps
Member #5,856
May 2005
avatar

Ok.

I have the speed a comfortable speed now(Rage 128 30FPS, Radeon 60FPS) with all all layers and also with other sprites than the player. Although I do have one question.

Which bitmaps use less memory?

Reg Bitmap?
Video Bitmap?
System Bitmap?
Loaded Bitmap?
Datafile Bitmap?
Loaded Bitmap and then copied to Video Bitmap?
Loaded Bitmap and then copied to System Bitmap?
Loaded Bitmap and then copied to Reg Bitmap?

Steve++
Member #1,816
January 2002

All I can tell you is the System bitmaps may use more memory than the others. Otherwise just use a regular memory bitmap. Also, you may want to consider using video bitmaps, as video-to-video blits (masked and unmasked) are almost always accelerated, even on non-3D cards. If you want to get really tricky, create a memory management layer that will cache tiles in the video RAM. You can implement a tile eviction policy such as LRU (least recently used) quite easily. This is fun for some people, like me. I did this on the GBA. It worked really well.

Tobias Dammers
Member #2,604
August 2002
avatar

Quote:

Reg Bitmap?
Video Bitmap?
System Bitmap?
Loaded Bitmap?
Datafile Bitmap?
Loaded Bitmap and then copied to Video Bitmap?
Loaded Bitmap and then copied to System Bitmap?
Loaded Bitmap and then copied to Reg Bitmap?

For RAM usage, it doesn't matter how you load or create a bitmap, or in what ways you copy it around.
A memory ("regular") bitmap uses pretty much the exact amount of memory needed to store the uncompressed bitmap data, plus some overhead. You can calculate it like this:

int bmp_size =
  bmp->w * bmp->h * (bitmap_color_depth(bmp)+7) / 8 + // bitmap data
  bmp->h * sizeof(char*) + // the line pointers
  overhead; // whatever the constant overhead is; usually negligible for larger bitmaps.

Video bitmaps consume almost no RAM at all, just the overhead, but they do consume VRAM. The actual size depends on how your graphics cards stores the data, but it is probably at least the size of a memory bitmap. Video cards tend to be pickier about memory alignment (in order to favour speed over memory usage), so they may add padding to the end of each scanline.
System bitmaps are as unpredictable as video bitmaps; they try to imitate the bitmap format of the video bitmaps to provide faster blitting to and from vram. On some platforms, though, they are just aliases for vanilla memory bitmaps.
"Loaded" and "datafile" bitmaps are just normal memory bitmaps, and blittiing them to a video bitmap produces a normal video bitmap. There is nothing special about them.

As for disk space usage; this depends heavily on the file format you use. Plain BMP, PCX and TGA files offer almost no compression at all (except for a whimsy RLE), but they load very fast, are lossless, allegro loads them natively, and virtually all image editing programs support them. Putting them into a datafile enables you to load them all in one go, and offers moderate compression, still lossless. For a beginner's tilemap game, this is what I recommend. Other image formats (GIF, PNG, JPG) offer higher compression rates, but you need add-on libraries to read them. JPG and some PNG sub-formats are also lossy, meaning that after running through the encoding-decoding process, you lose image quality. Most GIF implementation support 256 colors max., and it's a proprietary format. For massive amounts of high-quality bitmap data, (lossless) PNG is probably the way to go; for photo-realistic images with no sharp edges, and without masking, JPG may work too.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Specter Phoenix
Member #1,425
July 2001
avatar

I have a book that included a tutorial for parallax programming. OpenGL Game Programming.

axilmar
Member #1,204
April 2001

(I am reposting this from the other similar thread, because maybe it was not read)

Dear Kevin,

in order to ensure a good frame rate in a bitmap-based game, you have to do the following (assuming bitmap blitting is the issue here):

1) ensure that you use a mode like triple-buffering or page-flipping that uses vram buffers.

2) ensure your most frequently used/large bitmaps are loaded in vram.

An effective way to do parallax scrolling with multiple layers is to avoid drawing blocks twice.

You need a flag for each block of each layer that tells you if the block has already been covered by one of the above layers. Then you need to do two passes over your layers:

a) the first pass will be from top layer to bottom in order to set the 'covered' flag;

b) the second pass will be from bottom to top layer to draw those blocks at each layer that have not been covered yet.

By carefully choosing block sizes (i.e. not too small, not too big) you can minimize overdraw and do many layers of scrolling (even more than 9!).

Kevin Epps
Member #5,856
May 2005
avatar

Thanks all for everything!! :) I have it exactly where I want it now!! :) You guys are the greatest!! And yes, Death, I knew I had a book that talked about it, but I couldn't think of which one it was!! Thanks for that. I have that book and that helped me is well. I have sooo many books.

Go to: