スーファミのAボタンのような処理を実装したい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
taketoshi
記事: 222
登録日時: 15年前
住所: 日本国

スーファミのAボタンのような処理を実装したい

#1

投稿記事 by taketoshi » 12年前

現在SRPGを製作しています。

スーファミのAボタンのように、ひとつの処理に対してボタンを押したら決定し
様々なシーンに対応するといったような処理を施したいです。

今書いている決定処理は 2.9章 全てのキーの入力状態を取得する の処理を使っています。
http://dixq.net/g/02_09.html

DXライブラリのメインループのwhile文にこの関数を加えると常時キーの状態が取得できるのですが
いざボタンを押したときは、関連する処理が一気に実行されてしまいます。

SRPGの移動処理で例えると
キャラクタ選択→移動場所決定→移動後のメニュー表示→待機のようにボタンを押される度順次実行したいのですが
キャラクタ選択→その場で待機処理→メニュー表示→待機と
同じボタンの入力状態を調べているため、すべての処理が最後まで一気に流れてしまいます。

スーファミのAボタンのように、一度おしたらその処理を実行し、再度押されるまで次の処理を実行しない。と再度Aボタンを押さない限り次の処理を呼び出さないようにしたいです。
現在は以下のようにKey[KEY_INPUT_Z] に様々なフラグを組みあわせて入力状態を制御しています。
ただスマートではないと思っていてほかに何かよい方法はないかと考えています


プログラムをこのように組めばよいという指針を示していただけると助かります。

以下は現在組んでいるプログラムです *記述方法によってKey[KEY_INPUT_Z] を調べている箇所が一気に実行されて困っている

コード:


// キーの入力状態を更新する
int Task::gpUpdateKey(){
    char tmpKey[256]; // 現在のキーの入力状態を格納する
    GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
    for( int i=0; i<256; i++ ){ 
            if( tmpKey[i] != 0 ){ // i番のキーコードに対応するキーが押されていたら
                    Key[i]++;     // 加算
            } else {              // 押されていなければ
                    Key[i] = 0;   // 0にする
            }
    }
    return 0;
}

//メイン関数ループ部分 ほかの部分は割愛
	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && Task::gpUpdateKey()==0){//ここでgpUpdateKey関数を常時呼び出し
		c_map::MapProcedure(&cm);
		Charcter::CharProcedure((Charcter **)MyChar,(Charcter **)EnemyChar,&Cur);//ポインタ配列の受け取り方は*配列名[]で受け取る//ユニットクラスをキャラクタークラスに型キャストして無理やり代入
		Cursor::CursorProcedure(&Cur);
	}

//目的地決定処理
int Charcter::GoDestination(Cursor *Cur){

	//行動キャンセル処理
	if(Cur->nPos_x % nMapTipSize == 0 && Cur->nPos_y % nMapTipSize == 0){
		if(Key[KEY_INPUT_Z] == 1 && Cur->GetCharNumber != 0 && MoveFlag == false){
			Cur->GetCharNumber = 0;
			SerchClr();//移動範囲描写クリア
		}
	}

	//離れたところの目的地決定処理
	if(Cur->nPos_x % nMapTipSize == 0 && Cur->nPos_y % nMapTipSize == 0 && BelongCheck[Cur->nPos_y / nMapTipSize][Cur->nPos_x / nMapTipSize] == BelongDefault){
		if(Key[KEY_INPUT_X] == 1 ){//キャラクタ移動処理//ここでXボタンを調べている
			if(Task::MoveResult[Cur->nPos_y / Task::nMapTipSize][Cur->nPos_x / Task::nMapTipSize] == 0){//移動可能範囲内ならばキャラを移動させる
				if(Cur->GetCharNumber != 0){//カーソルが何かをつかんでいれば
					MoveFlag = true;//キャラクタ移動フラグを立てる
					Cur->MoveFlag = false;//カーソルを動かさないフラグを立てる
					//DrawFormatString(0,120,RGB(255,255,255),"%s",Task::MoveDirection[Cur->nPos_y / 32][Cur->nPos_x / 32].c_str());
				}
			}
		}
	}

	//その場に待機する処理
	if(Cur->nPos_x == nPos_x && Cur->nPos_y == nPos_y){//カーソルとキャラクタの座標が同じならば
		if(Key[KEY_INPUT_X] == 1 ){//ここでXボタンを調べている
			Cur->MoveFlag = false;
		}
	}

	return 0;
}

