Keeping track of the beat

SquareNote

  • Posts: 20
This is a long-ish post but I'm looking for advice & feedback..

I'm trying to create a basic framework for games like Rez where events in the game are sync'd with the rhythm of a song. Here's what I'm doing so far.

Play Track:

This behavior initializes a bunch of game attributes that I use for tracking the measure number, which beat in the measure it's on, what the tempo of the song is, and how many beats there are in a measure. Then it starts looping the track.  Ignore Weapon1BeatList for now. 

Metronome:

This behavior takes the tempo (in beats per minute) and every beat it updates the BeatPosition to the next beat number. 1, 2, 3, 4, 1, 2, 3, 4.  Every time it goes from 4 back to 1 it updates the measure number.

I use GameBeatWindow to let other behaviors trigger events on the beat. I set a short window around when the beat changes, and during that window, the flag is true and behaviors can check that to make sure they're firing on the beat. For example...

Explode Death Actor:

I attach this behavior to a death animation that spawns when the player dies. This waits until beat 1 rolls around and the beat window is open, then makes the dead player's body explode with a sound. That is, when you die, you're disabled but your body sticks around until the first beat of the measure, then it explodes, on the beat.

This is pretty cool when it works, it turns out. But what I'm finding is that the synchronization between the song that I'm looping and the metronome is really sensitive and prone to falling out of sync. So after a while when the metronome says it's on beat 1, the song isn't on beat 1.

I figure this is related to CPU load or having lots of 'always' behaviors or something.


So finally, my question(s)! 

Is trying to sync a behavior to the sound like this a dead end? Am I always going to have syncing issues?

Is there anything in particular I should be avoiding that would be making this worse? I'm using the pieces of the run&gun kit that constantly updates player x and player y in game attributes, for example.

Any other thoughts on better ways to accomplish this?

Thanks a ton! 


« Last Edit: March 23, 2012, 02:15:39 pm by SquareNote »

Hectate

  • *
  • Posts: 4643
Have you tried using the step size to keep track of how much time has passed instead of just relying on the timed tasks to repeat it?

If you're not sure how that works, the following information would help.

http://flashgamedojo.com/wiki/index.php?title=Timer_%28Flixel%29

FlxG.elapsed is essentially the measurement of the same thing as the step size if I understand the block correctly. It tells you how much time is between the last time it ran though the code. Thus, if you continually add the time (and watch how much has passed) you can use it to time the game regardless of FPS issues, hopefully.

« Last Edit: July 15, 2011, 07:48:07 am by Hectate »
:
:
Patience is a Virtue,
But Haste is my Life.
Proud member of the League of Idiotic Stencylers; doing things in Stencyl that probably shouldn't be done.

SquareNote

  • Posts: 20
That sounds promising..  are you saying that something like:

do every (1000 x step size) seconds

is somehow different than saying:

do every 10 seconds?


Hectate

  • *
  • Posts: 4643
Sorta, although that's not how you can create a timer. As an example of how I would do it in code via Flixel (since I don't have access to SW to create a screenshot for you right now).

Code: [Select]
_beatTimer += FlxG.elapsed; //always add the elapsed time to the timer so it accumulates

if ( _beatTimer >= 10 )  //have we reached 10 seconds on our timer yet? If so, then...
{
   doTenSecondStuff; //perform whatever actions you want to happen on every 10 second count
   _beatTimer -= 10; //subtract 10 seconds to make the beat timer go back to near-zero   
}

The way this will work is if it's been .0012 seconds since the last time this code ran, you'll get .0012 added to the _beatTimer variable. Eventually, since this code is getting run hundreds of times per second, you'll end up with a _beatTimer with a value of something like 10.0012, which is greater than 10 seconds. So, 10 seconds (and a hair more, not noticeable to the player unless we allow the variance to build up over time) pass and we do whatever we want to. Then, we subtract 10 (again, the value is in seconds) and it goes down to .0012 and starts adding up the next time around.
:
:
Patience is a Virtue,
But Haste is my Life.
Proud member of the League of Idiotic Stencylers; doing things in Stencyl that probably shouldn't be done.

SquareNote

  • Posts: 20
Ok, I'm not 100% sure I'm handling this correctly, but this seems to be working better.


"Sync Behavior Test" game on forge.

If you get a chance, can you look at the Metronome behavior and let me know if what I'm doing there makes sense?

http://www.stencyl.com/game/play/5460

Hectate

  • *
  • Posts: 4643
I don't have internet access at home, so for me to look it up on Forge means you'll have to wait for an entirely random event where I have both my laptop with me and general internet access. Generally I'm posting from here at work.

That said, everything seems to be working in your example game. I honestly couldn't follow the beat based on the music alone for most parts of the song, but the displayed values were consistent and the reaction of the actors was exactly as you intended.

Have you set it up to vary according to a customizable tempo, etc?
:
:
Patience is a Virtue,
But Haste is my Life.
Proud member of the League of Idiotic Stencylers; doing things in Stencyl that probably shouldn't be done.

SquareNote

  • Posts: 20
Yup, tempo's customizable.

I'm going to mark this solved for now. Thanks for the help!