ページ 11

サウンドノベルについて

Posted: 2009年8月07日(金) 21:44
by ペーシャン
今サウンドノベルを作ろうとしています。
「New Game」や「Option」を選択するメニュー画面まで作ったのですが、その先の処理がわかりません。
選択してエンターを押すとそれぞれの処理につなげるところまではいったんですが、続きができないのでおしえてください!
if(y==262){
	if(Key[KEY_INPUT_RETURN]==1){//
	kettei1 = LoadSoundMem( "kettei1.wav" );
	PlaySoundMem( kettei1 , DX_PLAYTYPE_BACK );
	}

}
if(y==292){
	if(Key[KEY_INPUT_RETURN]==1){
	PlaySoundMem( kettei1 , DX_PLAYTYPE_BACK );
				 	}
}
yは選択肢のカーソル位置です。
カーソルを選択肢に合わせそこでエンターを押すと処理に入ります。
kettei1.wavはテンターを押したときに流れる決定音です。
yが262のときは「New Game」で、ゲーム本編が始まります。
音を流した後に違う画面を表示させても一瞬だけ現われるだけで、画面はすぐに元のメニュー画面に戻ってしまいます。
画面を切り替えて、そのまま処理を続けるにはどうすればよいのでしょうか?

OSはvistaでVisual C++ 2008です。
C言語の経験は、簡単なプログラムを何度か作ったことがあります。
よろしくおねがいします!

Re:サウンドノベルについて

Posted: 2009年8月07日(金) 22:06
by クロウ
例としては、ゲームモードを切り替える変数を用意して、switchで切り替えるなどがあります。
int gameMode;//ゲームモード

/*
切り替える処理(例えば、特定のフラグが立っている状態(ここにカーソルがあったらここへ行く)でエンターを押す)
gameMode = /*処理の切り替え先の値*/;
*/
switch(gameMode){
   case 1:
   /*会話Aの処理*/
   break;

   case 2:
   /*会話Bの処理*/
   break;
etc...
}
とかですね。
ペーシャンさんのコードでは、(エンターキーが押し続けられている時間)==1なので、エンターキーが押された瞬間のみ、DrawBoxしているだけで、(エンターキーが押し続けられている時間)==2以降はif文を通っていないので、一瞬だけ表示して元に戻るだけとなっています。

Re:サウンドノベルについて

Posted: 2009年8月07日(金) 22:39
by kazuoni
ちなみにですけど、エンターが押されるたびに、
サウンドデータをロードするのは、危険かと。
あらかじめ、読み込んでおくほうが無難かと思います。
y=262でエンター押される前に、y=292になり、PlaySoundMemが呼ばれても、
音がならないなどのエラーが発生します。

Re:サウンドノベルについて

Posted: 2009年8月07日(金) 22:48
by ペーシャン
回答ありがとうございます!
この場合だとyが262にあるときにエンターを押して、そのあとcaseに飛ばせばいいんでしょうか?

あとサウンドの件もありがとうございました。

Re:サウンドノベルについて

Posted: 2009年8月08日(土) 15:39
by ペーシャン
回答ありがとうございます。
メニュー画面から次の画面へそれぞれ切り換えることができました。

ですがまた問題にぶつかってしまいました。
caseで処理を分けるまでは良かったのですが、そのあとまだメニュー画面の処理が残っており、
BGMが鳴りっぱなし、上下キーを押すと選択音が鳴り、エンターを押すと決定音が鳴り、画面が切り替わってしまいます。
つまり、「New Game」を選んだあと画面は変わるのですが、「Continue」も選べて画面がコンティニューのものに変わってしまうんです。

BGMのほうはStopSoundをcaseの中に入れたんですが止まりませんでした。
if(y==262){
			if(Key[KEY_INPUT_RETURN]==1){
			PlaySoundMem( kettei1 , DX_PLAYTYPE_BACK );
			gameMode = 1;
			}

		}
		if(y==292){
			if(Key[KEY_INPUT_RETURN]==1){
			PlaySoundMem( kettei1 , DX_PLAYTYPE_BACK );
			gameMode = 2;
			}
		}


