Large Display Size Middle Display Size Small Display Size
印刷用 概要 キーワード 著者

ゲームのしくみ:物体達の動作

複数の物体が同時に動く

test

 シューティングゲームなどで、複数の敵キャラが一度に動いて、自機に襲い掛かってくる…。
 RPGなどで、町の人々が同時に動き回っている…。
 ウィンドウシステムで、あるメニューがフェードアウトしながら、次の操作を行える…。


 このように、複数の物体が、時間軸に沿って同時に画面内を動くスクリプトのサンプルを作っていきましょう。

 いきなり完成したソースコードを見ても難しいと思うので、プログラミング開始時のシンプルな状態から、一つ一つコードを追加して順を追って見ていくような説明をします。

スクリプトの動作確認: Windows8.1 Firefox 29
Windows8.1 IE 11
Android4.0.3 Firefox 29
Android4.0.3 標準ブラウザ
Android2.2.1 標準ブラウザ


1. HTMLのDIVタグを利用

▲各物体はそれぞれ乱数を表示している。

ソースコード

 ここではHTMLのDIVタグを複数の物体として、簡単に複数の物体を作成します。
 Javascript の document.getElementsByName() を実行するだけで、物体の配列を簡単に作成できます。下記※1
 また、setInterval() により、一定時間ごとに各物体に対して操作を行います。下記※2
 ここでは各物体に乱数値を表示させています。下記※3


    function onloadx() {
        obj_names = document.getElementsByName( "obj_name" ); //※1
        intervalID = setInterval( "run()", 1000 ); //※2
    }

    function run() {
        var i;
        for( i = 0; i<obj_names.length; i++ ) {
            var obj = obj_names[ i ];
            obj.innerHTML = Math.random(); //※3
        }
    }


2. 手軽で簡単な乱数値を利用

▲各物体はそれぞれx,y座標を乱数で設定

ソースコード

 乱数値を物体のx,y座標とします。
 現状は、まだ物体の直接の座標 style.left, style.top には設定していません。



3. 複数の物体が同時に動いている処理を実現

▲各物体はそれぞれの座標に移動する。

ソースコード

 その座標を、物体の直接の座標に設定。
 これで、複数の物体が同時に動いている処理を実現できています。

 ソースコードを要約すると、”複数の物体を配列に入れて、一定時間ごとに各物体の座標を変更する” ということです。

 各物体は、それぞれで座標を持っているわけです。

 しかし、乱数で動いていると、わりとよくあるプログラムなので、以降は、それぞれの物体をもうちょっと個性的に、それぞれを独自路線で動かすようにしていきます。



4. 見た目を星に変更してキャラっぽく

▲星がキラキラ まばたいて いる。

ソースコード

 星★に変更しました。
 ちょっとした飾りのプログラムになりました。



5. ソースコードを合理的にする

▲星は斜め下へと移動していく。
流星群風。

ソースコード

 物体に個性的な動作を設定するためには、このソースコードのままだと、やりづらいのでソースコードの整備(合理的にする)を行います。
  • 最初に各物体の初期位置を乱数で決める。
  • 一定時間ごとの座標変更は関数にして、関数を切り替えるだけで、座標変更を直線的にしたり、円運動にしたりと自由に切り替えられるようにする。
 ひとまずは直線的に移動するノーマルな関数objmove()を作りました。 下記※1

《Before》
    function run() {
        var i;
        for( i = 0; i<obj_names.length; i++ ) {
            var obj = obj_names[ i ];
            //0~320
            obj.x = Math.floor( Math.random() * 320 );
            obj.y = Math.floor( Math.random() * 320 );
            obj.style.left = obj.x;
            obj.style.top = obj.y;
           
        }
    }
複数の物体を1つずつ処理するfor文。
座標の変更がじかに書かれている。

《After》
    function run() {
        var i;
        for( i = 0; i<obj_names.length; i++ ) {
            objmove( obj_names[ i ] ); //※1
        }
    }

    function objmove( obj ) {
        //0~320
        obj.x++;
        obj.y++;
        obj.style.left = obj.x;
        obj.style.top = obj.y;
    }
関数にすることで、物体ごとに座標の変更の仕方を変えやすくした。


6. 動きのバリエーション 動き方2:円運動

▲円運動。

ソースコード

 バリエーションを増やせるようになったので、
 次にバリエーションとして 円運動 を作成しました。
 円運動は見栄えがしますね。

  各物体ごとに動作方法を設定できるようにソースコードを変更しました。
 動作方法の設定は、各物体に "normal" とか "circle" とかの文字列変数を定義するだけです。
 一定時間ごとに各物体は、おのおのの動作方法で座標変更を実行します。


    function onloadx() {
~略~       
        //移動方法初期化
        obj_names[0].moveprogram = "normal";
        obj_names[1].moveprogram = "circle";
        obj_names[2].moveprogram = "circle";
        obj_names[3].moveprogram = "circle";
        obj_names[4].moveprogram = "circle";

        intervalID = setInterval( "run()", 100 );
    }

    function run() {
        var i;
        //各オブジェクトの移動
        for( i = 0; i<obj_names.length; i++ ) {
            var obj = obj_names[ i ];
            switch( obj.moveprogram ) {
                case "normal":
                    objmovenormal( obj );
                    break;
                case "circle":
                    objmovecircle( obj );
                    break;
                default:
                    objmovenormal( obj );
            }
        }
    }

 座標変更の関数 objmovenormal(), objmovecircle()  はオブジェクトを受け取り、オブジェクトのx,y座標値をじかに変更(絶対的に移動)したり、またはx,y座標値に加算(原点から相対的に移動)したりします。

