我正在编写类似于DDR的游戏,使用MIDI文件作为音乐。我写了一个小类来根据任何给定的MIDI文件中的音符生成箭头。在实际游戏中,当第一个箭头到达底部的白色箭头(http://puu.sh/5LuVO.png)时,歌曲开始播放。我的问题是,当歌曲和箭头同步开始时,在歌曲结束时它们会关闭3-5秒。有解决方案吗 以下是我如何生成箭头的代码:
Sequence sequence = MidiSystem.getSequence(new File("arbitrary.mid"));
int trackNumber = 0;
millisecondsPerTick = sequence.getMicrosecondLength()/(sequence.getTickLength()*(float)1000);
for (Track track : sequence.getTracks()) {
trackNumber++;
for (int i=0; i < track.size(); i++) {
MidiEvent event = track.get(i);
MidiMessage message = event.getMessage();
if (message instanceof ShortMessage) {
ShortMessage sm = (ShortMessage) message;
if (sm.getCommand() == NOTE_ON) {
int key = sm.getData1();
int velocity = sm.getData2();
if(velocity>20)
songArrows.add(new Arrow(-20, 20, key%4 , false, (int)event.getTick()));
}
}
}
}
所以基本上我经历了MIDI事件,将与事件相同的刻度线添加到数组中。这是我在主类中使用的计时器监听器,用于向面板添加箭头。
generateArrowsTimer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
for (int i = 0; i < GenerateArrowsTest.songArrows.size(); i++) {
if(Math.abs(musicTime - GenerateArrowsTest.millisecondsPerTick*((Arrow)GenerateArrowsTest.songArrows.get(i)).getTime())<=10)
movingArrows.add((Arrow)GenerateArrowsTest.songArrows.get(i));
//arrows show up at the top of the screen as they are added, then move down at 4px per 30 milliseconds, using updateTimer
}
if(musicTime >= updateTimer.getDelay()*520/Arrow.movementIncrement && musicTime < updateTimer.getDelay()*600/Arrow.movementIncrement)
sequencer.start(); //Starts playing music about when first arrow reaches a white arrow
if(sequencer.isRunning())
musicTime += generateArrowsTimer.getDelay(); //delay was initialized to be 30
repaint();
}
});
为什么箭头与音乐不同步?
答案 0 :(得分:0)
您的问题是musicTime
计算不正确。
不保证计时器在所需的时间内执行;可能会延迟一些随机数量。 因此,通过累加所需的延迟,任何错误都会累积。
要获取当前时间,请不要使用相对时间偏移,而是要求系统提供绝对时间戳。
对于Sequencer,请使用getMicrosecondPosition
或getTickPosition
。