Delaying with timers

Started by selmiak, Wed 12/12/2012 03:17:03

Previous topic - Next topic

selmiak

So after tweening the audio channels is not working this great I wrote my own (only linear) tweening function. When I use it with Wait(); it works, but of course it blocks and I want to fade in and out channels in the background without pausing the game.

this works, but blocks
Code: AGS
     while (channel.Volume < end_value) {
       if (channel.Volume + step <= end_value) {
           channel.Volume += step;
           Wait(waitloops);
       } else {
         channel.Volume = end_value;
       }
     }


channel is the audiochannelpointer given to the function in global script via a call in the room script, step is calculated before and the needed amount the chanel volume has
to be increase to make it in time (as an int so it might not exactly hit the end_value thus the if), waitloops is also calculated before to make it in time.
the timer id gets the channel id as I want to fade around more than one channel at once, aka crossfading. And therefor blocking is also a bad idea.

Code: AGS

  SetTimer(channel.ID, 0);
    
     while (channel.Volume < end_value) {
       if (channel.Volume + step <= end_value) {
         if (IsTimerExpired(channel.ID)) {
           channel.Volume += step;
           SetTimer(channel.ID, waitloops);
         } 
       } else {
         channel.Volume = end_value;
       }
     }


this doesn't work. The while loop loops too much and AGS aborts.
chanel, step, waitloops and end_value are all local variables in the function, so I wouldn't know what to do if I check the timer in repeatedly_execute_always() and also repeatedly restart it until it gets retarded.

Khris

#1
Just make all the variables global ones and use repeatedly_execute instead of the while loop.
If you want to fade more than one channel at the same time, use a struct to store all the values.

Code: ags
struct str_audio_fade {
  AudioChannel* channel;
  int end_value, step, delay;
  int remaining_loops;
  bool active;
};

import void Tween(this AudioChannel*, int end_value, int step, int delay);


Code: ags
str_audio_fade AudioTween[10];

int GetFreeTweenStruct() {
  int i;
  while (i < 10) {
    if (!AudioTween[i].active) return i;
    i++;
  }
  return -1;
}

void Tween(this AudioChannel*, int end_value, int step, int delay) {
  int i = GetFreeTweenStruct();
  if (i == -1) {
    Display("Increase AudioTween struct size!");
    return;
  }
  if (end_value == this.Volume) return;
  if ((end_value - this.Volume) * step < 0) step = -step;
  AudioTween[i].channel = this;
  AudioTween[i].end_value = end_value;
  AudioTween[i].step = step;
  AudioTween[i].delay = delay;
  AudioTween[i].active = true;
  AudioTween[i].remaining_loops = 0;
}

void DoTweens() {
  int i = 0;
  while (i < 10) {
    if (AudioTween[i].active) {
      if (AudioTween[i].remaining_loops) AudioTween[i].remaining_loops--;
      if (AudioTween[i].remaining_loops == 0) {
        int step = AudioTween[i].step;
        int new_value = AudioTween[i].channel.Volume + step;
        if ((step > 0 && new_value >= AudioTween[i].end_value) || (step < 0 && new_value <= AudioTween[i].end_value)) {
          AudioTween[i].active = false;
          new_value = AudioTween[i].end_value;
        }
        else AudioTween[i].remaining_loops = AudioTween[i].delay;
        AudioTween[i].channel.Volume = new_value;
      }
    }
    i++;
  }
}


Add DoTweens(); to repeatedly_execute.

Start a Tween like this:
Code: ags
  channel.Tween(100, 3, 3);


NOT TESTED, PROBABLY CONTAINS TYPOS AND ERRORS!

selmiak

Looks interesting, I get a Parse error at 'end_value' in GlobalScript.ash though.

where does this go, GlobalScript.ash or GlobalScript.asc :
Code: AGS
struct str_audio_fade {
  AudioChannel* channel;
  int end_value, step, delay;
  int remaining_loops;
  bool active;
};

If I add it to GS.ash I get the error that 'end_value' is already defined, if I add it to GS.acs the parse error above. So yeah, I added end_value to the global variables list, so it is defined?! The Struct str_audio_fade doesn't have to be global, does it?


Khris

Struct definitions and import lines always go into the header.

end_value also being a global variable shouldn't matter; I declared it as a member variable which should move it outside the global scope. Still, try removing or renaming yours.

If that doesn't work, try renaming all instances of "end_value" to "end" in my code.

I'll try the code myself sometime later this evening and will report what I find.