switch(gameMode){ 
                case 1: 
						DrawBox(0,0,640,480,GetColor(0,0,0),TRUE);
						StopSound();
						}

						break;
このあとcase2,3とつづきます。

問題は演奏が止まらないのと、メニュー画面の処理が残ってしまい、画面を切り替えた後でも他の選択肢が選べることです。

おしえたください!

P.S
新しく登校したほうが良かったでしょうか?

Re:サウンドノベルについて

Posted: 2009年8月08日(土) 17:33
by Kou
少し気になった部分があるんですが、この選択処理を呼び出している部分と、呼び出された後の部分の処理を
載せてもらえませんか?

もしかして、メニュー選択の処理自体メインループ等の中で、無条件に毎回呼ばれてませんか?

項目選択処理
 ↓
選択された項目の処理
 ↓
項目選択処理

それと、現在の状態だと、決定キーを押すまでDrawBoxが呼ばれないような気がするんですが・・・
つまり、上下のキーを押した時点ではどこが選択されているかわからず、決定した時点で初めて選択した場所が
わかる・・・DrawBoxの使い道が違うならこれでも問題ないと思いますが、現在の選択箇所を明示する目的ならば、
修正が必要だと・・・

あと、インデントがマチマチなので、コードが読みにくいです、インデントの幅を詰めて、統一してもらえると
みなさん読みやすいと思います。

Re:サウンドノベルについて

Posted: 2009年8月08日(土) 18:57
by kazuoni
新しく投稿も、登校もしないでいいかと思いますよ^^;

ifとswitchが同じ関数内に書かれているのなら、
そのような挙動になるかと。
エンターを押す前まではif文は通るけど、
エンターを押したら、通らないで一応回避できるかと。
ただ、ごちゃごちゃになりやすいので、いい具合に関数化したほうが、
あとあと管理しやすいかと思います。

StopSoundを使うと、ゲーム中にブチッと音が途切れているので、
あまりつかいたくないですかね^^;
CheckSoundFileで鳴りやむまで次の処理を行わないとすればうまくいきそうです。

Re:サウンドノベルについて

Posted: 2009年8月09日(日) 11:14
by ペーシャン
DrawBoxは確認のために色を変えて表示させてます。
登校はミスです;

とりあえずコード載せます。




int GetHitKeyStateAll_2(int KeyStateBuf[/url]){
		char GetHitKeyStateAll_Key[256];
		GetHitKeyStateAll( GetHitKeyStateAll_Key );
		for(int i=0;i<256;i++){
				if(GetHitKeyStateAll_Key==1) KeyStateBuf++;
				else							KeyStateBuf=0;
		}
		return 0;
}

