Flashゲーム講座 & アクションスクリプトサンプル集



ベクトルとは?

 
 


 
ベクトルとは?

ベクトルは、 方向 を矢印で現したもので、矢印の向きが方向になり長さが力を意味します。
 
 
ベクトルをプログラムで表現する

2D座標の場合、x 方向成分とy 方向成分で表現します。
 
 
例) ベクトルを変数で表現

    x = 2;
    y = 1;
 
ベクトルの概念

ベクトルは、方向と力だけを表した物なので矢印がどの座標から始まるかということに意味はありません。
 
 
どの位置にあっても矢印の向きと長さが一致していればそれは等しいベクトルです。
 
 
…と、こう書くと「あれ?じゃあベクトルで位置は表現できないの?」と思ってしまいます。というか筆者はこれでえらく混乱しましたが、ベクトルで位置を表現することは可能です。

「ある座標を開始位置として矢印が伸びる」という概念は確かに無いのですが、下の図のようにベクトルの x, y 成分と座標の値は一致するので「(ベクトルの x y 成分) = (座標)」と考える事ができます。(…と勝手に脳内解釈

この座標の意味を持たせているベクトルを、位置ベクトルと言います。
 

 
ベクトルから得られるデータ

ベクトルは ( x , y ) という2つのパラメータだけで表現しますが、ここから以下の式でいつでも、角度とベクトルの長さを求めることができます。
 
 
例) ベクトルから角度を抽出

    x = 2;
    y = 1;
    rotation = Math.atan2(y,x) * 180 / Math.PI;
 
 
例) ベクトルから長さを抽出

    x = 2;
    y = 1;
    length = Math.sqrt(x * x + y * y);
 
ということはベクトルは、2つの値だけで潜在的に、角度とベクトルの長さの情報も含まれていることになります。
 
ベクトルを使うために
 
ベクトルの計算をするためには、ベクトルの関数を使います。ここからソースをダウンロードして、中身をコピーアンドペーストしてタイムラインの1番目に張るか、ファイルごとインクルードしてください。Flash8以降なら Point クラスを使用することをお勧めします。
 
ベクトルが内部でどういう演算をしているかを理解する必要はありません。それより、関数の使い方を理解しパズルの要領で使いこなせるようになる事が重要です。 将来どこかの会社から供給されているベクトルのライブラリにめぐり合ったとしても同等の機能を持つ関数がある事でしょう。
 
 




ベクトルで座標を移動させよう

 
サンプルをダウンロード
 


 
ベクトルを作ろう


さて、これからベクトルを使ってムービークリップの位置を表現してみようと思います。まず適当なムービークリップを作って player というインスタンス名を付けましょう。
 
 
まず、位置ベクトルを作ります。Vec2dCreate( x , y ) という関数を使います。 第01引数にx方向の成分、第02引数に y 方向の成分を入れてください。
 
例) (10 ,2) の位置ベクトルを作成

onClipEvent (load) {
    var pos = _root.Vec2dCreate(10, 2);
}
 
pos という変数にオブジェクトが返ります。
このオブジェクトには x と y という2つのパラメータがあります。


    pos.x;
    pos.y;
 
そこでオブジェクトからパラメータを取り出して、座標に代入します。
 
例) ベクトルを取り出して座標に反映

onClipEvent (load) {
    var pos = _root.Vec2dCreate(10, 2);
}

onClipEvent (enterFrame) {
    _x = pos.x;
    _y = pos.y;
}
 
これで位置が表現できました。
 
ベクトルを加算しよう


ベクトルの加算を図に表すと下のようになります。ベクトルAとベクトルBを加算したい場合はベクトルAの最後にベクトルBを配置して、ベクトルAの開始座標からベクトルBの終了座標まで線を引きます。
 
 
 
 
プログラムで計算するには、Vec2dAdd( v , v ); 関数を使います。 第一引数にベクトル、第二引数にベクトルを代入すると戻り値として加算されたベクトルが返ってきます。
 
例) 加算ベクトルの使用例

    var vec1 = _root.Vec2dCreate(0, 0);
    var vec2 = _root.Vec2dCreate(1, 1);

    var vec3 = _root.Vec2dAdd( vec1 , vec2 );
 
加算を使ってキャラクターを動かそう
 
