Animated turns / is it bad to abuse PauseGame()?

Started by duckwizard, Sat 12/03/2011 01:30:57

Previous topic - Next topic

duckwizard

TL,DR: Need multi-frame animated turns that work even when navigating pathfinding waypoints.  Currently using a lot of PauseGame() to get the effect.  Need to know if that's OK and if there's a better way to do it.

I have a situation where it's important for my character to have multi-frame animated turns (i.e. a single diagonal frame is not sufficient).

I scanned the forums and most suggestions amounted to intercepting the walk click, firing a dummy "bullet" character from the ego's position to the click, and then use that dummy character's loop number to figure out which direction to animate to, then processing the click for the character.

After thinking about this I realized it wasn't sufficient because if the character has to navigate around a complex path, he will turn several times during that.  So with the "bullet" idea you get the initial turn (from stopped to the direction of initial walk) but you don't get animated turns while walking.

So I came up with a new idea where I have some logic in repeatedly_execute() that checks A) if the character is moving, and B) if his loop is different from his last loop.  If both these conditions are met, it should simply do the appropriate turning animation(s) to get from the old direction to the new direction.

The problem I had with this was that executing the animations using Animate() caused the actual movement to be cancelled.  So you would click and he would turn, but then he wouldn't actually walk unless you clicked again (or he was already facing that direction).  Checked the manual, and yep - Animate() stops the character if he is moving.

So I tried writing a function to do the animation manually, incrementing/decrementing the frame as appropriate and then calling Wait() in between.  Turns out Wait() doesn't pause his walking so it just ends up being really strange and not working at all.  So I added PauseGame() and UnPauseGame() calls around that to pause his walk.

Code: ags

//Animate Don't Stop
//always blocks, ignores blocking style
//always plays once, ignores repeat style
function AnimateDS(this Character*, int loop, int delay, RepeatStyle rep,  BlockingStyle block, Direction dir)
{
  this.Loop = loop;
  int numFrames = Game.GetFrameCountForLoop(this.View, this.Loop);
  
  
  if(dir == eBackwards)
  {
    this.Frame = numFrames - 1;
    while(this.Frame > 0)
    {
      PauseGame();
      Wait(delay);
      UnPauseGame();
      this.Frame--;
    }
  }
  else
  {
    this.Frame = 0;
    while(this.Frame < numFrames - 1)
    {
      PauseGame();
      Wait(delay);
      UnPauseGame();
      this.Frame++;
    }
  }
  
  PauseGame();
  Wait(delay);
  UnPauseGame();
}


The good news is, it works perfectly.  Animated turns work even while navigating a complex path.

The bad news is, I feel really unsure about subverting PauseGame() to this effect.

This effect is only necessary for a small part of the game (when the character is on a horse) and I don't *think* there will be much background stuff happening (which would get artificially choppy when the turning was happening) but even so it feels wrong to me.

So my question is - what reasons are there why doing this could be bad?  And is there a simpler way to effect animated turns, even while navigating, without resorting to this?

monkey0506

I'd actually say that this is a pretty good workaround for your particular scenario, but I do have a question. Why do you even have the RepeatStyle and BlockingStyle parameters if they are always ignored? Obviously for the purposes that you've written this function (to perform an animation during an active movement without halting the movement) it's not really reasonable to use eRepeat or eNoBlock, so they should always be considered eOnce and eBlock..but then why even have the parameter? For all other cases the existing Animate function is sufficient..so.

Anyway, there's no real issue with using PauseGame/UnPauseGame, so long as you realize that this is a blocking function, and use it appropriately.

Oh, and one thing that I noticed..you're not making use of any frame-specific delay/speed which may have been set in the editor. I'd suggest doing something like:

Code: ags
    while (/* do this for each of the two blocks */)
    {
      ViewFrame *frame = Game.GetViewFrame(this.View, this.Loop, this.Frame);
      Wait(delay + frame.Speed);
      // ...
    }

duckwizard

Thanks for the reply.  I've been using AGS for under a week now so I wasn't sure if I was doing something bad.

The reason I added those unused parameters was just to make the calls compatible with the standard Animate method.  At the time I was replacing many lines of Animate() with AnimateDS() and it seemed like the path of least resistance.  *shrug*  Plus now I can just add or remove the "DS" to switch back and forth if I need to for some reason.


I'll look at the frame speed.  Does Animate() use the sum of frame speed and delay as you show here?


Calin Leafshade

Yes, the engine calculates the delay of any frame using the sum of the global delay for the animation and frames individual delay.

This means you can actually use negative frame delays to counteract the global delay for individual frames if you so desire.

SMF spam blocked by CleanTalk