void char_disp(int Black,int y){

		LoadGraphScreen( 230 , y , "icon1.bmp" , TRUE );
		LoadGraphScreen( 260 , 260 , "menue.bmp"  , TRUE );

}
 
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){

	Black = GetColor( 0 , 0 , 0 ) ;//色の取得

		message_box();
 
	if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

		ClearDrawScreen();   // 裏画面のデータを全て削除
		LoadGraphScreen( 0, 0, "seisaku.bmp" , TRUE ) ; //裏画面へ画像を描写
		ScreenFlip() ;                             // 裏画面データを表画面へ反映
		Sleep(2500);

		opening = LoadSoundMem( "opening.mp3" );
		kettei1 = LoadSoundMem( "kettei1.wav" );
		sousa1 = LoadSoundMem( "sousa1.wav" );

		PlaySoundMem( opening , DX_PLAYTYPE_BACK );//バックグラウンド再生
 
	while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
          //↑メッセージ処理         ↑画面をクリア         ↑入力状態を保存       ↑ESCが押されていない

		LoadGraphScreen( 0 , 0 , "back.bmp", FALSE ) ;
		LoadGraphScreen( 0 , 0 , "title1.bmp",TRUE);

		char_disp(Black,y);                              // 文字を描画

		if( Key[KEY_INPUT_DOWN]==1 ||( Key[KEY_INPUT_DOWN]%5==0 && Key[KEY_INPUT_DOWN]>5)){
        // たった今押したか、1カウンター以上押しっぱなしかつ5回に一度

			y+=30;                                           
			if(y==412)                            // y座標が412なら(選択が一番下なら)
				y=262;                        // 選択座標を一番上に

			PlaySoundMem( sousa1 , DX_PLAYTYPE_BACK );

		}

		if( Key[KEY_INPUT_UP]==1 ||( Key[KEY_INPUT_UP]%5==0 && Key[KEY_INPUT_UP]>5)){

		PlaySoundMem( sousa1 , DX_PLAYTYPE_BACK );

			y-=30;
			if(y==232)
				y=382;
		}

		if(y==262){
			if(Key[KEY_INPUT_RETURN]==1){//今の瞬間押されたら
			PlaySoundMem( kettei1 , DX_PLAYTYPE_BACK );
			gameMode = 1;
			}
		}
		if(y==292){
			if(Key[KEY_INPUT_RETURN]==1){
			PlaySoundMem( kettei1 , DX_PLAYTYPE_BACK );
			gameMode = 2;
			}
		}
		if(y==322){
			if(Key[KEY_INPUT_RETURN]==1){
			PlaySoundMem( kettei1 , DX_PLAYTYPE_BACK );
			gameMode = 3;
			}
		}
		if(y==352){
			if(Key[KEY_INPUT_RETURN]==1){
			PlaySoundMem( kettei1 , DX_PLAYTYPE_BACK );
			gameMode = 4;
			}
		}
		if(y==382){
			if(Key[KEY_INPUT_RETURN]==1){
			PlaySoundMem( kettei1 , DX_PLAYTYPE_BACK );
			int end;
				end=MessageBox(
				NULL ,
				TEXT("ゲームを終了しますか?") ,
				TEXT("終了") , 
				MB_YESNO | MB_ICONQUESTION );
					if(end==IDYES){
					DxLib_End();
					return 0;
					}
			}

		}

Re:サウンドノベルについて

Posted: 2009年8月09日(日) 14:10
by kazuoni
いろいろツッコむところがありますが・・・
質問は何でしょうか?
(どうせなら、ソースファイルごとアップしたほうがいいような^^;)

#横道にそれますが・・・
LoadGraphScreenは重い処理のようなので、
画像はLoadGraphとDrawGraphで描写したほうがよいようです。

Re:サウンドノベルについて

Posted: 2009年8月09日(日) 15:04
by Kou
ソースを載せてくださいと言っておいて申し訳ないですが、この状態だとただ記述方法に突っ込みを入れるだけで、
処理を把握できませんね・・・kazuoniさんの言うとおり、まるごとアップしたほうが早いと思います。

ここまででは、前回の選択画面が残るとか、音が鳴りっぱなしとかの要因に繋がりそうな部分が記述されてい
ないようなので。

このソースを見た限りでは初心者の私から見ても、突っ込み所が多い気が・・・

Re:サウンドノベルについて

Posted: 2009年8月09日(日) 15:08
by sizuma
とりあえずソースのインデントが異常に汚いです。
もしメモ帳でコーディングしてるんだったら、何かソフトを使うことをオススメします

Re:サウンドノベルについて

Posted: 2009年8月09日(日) 16:33
by ペーシャン
ソースコードです。

Re:サウンドノベルについて

Posted: 2009年8月09日(日) 17:53
by Kou
選択画面に戻るのについては、gamemodeがリセットされていない為、ループで戻ってきた時に何も入力が無ければ、
前回と同じcase文に引っ掛かるのと、基本的にメインループに直接項目の選択処理があるので、
無条件で項目選択の処理が実行されているみたいですね。

とりあえず、screenfripの後にでもgameModeを0にリセットして、動作を確認してみてはどうでしょうか?
但し、この記述形式では、根本的な解決にはならないと思います。
処理を関数化するなどして分けた後、その処理を実行する、しないの条件判断等が必要ではないでしょうか?

追記編集です
 ・y == 262の時gameModeが変更されていないようですが。
 ・gameModeが1以外では、BGMの停止をしていないようです。
 ・BGMの再生がバックグラウンドの時って、停止しない限りループ再生しませんでしたか?

以上の部分は記述ミスでしょうか?

Re:サウンドノベルについて

Posted: 2009年8月09日(日) 19:42
by Kou
連投稿失礼します。

StopSound関数にハンドルを渡していないのに今気付きました。
確認してはいませんが、PlaySoundMemで再生したサウンドファイルは、StopSoundMemで停止しなければなら
ないのではないでしょうか?

Re:サウンドノベルについて

Posted: 2009年8月09日(日) 20:16
by kazuoni
>StopSound関数にハンドルを渡していないのに今気付きました。
StopSoundは引数はなしみたいです。

>PlaySoundMemで再生したサウンドファイルは、
>StopSoundMemで停止しなければならないのではないでしょうか?
特に強制はないかと思います。
音を止めたいときに、StopSoundMemを使えばよいみたいです。
参考までに、本家を・・・。
DXライブラリ 関数リファレンスページ - PlaySoundMem
ttp://homepage2.nifty.com/natupaji/DxLib/function/dxfunc_sound.html#R8N5

Re:サウンドノベルについて

Posted: 2009年8月09日(日) 20:20
by クロウ
すみません。上に書いた例が悪かったようです。

例)
switch(gameMode){
  case menuMode:
      menuMain();//メニュー画面の処理
      break;
  case newGameMode:
      gameMain();//ゲームスタート
      break;
  case continueMode:
      readSaveMain();//セーブデータの読み込み
      break;
  case option:
      optionMain();//オプションモードの処理
      break;
}
関数分けは大事というよりも、メインループは関数を呼び出すだけ位の勢いで。
画像データなどの読み込みも関数分けしておきましょう。

