[SOLVED] Removing older room overlays causes newer room overlays to behave strangely

Started by Falsely, Thu 14/12/2023 08:03:28

Previous topic - Next topic

Falsely

I've got a room that uses graphical room overlays for faux lighting effects. Whenever the player turns a light on, the game takes a copy of the "lit" background, places "lit" versions of object sprites on it, copies the transparency of a lighting mask sprite, then applies the resulting image to an overlay to create the illusion of lighting.

This itself works fine. The problem arises when using Overlay.Remove() to turn a light off.

If the overlays are removed in the order they were created, the lights continue to work as expected. But if, say, you turn on the overhead light, then open the fridge, then turn the overhead light off and on again - everything breaks. Like so:


I've tested it with up to five lights and this only occurs when removing the non-newest overlay. My best guess is that the overlays are getting jumbled up, somehow? At the 0:18 mark you can just barely see the lamp's beam clip with the lamp itself, which implies it's gotten the fridge's z value of 220 instead of it's usual 1.

Any suggestions would be greatly appreciated!

Relevant bits of code (apologies for the spaghetti, things got progressively more chaotic the more things I tried/deleted):

Room Code
Code: ags
Overlay* lLamp;
Overlay* lFridge;

function oSwitch_Interact()
{
  if (kitchenState!="lit"){
  oLamp.Visible=true;
  oLamp.Graphic=223;
  lLamp=TurnOn(lLamp, 224, 1);
  kitchenState="lit";
  
  }
  
  else{
  oLamp.Graphic=239;
  kitchenState="unlit";
  lLamp.Remove();
  }
}

function oFridge_Interact()
{
  if (!oFridge.isOpen()){
    oFridge.Open();
    lFridge=TurnOn(lFridge, 240, 220);
    oFridge.Baseline=220;
  }
    
  else{
    oFridge.Close();
    oFridge.Baseline=1;
    lFridge.Remove();
  }
}


Lighting Script
Code: ags
DynamicSprite* litBG;

///Grabs the full "lit" version of the scene for later use
DynamicSprite* PrepLight(){  
  DynamicSprite* lightBG = DynamicSprite.CreateFromBackground(1, 0, 0, 320, 240);
  DrawingSurface* surface = lightBG.GetDrawingSurface();
  
  for (int i = 0; i<Room.ObjectCount; i++)
  {
    int sprite;
    if (object[i].isOpen()) sprite = object[i].GetProperty("spriteOpen");
    else sprite = object[i].GetProperty("spriteClose");
    
    if (object[i].Visible && sprite>0){
      surface.DrawImage(object[i].X, object[i].Y -  Game.SpriteHeight[object[i].Graphic], sprite);
    }
  }
  
  surface.Release();
  return lightBG;
}


///Crops the lightBG to a sprite mask, applies it to an overlay, then returns the overlay.
Overlay* TurnOn(Overlay* light, int mask, int z){
  PrepLight();
  litBG=PrepLight();
  litBG.CopyTransparencyMask(mask);
  
  Overlay* toReturn = Overlay.CreateRoomGraphical(0, 0, litBG.Graphic, true, true);
  toReturn.ZOrder=z;
  return toReturn;
}

Khris

Side note: unless there's a third state, you can use a bool variable to store the state of a light.
Code: ags
bool lampLit = false;

  // turn on
  lampLit = true;

  // check
  if (lampLit) ...

I've also noticed that your TurnOn function doesn't seem to use the light parameter. Since you're passing in the overlay that gets toggled but then simply ignore it, that's probably where the issue arises.

Tbh I'd change the approach entirely. I'd use a function that redraws the entire room back to front once a bool changes and simply call that when a switch occurs.

Falsely

@Khris: Yup, there's a lot more than two kitchen states. ...But you're right, that variable shouldn't be factor any of the lights in anyway. It's about time I made the overhead lamp its own separate bool. (laugh)

Anyway, noted! I've had a bit of practice drawing on room backgrounds. Might have a play around with that tomorrow.

I went with Overlays for this test as I was considering making some of the lights animated (flickering, waving if the overhead lamp gets bumped, etc.), and wasn't sure if redrawing the whole room for every frame would be too system intensive. I'll play around and see what I can come up with.

eri0o

First important note about Overlays is they all get removed after exiting a room - this is not relevant to this case specifically.

I think you can just create and order/position all Overlays you need on room load and then you just alternate their transparency between 0 (on) and 100 (off). This should make this logic simpler.

Falsely

@eri0o Ohhhhh yeah, that's much easier. Somehow forgot Transparency was a thing. :-[

Thanks a bunch!

SMF spam blocked by CleanTalk