Fading one background into another

Started by Laura Hunt, Fri 21/06/2019 13:06:34

Previous topic - Next topic

Laura Hunt

My first post in the advanced technical forum, oh my.

In the game I'm working on, we have several instances of large rooms that are actually made up of several rooms. In this example, we have a living room and a bedroom which are in fact a single game room with two background frames. When the character crosses the threshold between them, the frames get swapped so that the new room is the "active" one and the other is greyed out. Easy peasy, tried it already and it works perfectly (the game resolution is 320x200, so the rooms actually scroll when you walk around, but that isn't shown here for clarity's sake).

However, the artist has now asked me if it is possible to do the following fade:



I'm guessing that this would imply something like grabbing the first background, drawing it on top of itself, switching the original background to the second frame, and then fading out the drawn surface using the tween module? Am I on the right track? Any suggestions as to how to actually do this, code-wise? Like I've mentioned already in some other thread, I've never used drawing surfaces or dynamic sprites before and I wouldn't even know where to start.

Khris

The gif URL is restricted to being logged in; can you host it on imgur or another host?

In general, the idea is to put the image as background on a GUI as big as the screen, then fade its transparency to 100.

Laura Hunt

Ah crap, sorry! Let me know if you can see it now.

In any case, if I put the background image on a GUI, wouldn't that cover my character and any objects in the screen, though?

Khris

The GUI would indeed cover everything else, but a) the image is going to have transparency, just like a regular sprite b) the GUI can be set to non-clickable.
That way the GUI will not interfere with the game in any way, not visually or gameplay-wise.

However it looks like we're talking about isometric graphics and walkbehinds/objects in both rooms, which makes it a bit more complicated.

That mockup looks awesome, btw!

morganw

#4
I'd probably try the same approach, but with room objects instead of GUIs. This would also let you call Object.MergeIntoBackground to permanently disable an area and remove the overhead of the object if you no longer needed it.

Edit: hopefully the merge would use the current transparency state, I've never tried this

Laura Hunt

#5
Thanks, Khris! The artist will be very happy to hear that  :)

I'm not sure I understand completely, though. How can I make the GUI (or morganw's object) NOT cover my character? The whole living room is solid, there are no transparent areas. Would it be a matter of setting different z-indexes?

morganw

For an Object you'd override the walkbehind baseline, not the option to ignore it, but just set it to an extreme value where the object is always treated as being 'behind' everything else. I'm not sure about GUIs, z-order is documented as working within the context of other GUIs.

Laura Hunt

#7
Quote from: morganw on Fri 21/06/2019 13:50:48
For an Object you'd override the walkbehind baseline, not the option to ignore it, but just set it to an extreme value where the object is always treated as being 'behind' everything else. I'm not sure about GUIs, z-order is documented as working within the context of other GUIs.

Ahhhhh gotcha! Actually I've done this before when creating floor tiles as animated objects (moving reflections, basically) that I wanted the character to be able to walk over.

Would this also avoid any objects / items in the room that are not part of the background (say, those flower pots in the front) being covered by my Big Room-Sized Background Object?

morganw

Quote from: notarobotyet on Fri 21/06/2019 13:57:14
Would this also avoid any objects / items in the room that are not part of the background (say, those flower pots in the front) being covered by my Big Room-Sized Background Object?
Yes, if the baseline of other objects is just set normally, or is set to a less extreme value than the 'background' object, they should appear in front of the 'background' object.

Laura Hunt

Fantastic, thanks! So just as a recap, this would be my sequence of events:

- room loads with Frame 0 as background (living room active, as we see in the gif)

- character moves towards threshold, steps on the region that triggers the swap.

- I make oLivingRoom visible, and swap the background frame from 0 to 1.

- The background is now bedroom-active, but not visible yet because it's still covered by my oLivingRoom object.

- I use the tween module to fade out the transparency of oLivingRoom from 100 to 0. When transparency reaches 0, I disable the object.