さてキャラクターをベクトルで移動させたいと思います。移動量用のベクトルを新たに作って位置ベクトルと加算してみます。 Vec2dCreate() 関数を使って移動量ベクトルを作ります。 ここでは、1 フレームごとに (1,1) ずつ移動させる事にします。
 
例) 移動量ベクトルを作成

onClipEvent (load) {
    var pos = _root.Vec2dCreate(0, 0);
    var spd = _root.Vec2dCreate(1, 1);
}

onClipEvent (enterFrame) {
    _x = pos.x;
    _y = pos.y;
}
 
位置ベクトルに移動量ベクトルを加算して新たな位置ベクトルを生成します。
 
 
 
 
これを繰り返せば少しずつ右下に移動していく事がわかると思います。
 
例) 移動量ベクトルを作成

onClipEvent (load) {
    var pos = _root.Vec2dCreate(0, 0);
    var spd = _root.Vec2dCreate(1, 1);
}

onClipEvent (enterFrame) {
    pos = _root.Vec2dAdd( pos , spd );
    _x = pos.x;
    _y = pos.y;
}
 

 




ベクトルで目的地まで移動させよう

 
サンプルをダウンロード
 


 
ベクトルを減算しよう


ベクトルの減算を図に表すと下のようになります。ベクトルAからベクトルBを減算したい場合はベクトルAの開始点にベクトルBを配置して、ベクトルBの終了座標からベクトルAの終了座標まで線を引いた矢印になります。
 
 
 
 
減算ベクトルは、計算する順番が違うと向きが変わってしまうので注意してください。
 
プログラムで計算するには、Vec2dSub( v , v ); 関数を使います。 第一引数にベクトル、第二引数にベクトルを代入すると戻り値として減算されたベクトルが返ってきます。
 
例) 減算ベクトルの使用例

    var vec1 = _root.Vec2dCreate(0, 0);
    var vec2 = _root.Vec2dCreate(1, 1);

    var vec3 = _root.Vec2dSub( vec1 , vec2 );
 
減算を使って目的地までのベクトルを調べよう
 
さてキャラクターを目的地まで移動させたいと思います。自分の立っている座標をAとします。目的地の座標をBとします。 まずAからBに向かって矢印を引くようなベクトルを調べる事にしましょう。
 
 
 
 
図のように位置ベクトルBから位置ベクトルAを減算すると、座標Aから座標Bまで線を引いたベクトルを求める事ができます。
 
例) AからBまでのベクトル

    var pos_a = _root.Vec2dCreate(50, 10);
    var pos_b = _root.Vec2dCreate(10, 50);

    var vec = _root.Vec2dSub( pos_b , pos_a );
 
このベクトルはさらに加工する必要があります。というのもこのベクトルは方向成分は使えるのですが、長さを何とかしないと目的地まで少しずつ動かすという目的が達成できません。 そこで、スケーリングを使います。
 
ベクトルをスケーリングしよう


ベクトルのスケーリングです。矢印全体に倍率を指定して拡大縮小変換します。方向成分を変えずに長さ(スカラー)だけ変えれるのが特徴です。
 
 
 
 
プログラムで計算するには、Vec2dScale( v , scale ); 関数を使います。 第一引数にベクトル、第二引数に倍率を代入すると戻り値としてされたベクトルが返ってきます。
 
例) スケーリングベクトルの使用例

    var vec1 = _root.Vec2dCreate(1, 2);
    var vec2 = _root.Vec2dScale( vec1 , 0.75 );
 
 
 
数フレームで目的地に到達させよう
 
先ほどは、目的地の位置ベクトルから今いる位置ベクトルを減算すると、目的地までのベクトルが計算できる事がわかりました。
 
このベクトルを、加工して5フレームで目的地に到達できるような移動量を持つベクトルに変換してみましょう。
 
 
 
 
 
例) AからBまでのベクトル

    var pos_a = _root.Vec2dCreate(100, 20);
    var pos_b = _root.Vec2dCreate(10, 100);

    var vec = _root.Vec2dSub( pos_b , pos_a );
    var vec = _root.Vec2dScale( vec , 1/5 );
 
これだと、数フレームで到達する移動ベクトルが求まりますが、目的地までの距離によって速さが変化してしまいます。好きな移動速度にしたい場合は、次で解説する正規化を使用します。
 

 




