STGは特にキーコンフィグが大切なゲームです。
最初に設定しておかないと、後々のプログラムソースがごっそり変わってしまうので、
面倒ですが、最初に設定しておきましょう。
まず、キーの入力状態を取得します。(これは前節で既に行いました)
次にパッドの入力状態を取得します。キーボードで入力してもパッドで入力しても対応させたいので、
キーボードの入力状態を、コンフィグで設定したパッド情報にいれて両方に対応出来るようにしてやります。
今回GetJoypadInputStateという関数を使いますが、使い方がわからなければ本家リファレンスで確認しておいて下さい。
ではパッドとコンフィグに使用する構造体をPAD_MAXを16として以下のように定義します。
--struct.hに以下を追加-- //パッドに関する構造体 typedef struct{ int key[PAD_MAX]; }pad_t; //コンフィグに関する構造体 typedef struct{ int left,up,right,down,shot,bom,slow,start,change; }configpad_t;
--define.hを変更-- //フィールドの広さ #define FIELD_MAX_X 384 #define FIELD_MAX_Y 448 //フィールドの左上の座標 #define FIELD_X 32 #define FIELD_Y 16 //パッドキーの最大数 #define PAD_MAX 16 #include "struct.h"
パッドで使うキーはPAD_MAXである16個を最大数として用意し、とりあえず
「左・上・右・下・ショット・ボム・低速・スタート・変身」 の9つのキーを用意します。
それぞれのキーに0〜15のどれかの数字を対応させる事で好きに設定したパッドキーを利用する事が出来ます。
パッドキーの何番がどこのボタンに対応するかは、実際に自分で確認して下さい。
こちらで確認したところ、以下に示す番号が一般的に使えるので、初期化関数でその値を代入しておきます。
--ini.cppを変更-- #include "../include/GV.h" //一番最初の初期化 void first_ini(){ ch.x=FIELD_MAX_X/2; ch.y=FIELD_MAX_Y*3/4; configpad.down=0; configpad.left=1; configpad.right=2; configpad.up=3; configpad.bom=4; configpad.shot=5; configpad.slow=11; configpad.start=13; configpad.change=6; }
--GV.hに以下を追加-- GLOBAL configpad_t configpad;
GetHitPadStateAll関数では現在のパッドの入力状態を取得し、キーボードの入力状態と比較し、
入力時間の長い方を採用してパッドの入力変数に代入します。上の2つの関数に変更はありません。
その時に使用する引数1と引数2のうち大きい方を引数1に代入する関数が
void input_pad_or_key(int *p, int k)
これです。この関数に使われている条件演算子の使い方がわからない方はそちらを調べて下さい。
CheckStatePad関数は初期化関数で設定したパッド番号を渡せばその入力状態を返す関数です。
既に作ったCheckStateKey関数と仕組みは同じです。
--key.cppを変更-- #include "../include/GV.h" unsigned int stateKey[256]; int GetHitKeyStateAll_2(){ char GetHitKeyStateAll_Key[256]; GetHitKeyStateAll( GetHitKeyStateAll_Key ); for(int i=0;i<256;i++){ if(GetHitKeyStateAll_Key[i]==1) stateKey[i]++; else stateKey[i]=0; } return 0; } int CheckStateKey(unsigned char Handle){ return stateKey[Handle]; } //パッドの入力状態を格納する変数 pad_t pad; //引数1と引数2のうち大きい方を引数1に代入する void input_pad_or_key(int *p, int k){ *p = *p>k ? *p : k; } //パッドとキーボードの両方の入力をチェックする関数 void GetHitPadStateAll(){ int i,PadInput,mul=1; PadInput = GetJoypadInputState( DX_INPUT_PAD1 );//パッドの入力状態を取得 for(i=0;i<16;i++){ if(PadInput & mul) pad.key[i]++; else pad.key[i]=0; mul*=2; } input_pad_or_key(&pad.key[configpad.left] ,CheckStateKey(KEY_INPUT_LEFT )); input_pad_or_key(&pad.key[configpad.up] ,CheckStateKey(KEY_INPUT_UP )); input_pad_or_key(&pad.key[configpad.right] ,CheckStateKey(KEY_INPUT_RIGHT )); input_pad_or_key(&pad.key[configpad.down] ,CheckStateKey(KEY_INPUT_DOWN )); input_pad_or_key(&pad.key[configpad.shot] ,CheckStateKey(KEY_INPUT_Z )); input_pad_or_key(&pad.key[configpad.bom] ,CheckStateKey(KEY_INPUT_X )); input_pad_or_key(&pad.key[configpad.slow] ,CheckStateKey(KEY_INPUT_LSHIFT )); input_pad_or_key(&pad.key[configpad.start] ,CheckStateKey(KEY_INPUT_ESCAPE )); input_pad_or_key(&pad.key[configpad.change] ,CheckStateKey(KEY_INPUT_LCONTROL)); } //渡されたパッドキー番号の入力状態を返す。返り値が-1なら不正 int CheckStatePad(unsigned int Handle){ if(0<=Handle && Handle<PAD_MAX){ return pad.key[Handle]; } else{ printfDx("CheckStatePadに渡した値が不正です\n"); return -1; } }
input_pad_or_key関数に渡す為に長々と書いていますが、配列とポインタを使えば省略してかけるので、
余力のある人は短くしてみて下さい。
--char.cppを変更-- #include "../include/GV.h" void calc_ch(){ ch.cnt++; ch.img=(ch.cnt%24)/6; if(CheckStatePad(configpad.left)>0)//左が押されていたら ch.x-=3;//座標を左に if(CheckStatePad(configpad.right)>0)//右が押されていたら ch.x+=3;//座標を右に }
CheckStatePad関数は上のようにつかいます。設定したキー、例えば左キー番号はconfigpad.leftに入っているので、
この番号をCheckStatePad関数に渡します。入力されているカウンタが返って来るので、0じゃなければ押されている事が
わかります。
それでは今回追加した関数をヘッダに追加しておきましょう。
--function.hに以下を追加-- GLOBAL void GetHitPadStateAll(); GLOBAL int CheckStatePad(unsigned int Handle);
今回メインファイルに変更があったのは以下の赤い所だけです。
--main.cppを変更-- #define GLOBAL_INSTANCE #include "../include/GV.h" //ループで必ず行う3大処理 int ProcessLoop(){ if(ProcessMessage()!=0)return -1;//プロセス処理がエラーなら-1を返す if(ClearDrawScreen()!=0)return -1;//画面クリア処理がエラーなら-1を返す GetHitKeyStateAll_2();//現在のキー入力処理を行う GetHitPadStateAll(); //現在のパッド入力処理を行う return 0; } int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){ ChangeWindowMode(TRUE);//ウィンドウモード if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化 while(ProcessLoop()==0){//メインループ switch(func_state){ case 0: load(); //データロード first_ini();//初回の初期化 func_state=100; break; case 100: calc_ch(); //キャラクタ計算 graph_main();//描画メイン break; default: printfDx("不明なfunc_state\n"); break; } if(CheckStateKey(KEY_INPUT_ESCAPE)==1)break;//エスケープが入力されたらブレイク ScreenFlip();//裏画面反映 } DxLib_End();//DXライブラリ終了処理 return 0; }
実行結果
- Remical Soft -