- Same thing but the other way around (and with a oBedroom object) when changing rooms again.

I would not want to destroy the objects by merging them into the background, because I need to re-use them every time the player changes from one room to another, but otherwise, I think I have the gist of it. Anything I might be missing?


morganw

This sounds fine, I'd just add that:

  • Technically, you don't need a background frame at all if you create the room entirely from objects - I guess it just depends on the visual effect you want to achieve and whether there is a benefit to keeping it
  • I've never tweened transparency to know if the tween module works around the rounding issues in the transparency value. Typically you can't do things like Object.Transparency ++ so when modifying this value manually I usually do it on alternate game loops (i.e. change it ever-other time the repexec function is called)
  • You might want to generalise this concept so that instead of hard-coding what to do for each room, you just track which room you are in and then look to fade out all other rooms

Laura Hunt

#11
ok, so I gave it a try and it works almost perfectly. ALMOST.

(and I didn't even have to use the tween module!)

Code: ags
function region1_WalksOnto()
{
  if (GetBackgroundFrame() == 0) {
    oLivingRoom.Visible = true;  
    SetBackgroundFrame(1);
    while (oLivingRoom.Transparency < 100) {
      oLivingRoom.Transparency++;
      Wait(1);
    }
    oLivingRoom.Visible = false;
    oLivingRoom.Transparency = 0;
  }
}


The problem I'm getting here is that when I swap to the new background under my oLivingRoom object, all walk-behind areas in the room act like "holes", so I can see the new background through those "holes" BEFORE it's finished fading in.

So in other words, if I remove the whole fade and leave only these lines just for the sake of troubleshooting, what I see is the living room with a bunch of holes shaped like my walk-behind areas, through which I can see the "greyed out" living room:

Code: ags
function region1_WalksOnto()
{
  if (GetBackgroundFrame() == 0) {
    oLivingRoom.Visible = true;  
    SetBackgroundFrame(1);
     }
}


I didn't even know this was possible. It would make sense if they were objects, since they're actually on screen, but I don't understand why the outline of the walk-behind areas would even be visible.

The only way I can see around this is to set all baselines for all walking areas to 0 when the character leaves the room, and restore them when he comes back in, which works, but is a huge pain... But at least it kind of works?

Edit: or maybe this won't even work? There's a SetWalkBehindBase but no GetWalkBehindBase so I can know the baseline value of a walk-behind and store it in a variable?  :confused:

Laura Hunt


Quote from: morganw on Fri 21/06/2019 16:29:10
This sounds fine, I'd just add that:

  • Technically, you don't need a background frame at all if you create the room entirely from objects - I guess it just depends on the visual effect you want to achieve and whether there is a benefit to keeping it

That's what I was thinking too, I might give it a try and simply not use backgrounds at all, but an issue that I'm anticipating is that I would have to switch their baseline value all the time so that one of them has a value of 1 and the other is 2, for example, in order to control which one is on top of the other. Seems very doable though!

Quote from: morganw
  • I've never tweened transparency to know if the tween module works around the rounding issues in the transparency value. Typically you can't do things like Object.Transparency ++ so when modifying this value manually I usually do it on alternate game loops (i.e. change it ever-other time the repexec function is called)

I thought the whole purpose of the tween module was precisely to allow you to do non-blocking transparency fades and stuff like that? I haven't used it yet though, so I'm not really aware of its limitations and issues.

Quote
  • You might want to generalise this concept so that instead of hard-coding what to do for each room, you just track which room you are in and then look to fade out all other rooms

Depends on how often we're going to use this idea, it definitely might be worth the trouble. But if we end up using it in just 2 or 3 settings and everything else are regular room transitions, it's probably quicker to just code the behaviour for each room and moving on to other things. We'll see, we're still in the very early stages of level design!


morganw

Quote from: notarobotyet on Fri 21/06/2019 16:46:38
So in other words, if I remove the whole fade and leave only these lines just for the sake of troubleshooting, what I see is the living room with a bunch of holes shaped like my walk-behind areas, through which I can see the "greyed out" living room
It sounds like an internal issue with the rendering, rather than something intentional. Can I just check, which renderer is your game set to use? When the game is running you can press CTRL+ALT+V to display this information.

Quote from: notarobotyet on Fri 21/06/2019 16:56:45
Quote from: morganw on Fri 21/06/2019 16:29:10
This sounds fine, I'd just add that:

  • Technically, you don't need a background frame at all if you create the room entirely from objects - I guess it just depends on the visual effect you want to achieve and whether there is a benefit to keeping it
That's what I was thinking too, I might give it a try and simply not use backgrounds at all, but an issue that I'm anticipating is that I would have to switch their baseline value all the time so that one of them has a value of 1 and the other is 2, for example, in order to control which one is on top of the other. Seems very doable though!
It probably depends exactly how the rooms join together and what overlaps, but yes, modifying the baseline values to be slightly re-ordered is probably not too hard compared to running the transparency changes.

Quote from: notarobotyet on Fri 21/06/2019 16:56:45
Quote from: morganw
  • I've never tweened transparency to know if the tween module works around the rounding issues in the transparency value. Typically you can't do things like Object.Transparency ++ so when modifying this value manually I usually do it on alternate game loops (i.e. change it ever-other time the repexec function is called)
I thought the whole purpose of the tween module was precisely to allow you to do non-blocking transparency fades and stuff like that? I haven't used it yet though, so I'm not really aware of its limitations and issues.
You don't have to use it just to get a non-blocking fade, it just means that you need to implement the fade as a gradual change that takes places over multiple executions of your scripts, not one that blocks later execution of the script. So I typically try to avoid any kind of loop that blocks, like this:

Code: ags
while (oLivingRoom.Transparency < 100) {
    oLivingRoom.Transparency++;
    Wait(1);
}

Using the tween module is a good way to avoid this type of blocking, it is just that for the transparency property the returned value is dependent on the blocking nature of this loop and I don't know for certain that the tween module works around this. It probably does, I just can't say for sure.

Quote from: notarobotyet on Fri 21/06/2019 16:56:45
Quote from: morganw
  • You might want to generalise this concept so that instead of hard-coding what to do for each room, you just track which room you are in and then look to fade out all other rooms
Depends on how often we're going to use this idea, it definitely might be worth the trouble. But if we end up using it in just 2 or 3 settings and everything else are regular room transitions, it's probably quicker to just code the behaviour for each room and moving on to other things. We'll see, we're still in the very early stages of level design!
Yes, definitely. Unless this is for some government contract, if you can read it back and understand it, that is good enough!

Laura Hunt

#14
Quote from: morganw on Fri 21/06/2019 17:25:41
Quote from: notarobotyet on Fri 21/06/2019 16:46:38
So in other words, if I remove the whole fade and leave only these lines just for the sake of troubleshooting, what I see is the living room with a bunch of holes shaped like my walk-behind areas, through which I can see the "greyed out" living room
It sounds like an internal issue with the rendering, rather than something intentional. Can I just check, which renderer is your game set to use? When the game is running you can press CTRL+ALT+V to display this information.

I'm using Direct3D 9, but tried switching to OpenGL, and same issue, unfortunately. I can't provide a gif or video right now, but here's a screengrab if it makes it easier to see what I mean:



This is what I see when the command SetBackgroundFrame(1) gets executed, right before the fade starts.
(Frame 1 is the one with the darkened living room and the "active" bedroom)

So basically, although I have an object covering my actual background, I'm seeing that background through the object as if the walk-behind areas were holes. wtf?

Crimson Wizard

#15
@notarobotyet could you tell which version of AGS are you using?

I need to read all the above and understand what's happening...

PS. Maybe you could draw a simple picture of how objects and walkbehinds are positioned, just to help understand the situation?

EDIT: Ok, nevermind, morganw sent me a test project.

Crimson Wizard

#16
Alright, so morganw helped me to understand the situation.

To put it briefly, the walk-behind may be considered another object that is "cut out" from the background, and has a copy of background gfx. Technical details may differ between different graphic drivers, but the visual result should be all the same.

Since your walkbehinds have higher baselines that the "fading" object, this means that they actually are always drawn above the fading object. And when you switch room frames its gfx instantly switches ofcourse.

The first solution that comes to mind in this situation is to refuse to use walk-behinds at all, and use room objects only, or, if you run out of room objects, then use "static" characters as a prop. Then you fade-out/fade-in multiple pieces of room at once.
Ofcourse you'd need to tell artist to have these props on separate layer to be able to cut them out to sprites from now on.

PS. Idk if its worth keeping background frames at all in such case, maybe you could just have one completely black room frame and rely on objects to work as a background.

PPS. The effect is epic by the way :D

Laura Hunt

#17
Quote from: Crimson Wizard on Fri 21/06/2019 19:53:01
Alright, so morganw helped me to understand the situation.

To put it briefly, the walk-behind may be considered another object that is "cut out" from the background, and has a copy of background gfx. Technical details may differ between different graphic drivers, but the visual result should be all the same.

Since your walkbehinds have higher baselines that the "fading" object, this means that they actually are always drawn above the fading object. And when you switch room frames its gfx instantly switches ofcourse.

The first solution that comes to mind in this situation is to refuse to use walk-behinds at all, and use room objects only, or, if you run out of room objects, then use "static" characters as a prop. Then you fade-out/fade-in multiple pieces of room at once.
Ofcourse you'd need to tell artist to have these props on separate layer to be able to cut them out to sprites from now on.

PS. Idk if its worth keeping background frames at all in such case, maybe you could just have one completely black room frame and rely on objects to work as a background.

Yeah, using objects instead of walk-behinds is totally doable, the artist has every single piece of furniture and item drawn on separate layers, so it's not a problem for him to send me as many sprites as needed.

morganw also suggested getting rid of the background frames altogether because they're really not needed at all. Might work on that next now that this is solved!  ;-D

CW, morganw, thanks so much both of you for your help!

Quote from: Crimson Wizard on Fri 21/06/2019 19:53:01
PPS. The effect is epic by the way :D

Thank you! At first I was adamantly against it because "why complicate things when we can just do a straight background swap that only needs 2 lines of code and also I have no idea how to do this grumble mumble" but he insisted that I gave it a try and I'm so glad I did! It's more work for sure (plus getting you guys involved), but it's going to be totally worth it  :)

morganw

Here is a non-blocking version that doesn't use the background, it isn't particularly readable and the starting values are hard-coded but you might want to compare the effect to your orginal one. As a concept though, this doesn't care how many rooms you have. It just just fades in where you are and fades out where you are not. If you go with this approach it is probably easier to also have each room on its own so you can process each room separately (instead of including a faded version in each object).

Code: ags
int room = 0;
int ROOM_MAX=1;

function room_Load()
{
  oLivingRoom.Visible = true;
  oLivingRoom.Transparency = 0;
  oBedroom.Visible = true;
  oBedroom.Transparency = 100;
}

function region1_WalksOnto()
{
  room = 1;
  object[0].Baseline = 2;
  object[1].Baseline = 1;
}

function region2_WalksOnto()
{
  room = 0;
  object[0].Baseline = 1;
  object[1].Baseline = 2;
}

function room_RepExec()
{
  for(int i = 0;i <= ROOM_MAX;i ++)
  {
    if (i == room)
    {
      if (object[i].Transparency > 0)
      {
        object[i].Transparency = object[i].Transparency - 2;
      }
    }
    else if (object[i].Transparency < 100)
    {
      object[i].Transparency = object[i].Transparency + 2;
    }
  }
}


SMF spam blocked by CleanTalk