ベクトルで移動制限を付けよう

 

サンプルをダウンロード
 


 
ベクトルを正規化しよう


ベクトルの正規化とは向きをそのままで長さが 1 になるような矢印にする事です。ベクトルの正規化を図に表すと下のようになります。
 
 
 
プログラムで計算するには、Vec2dNormalize( v ); 関数を使います。 第一引数にベクトルを代入すると戻り値として正規化されたベクトルが返ってきます。
 
例) ベクトルの正規化例

    var vec1 = _root.Vec2dCreate(2, 5);
    var vec2 = _root.Vec2dNormalize(vec1);
 
長さが 1 になるということは、この後スケーリング変換をかけると好きな長さに変換する事ができます。
 
 
例えば 2.5 という長さにしたいときは、適当なベクトルを正規化してから、2.5 倍にすると求まります。
 
 
目的地まで一定の速度で進むベクトルを調べよう
 
さてキャラクターを目的地まで移動させたいと思います。自分の立っている座標をAとします。目的地の座標をBとします。 まずAからBに向かって矢印を引くようなベクトルを調べる事にしましょう。
 
 
 
 
図のように位置ベクトルBから位置ベクトルAを減算し、そのベクトルを正規化します。その後に好きな値でスケーリング変換をかけると その長さのベクトルが求まります。
 
例) AからBの方向を向いた長さが2のベクトル

    var pos_a = _root.Vec2dCreate(100, 20);
    var pos_b = _root.Vec2dCreate(10, 100);

    var vec = _root.Vec2dSub( pos_b , pos_a );
    vec = _root.Vec2dNormalize( vec );
    vec = _root.Vec2dScale( vec , 2 );

サンプル - vector_02_fla5.zip(5kバイト)ZIP ファイル



これでベクトルを好きな長さに変換する方法がわかりました。
 
さらに別の使い方を見てみましょう。
 
最高速度を設定しよう


実際にベクトルを使った操作を考えてみましょう。まず自分の座標を表す位置ベクトルと、自分の移動量を表す移動ベクトルを作りましょう。
 
例) 位置ベクトルと移動ベクトルを作る

onClipEvent (load) {
    var pos = _root.Vec2dCreate(200, 150);
    var spd = _root.Vec2dCreate(0, 0);
}
 
毎フレーム、移動ベクトルを位置ベクトルに加算する処理を実行します。
 
例) 移動ベクトルを位置ベクトルに加算する

onClipEvent (enterFrame) {
    var pos = _root.Vec2dAdd(pos, spd);
}
 
位置ベクトルからパラメータを取り出して座標に反映します。
 
例) 位置ベクトルを座標に反映する

onClipEvent (enterFrame) {
    var pos = _root.Vec2dAdd(pos, spd);

    _x = pos.x;
    _y = pos.y;
}
 
キーボードの入力から方向データを抽出します。成分 (0, 0) のベクトルを作り押された方向によって ±1 加算します。
 
 
例) キー入力からベクトルを作る

onClipEvent (enterFrame) {

    // 押した方向によってベクトル成分を加算
    var vec = _root.Vec2dCreate(0 , 0);
    if(Key.isDown(Key.UP))      vec.y -= 1;
    if(Key.isDown(Key.DOWN))    vec.y += 1;
    if(Key.isDown(Key.LEFT))    vec.x -= 1;
    if(Key.isDown(Key.RIGHT))   vec.x += 1;

    var pos = _root.Vec2dAdd(pos, spd);

    _x = pos.x;
    _y = pos.y;
}
 
一度正規化して方向成分だけにします。
 
 
例) 正規化して長さを一定にする

onClipEvent (enterFrame) {

    // 押した方向によってベクトル成分を加算
    var vec = _root.Vec2dCreate(0 , 0);
    if(Key.isDown(Key.UP))      vec.y -= 1;
    if(Key.isDown(Key.DOWN))    vec.y += 1;
    if(Key.isDown(Key.LEFT))    vec.x -= 1;
    if(Key.isDown(Key.RIGHT))   vec.x += 1;
    vec = _root.Vec2dNormalize( vec );

    var pos = _root.Vec2dAdd(pos, spd);

    _x = pos.x;
    _y = pos.y;
}
 
