home > programming > notes >

アナログ入力の斜め補正

2Dのアクションゲームでよく言われるのが、斜めに入力したときのキャラクタの移動速度です。

X軸、Y軸の入力値をそのままキャラクタの移動量に反映させると、X軸またはY軸に水平に移動したときに比べて、斜め移動したときの移動量が大きくなってしまうという問題です。

斜め移動の問題

これを回避するには、移動量が同じになるよう補正しなければなりません。図の緑色のベクトルが補正後の移動量となります。

デジタル8方向入力の場合、斜め45度の入力に対しX,Yの移動量をそれぞれ1/ルート2にすれば良い事になります(1/ルート2は約0.7)。

アナログ入力の場合、少し面倒な事になります。入力最大値をmaxとすると、X,Yの入力値はそれぞれ-max〜maxの自由な値を取るので、これをうまく変換しなくてはなりません。具体的には、図の四角い領域から、丸い水色の領域へ変換を行います。

この処理を行うC++ソースは以下のようになります。

// ix, iy : 入力値(-imax〜imax)
// imax   : 入力最大値
// x , y  : キャラクタ座標
// speed  : キャラクタの移動速度

float vx, vy;
vx = static_cast<float>(ix) / static_cast<float>(imax);
vy = static_cast<float>(iy) / static_cast<float>(imax);

if (vx * vx + vy * vy > 0.000001f)  //長さが0に近くなければ斜め補正を行う
{
        float a = (fabs(vx) >= fabs(vy)) ? vy / vx : vx / vy;       //絶対値の小さい方を大きい方で割る
        float b = 1.0f / sqrt(1.0f + a * a);        //補正比

        vx *= b;
        vy *= b;
}

//スピードを掛けて、移動。ifの中に置いても問題ない
vx *= speed;
vy *= speed;

x += vx;
y += vy;

処理内容ですが、入力ベクトルを外側の四角まで伸ばしたときの長さとそれを円に接するよう補正したときの長さの比を求め、それを元の入力ベクトルに適用する……といった感じです。

変換