the best way to save room backgrounds during play?

Started by bolfar, Sun 07/10/2007 10:41:49

Previous topic - Next topic

bolfar

I did this one room game, where you roll a ball around. When you exit the room at top, you apear at bootom, same for left - right.
The thing is: the ball leaves a trace as you roll. So, when "changing rooms" the trace should be as it was in that "room" when you left.

Now it is done by saving background to dynamic sprite, then .pcx to disk, then delete dynamic sprite - before you change room. Before fadein the apropriate background is loaded from disk if exists, else it is default empty screen.
Screens are named by relative coordinates to room 0. (NNN.pcx - 3 times north; NNEEE - 2 north, 3 east; SW - south and west ... and so on)

Is it wise to just keep screens as dynamic sprites? I can't really predict how much of them will player create with his/hers path. If you keep close to room 0, then they are rewriten eact time you visit, but if you go in straight line, there is allways a new one.

How much dynamic sprites of 320àâ€"240 can I create before I get in trouble?

And I am not sure how to asign variable names to dynamic sprites, since I don't get the room name until I visit. In theory, there can be infinite number of rooms.

So what wil crash first - disc or memory?

The game thread with download is here.

Pumaman

If your game is 320x240 at 16-bit colour, that's 150 KB per dynamic sprite. If you're saving them to disk and deleting them from memory, then you've only got one in memory at a time so it's not a problem.

Assuming that the player has a decent amount of free disk space, you should be able to create several hundred files without a problem. Of course, this method leads to problems if you want save/restore game functionality since you won't be able to save old versions of rooms without even more work.

Gilbert

I didn't try your game yet, but alternatively, maybe you can save the coordinates of the raw-drawn traces in am array of reasonably size in each room (didn't know how you drew the traces so I'm not sure if it's really practical), so the traces would be redrawn whenever a room is entered again (in 'enters room before fade-in' perhaps). This method may save a bit of memory compared to saving the background everytime you leave a room.

bolfar

That was suggested in the game thread by KhrisMUC.
Traces are drawn by raw-drawing a 16àâ€"13px sprite.
Game is 32bit so it can use alpha.

How many ints can array hold?
If I roll around in one room forever, that could again mean an array of infinite size.
And is there a problem raw-drawing some thousand (or more) sprites before fade-in?

Gilbert

I never tried the game, so I can't judge on the usage.
But say I think if you want excessive, 10000 entries may be more than enough.
In each room just define something like:
int savedx[10000], savedy[10000];

Since an int variable consumes 4 bytes. that'll be about 4*2*10000 = 80000 ~ 80kb (plus some overhead maybe), if you use short (2 bytes each) instead of int you can even cut the usage in half. (Note that I think 10000 is excessive, if you reduce the number of entries you can even save more.

If you fear that the player will roll (paint) on the screen indefinitely, just add some check to do either one of the following actions when the limit is reached:
1) Stop recording further the coordinates once the limit is reached.
2) Loop back the index to 0, so to overwrite the oldest entries once the limit is reached.
I think it's fair and personally I prefer 2.