一例ですが、このようにして、menuMain()関数の中に先ほどのif文などの処理を書いておけば、タイトル画面の処理が残るといった解決すると思います。
BGMを鳴らすといったことも関数内で処理すれば、解決すると思います。ゲームモードを切り替えて、呼ぶ関数を変えてあげたとき、BGMを鳴らしている関数が呼ばれていないときは、その鳴らすという処理も呼ばれていないため、呼ばれていないものは鳴らしようがないからです。

それでも、一瞬だけ鳴ったりする場合は配列の要素数を超えてアクセスしたりなど、ポインタの不正なアクセスが疑われたりしますが・・・・。

Re:サウンドノベルについて

Posted: 2009年8月09日(日) 21:13
by Kou
すみません。
StopSoundMemとStopSoundがごっちゃになってました(汗)
停止処理が強制でないようならば、私のStopSoundに関する記述はキレイサッパリ忘れてください。
普段あまり音に関する処理をしていないので、私自身確認していませんでした。

Re:サウンドノベルについて

Posted: 2009年8月09日(日) 22:58
by ペーシャン
皆さん回答ありがとうございました
おかげさまでなんとかなりそうです

これから数日間PCいじれなくなるんですが、
再開した時また何かありましたらそのときはよろしくお願いします!

Re:サウンドノベルについて

Posted: 2009年8月09日(日) 23:38
by conio
とりあえず、『音を出してそれぞれの状態へ遷移する』という処理は
大体こんな感じでよいのではないでしょうか。
(一部 適当な部分アリ)

音の部分はコメントアウトしてるので、任意のファイル名にして
コメントアウトを外すと動くと思います。
---------------------------------------------------------------------------------------
#include "DxLib.h"

