While specific clip is playing

Started by Nixxon, Wed 17/08/2016 00:51:33

Previous topic - Next topic

Nixxon

Hey All,

During one of my rooms. I have a handful of background audio clips that play intermittently.

I would like to have one of the characters play a dance animation while these are occurring. I'm looking at the 'while' command in the rooms repeatedly execute function as a possible solution.

I'm just lacking the specifics.

Code: ags
function room_RepExec()
{
while (aSong01.IsPlaying)) //While song01 is playing
{
  cPedoMan.Animate(5, 0);  //character dances
}


Obviously the above code doesn't work as IsPlaying isn't a thing. Am I close??

Nixxon

#1
I also tried the below after perusing the forums some more. Do I have to allocate the clip to a channel?

Unfortunately this did not work. Whilst the game compiled and ran, it simply waited eternally when I entered the room (due to the animate wait '0').

Code: ags
function room_RepExec()
{
AudioChannel *channel = aPEDO7.Play();
while (channel.IsPlaying) cPedoMan.Animate(5, 0);

{

Crimson Wizard

#2
Putting anything blocking, including "wait" loops, in the repeatedly execute function is a bad idea. RepExec is suited only for starting non-blocking actions (or ending ones). If you put blocking action there game will simply freeze, because engine won't have a chance to update.

Instead, try to make a code that only changes states in repexec. For example, starts non-blocking animation if the music has just begun playing and stops it when it is not playing anymore.

Make sure to set up conditions so that the actions don't run every time repexec is called, otherwise they will be started 40 times per second over and over again.


Very crude example:
Code: ags

AudioChannel *DanceChannel;
function room_RepExec()
{
    if (DanceChannel == null || !DanceChannel.IsPlaying)
    {
        // start the song only when it is not playing
        // NOTE: you may want to modify this condition for your needs
        DanceChannel = aPEDO7.Play();
    }

    if (DanceChannel.IsPlaying && cPedoMan.View != DANCE_VIEW_NUMBER)
    {
        // only start animation if the song is already playing AND man is NOT dancing
        cPedoMan.LockView(DANCE_VIEW_NUMBER);
        cPedoMan.Animate(5, 0, eRepeat, eNoBlock);
    }
    else if (!DanceChannel.IsPlaying && cPedoMan.View == DANCE_VIEW_NUMBER)
    {
        // only stop animation if the song is NOT playing but man is still dancing
        cPedoMan.UnlockView();
    }    
}

Nixxon

#3
Thanks Crimson,

It seems now that as soon as the player enters the room. Our character switches to view 4. It's not triggering when aPED07 is playing.

The songs/sound clips play on a timer. Any ideas?

It should be noted that the characters original view is 2.

Code: ags

    AudioChannel *DanceChannel;
    function room_RepExec()
    {
        if (DanceChannel == null || !DanceChannel.IsPlaying)
        {
            // start the song only when it is not playing
            // NOTE: you may want to modify this condition for your needs
            DanceChannel = aPEDO7.Play();
        }
     
        if (DanceChannel.IsPlaying && !cPedoMan.Animating)
        {
            // only start animation if the song is already playing AND man is NOT dancing
            cPedoMan.LockView(4);
            cPedoMan.Animate(1, 4, eRepeat, eNoBlock);
        }
        else if (!DanceChannel.IsPlaying && cPedoMan.View == 2)
        {
            // only stop animation if the song is NOT playing but man is still dancing
            cPedoMan.UnlockView();
        }    
    }
     



Crimson Wizard

Firstly, you made incorrect fix to the code, putting View number 2 in condition. That condition should check for dancing view, not normal view:
Code: ags

else if (!DanceChannel.IsPlaying && cPedoMan.View == 4)


Also I always recommend to not use numbers in script -- it is easy to forget what they mean. You may use the name you gave to your view instead, for example:
Code: ags

cPedoMan.LockView(DANCE_VIEW);
...
else if (!DanceChannel.IsPlaying && cPedoMan.View == DANCE_VIEW)

and so on.



Secondly, there were some issue with channels that they may refer to another song playing. So probably it may be safer to change the way you check if particular music is playing at the moment by introducing this extender function:
Code: ags

bool IsPlaying(this AudioClip *clip)
{
  int i = 0;
  while (i < System.AudioChannelCount)
  {
    AudioChannel* ac = System.AudioChannels[i]; 
    if (ac.PlayingClip == this)
      return true;
    i++;
  }
  return false;
}


Usage:
Code: ags

bool is_dance_music_playing = aPEDO7.IsPlaying();
if (is_dance_music_playing && !cPedoMan.Animating)
{
    // only start animation if the song is already playing AND man is NOT dancing
    cPedoMan.LockView(DANCE_VIEW);
    cPedoMan.Animate(1, 4, eRepeat, eNoBlock);
}
else if (!is_dance_music_playing && cPedoMan.View == DANCE_VIEW)
{
    // only stop animation if the song is NOT playing but man is still dancing
    cPedoMan.UnlockView();
}

Khris

Could you show us the code you use to play the background audio? To me it seems simpler to set a variable when the one specific audio file is played and use that to control the character's animation.

Nixxon

Thanks guys,

Here is the code for the audio clips. Perhaps I could integrate the change char view into this code instead? Last time I tried that, it would stay in the view until the next line of code (timer) ran. *See line 21*

Code: ags
// room script file
int cPedoMan_speechTimer = 0;

// A helper function to simplify the job of background speech with voice
void SayBackgroundClip(this Character*, String message, AudioClip* clip)
{
  this.SayBackground(message);
  if(clip != null)
    clip.Play();
}
 
function repeatedly_execute_always() {
  cPedoMan_speechTimer++;
  if (cPedoMan_speechTimer % 900 == 0) {
    int which = cPedoMan_speechTimer / 900; 
    if (cPedoMan.Room != player.Room)
      return; // do nothing
 
    if (which == 1) {
      cPedoMan.SayBackgroundClip("&1 DIALOG 1", aPEDO7);
cPedoMan.Animate(5, 2, eOnce,  eNoBlock);
    }
    else if (which == 2) {
      cPedoMan.SayBackgroundClip("&2 DIALOG 2", aStonethrow);
    }
    else if (which == 3) {
      cPedoMan.SayBackgroundClip("&3 DIALOG 3", aMonstereat);
    }
    else if (which == 4) {
      cPedoMan.SayBackgroundClip("&4 DIALOG 4", aPickuppebble);
    }
    else if (which == 5) {
      cPedoMan.SayBackgroundClip("&5 DIALOG 5", aPEDO7);
    }
    else
      cPedoMan_speechTimer = 0; // Loop around
  }
}



Thank you so much.

Khris

Try this:
Code: ags
function repeatedly_execute_always() {
  cPedoMan_speechTimer++;
  if (cPedoMan_speechTimer % 900 == 0) {
    int which = cPedoMan_speechTimer / 900; 
    if (cPedoMan.Room != player.Room)
      return; // do nothing
 
    if (which == 1) {
      cPedoMan.SayBackgroundClip("&1 DIALOG 1", aPEDO7);
      cPedoMan.LockView(DANCE_VIEW);
      cPedoMan.Animate(0, 2, eOnce,  eNoBlock);
    }
    else if (which == 2) {
      cPedoMan.SayBackgroundClip("&2 DIALOG 2", aStonethrow);
    }
    else if (which == 3) {
      cPedoMan.SayBackgroundClip("&3 DIALOG 3", aMonstereat);
    }
    else if (which == 4) {
      cPedoMan.SayBackgroundClip("&4 DIALOG 4", aPickuppebble);
    }
    else if (which == 5) {
      cPedoMan.SayBackgroundClip("&5 DIALOG 5", aPEDO7);
    }
    else
      cPedoMan_speechTimer = 0; // Loop around
  }
  if (cPedoMan.View == DANCE_VIEW && !cPedoMan.Animating) cPedoMan.UnlockView();
}


Note that animations should always be placed in separate views; putting them in the character's NormalView is not recommended.
Just move the frames to a new view's loop 0 and call it DANCE_VIEW.

Nixxon

Beauty. I learnt two valuable lessons. I will try this out tonight :)

SMF spam blocked by CleanTalk