Mini-Module: Take a full screenshot of a scrolling room

Started by RootBound, Thu 10/04/2025 12:31:34

Previous topic - Next topic

RootBound

Maybe I'm the only one who wants this, but if you have a big scrolling room in your game and you want to take a screenshot of the whole room at once, with characters and objects overlays and so on all in their proper places, here's a function you can use to do that!

The screenshot will be saved to where you have your saved game files.

NOTE: If you have custom viewports or multiple cameras, this will not work properly. You'll need to disable them and go back to the default game viewport and camera, and re-enable them afterward.

Please let me know if you have any questions (or if you find any bugs)!

EDIT: Code revised as suggested by Crimson Wizard below.

Code: ags
//place this function in global script, then call it in on_key_press, or when clicking a GUI button, etc., whatever you prefer
function take_fullroom_screenshot()
{
  PauseGame();
  //saves original camera coordinates and checks if camera was tracking player character
  int oldCameraX = Game.Camera.X;
  int oldCameraY = Game.Camera.Y;
  bool WasAutoTrackingOn;
  if(Game.Camera.AutoTracking == true){
    WasAutoTrackingOn = true;
  }
  else{
    WasAutoTrackingOn = false;
  }
  //if you want to hide GUIs and the mouse cursor, feel free to do so here. 
  //or you can also specify the render layer in the parameters of every DynamicSprite.CreateFromScreenShot() instance.
  
  //creates dynamic sprite, pans camera around room, takes screenshots of each part of room,
  //splices them onto dynamic sprite, and saves sprite to file
  DynamicSprite* BigScreenShot = DynamicSprite.Create(Room.Width, Room.Height);
  DrawingSurface* DrawOntoBig = BigScreenShot.GetDrawingSurface();
  DynamicSprite* PartialScreenShot;
  for (int y = 0; y < Room.Height; y += Game.Camera.Height)
  {
    for (int x = 0; x < Room.Width; x += Game.Camera.Width)
    {
        Game.Camera.SetAt(x, y);
        Wait(1);
        PartialScreenShot = DynamicSprite.CreateFromScreenShot();
        DrawOntoBig.DrawImage(Game.Camera.X, Game.Camera.Y, PartialScreenShot.Graphic);
    }
  }
  DrawOntoBig.Release();
  BigScreenShot.SaveToFile("$SAVEGAMEDIR$/BigScreenShot.pcx");
  //removes dynamic sprite, returns camera to original coordinates, and reactivates auto-tracking if it was on
  BigScreenShot.Delete();
  PartialScreenShot.Delete();
  Game.Camera.SetAt(oldCameraX, oldCameraY);
  if(WasAutoTrackingOn == true){
    Game.Camera.AutoTracking = true;
  }
  //if you manually hid GUIs and the cursor, re-enable them here!
  UnPauseGame();
}
They/them. Here are some of my games:

Crimson Wizard

#1
I suggest replacing the drawing part with a classic 2 nested for loops, running along Y and X axis:

Code: ags
for (int y = 0; y < Room.Height; y += Game.Camera.Height)
{
    for (int x = 0; x < Room.Width; x += Game.Camera.Width)
    {
        Game.Camera.SetAt(x, y);
        Wait(1);
        PartialScreenShot = DynamicSprite.CreateFromScreenShot();
        DrawOntoBig.DrawImage(Game.Camera.X, Game.Camera.Y, PartialScreenShot.Graphic);
    }
}

This may replace all the code after line
"DynamicSprite* BigScreenShot = DynamicSprite.Create(Room.Width, Room.Height);"
up to line
"DrawOntoBig.Release();"

But still there's a case when the room is not evenly divided by camera size. AGS will clamp the camera position in such case, meaning that the code might draw only part of the screenshot for the edge parts in sake of being optimal.
NOTE: this is only a problem with code doing extra work, so may be ignored.
Spoiler
I think the DrawImage code should then be something like this (but did not test it yet):
Code: ags
    // Set up offsets in case room size is not evenly divided by camera size,
    // and camera position was adjusted by the engine for the edge tile
    int xdiff = x - Game.Camera.X;
    int ydiff = y - Game.Camera.Y;
    DrawOntoBig.DrawImage(x, y, PartialScreenShot.Graphic, 0,
            PartialScreenShot.Width - xdiff, PartialScreenShot.Height - ydiff,
            xdiff, ydiff, PartialScreenShot.Width - xdiff, PartialScreenShot.Height - ydiff);
[close]

RootBound

@Crimson Wizard Thanks for the code-tidying suggestion. I revised it. It certainly looks much more efficient and elegant now. :)
They/them. Here are some of my games:

SMF spam blocked by CleanTalk