さらに好きな値でスケーリングします。このベクトルを加速ベクトルとします。
 
例) スケーリングして加速量を設定する

onClipEvent (enterFrame) {

    // 押した方向によってベクトル成分を加算
    var vec = _root.Vec2dCreate(0 , 0);
    if(Key.isDown(Key.UP))      vec.y -= 1;
    if(Key.isDown(Key.DOWN))    vec.y += 1;
    if(Key.isDown(Key.LEFT))    vec.x -= 1;
    if(Key.isDown(Key.RIGHT))   vec.x += 1;
    vec = _root.Vec2dNormalize( vec );
    vec = _root.Vec2dScale( vec , 0.5);

    var pos = _root.Vec2dAdd(pos, spd);

    _x = pos.x;
    _y = pos.y;
}
 
加速ベクトルを移動ベクトルに加算します。
 
例) 加速量を移動量に加算する

onClipEvent (enterFrame) {

    // 押した方向によってベクトル成分を加算
    var vec = _root.Vec2dCreate(0 , 0);
    if(Key.isDown(Key.UP))      vec.y -= 1;
    if(Key.isDown(Key.DOWN))    vec.y += 1;
    if(Key.isDown(Key.LEFT))    vec.x -= 1;
    if(Key.isDown(Key.RIGHT))   vec.x += 1;
    vec = _root.Vec2dNormalize( vec );
    vec = _root.Vec2dScale( vec , 0.5 );
    
    spd = _root.Vec2dAdd(spd , vec);

    var pos = _root.Vec2dAdd(pos, spd);

    _x = pos.x;
    _y = pos.y;
}
 
ここが本題です。このまま実行すると、いくらでも移動量が増えてしまいます。そこで移動量に制限をつけることにしましょう。 移動量が5以上のときは 5 に戻すようにします。まず、現在の移動量の長さを調べます。
 
 
 
 
ベクトルの長さを調べるには、Vec2dLength( v ); 関数を使います。 第一引数にベクトルを代入すると戻り値として長さが返ってきます。
 
例) ベクトルの長さを調べる

    var vec = _root.Vec2dCreate(50, 10);

    var length = _root.Vec2dLength( vec );
 
 
 
では、プログラムを見てみましょう。
まず移動量の長さが 5 より大きいか調べます。
 
例) 最高移動量を超えていないかを調べる

onClipEvent (enterFrame) {

    // 押した方向によってベクトル成分を加算
    var vec = _root.Vec2dCreate(0 , 0);
    if(Key.isDown(Key.UP))      vec.y -= 1;
    if(Key.isDown(Key.DOWN))    vec.y += 1;
    if(Key.isDown(Key.LEFT))    vec.x -= 1;
    if(Key.isDown(Key.RIGHT))   vec.x += 1;
    vec = _root.Vec2dNormalize( vec );
    vec = _root.Vec2dScale( vec , 0.5 );
    
    spd = _root.Vec2dAdd(spd , vec);
    
    if(_root.Vec2dLength(spd) > 5){
    
    }

    var pos = _root.Vec2dAdd(pos, spd);

    _x = pos.x;
    _y = pos.y;
}
 
5 より大きい場合、移動量を正規化して長さが 5 になるようにします。
 
例) 移動量制限を付ける

onClipEvent (enterFrame) {

    // 押した方向によってベクトル成分を加算
    var vec = _root.Vec2dCreate(0 , 0);
    if(Key.isDown(Key.UP))      vec.y -= 1;
    if(Key.isDown(Key.DOWN))    vec.y += 1;
    if(Key.isDown(Key.LEFT))    vec.x -= 1;
    if(Key.isDown(Key.RIGHT))   vec.x += 1;
    vec = _root.Vec2dNormalize( vec );
    vec = _root.Vec2dScale( vec , 0.5 );
    
    spd = _root.Vec2dAdd(spd , vec);
    
    if(_root.Vec2dLength(spd) > 5){
        spd = _root.Vec2dNormalize( spd );
        spd = _root.Vec2dScale( spd , 5 );
    }

    var pos = _root.Vec2dAdd(pos, spd);

    _x = pos.x;
    _y = pos.y;
}
 
 
最後に移動時の摩擦として速度に( 0 ~ 1.0) の値でスケーリングし続けます。
 
