ゲームプログラミング技術集 
ひっと

十字キーと8方向キーの方向判定

スマホアプリに方向キーを実装したり、ドラッグ方向の判定に使います。十字キーと8方向キーの方向判定について説明します。

十字キーの入力方向判定

十字キーの中心を原点とすると、図のようになります。

上: y > |x|
下: y < -|x|
右: x > |y|
左: x < -|y|

境界上を判定に加える場合は、等号を含めます。
y >= |x|

8方向キーの入力方向判定

 8方向キーの場合は、境界ベクトルと入力方向の内積から判定できます。 (ベクトル内積には順方向だとプラス。逆方向だとマイナスになる性質があります)

オレンジ色のエリアにPがあると、V1・Pがプラスになります。
グリーン色のエリアにPがあると、V4・Pがプラスになります。

 図の点Pは、V1・PとV4・Pが両方プラスなので左上と判定できます。


方向キーの入力方向判定 プログラミング例

十字キー用と8方向キー用。それぞれ独立した関数です。
#include <math.h>

//ベクトルの方向判定( 上下左右の4方向 )
int VectorDirection4( double x, double y )  //戻り値 0:上    1:左    2:下    3:右    -1:エラー
{
    if( y == 0 && x == 0 ) { return -1; }

    //境界上の判定の場合、左右より上下が優先になります

    if( y >=  abs(x) ) { return 0; } //上
    if( y <= -abs(x) ) { return 2; } //下

    if( x < -abs(y)  ) { return 1; } //左
    if( x >  abs(y)  ) { return 3; } //右
        
    return -1;    //こないはず
}

//ベクトルの方向判定( 縦横斜めの8方向 )
int VectorDirection8( double x, double y )  //戻り値  0:上  1:左上  2:左  3:左下  4:下  5:右下  6:右  7:右上 -1:エラー
{
    #define M_PI       3.14159265358979323846
    int i;

    if( y == 0 && x == 0 ) { return -1; }

    //境界のベクトル 境界ベクトルは8本ですがそのうち4つあれば計算できます。
    //固定値なのであらかじめ計算しておくとよいでしょう。
    double work_vx[4];    
    double work_vy[4];
    double rad;
    for( i = 0 ; i < 4; i++ ) {
        rad = ( ( 22.5 + i * 45 ) * M_PI ) / 180;

        work_vx[i] = cos( rad ); 
        work_vy[i] = sin( rad );
    }

    //各ベクトルと内積を行い結果を格納します
    double dot_result[8];
    for( i = 0 ; i < 4; i++ ) {
        dot_result[i] = work_vx[i] * x + work_vy[i] * y;

        //反対側ベクトルの内積値は符号反転でよい
        dot_result[i+4] = - dot_result[i];
    }

    //境界ベクトル上に入力点があった場合は、半時計周りにある方向を優先します
    if( dot_result[0] > 0 && dot_result[3] >= 0 ) { return 0; }//上
    if( dot_result[1] > 0 && dot_result[4] >= 0 ) { return 1; }//左上
    if( dot_result[2] > 0 && dot_result[5] >= 0 ) { return 2; }//左
    if( dot_result[3] > 0 && dot_result[6] >= 0 ) { return 3; }//左下
    if( dot_result[4] > 0 && dot_result[7] >= 0 ) { return 4; }//下
    if( dot_result[5] > 0 && dot_result[0] >= 0 ) { return 5; }//右下
    if( dot_result[6] > 0 && dot_result[1] >= 0 ) { return 6; }//右
    if( dot_result[7] > 0 && dot_result[2] >= 0 ) { return 7; }//右上
    
    return -1;    //こないはず
}