yoppa.org


Web動画表現 2010

AS3でアニメーションを作成する 3 – たくさん物体を同時に動かす

たくさんの図形を動かすには

先週の授業では、ムービークリップの座標(x, y)の情報を、フレームが更新するたびに少しずつ変化させることで物体が動いてみえるという、アニメーションの基本原理について、ActionScriptでプログラムしました。

では、複数の図形を別々に同時に動かすにはどうすれば良いでしょうか。その方法について、考えていきたいと思います。

スクリプトのテンプレート

今回もプログラムを進めるにあたって利用すると便利なテンプレートを作成しました。下記のコードをコピーして使用してください。

package {
  import flash.display.*;
  import flash.events.*;

  public class Main extends Sprite {
  //ここにグローバルな変数を記入

    public function Main() {
    //初期設定の項目を記入
            
      //フレーム更新のイベントリスナーの登録
      this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
    }

    //イベントハンドラ
    function enterFrameHandler(event:Event):void {

    }
  }
}

ムービクリップの用意

まず、先週と同様にAS3形式のFLAファイルを用意します。その上でムービークリップシンボルとして「Ball」というクラス名でシンボルを用意します。ムービークリップには円の形を描いておきます。

次に、このFLAファイルのムービーのプロパティーで、クラスの設定を「Main」にします。そしてこのFLAファイルがあるフォルダと同じフォルダに「Main.as」というファイルをActionScriptファイルとして作成します。このMain.as内に先程のスクリプトのテンプレートをコピーしてペーストしてください。

これで準備は完了です。

アニメーションの基本形

今日は、まず下記のような上下にバウンドするボールのアニメーションを、基本的な動きとして使用します。単体のアニメーションを実現するスクリプトは下記のようになります。

package {
  import flash.display.Stage;
  import flash.display.*;
  import flash.events.*;

  public class Main extends Sprite {
    var ball:Ball = new Ball();
    var speedY:Number;

    public function Main() {
      this.addChild(ball);
      ball.x=stage.stageWidth/2;
      ball.y=stage.stageHeight/2;
      speedY=10;

      this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
    }

    function enterFrameHandler(event:Event):void {
      ball.y+=speedY;
      if (ball.y<0||ball.y>stage.stageHeight) {
        speedY*=-1;
      }
    }
  }
}

画面クリックでスタート

方法1:複数のムービクリップのインスタンスを作成する

複数の物体を動かす方法で一番簡単なのは、その数だけムービークリップのインスタンスを生成して、全てに対してアニメーションの設定をしていく方法です。ここでは、2つのBallを上下にバウンドさせています。

package {
  import flash.display.Stage;
  import flash.display.*;
  import flash.events.*;

  public class Main extends Sprite {
    var ball1:Ball = new Ball();
    var ball2:Ball = new Ball();
    var speedY1:Number;
    var speedY2:Number;

    public function Main() {
      this.addChild(ball1);
      ball1.x=stage.stageWidth/3;
      ball1.y=stage.stageHeight/2;
      speedY1=10;

      this.addChild(ball2);
      ball2.x=stage.stageWidth/3*2;
      ball2.y=stage.stageHeight/2;
      speedY2=12;

      this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
    }

    function enterFrameHandler(event:Event):void {
      ball1.y+=speedY1;
      if (ball1.y<0||ball1.y>stage.stageHeight) {
        speedY1*=-1;
      }

      ball2.y+=speedY2;
      if (ball2.y<0||ball2.y>stage.stageHeight) {
        speedY2*=-1;
      }
    }
  }
}

画面クリックでスタート

方法2:配列を使用する

複数のムービークリップのインスタンスを生成する方法では、すぐに数が増えた際に破綻してしまいます。物体の数が10から20個、100個と増えていったら、その数に比例してプログラムの分量が増えていってしまい、すぐに把握できなくなってしまうでしょう。

こうした大量のデータを管理するには、配列(Array)と呼ばれるデータ形式を利用すると便利です。配列とは関係をもつ一連のデータを格納できる仕組です。変数を箱とすると、配列は箱を沢山連結した「ロッカー」のようなものだとイメージするとわかりやすいかもしれません。同じ型の数値であれば、指定した数だけ一気に値を格納する領域を用意することが可能です。先程の円の中心座標を例にすると、4つの円の中心座標を格納するには、以下の宣言をします。

var 《配列の名前》:Array = new Array();

こうすることで、複数のデータを格納するロッカーのようなものが生成されます。このロッカーには0番から順番に番号が割り振られていて、「《配列の名前》[番号]」というように指定すると、特定の番号のロッカーに格納したデータを取りだすことが可能となります。

このロッカーに値を追加するには以下のように行います。

《配列の名前》.push(《格納するデータ》);

例えば、ロッカーに順番にアルファベットの文字を保存していき、取り出すプログラムは下記のようになります。

var alphabet:Array = new Array();

alphabet.push("a");
alphabet.push("b");
alphabet.push("c");
alphabet.push("d");

trace(alphabet[0]); // a 
trace(alphabet[1]); // b
trace(alphabet[2]); // c
trace(alphabet[3]); // d

この仕組みを利用して、複数のムービクリップとそのY軸方向へのスピードを、配列で管理してみましょう。

package {
  import flash.display.Stage;
  import flash.display.*;
  import flash.events.*;

  public class Main extends Sprite {
    var ballArray:Array = new Array();
    var speedArray:Array = new Array();
    var ballNum:int;

    public function Main() {
      ballNum=8;

      for (var i:int = 0; i < ballNum; i++) {
        var ball:Ball = new Ball();
        ball.x=stage.stageWidth/ballNum*i+30;
        ball.y=stage.stageHeight/2;
        ballArray.push(ball);
        this.addChild(ballArray[i]);

        var speedY:Number=i+10;
        speedArray.push(speedY);
      }

      this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
    }

    function enterFrameHandler(event:Event):void {
      for (var i:int = 0; i < ballNum; i++) {
        ballArray[i].y+=speedArray[i];
        if (ballArray[i].y<0||ballArray[i].y>stage.stageHeight) {
          speedArray[i]*=-1;
        }
      }
    }
  }
}

画面クリックでスタート

応用:ランダムな方向にアニメーションさせる

この複数の動きを配列で管理する仕組みを応用して、X軸方向とY軸方向にランダムなスピードで移動するアニメーションを作成してみましょう。

package {
  import flash.display.Stage;
  import flash.display.*;
  import flash.events.*;

  public class Main extends Sprite {
    var ballArray:Array = new Array();
    var speedXArray:Array = new Array();
    var speedYArray:Array = new Array();
    var ballNum:int;

    public function Main() {
      ballNum=50;

      for (var i:int = 0; i < ballNum; i++) {
        var ball:Ball = new Ball();
        ball.x=stage.stageWidth/2;
        ball.y=stage.stageHeight/2;
        ballArray.push(ball);
        this.addChild(ballArray[i]);

        var speedX:Number=Math.random()*20 - 10;
        var speedY:Number=Math.random()*20 - 10;
        speedXArray.push(speedX);
        speedYArray.push(speedY);
      }

      this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
    }

    function enterFrameHandler(event:Event):void {
      for (var i:int = 0; i < ballNum; i++) {
        ballArray[i].x+=speedXArray[i];
        ballArray[i].y+=speedYArray[i];
        if (ballArray[i].x<0||ballArray[i].x>stage.stageWidth) {
          speedXArray[i]*=-1;
        }
        if (ballArray[i].y<0||ballArray[i].y>stage.stageHeight) {
          speedYArray[i]*=-1;
        }
      }
    }
  }
}

画面クリックでスタート