//移動後のメニュー処理:戦うとか杖とかアイテム交換とか実装予定
int Charcter::MenuDispose(Cursor *Cur){

	int nSelectRet;

	if(MenuStripFlag == true){//キャラクタが目的地に到達していればメニューを出す
		nSelectRet = MenuStrip::Updata();
		MenuStrip::DrawMenu();
		if(Key[KEY_INPUT_X] == 1 && MenuStripFlag == true){//ここでXボタンを調べている
			switch(nSelectRet){
				case Fight://戦う
					break;
				case MagicWand://杖
					break;
				case UseItem://アイテム
					break;
				case WaitChar://待機
					MenuStripFlag = false;//メニューを非表示にする
					Cur->MoveFlag = true;
					Cur->GetCharNumber = 0;
					nDirection = 2;//何も無いときは下向きにしておく
					BelongPointer(Cur,OldPosition.y,OldPosition.x);//マップ上に所属を書き込む
					break;

			}
		}

		if(Key[KEY_INPUT_Z] == 1 && MenuStripFlag == true){//行動をキャンセルする処理
			MenuStripFlag = false;//メニューを非表示にする
			nPos_x = OldPosition.x;
			nPos_y = OldPosition.y;
			Cur->MoveFlag = true;
			Cur->GetCharNumber = 0;
			nDirection = 2;//何も無いときは下向きにしておく
		}
	}

	return 0;
}

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: スーファミのAボタンのような処理を実装したい

#2

投稿記事 by softya(ソフト屋) » 12年前

状態遷移をうまく使う必要があります。
キャラクタ選択→移動場所決定→移動後のメニュー表示→待機
のそれぞれの状態を1つの変数で保持して、同時には処理しないようにしておくのです。
現在キャラクタ選択処理ならば、switch~caseでキャラクタ選択処理だけを呼び出せば良いでしょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

dic
記事: 658
登録日時: 15年前
住所: 宮崎県
連絡を取る:

Re: スーファミのAボタンのような処理を実装したい

#3

投稿記事 by dic » 12年前

今のゲームの、状態により switch, case で分ければ対応できます。
下にサンプルを用意しました。
参考になれば幸いです。

コード:


int _tmain(int argc, _TCHAR* argv[])
{
	//	mode:100	キャラクタ選択しているとき
	//	mode:200	移動場所決定する
	//	mode:300	移動後のメニュー表示
	//	mode:400	待機(メニューの処理)

	static	int	Game = 1;
	while( Game )
	{
		//	キーの入力状態を更新する
		Task::gpUpdateKey();

		static	int		mode = 0;
		//	現在の状態によってキーの入力を切り替える
		switch( mode )
		{
		case 0:
		case 100:
			//	キャラクタ選択しているときzボタンを押した
			if( Key[KEY_INPUT_Z] == 1 )
				mode = 200;
			break;
		case 200:
			//	移動場所を決定するときにxボタンを押した
			if( key[KEY_INPUT_X] == 1 )
				mode = 100;
			//	移動場所を決定するときにzボタンを押した
			if( key[KEY_INPUT_Z} == 1 )
				mode = 300;
			break;
		case 300:
			//	移動後のメニュー表示でzボタンを押した
			if( key[KEY_INPUT_Z} == 1 )
			{
				switch( select )
				{
				case 1:	//	zボタンを押したとき、待機を選んでいた
					mode = 400;
					break;
				case 2:	//	zボタンを押したとき、ステータスを選んでいた
					break;
				}
			}
			break;
		case 400:
			//	待機の処理
			//	ユニット1 = 行動完了
			mode = 0;
			break;
		default:
			//	実装していないmodeの値
			break;
		}

		//	ゲームを更新
		GameUpdate();

		//	ESCAPE でゲームを抜ける
		if( key{KEY_INPUT_ESCAPE] == 1 )
			break;
	}
	
	return 0;
}


taketoshi
記事: 222
登録日時: 15年前
住所: 日本国

Re: スーファミのAボタンのような処理を実装したい

#4

投稿記事 by taketoshi » 12年前

softyaさんdicさんアドバイスありがとうございます。

アドバイスいただいてからずっと考えていて、以下のように実装しなおしました。
かなりコードもすっきりして、目的どおりの処理を施すことが出来ました。

この遷移状態を保存しておく技術は他のシーンでも役に立ちそうです。ありがとうございます。

コード:

//*各スイッチ部分を関数として分離する
//*メニューの描写フェーズをここから抜き出し独立させる
//*Switch化したことで不要なフラグが出てきているので整理する

int Charcter::MoveCharProc(Cursor *Cur){

	switch(nStatusTransition){
		case dFree://キャラクターをピックアップしていないフリーな状態
			this->PickChar(Cur);
			break;
		case dPickup://キャラクターピックアップ中
			this->GoDistnation(Cur);
			break;
		case dMove:
			this->MoveChar(Cur);
			break;
		case dMenu:
			this->MenuCalc(Cur);
			break;
		default:
			break;
		}
		
	return 0;
}

閉鎖

“C言語何でも質問掲示板” へ戻る