コラム:円運動を使いこなしたい

 円運動は sin(), cos() という数学の関数を使います。
 小中学生には難しいところです。
 円運動なんて、ぜひゲームで使いたいような計算なのに。

 直線的な移動は、 x と y いずれかを増減させるだけなので簡単です。

 それに対し円運動は、円運動の中心からの角度を増減させて、その角度に対する x, y 座標を、y 座標は sin(角度), x 座標は cos(角度) を使って求める、というようなことを行います。

 sin(角度) や cos(角度) の中の角度は、0度~360度ではなく、0~2πラジアンという別の単位になっているので、難しく感じます。これは cm を インチ であらわすとか、円 を ドル であらわすとかと ほとんど同じことなので、ちょっと難しく 感じる、というそれだけのものです。
 また、sin() や cos() にラジアンの角度を入れて答えを出すと、0~1の数値が出てきます。円の半径を1としたとき、x 座標はいくつ、y 座標はいくつ、というモノなので、こんな感じになります。

 x座標 = cos( ラジアンの角度 ) * 半径
 y座標 = sin( ラジアンの角度 ) * 半径

そしてさらに、プログラムではこうなっています。

var x = Math.floor( Math.cos( 2*3.14/360 * kakustep * obj.counter ) * 100 );
var y = Math.floor( Math.sin( 2*3.14/360 * kakustep * obj.counter ) * 100 );

ラジアンの角度の部分が複雑です。

2*3.14/360

 ラジアンの角度では、0~2π ラジアンが単純に 0~360 度に対応します。
 2π は 2*3.14 です。
 2*3.14 を 360 度で割ると、1 度当たりのラジアンとなります。
 2*3.14/360 は 1 度当たりのラジアンを求めています。


kakustep * obj.counter

 kakustep は、たとえば直線移動では 「何ドットずつ右に進む」 とかありますが、それと同じです。何度ずつ回るのか 0~360 度の角度であらわしています。
 obj.counter は、その物体の円運動の進み具合です。直線移動でいえば、1回の移動が16ドットずつであるとき、5回の移動で16*5ドット移動したことになります。この5回というのと同じ進み具合のことです。
 というわけで kakustep * obj.counter の式は、その物体の円運動の進み具合を 0~360 度の角度であらわしている、ということになります。

 そこに 1 度当たりのラジアンを掛ければ、その物体の円運動の進み具合をラジアンの角度であらわすことになります。

 以上説明ではとりあえず、小中学生でもなんとか物体を円運動させられるかなと思いますが、この説明だけだと、本当に自由に円運動を使いこなせないと思います。任意の場所から回し始めるとか、逆向きに回すとか、説明していません。また、ちょっと説明が丁寧じゃないかも?
(時間の関係で割愛します)


7. ソースコードを合理的にする 2

▲見た目の動きは特に変わらないが、可能性が高まっている。

ソースコード

 オブジェクトごとに細かい動作設定をできるようにしました。

《Before

obj_names[1].moveprogram = "circle";
 この文字列を一定時間ごとにswitch文に渡し、対応する座標計算を行っていた。
  ↓
《After》
obj_names[1].moveprogram = "objmovecircle( obj, 12, 20 )";
 この文字列を一定時間ごとに、JavaScriptのeval()関数に渡し、座標計算の関数を実行。
 引数を文字列中に記述できるので、細かい設定が可能になる。



8. 動きのバリエーション 動き方2:逆向きの円運動

▲逆に回っている星を作成

ソースコード

 本題とはあまり関係ありませんが、バリエーションを増やしました。



9. 動きのバリエーション 動き方3:細かく決めた座標に沿って移動と、動き方4:サインカーブ

▲2種類の動きを追加

ソースコード

 サインカーブと、それから、計算ではなく決めた座標の通りに動くという動きも追加しました。



10. 色の違いをつけました。

▲色付き。

ソースコード

 色を付けました。



11. 最終的なソースコード

▲複数の物体を同時に動かす。

ソースコード

 本題とはあまり関係のない装飾をいろいろつけすぎたので、説明のため、動きも、ソースコードもシンプル化しました。

 このページの冒頭の横長の黒い部分で行っていた星の動きと同じものです。

 一定時間ごとに繰り返す、複数の物体を配列に入れて管理する、という感じで、複数の物体が、時間軸に沿って同時に画面内を動くという処理を実現できます。




ページ制作 homepage6047


ページの上端へ (もくじ開く)