こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

Java言語プログラムと、音楽の同期(?)について

初の投稿となります。
皆様からのご意見がお聞き出来れば幸いです。

現在、Java言語を使ってゲームのプログラミングを行っております。
ジャンルは音楽ゲームで、
上部から音楽に合わせて落下してくるオブジェクトを
対応するキーを押して消滅させる形のゲームです。
(ビートマ○アやポップンミュー○ックのようなものを
 想像していただけるとイメージしやすいと思うのですが・・・)


ところが、いざ作って実行して見ると
起動の度に、毎回叩くタイミングに微妙な誤差が出てしまいます。
本当にわずかな誤差なのですが(0.0~1.0秒程度)、
ジャンルを音楽ゲームにしている以上、
わずかな誤差でも致命的となってしまいます。

そこで質問なのですが、音楽とJava言語プログラムを
同期化させることは可能なのでしょうか?
また、毎回定まったタイミングでの音楽再生は可能なのでしょうか?

ちなみに現在、音楽の管理はAudioClipを使用しており、
再生に至っては、play()を呼び出すだけという安直な作りになっています。

それでは、ご指導の程 よろしくお願い致します。

投稿日時 - 2007-05-04 00:08:02

QNo.2971366

すぐに回答ほしいです

質問者が選んだベストアンサー

#2です。
全く自信ありません。
---

同期のアイデアですが、
たとえば、
サウンドを再生させたのち、
「音声再生の進行具合」自体を「ゲーム内部時計」にする、
とか・・・。


再生はClip#open()などで。
再生の進行具合はgetFramePosition()などで取得。(これを時計にする)
http://java.sun.com/j2se/1.5.0//ja/docs/ja/api/javax/sound/sampled/Clip.html

音声ファイルの各種情報は
AudioFormatクラスで。
http://sdc.sun.co.jp/java/docs/j2se/1.5.0/ja/docs/ja/api/javax/sound/sampled/AudioFormat.html

JavaのサウンドAPIについては、詳しくはしらないので、
ネットで調べてみてください。

(参考サイト:
「Javaでゲーム作りますが何か」ClipでWAVE再生
http://javagame.main.jp/index.php?Clip%A4%C7WAVE%BA%C6%C0%B8)

投稿日時 - 2007-05-08 02:31:26

お礼

kacchann様、またまたご回答ありがとうございます。
提案してくださった時計システムでどうにかなりそうです。
本当にありがとうございました!

投稿日時 - 2007-05-19 11:24:13

このQ&Aは役に立ちましたか?

2人が「このQ&Aが役に立った」と投票しています

回答(3)

ANo.2

「ただ音を流しているだけ」のサンプルコード書いてみました。
同期とかは、させてません。
オーディオファイルは24秒間のauファイルをループ再生して、
再生テンポと表示が一致しているかどうかを確認。
java1.5のappletviewerではOK.
java1.4のappletviewerではアウト。(※再生スピードが正確でなく
やや遅いし、ノイズがわりと頻繁に入る)

動作確認
OS:WinMe
マシン:pentium3 500MHz

import java.net.*;
import javax.sound.sampled.*;

public class Demo extends Applet{
static boolean gameStart;AudioClip ac;
public void init(){
setLayout(new BorderLayout());
MyP myP=new MyP();add(myP,"Center");
final GameLoop gameLoop=new GameLoop(myP);
gameLoop.start();
Button btn=new Button("1");
btn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
ac=getAudioClip(getDocumentBase(),"test.au");
gameStart=true;ac.loop();gameLoop.init();
}
});
add(btn,"North");
}
}

class MyP extends Canvas{
boolean mark;
void showMark(boolean b){mark=b;}
public void paint(Graphics g){
if(!Demo.gameStart){g.drawString("準備中",20,40);
}else{
if(mark)g.drawString("打",20,40);
else g.drawString("",20,40);
}
}
}

class GameLoop extends Thread{
MyP myP;boolean agenda;
final long period=1000;final long showPeriod=100;
boolean musicStart;long agendaTime;long lastTime;
GameLoop(MyP myP){this.myP=myP;}
void init(){musicStart=true;}

/**ゲームループ*/
public void run(){
while(true){
oneFrame();
try{Thread.sleep(30);}catch(InterruptedException e){}
}
}

void oneFrame(){
if(!Demo.gameStart){return;}
if(musicStart){
musicStart=false;agenda=true;
lastTime=System.currentTimeMillis();
}
long now=System.currentTimeMillis();
if(agenda){
myP.showMark(true);agendaTime=now;
}else{
if(now-agendaTime>showPeriod){
myP.showMark(false);
}
}
agenda=false;
now=System.currentTimeMillis();long d=now-lastTime;
if(d>=period){
long times=d/period;lastTime+=period*times;agenda=true;
}
myP.repaint();
}
}

投稿日時 - 2007-05-07 01:30:53

お礼

ご回答ありがとうございます。

kacchann様のおっしゃる
java1.5、java1.4 というのは
コンパイル時の -target オプションでの指定、
もしくは実行環境の事だという取り方でよろしいでしょうか?

とにかく、わざわざ記述していただいたサンプルプログラム、
是非参考にさせていただきます。ありがとうございます。

投稿日時 - 2007-05-08 22:34:26

ANo.1

「対応するキー」を押した時に毎回何かのオブジェクトをnew()している
場合、オーバーヘッドが気になるかもしれません。そこで、そのオブジェクト
をあらかじめ(起動時に)複数プールしておき、キーが押された時に一つ
つかうというのはどうでしょうか。

はずしていたらすみません。

投稿日時 - 2007-05-04 00:52:52

補足

早速のご回答ありがとうございます。

ゲームプレイ中に、オブジェクトの生成をするような
プログラムの記述はしていないので、その心配はございません。
CXI00554様がおっしゃるように、ゲームで使うオブジェクトに関しては
プログラムの初めで全て用意しておく形でプログラムを組んでいます。

試しに、実際のゲームプレイ中にキー操作を
全く行わずに実行してみたりもしましたが、
やはり微妙な誤差が生じます。

System.currentTimeMillis()メソッドで時間を計り、
ゲームのループを回しているのですが、
このSystem.currentTimeMillis()メソッドは
しっかりとした値を返さない場合があると言われてるので(笑)、
このメソッドにも問題があるのかと、一人悩んでおります。

投稿日時 - 2007-05-04 01:42:05

あなたにオススメの質問