2013-12-14 110 views
0

所以我正在編寫類似DDR的遊戲,使用MIDI文件作爲音樂。我寫了一個小課程,根據任何給定的MIDI文件中的音符生成箭頭。在實際的遊戲中,當第一個箭頭到達底部的白色箭頭(http://puu.sh/5LuVO.png)時,歌曲開始播放。我的問題是,雖然歌曲和箭頭同步開始,但在歌曲結束時,它們會關閉3-5秒。任何解決方案 這裏是我如何產生的箭頭,代碼:Java DDR遊戲,箭頭和音樂不同步

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

您的問題是musicTime計算不正確。

計時器不能保證在確切的時間執行;它可能會延遲一些隨機數量。 因此,通過加上所需的延遲,任何錯誤都會累積。

要獲取當前時間,請不要使用相對時間偏移量,而是要求系統提供絕對時間戳。 在序列發生器的情況下,使用getMicrosecondPositiongetTickPosition