例) 摩擦

onClipEvent (enterFrame) {

    // 押した方向によってベクトル成分を加算
    var vec = _root.Vec2dCreate(0 , 0);
    if(Key.isDown(Key.UP))      vec.y -= 1;
    if(Key.isDown(Key.DOWN))    vec.y += 1;
    if(Key.isDown(Key.LEFT))    vec.x -= 1;
    if(Key.isDown(Key.RIGHT))   vec.x += 1;
    vec = _root.Vec2dNormalize( vec );
    vec = _root.Vec2dScale( vec , 0.5 );
    
    spd = _root.Vec2dAdd(spd , vec);
    
    if(_root.Vec2dLength(spd) > 5){
    
    }
    
    spd = _root.Vec2dScale(spd , 0.9);
    

    var pos = _root.Vec2dAdd(pos, spd);

    _x = pos.x;
    _y = pos.y;
}
 
 
ベクトルの移動の使い方は以上です。

3Dベクトルの移動計算は、さらにZ軸が増えるだけです。基本的な使い方は同じです。
 

 




反射ベクトルと滑りベクトル

 

サンプルをダウンロード
 

サンプルをダウンロード
 


 
ベクトルと壁との衝突


ベクトルが壁に当たったときに移動する方向を調べます。 壁との衝突を調べる方法はこちらで解説しています。

レイ交差判定(=線分と線分の当たり判定)

円と線分の衝突判定

 
 
 
 
 
法線とは?


法線とは、坂から垂直に立っている長さが1のベクトルの事です。

 
 
 
法線の計算方法


2D座標の場合、坂は2つの座標で現せます。 1つ目の座標から2つ目の座標まで線を引いて、時計回りに 90 回転して正規化してみましょう。それが法線となります。
 
 
もし1つ目の座標と2つ目の座標の順序が入れ替わると法線は反転しまったく別の法線になるので注意しましょう。
 
 
また、図のように表と裏が出来る事にも注目しましょう。法線の伸びる方向が表となります。この表と裏は重要です。 なぜなら表側から進入してきたベクトルは計算できますが裏側から進入してきたベクトルとでは物理的に計算できないからです。
 
また、進入ベクトルの長さが 0 の場合や進入ベクトルと法線が平行の場合も物理的に接触できないため計算できません。






反射ベクトルの計算方法


 
 
反射ベクトルを計算する関数です。 第01引数にスピードベクトル、第02引数に法線を指定します。戻り値に反射後のベクトルが返ります。
 
例) 2D反射ベクトルを計算する関数

function Vec2dReflect(spd,nor){
    var t = -(nor.x * spd.x + nor.y * spd.y)/
(nor.x * nor.x + nor.y * nor.y); return { x : spd.x + t * nor.x * 2.0, y : spd.y + t * nor.y * 2.0 }; }
 
3Dの場合です。
 
例) 3D反射ベクトルを計算する関数

function Vec3dReflect(spd,nor){
    var t = -(nor.x * spd.x + nor.y * spd.y + nor.z * spd.z)/
(nor.x * nor.x + nor.y * nor.y + nor.z * nor.z); return { x : spd.x + t * nor.x * 2.0, y : spd.y + t * nor.y * 2.0, z : spd.z + t * nor.z * 2.0 }; }







滑りベクトルの計算方法


 
 
滑りベクトルを計算する関数です。 第01引数にスピードベクトル、第02引数に法線を指定します。戻り値に滑りベクトルが返ります。
 
例) 2D滑りベクトルを計算する関数

function Vec3dSlide(spd,nor){
    var t = -(nor.x * spd.x + nor.y * spd.y)/
(nor.x * nor.x + nor.y * nor.y); return { x : spd.x + t * nor.x, y : spd.y + t * nor.y }; }
 
3Dの場合です。
 
例) 3D滑りベクトルを計算する関数

function Vec2dSlide(spd,nor){
    var t = -(nor.x * spd.x + nor.y * spd.y + nor.z * spd.z)/
(nor.x * nor.x + nor.y * nor.y + nor.z * nor.z); return { x : spd.x + t * nor.x, y : spd.y + t * nor.y, z : spd.z + t * nor.z }; }