"flicker" effect when modifying ViewFrames while walking

Started by wynni2, Sun 16/12/2018 19:42:21

Previous topic - Next topic

wynni2

Hi all -

I'm working on an effect where characters appear to "wade" through water.

Right now it works by (1) making a DynamicSprite* dyWade from the character's currently displayed ViewFrame*, vwCurrent, (2) drawing a transparent rectangle over the bottom of dyWade, (3) assigning vwCurrent.Graphic = dyWade.Graphic, and (4) restoring vwCurrent.Graphic to its default value when the next animation frame is displayed.

This works well at low res with one issue: there's a "flicker" effect. I assume this is from the default sprite being drawn, and then the modified sprite being drawn an instant later. It's just a little distracting.

Is this something that I can work around (ie, is it possible to modify a character's current ViewFrame before it's drawn onto the screen)?

Here's the relevant code (dyWade, vwCurrent, vwLast, and lastgraphic are arrays declared elsewhere):

Code: ags

void RestoreLastViewFrame(this Character*) {
  //restores the previously displayed ViewFrame for "this" to "lastgraphic," its default sprite
  //must be called after lastgraphic is stored
  
  vwLast[this.ID].Graphic = lastgraphic[this.ID]; 
  vwLast[this.ID] = null; 
}

void MakeWadingSprite(this Character*, int depth) {
  //makes a wading sprite out of "this"'s current viewframe
  //  and stores it to dyWade[this.ID]
  //also saves the default graphic for "this"'s current ViewFrame to lastgraphic[this.ID]
  
  //must have stored vwCurrent[this.ID] before calling
  dyWade[this.ID] = DynamicSprite.CreateFromExistingSprite(vwCurrent[this.ID].Graphic, true); 
  DrawingSurface* dwWade = dyWade[this.ID].GetDrawingSurface(); 
  dwWade.DrawingColor = COLOR_TRANSPARENT; 
  int x1 = 0; 
  int x2 = dyWade[this.ID].Width; 
  int y2 = dyWade[this.ID].Height; 
  int y1 = y2 - depth; 
  dwWade.DrawRectangle(x1, y1, x2, y2); 
  dwWade.Release(); 
  
  lastgraphic[this.ID] = vwCurrent[this.ID].Graphic;   
}

void Wade(this Character*) { //CALLED IN REPEATEDLY_EXECUTE
  
  vwCurrent[this.ID] = this.GetCharacterFrame(); //GetCharacterFrame(this Character*) returns ViewFrame for this.View, this.Loop, this.Sprite
  
  if (vwLast[this.ID] == null) {
    vwLast[this.ID] = vwCurrent[this.ID]; 
    this.MakeWadingSprite(15); 
    vwCurrent[this.ID].Graphic = dyWade[this.ID].Graphic; 
  }
  else if (vwLast[this.ID] != vwCurrent[this.ID]) {
    this.RestoreLastViewFrame(); 
  }
}

Snarky

Try calling it in late_repeatedly_execute_always()

wynni2

Yep, that did it.

That was simpler than I expected. I had completely forgotten about late_repeatedly_execute.

Thanks.


SMF spam blocked by CleanTalk