ある書籍を参考にc++のゲーム製作について勉強しておりまして、本当に初歩の初歩ですが、一応動くようになりました。
しかし、意図していない挙動をしていて、その原因もいまいち分かりません。具体的には
ユーザーから、cinで入力を受け取る部分で、複数回の入力( 例えば、"aaa" など )を一度に受け付けてしまう状態になっています。
本当は一度の入力( エンターキー )に対して、1マスだけ動いてほしいのです。
どうか原因をヒントだけでも結構ですので、教えていただけませんでしょうか?
それとよろしければ、構造やコードの書き方などで「 もっとこうした方がよい 」という点がありましたら、ご指摘していただければ嬉しいです。
下記は、拙いですが、書籍を参考に私が書いたコードです。よろしくお願い致します。
#include <iostream>
using namespace std;
/*
仕様 :
ユーザーの入力を受け取り、ステージ上の ' p ' を動かす。
最終的にブロック( ' o ' )をゴールである ' . ' の位置に2つ共全て動かせば、ゲームクリアとなる
ゴール地点にある ' p ' や ' o ' は判別の為、大文字になる
*/
/* グローバル変数群 */
struct StgMaterial{
static const int width = 9;
static const int height = 5;
static const char wall = '#'; //壁
static const char space = ' '; //空き場所
static const char goal = '.'; //ゴール地点
static const char block = 'o'; //荷物
static const char blockIn = 'O'; //ゴール上の荷物
static const char player = 'p'; //プレイヤー
static const char playerIn = 'P'; //ゴール上のプレイヤー
const char stgData[ width * height ]; //読み取り用のステージデータ
};
static const StgMaterial stObj = {"\
########\n\
# .. p #\n\
# oo #\n\
# #\n\
########"
};
const enum ComFlag{ QUIT = 0, ENIT, LEFT, RIGHT, UP, DOWN, MISS }; //ユーザーのコマンド(QUITは終了用)
/* 関数プロトタイプ群 */
void initStg(char* const stgArr, const char* gStgData); // ステージデータの初期化
void disp(char* stgArr); // ゲーム画面出力
ComFlag getInput(char* stgArr, const StgMaterial* obj); // ユーザー入力を受け取る
void update(ComFlag flg, char* stgArr, const StgMaterial* obj); // ゲームの状態更新
bool checkClear(const char* stage, const StgMaterial* obj); // ゲームクリアしたかをチェック
/* 関数群 */
int main(){
char* stage = new char[ stObj.width * stObj.height ];
ComFlag flg = ENIT; //最初の初期化用
do{
if(flg != MISS){
update(flg, stage, &stObj);
disp(stage);
checkClear(stage, &stObj);
}
}while( flg = getInput(stage, &stObj) ); //QUITだったら抜ける
delete[] stage;
stage = NULL;
return 0;
}
void initStg(char* stgArr, const char* gStgData){
while( (*stgArr++) = (*gStgData++) ) ;
}
void disp(char* stgArr){
cout << stgArr << endl;
cout << "\na:left s:right w:up z:down q:end e:enitialize command?" << endl;
}
ComFlag getInput(char* stgArr, const StgMaterial* obj){
char command = '\0';
cin >> command;
switch( command ){
case 'a' : return LEFT;
case 's' : return RIGHT;
case 'w' : return UP;
case 'z' : return DOWN;
case 'e' : return ENIT;
case 'q' : return QUIT;
default:
cout << "入力データが不正です! a,s,w,z,e,q のいずれかを押してください\n" << endl;
return MISS;
}
}
void update(ComFlag flg, char* stgArr, const StgMaterial* obj){
if( flg == ENIT ){ //初期化コマンドが入力されていたら初期化する
initStg(stgArr, obj->stgData);
return;
}
int moveD = 0; //移動する方向
int pPos = 0; //プレイヤーの位置
int fPos = 0; //プレイヤーの移動先
char* dummy = stgArr;
for(; (*dummy != obj->player) && (*dummy != obj->playerIn); ++dummy){ pPos++; }
switch( flg ){
case LEFT : moveD = -1; break; //左のインデックスへ向ける
case RIGHT : moveD = 1; break; //右のインデックスへ向ける
case UP : moveD = -(obj->width); break; //上のインデックス(+9)へ向ける
case DOWN : moveD = obj->width ; break; //下のインデックス(-9)へ向ける
}
fPos = ( pPos + moveD );
if( (fPos >= 0) && (fPos <= (obj->width * obj->height)) ){ //はみ出し確認
if( (stgArr[ fPos ] == obj->space) || (stgArr[ fPos ] == obj->goal) ){ //移動先が空きスペースか、ゴールの場合
stgArr[ fPos ] = (stgArr[ fPos ] == obj->goal) ? obj->playerIn : obj->player; //移動先がゴールならゴール上のプレイヤーに(P)
stgArr[ pPos ] = (stgArr[ pPos ] == obj->playerIn) ? obj->goal : obj->space; //現在地がゴール(P)ならゴール(.)に
}else if( (stgArr[ fPos ] == obj->block) || (stgArr[ fPos ] == obj->blockIn) ){ //移動先が荷物の場合
if( (stgArr[ fPos + moveD ] == obj->wall) || (stgArr[ fPos + moveD ] == obj->block) || (stgArr[ fPos + moveD ] == obj->blockIn) ){
return; //荷物の先が壁か、荷物(ゴール上の荷物)の場合は何もせず抜ける
}
stgArr[ fPos + moveD ] = (stgArr[ fPos + moveD ] == obj->goal) ? obj->blockIn : obj->block; //荷物の先がゴールならゴール上の荷物(o → O)に
stgArr[ fPos ] = (stgArr[ fPos ] == obj->blockIn) ? obj->playerIn : obj->player; //荷物があった位置がゴールだった場合、ゴール上のプレイヤーに
stgArr[ pPos ] = (stgArr[ pPos ] == obj->playerIn) ? obj->goal : obj->space;
}else{ ;/* 壁なので何もしない */ }
}
}
bool checkClear(const char* stgArr, const StgMaterial* obj){
const char* check = stgArr;
while(*check++){
if( *check == obj->block ){
return false;
}
}
cout << "\nCongratulation's!!" << endl;
return true;
}