int Key[256];
int kettei1 ;

int GetHitKeyStateAll_2(int KeyStateBuf[/url]){
        char GetHitKeyStateAll_Key[256];
        GetHitKeyStateAll( GetHitKeyStateAll_Key );
        for(int i=0;i<256;i++){
                if(GetHitKeyStateAll_Key==1) KeyStateBuf++;
                else                            KeyStateBuf=0;
        }
        return 0;
} 

enum SeqID{
	SEQ_TITLE,
	SEQ_NEW_GAME,
	SEQ_CONTINUE,
	SEQ_OPTION,
	SEQ_EXIT
};
SeqID NowSeq = SEQ_TITLE;

typedef struct{
	POINT pt;
	char* msg;
	SeqID next;
}A;

A mozi[/url] = {{100,20,"NewGame",SEQ_NEW_GAME},
			{100,40,"Continue",SEQ_CONTINUE},
			{100,60,"Option",SEQ_OPTION},
			{100,80,"Exit",SEQ_EXIT}};


void Title(void)
{
	int White = GetColor( 255 , 255 , 255 ) ; // 白色の値を取得
	int Yellow = GetColor( 255 , 255 , 0 ) ; // 黄色の値を取得
	int Cyan = GetColor( 0 , 255 , 255 ) ; // 水色の値を取得
	int TempColor = 0;
	static int Cursor = 0;
	int count = sizeof(mozi) / sizeof(mozi[0]);

	
	//カーソルの移動
	if(Key[KEY_INPUT_DOWN] == 1 || (Key[KEY_INPUT_DOWN] > 20 && Key[KEY_INPUT_DOWN] % 10 == 0))
		Cursor = (Cursor + 1) % count;
	else if(Key[KEY_INPUT_UP] == 1 || (Key[KEY_INPUT_UP] > 20 && Key[KEY_INPUT_UP] % 10 == 0))
		Cursor = (Cursor + count - 1) % count;
		
	//選択肢の表示
	for(int i = 0; i < count; i++){
		if(i == Cursor)TempColor = Cyan;
		else TempColor = White;
		DrawString(  mozi.pt.x,  mozi.pt.y, mozi.msg , TempColor);
	}
	//カーソルの表示
	DrawString(  mozi[Curso[/url].pt.x - 20,  mozi[Curso[/url].pt.y, "⇒" , Yellow);

	//遷移先決定
	if(Key[KEY_INPUT_RETURN] == 1){
		//PlaySoundMem( kettei1 , DX_PLAYTYPE_BACK );
		NowSeq = mozi[Curso[/url].next;
		Cursor = 0;
	}
}

void NewGame(void)
{
    int White = GetColor( 255 , 255 , 255 ) ; // 白色の値を取得
	DrawString(  100,  100, "NewGame画面です。" , White);
}
void Continue(void)
{
    int White = GetColor( 255 , 255 , 255 ) ; // 白色の値を取得
	DrawString(  100,  100, "Continue画面です。" , White);
}

void Option(void)
{
    int White = GetColor( 255 , 255 , 255 ) ; // 白色の値を取得
	DrawString(  100,  100, "Option画面です。" , White);
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
	ChangeWindowMode( TRUE );

	if(DxLib_Init() == -1 ) return -1;
	SetDrawScreen( DX_SCREEN_BACK );
	
	//kettei1 = LoadSoundMem( "bgm_config.wav" ) ;

	while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0 && NowSeq != SEQ_EXIT){

		switch(NowSeq){
			case SEQ_TITLE:	Title();
							break;
			case SEQ_NEW_GAME:	NewGame();
								break;
			case SEQ_CONTINUE:	Continue();
								break;
			case SEQ_OPTION:	Option();
								break;
			default:break;
		}
		ScreenFlip();
	}
	DxLib_End();
	return 0;
}
---------------------------------------------------------------------------------------