如何使用多个计时器来计划程序中的事件?

时间:2013-11-07 12:54:48

标签: c++ timer sdl

我正在使用C ++和SDL构建类似摇滚乐的程序,并且希望能够计时事件,以便我可以在程序中编排一首歌曲。以下是我迄今所取得的成就:

  1. 4个从窗口顶部落到中间的圆圈,分成4个指定的击球点。

  2. 圆圈随机间隔下降(不使用时间,随机数生成器确定它们开始下降到窗口顶部的距离)

  3. 我可以确定何时点击一个音符,并在右上角显示一个分数

  4. 在标记周围应用简单的火花,让您知道音符被击中

  5. 我可以打开文件并从中读取文字

  6. 现在我希望能够使用该文件为程序编写歌曲以进行读取和执行。我正在思考" 1g,2g,4y,3r等等等等。"数字是毫秒等待下一个音符和字母指定哪种颜色应该下降。

1 个答案:

答案 0 :(得分:1)

你真的不需要(或想要)多个计时器;只需驱动窗口刷新的单个计时器(30fps或其他)就足够了。

当您加载歌曲文件时,对于歌曲中的每个音符,您应该存储在歌曲开始播放之间和特定音符播放之间应该经过的毫秒数,例如(伪代码):

int millisCounter = 0;
int note, noteLengthMillis;
while(ReadNextNoteFromSongFile(note, noteLengthMillis))
{
   songNoteRecordsVector.push_back(NoteRecord(millisCounter, note));
   millisCounter += noteLengthMillis;
}

然后,当你开始游戏关卡时,在歌曲开始播放的瞬间,以毫秒为单位记录当前时间。只要歌曲继续播放,您就会将此值用作零时间参考。

现在在每个视频帧(或实际上在任何时间),您可以计算相对于当前系统时钟时间播放给定音符之前的毫秒数:

int NoteRecord :: GetMillisecondsUntilNoteIsPlayed(int songStartTimeMillis, int currentTimeMillis) const
{
   return this->myNoteOffsetMillis - (currentTimeMillis - songStartTimeMillis);
}

请注意,如果音符的播放时间已经过去,则返回的值将为负数。

一旦你有了这个,只需将每个音符的当前毫秒 - 直到音符播放结果转换为相应的屏幕上位置,你知道在哪里绘制当前帧的音符圆:

int millisUntilNotePlayTime = note.GetMillisecondsUntilNoteIsPlayed(songStartTimeMillis, currentTimeMillis);
int circleY = someFixedOffsetY + (millisUntilNotePlayTime/(1000/pixelsScrolledPerSecond));
DrawCircleAt(circleX, circleY);

...如果用户按下某个键,您可以使用相同的功能计算用户距离给定音符的正确时间的距离,例如:

int errorMillis = note.GetMillisecondsUntilNoteIsPlayed(songStartTimeMillis, currentTimeMillis);
if (errorMillis < -50)
{
   printf("You're too slow!\n");
}
else if (errorMillis > 50)
{
   printf("You jumped the gun!\n");
}
else
{
   printf("Good job!\n");
}