Get Drawing Surface for Part of the Background

Started by TheMagician, Sat 16/01/2010 14:40:39

Previous topic - Next topic

TheMagician

Hi everybody.
I'm creating a platform game (640x480) which uses very large rooms as backgrounds. I use GetDrawingSurfaceForBackground to draw stuff like 1-Ups to the background. Whenever I collect a 1-Up and the background gets updated the game freezes for 20 ms. I'm pretty sure this is related to the drawing function caching the whole 5000x5000 background.
Do you have any ideas how I can only catch the part of the background that is currently visible on screen? (or give me an alternate method for handling the 1-Ups :P )

Thanks in advance,
Stefan

monkey0506

#1
You can use DynamicSprite.CreateFromBackground which will allow you to grab a specific portion of the background into a sprite and then use DynamicSprite.GetDrawingSurface. ;)

Edit: Although to merge it back into the background you'd still need a drawing surface for that anyway... :-\ Is there any possibility you could use a character or object instead of using the background directly?

TheMagician

Thought about that, too. But as you mention you still need GetDrawingSurfaceForBackground to merge it back into the background.

I already use characters for all the other RawDrawing functions like for example 2D water and moving platforms. However, with collectables like 1-Ups and coins I just can't see how I do that with characters - I mean technically I could create 100 new characters and dynamically load them to the different levels but I'm open to other ideas ;)

monkey0506

I believe (although I've never managed to get it to work) that you can use Object.MergeIntoBackground more than once. Perhaps you could just assign one object per room, move it around as needed, use a single DynamicSprite with the DrawingSurface functions to create the necessary image, and then merge it where you need it. Maybe.

TheMagician

About MergeObject the manual states "NOTE: after calling this function, you cannot use the object any more and it is permanently removed from the game." so it doesn't really sound as if you can use it more than once.
However, your idea just got me thinking: perhaps I can have one dynamic sprite for the 1-Ups applied to a character which covers the entire screen (640x480) and then update its graphics according to the x- and y-offset of the viewport. The disadvantage of this method is that it needs to be calculated permanently in the background.
Thanks for your help monkey :)

monkey0506

#5
Well CJ has said that Object.MergeIntoBackground is the same as raw drawing its image into the background and then turning it off. However, I've never managed to get it turned back on. :P

You're definitely welcome though. Good luck with your game.

Edit: I don't know what I was doing wrong before, but this just worked for me:

Code: ags
function on_key_press(eKeyCode keycode) {
  if (keycode == 'A') {
    object[0].MergeIntoBackground();
    object[0].X += Game.SpriteWidth[object[0].Graphic];
    object[0].Y += Game.SpriteHeight[object[0].Graphic];
    object[0].Visible = true;
  }
}


Works like a charm.

Pumaman

Are you using Direct3D when you get this freeze? If so, it's because when you update any image (including the background), AGS re-uploads the image into video memory which can be quite a slow process.

If you try DirectDraw mode you probably won't get this slowdown.

TheMagician

You're right CJ, Direct3D is much slower. However, I'm already using DirectDraw because that supports VSync and without it the game would look horrible.

Can't you make the RawDraw functions a bit faster? ;) Somehow I keep coming back to them. I use them for 2D wave simulation, dynamic rope simulation. However, drawing 50 circles on the screen per frame already lets the FPS on my netbook drop to 5 FPS in DirectDraw mode.

Anyway I don't want to complain. AGS is and always will be a great flexible engine :)

Pumaman

You shouldn't get any freezes like that in DirectDraw mode -- however, AGS wasn't designed for working with backgrounds of that size; bear in mind that a 5000x5000 image at 32-bit takes up 100 MB of memory. This is something that AGS could be optimised to handle better, but it's quite a specialist requirement compared to what people usually do with AGS, which is why it's not something that I've really spent any time on improving.

Ryan Timothy B

Quote from: Pumaman on Sun 31/01/2010 15:57:14
5000x5000 image at 32-bit takes up 100 MB of memory
Oh wow.  I honestly didn't know it was that much.
Is that for the background alone when AGS is running the room, or is it only when it gets stored in memory with drawing surface? 

If that is the case perhaps I should rethink how I design my large background games when I need to use the drawingsurface.


QuoteThis is something that AGS could be optimised to handle better
Curious, getting the drawing surface for a custom sized rectangle portion (for some people it would be the size of the viewing area).
This code (copied from the manual):  DynamicSprite.CreateFromBackground(GetBackgroundFrame(), x1, y1, x2, y2);
Would this optimize the use of the drawing surface, or no?

Pumaman

Quote from: Ryan Timothy on Sun 31/01/2010 17:51:28
Oh wow.  I honestly didn't know it was that much.
Is that for the background alone when AGS is running the room, or is it only when it gets stored in memory with drawing surface? 

It's just the background alone -- a bit of simple maths:
5000 x 5000 x 4 (bytes per pixel in 32-bit mode) = 100000000 bytes = 100 MB

QuoteCurious, getting the drawing surface for a custom sized rectangle portion (for some people it would be the size of the viewing area).
This code (copied from the manual):  DynamicSprite.CreateFromBackground(GetBackgroundFrame(), x1, y1, x2, y2);
Would this optimize the use of the drawing surface, or no?

Well, that's different, because you're creating a dynamic sprite rather than drawing directly on to the background. So in a way it's slower because it has to create a dynamic sprite; but in another way it's faster because it'd be a much smaller surface that you were actually drawing onto.

Calin Leafshade

I had a similar problem when i designed my platformer (i use objects for the power ups by the way).

The parallaxing really killed it since i was drawing several huge sprites to the screen every frame (Life has the same issue)

The way i dealt with the huge dynamic sprite problem is to split it into a grid and have a function which only gets the required area and draws it to the screen.

Cropping sprites doesnt help since it still needs to load the main image to memory but loading a couple of smaller sprites in the region of like 320x240 is trivial for the engine compared to 1 huge 5000^2 image.

Using this method you can have several layers of parallaxing,a particle system and several objects without any problem at all.

TheMagician

Thanks for the insight, CJ.

And thanks Calin for explaining your solution. I'll have a look at your sourcecode to get a better idea of this grid of Dynamic Sprites. My latest effort was to use just one single sprite - the size of the viewarea - and move that along with the viewport. All the drawing functions would then need to be shifted by the value of GetViewportX and Y.

Calin Leafshade

actually the source doesnt include that trick.. since i never finished that section and lost the updated version.

But if you look at the cpu usage in the second room I get about 25% without the grid system but i got about 4% with the grid system.

TheMagician

Oh, sorry to hear that you lost it. I think I know enough about it to recreate it. Thanks again.

SMF spam blocked by CleanTalk