ちょっと改良
とりあえず、プレイヤーの位置を動かして表示することはできた。
ここで、UpdateDraw()を少し見直してみよう。
void UpdatePlay() { int c = _getch(); Point crrP = GetPlayerPos(sampleSatge); Point nextP; if (c == 'd' || c == 'D') { nextP = { crrP.x + 1, crrP.y }; } else if (c == 'a' || c == 'A') { nextP = { crrP.x - 1, crrP.y }; } else if (c == 'w' || c == 'W') { nextP = { crrP.x, crrP.y - 1 }; } else if (c == 's' || c == 'S') { nextP = { crrP.x, crrP.y + 1 }; } else { nextP = crrP; //変な入力あったら(wasd以外)何も変わらず } SetObjtoMap(OBJNAME::FLOOR, crrP, sampleSatge); SetObjtoMap(OBJNAME::HUMAN, nextP, sampleSatge); }
こういうコードは、実際よく見ます。入力によってif文を分けて、方向別に座標を移動しよう!ってコード。
4方向移動 その1
4方向移動 その2
探すとなんぼでもあるし、特に悪いことのあるコードではないしよく書くと思う。
(でも多少うざいし、やってることがプラスする座標値が違うだけで全部一緒なんだよねぇ)
こういうところはすっきりかけるか可能性を探りましょう。
まず、ちょっと書き方を変えてみよう。
void UpdatePlay() { int c = _getch(); Point crrP = GetPlayerPos(sampleSatge); Point nextP; if (c == 'd' || c == 'D') { nextP = { crrP.x + 1, crrP.y + 0 }; } else if (c == 'a' || c == 'A') { nextP = { crrP.x - 1, crrP.y + 0 }; } else if (c == 'w' || c == 'W') { nextP = { crrP.x + 0, crrP.y - 1 }; } else if (c == 's' || c == 'S') { nextP = { crrP.x + 0, crrP.y + 1 }; } else { nextP = { crrP.x + 0, crrP.x + 0 }; //変な入力あったら(wasd以外)何も変わらず } SetObjtoMap(OBJNAME::FLOOR, crrP, sampleSatge); SetObjtoMap(OBJNAME::HUMAN, nextP, sampleSatge); }
まったく同じ形(数式上)で上下左右の移動を書くことができている気がする。
抜き出してみよう
右移動 nextP = { crrP.x + 1, crrP.y + 0 }; => nextP = crrP + Point{+1, 0}
左移動 nextP = { crrP.x - 1, crrP.y + 0 }; => nextP = crrP + Point{-1, 0}
上移動 nextP = { crrP.x + 0, crrP.y - 1 }; => nextP = crrP + Point{ 0, -1}
下移動 nextP = { crrP.x + 0, crrP.y + 1 }; => nextP = crrP + Point{ 0, +1}
無移動 nextP = { crrP.x + 0, crrP.x + 0 }; => nextP = crrP + Point{ 0, 0}
つまり$ nextP = crrP + dirVector $の形で書けているのがわかる。
後ろのdirVectorをenumと配列を組み合わせて以下のようにしてみると
enum direction { UP,LEFT,DOWN,RIGHT,NONE }; dirVector[5]; dirVector[ UP] = { 0, -1}; dirVector[ LEFT] = {-1, 0}; dirVector[ DOWN] = { 0, +1}; dirVector[RIGHT] = {+1, 0}; dirVector[ NONE] = { 0, 0};
入力方向directionさえわかれば、4つあった移動の式が
direction _dir=//入力でとってきて値を入れる\\ nextP = {crrP.x + dirVector[_dir].x, crrP.y + dirVector[_dir].y};
こうまとめられる。
あとは、_dirをどうにかこうにか入力から導き出せれば勝てそうな気がする。
入力から方向を返す関数を作る
現在は、入力方向の取得はUpdatePlay()の中で以下のようになっている。
void UpdatePlay()
{
//入力を取得
int c = _getch();
//上下左右の移動の処理ずらずら。。。
}
このcを受け取って、directionにして返す関数を作る
やることは簡単でwasdに対応したdirectionとして、
- w or W ⇒ UP
- a or A ⇒ LEFT
- s or S ⇒ DOWN
- d or D ⇒ RIGHT
- その他 ⇒ NONE
を返す関数を作る
enum direction
{
UP,LEFT,DOWN,RIGHT,NONE
};
何の型返す? GetDirection(char _c)
{
switch (何でスイッチすればいい?)
{
case 'a':
case 'A':
return(対応する方向を返す);
break;
case 's':
case 'S':
return(対応する方向を返す);
break;
case 'd':
case 'D':
return(対応する方向を返す);
break;
case 'w':
case 'W':
return(対応する方向を返す);
break;
default:
return(対応する方向?を返す);
}
}
これを作っておいて、UpdatePlayに追加してみよう
Point dirVector[5] =
{
{ 0, -1 },{ -1, 0 },{ 0, +1 },{ +1, 0 },{ 0, 0 }
};
void UpdatePlay()
{
int c = _getch()
//入力された方向を表す文字のASCIIコードから、direction型の方向に変換する
direction nextDir = GetDirection(c);
Point crrP = GetPlayerPos(sampleSatge);
Point nextP = { crrP.xとdirVector[nextDir].xでx座標を更新, crrP.yとdirVector[nextDir].yでy座標を更新 };
SetObjtoMapでグローバル変数sampleSatgeのcrrPに対応する位置にOBJNAME::FLOORを設定(元居た場所からプレイヤーを削除して床をセット)
SetObjtoMapでグローバル変数sampleSatgeのnextPに対応する位置にOBJNAME::HUMANを設定(計算したプレイヤー位置にプレイヤーをセット)
}
UpdatePlayから、if文の羅列が消えてとてもすっきりしたね。