About performance when raw drawing them after a room loads, I think for slow systems, loading/saving image files and creating dynamic sprites can be slow already, so I think (I'm not sure) this method won't perform much worse than the dynamic sprite method.

bolfar

ok, that variant with array of short-s would work ok, I guess.
So, how can I define a name for array, when I need it?
The game has only one room, and the "name" property changes each time you enter. So if I stay in a room I only need one array (actually none, if I don't leave), but if I go in straight line through a lot of screens, then I need a new array each time. Currently there is only a problem with 255 char limit for file names. So one can only go 255 rooms from room 0 in each direction (65.025 posible rooms (64k)). But with arrays, should I define 128k (x,y) of arrays manualy?
(and there are two different tracks in each "room" so that would be 256k of arrays).

So, can I do somethnig like this:
short *room_name*_x[10000], *room_name*_y[10000];

About performance when raw drawing the sprites after a room loads:
Now I only read one .pcx and raw-draw it. With array I could end up with raw-drawing 10000(àâ€"2) sprites onBeforeFadein. This sounds much more memory and time consuming. Or am I wrong?

KhrisMUC suggested something more like:
struct position{short x[10000]; short y[10000]; short sprite_number[2]; String room_name[65025];};
But I am not familiar with struct-s. How do I read it right? How do I get only the data for the current "room"?
I guess I loop through room_name and if fits current room then read other values from x, y, and sprite_number, then rawdraw, then loop room_name again, starting on latest index and so on .... a lot of looping every time I enter a room.

Ok, now I know some more ways to do what I want, but the question remains: What is the most optimal solution?

Khris

What I suggested was the pretty memory-intensive way of storing multiple dynamic sprites.

Code: ags
//header 

struct screen_struct {
  int x;
  int y;
  DynamicSprite*s;
};

import screen_struct screen[200];

// global script

screen_struct screen[200];


Visiting a room for the first time will increment some room counter, then upon leaving the room, the background is stored:
Code: ags
  screen[roomcount].x=x;  // offset from room 0
  screen[roomcount].y=y;  // offset from room 0
  screen[roomcount].s=DynamicSprite.CreateFromBackground();  // or whatever it is called


Entering a previously visited room searches the array for matching x/y-offsets, then draws the DSprite on the background.

bolfar

Thanks to KhrisMUC and a day of learning on Complie errors, now I understand what struct is. To me that was a giant step.

The code works fine ... but now, when/where do I delete all those dynamic sprites (as help file strongly suggests)? Or is it just ok, as it is?

And again: is this more efficient than saving to disk?

Code: ags

// main global script file


int start = 0, i, room_curr, room_nr = 0, off_curr_x = 0, off_curr_y = 0;

struct background
{
   int off_x;
   int off_y;
   DynamicSprite* screen_bg;
};

background room[512];


function on_event(EventType event, int data)
{
   if (event == eEventEnterRoomBeforeFadein)
   {
      if (start == 0)
      {
         start = 1;
         room_curr = 0;
      }
      else
      {
         if (from == 1) off_curr_y = off_curr_y + 1; // from top
         else if (from == 2) off_curr_x = off_curr_x - 1; // from right
         else if (from == 3) off_curr_y = off_curr_y - 1; // from bottom
         else if (from == 4) off_curr_x = off_curr_x + 1; // from left
         
         room_curr = -1;
         i = 0;
         while (i < 512)
         {
            if ((room[i].off_x == off_curr_x) && (room[i].off_y == off_curr_y))
            {
               room_curr = i;
               i = 512;
            }
            i++;
         }
         
         if (room_curr == -1)
         {
            room_nr = room_nr + 1;
            room_curr = room_nr;
         }
         
         room[room_curr].off_y = off_curr_y;
         room[room_curr].off_x = off_curr_x;
         
         if (room[room_curr].screen_bg != null) {
            RawDrawImage(0, 0, room[room_curr].screen_bg.Graphic);
         }
      }
   }
}

function save()
{
   room[room_curr].screen_bg = DynamicSprite.CreateFromBackground();
}


function repeatedly_execute()
   {
      
         if (player.x < 1) // left
         {
            save();
            from = 2;
            player.ChangeRoom(1, 315, player.y);
         }
         
        // ... and so on ...
        // ...
        // ...
      
   }

Khris

This method will use around 150*visited_rooms kB of RAM.
Even if an average gaming session implied visiting 100 rooms, that'd be only 15 MBs of RAM. That's not that much.

It's difficult to answer the efficiency question. Using RAM is faster, and you don't have to erase the files afterwards. I'd say as long as the amount of memory is manageable, go for RAM.

If you are concerned about deleting the DynamicSprites, do so before the game is quit.

SMF spam blocked by CleanTalk