selmiak

Quote from: Khris on Thu 13/12/2012 18:53:03
Struct definitions and import lines always go into the header.
of the global script? Or local room script? I never used structs before, though they seem quite handy... ;)

Quote from: Khris on Thu 13/12/2012 18:53:03
end_value also being a global variable shouldn't matter; I declared it as a member variable which should move it outside the global scope. Still, try removing or renaming yours.

If that doesn't work, try renaming all instances of "end_value" to "end" in my code.
commented my code out as it was crashing the game anyways, so there should be no collision. I had to rename the step to audio_step though as the tween module uses a step variable which doesn't want to be global it seems.

First I hoped you and the forums could help me improve my code so that I learn something from it, now I just copy+paste your code and understand 70%. Then again, your code is propaply highly optimized already and I can learn even more from understanding it than from painfully fiddeling around with my code... if I understand it...
Quote from: Khris on Thu 13/12/2012 18:53:03
I'll try the code myself sometime later this evening and will report what I find.
maybe I'll just wait a bit longer...


back to the photoshop!

Crimson Wizard

Quote from: selmiak on Thu 13/12/2012 21:15:30
Quote from: Khris on Thu 13/12/2012 18:53:03
Struct definitions and import lines always go into the header.
of the global script? Or local room script? I never used structs before, though they seem quite handy... ;)

Struct definitions may go anywhere, it is a question of where do you want them to be usable.
(Import lines too, btw, I think, although putting them in source file will make not much sense).

Module system in AGS works so, that room scripts can "see" only what is declared in Global script header. Therefore, if you want all rooms be able to use something from global script, then put struct declarations and import lines in GlobalScript.ash.
If, on other hand, you need a struct only to be used in global script, internally, then you mat put it in the GlobalScript.asc. In which case you will be able to use it global script, but not room scripts.

Khris

True. And in fact, my code would be an example of a situation where the struct definition doesn't need to be in the header since it's only used in the global script.

Selmiak:
Room scripts don't have (editable) headers.

I found a few errors; the parse error was due to "int" missing in front of the function parameters, both in the function and import line.
The other error was me using "step" instead of "AudioTween[i].step" several times.
I have corrected both errors, just copy-paste everything again.
Now the code works fine; I didn't test multiple tweens at the same time though.

As for you understanding only 70%, why don't we make it 100%?
I'm storing the data of each AudioChannel.Tween() call in the next free struct, and inside rep_ex, active tweens are processed by counting down the delay / changing the volume and resetting the delay.
Which part are you having problems with?

selmiak

First off: Yay, got it running, Thanks a lot!!!

I had problems with the DoTweens, but after your explanation it is clearer.
just to check, The DoTweens() checks all ten possible audiochannels every game loop and adjusts the volume or counts down one wait loop, right?

about room headers that are nonexistent, how would you refer to the top of a room script where you declare room variables and import functions?

and yes, I was not sure if I need to access the struct from the room, but after examining the code again (and again) it's a GS only thing.

and with your
Just make all the variables global ones and use repeatedly_execute instead of the while loop.
do you mean to add all the variable in the struct to the global variables tab? AGS then complains that the variable is aready defined when the struct is initialized. Or are variables declared in global script automatically global variables that can also be accessed from the room scripts?

Crossfading audio channels works like a charm!

Again, a big thank you!!!

Crimson Wizard

#8
Quote from: selmiak on Thu 13/12/2012 23:47:32
about room headers that are nonexistent, how would you refer to the top of a room script where you declare room variables and import functions?
By "header" we mean *.ash files. They exist for GlobalScript and also any custom module (not room modules).
The modules (except room modules) are split into Header and Source files (*.ash and *.asc). Rooms have only *.asc.

The top of the room script is.... well, the top of the room script :)
You may declare variables anywhere in the script (i.e. in the middle), it just will be visible only for functions that lie below, and not those that lie above.
That's a matter of personal preference and overall convenience. For example, you may divide your script into "sections" by grouping functions related to similar task. And declare related variables at the start of each section.

Khris

Cool, glad it's working :)

Headers aren't just the top part of the script; they are separate things. If the header and main part could just as well be part of the same script, why split it in the first place, right?
What happens is, when the game is compiled, every header gets put on top of every subsequent script, first in the order of the additional scripts, then the global script, then finally the room script.

Thus, instead of importing a module's function at the top of every room script, if you put the import line in the module's header, it'll end up at the top of each room script automatically.

SMF spam blocked by CleanTalk