Flashのフレームワーク「Progression3」を始めてみよう!

第5回Progression3でWebサイトを作る(後編)

いよいよこの集中連載も最終回となりました。今回は難易度が上がりますので、解説を読んだだけでは分からない方はサンプルソースコードをじっくり眺めて、自分なりにいじってみてください。

また、前回まではチュートリアル形式で進めさせていただきましたが、今回はチュートリアル形式で進めるにはあまりにもボリュームがありすぎるため、あらかじめ用意されたプロジェクトファイルに対しての説明という形式で進めさせていただきます。

以下より、元素材となるプロジェクトファイル一式をダウンロードしてください。

今回配布する完成版のプロジェクトファイルを見ながら、前回作成したプロジェクトファイルを完成させてください。全くのコピーでもかまいません。

自分で手を動かすことがなにより最大のプラクティスになります。もちろん、もっと良い方法を思いついたらどんどん書き換えていってかまいません。

Informationシーンの作りこみ

シーンの遷移処理

早速プロジェクトファイルを見てください。かなりクラスファイルや処理の記述が増えていて驚くかもしれません。

最終的なファイルはinformationとgalleryの子シーン、トップのシーンから見たら孫にあたるシーンを作成してあります。

図1 最終的なクラスの構造
図1 最終的なクラスの構造

ここで、informationとgalleryのシーンのクラスファイル、InformationScene.asとGalleryScene.asを見てください。

_onInit、_onGotoメソッドの記述が一切無くなり、_onLoad、_onUnloadメソッドへ移動しています。

これは、なぜでしょうか?

_onInit、_onGotoメソッドに記述したままにしてみると分かるのですが、そのままですと孫シーンの遷移時に表示がおかしくなる場合が生じます。InformationSceneの初期化処理や終了処理が実行されないケースがあるためです。

今回のサイトは直接「孫シーン」を指定する場合や、⁠孫シーン」から「孫シーンの親では無い子シーン」という遷移が発生します。図で説明すると以下のような遷移です。

図2 孫シーンの移動
図2 孫シーンの移動

この場合、InformationSceneの_onLoad、_onUnloadメソッドへ記述することで、孫シーンが遷移処理をする場合親であるInformationSceneの処理を経由させることができます。連載第4回にシーン遷移の際の図を掲載してありますので、そちらを参照してください。

このシーン遷移処理の動作がProgressionでシーンを利用する上での大きなポイントです。通常このような動作をさせる物を作成しようとした場合、少し考える必要が生じますが、Progressionであれば特に悩む必要も無く実装できてしまうのです。

Funcコマンドの省略形

さて、実際に孫シーンを生成している箇所を説明します。InformationScene.asの_onLoadメソッドを見てください。

protected override function _onLoad():void 
{
  addCommand(
    // 任意のコマンドを記述してください。
    new Prop(_btn_Close, { x:700, y:0 ,sceneId:progression.root.sceneId} ), 
    new AddChild(_page, _btn_Close),
    new Prop(_page, { x:50, y:100 } ), 		
    function():void {
      //コマンド登録の為のパラレルリストの作成
      var pList:ParallelList = new ParallelList();		      //削除の為の参照を保持する配列の用意
      _arr_Btn_Info_Title = new Array();
      //子シーンは4つ作成します
      for (var i:int = 0; i < 4; i++) {
        //シーンの作成
        var infoTextScene:InfoTextScene = new InfoTextScene("information" + i, { container:_page, infoNum:i } );
        addScene(infoTextScene);
        //ボタンの作成(クラス名よりインスタンスの作成)
        var btn_Info_Title_Class:Class = Class(getDefinitionByName("myproject.buttons.Btn_Info_Title" + (i + 1)));
        var btn_Info_Title:CastButton = new btn_Info_Title_Class();
        //削除時の為の参照を保持
        _arr_Btn_Info_Title.push(btn_Info_Title);
        //ボタンに遷移先シーンIDの設定
        btn_Info_Title.sceneId = scenes[i].sceneId;
        pList.addCommand(
        //パラレルリスト内にシリアルリストの作成
          [
          new Prop(btn_Info_Title, { x:50, y:(i * 20) + 30 } ),  
          new AddChild(_page, btn_Info_Title)
          ]
        );
      }
      insertCommand(pList);
    },
    new AddChild(progression.container, _page)
  );
}

まず、目に付くのは、コマンド内にfunctionを直接記述している点でしょうか。

Progressionには指定した関数を実行できるFuncというコマンドが用意されていますが、そのFuncコマンドの省略形という形でコマンドリスト内に直接functionを記述できるようになっています。

一つのクラスファイルを使いまわす

処理の内容を見ていきましょう。For文で繰り返し処理を行って、シーンの作成を行っているのがわかります。

前回まで説明した方法では、一つのシーンを作る際、個々のクラスファイルを作成していました。しかし、この方法ですと、シーンが増えるに従い、用意しなければならないクラスファイルの数も多くなってしまいます。同じようなシーンであれば、一つのクラスファイルを使いまわしたい所です。

今回は一つのシーンクラスで4つのシーンのインスタンスを作成しています。

var infoTextScene:InfoTextScene = new InfoTextScene("information" + i, { container:_page, infoNum:i } );

そして各シーンに対応するボタンや設置する文章のクラスファイルをgetDefinitionByNameで文字列から生成しています。

var btn_Info_Title_Class:Class = Class(getDefinitionByName("myproject.buttons.Btn_Info_Title" + (i + 1)));
var btn_Info_Title:CastButton = new btn_Info_Title_Class();

少々力技になっていしまっている感はいなめませんが、今回はテキスト等の表示部分をスクリプトで生成せず、Flashファイルのムービークリップで作成している為、表示部部分に関しては個々のクラスファイルが必要でした。

今回は孫シーンへ遷移する為のボタンをシーン数分用意してFlashファイルのムービークリップと関連付け、クラス名に連番を振り、そのクラス名の連番から配置するムービークリップを判断させています。

子シーンの一括削除

さて、_onLoadメソッドでシーンを作成している場合、もう一度同じ_onLoadメソッドが処理されてしまうとシーンの重複登録となり、エラーとなってしまいます。

そこで、_onUnloadメソッドでシーンを削除する必要が生じます。

protected override function _onUnload():void 
{
  addCommand(
    // 任意のコマンドを記述してください。
    //子シーン遷移用ボタンの削除
    function ():void {
      for (var i:int = 0; i < _arr_Btn_Info_Title.length; i++) {
        insertCommand(new RemoveChild(_page, _arr_Btn_Info_Title[i]));
      }
    },
    //閉じるボタンの削除
    new RemoveChild(_page, _btn_Close),
    //ページイメージの削除
    new RemoveChild(progression.container, _page),
    //子シーンの削除
    removeAllScenes
  );
}

シーンオブジェクトはremoveAllScenesという自身の子シーンを全て削除するメソッドを持っていますので、Funcコマンド内で実行させ、子シーンを全て削除しています。

Funcコマンドの省略形はこのように直接関数を指定する事も可能です。

initObjectで値を渡す

シーンクラスのインスタンスを作成している箇所で、シーンクラスのパラメータにシーン名以外のパラメータを設定しています。

var infoTextScene:InfoTextScene = new InfoTextScene("information" + i, { container:_page, infoNum:i } );

Progressionで用意されているクラスはinitObjectという初期化用のパラメータを持っています。それを利用してコンテナの参照と連番の番号を渡しています。以下InfoTextSceneのコンストラクタです。

public function InfoTextScene( name:String = null, initObject:Object = null ) 
{
  super( name, initObject );
  //initObjectの値を受け取る
  //コンテナの参照
  _container = initObject.container;
  //番号
  _infoNum = String(int(initObject.infoNum) + 1);

  //番号に応じたクラスを取得
  var txtInfo_Class:Class = Class(getDefinitionByName("myproject.texts.Txt_Info" + _infoNum));
  //インスタンスの作成
  _txtInfo = new txtInfo_Class();
  _txtInfo.x = 50;
  _txtInfo.y = 120;
}

initObjectで得た値を利用し、シーンの作成を行っています。

もちろんsetter、getterで値を受け渡す事も出来ますが、折角用意されているのですからinitObjectを利用しない手はありません。

コマンドのシリアルリストとパラレルリスト

再度InformationScene.asの_onLoadメソッドのコマンド内に登録しているfunction内を見てください。

//コマンド登録の為のパラレルリストの作成
var pList:ParallelList = new ParallelList();		
~
for (var i:int = 0; i < 4; i++) {
~
  pList.addCommand(
    //パラレルリスト内にシリアルリストの作成
    [
    new Prop(btn_Info_Title, { x:50, y:(i * 20) + 30 } ),  
    new AddChild(_page, btn_Info_Title)
    ]
  );
}
insertCommand(pList);

コマンドのシリアルリスト、パラレルリストの説明は連載第2回で軽く触れましたが、上記コードはコマンド実行の応用編です。

function内でパラレルリストコマンドを作成し、実行されているコマンドに差込む事でそのパラレルリストコマンドを実行させています。 さらにパラレルリスト内のコマンドをシリアルリストに変換しています。

シリアルリスト内のコマンドを[ ]で括るとパラレルリストに、パラレルリスト内のコマンドを[ ]で括るとシリアルリストに変換されます。

今回は"各ボタンの設置は同時に行いたいのだけれど、各ボタンはパラメータを設定してから設置したい"という処理を実現させるため、このようなコマンドを作成しました。

上手くコマンドリストを扱うことにより、もっと複雑な処理フローも実現できます。

各キャストオブジェクトの動作を調整する

シーンやボタン等キャストオブジェクトの配置が終了したら、最後に各キャストオブジェクトに動きを付けてあげます。

今回はテキストが表示される際、上から下に少しスライドさせて、退出時は逆の動きをするようにしてみました。

以下は、Txt_Info1.asの_onCastAddedメソッドと_onCastRemovedメソッドの部分です。


protected override function _onCastAdded():void 
{
  addCommand(
    // 任意のコマンドを記述してください。
    new Prop(this, { alpha:0 } ), 
    new DoTweener(this, { y:y + 10, alpha:1, time:0.5 } )
  );
}
protected override function _onCastRemoved():void 
{
  addCommand(
    // 任意のコマンドを記述してください。
    new DoTweener(this, { y:y - 10, alpha:0, time:0.5 } )
  );
}

これでInformationシーン側の説明を終了します。実はもっとクラスファイルをまとめてしまうことも可能ですが、今回は割愛します[1]⁠。

図3 完成したInformationシーン
図3 完成したInformationシーン

Galleryシーンの作りこみ

PRML形式のXMLデータからシーンを生成する

さて、informationシーンで一つのクラスファイルでシーンを複数生成してみましたが、写真ギャラリーページ等、増減するコンテンツの場合、いちいちシーン内のクラスファイルを作成しなければならないのが面倒です。

しかし、Progressionには決められた書式のXMLファイルからシーンを作成するという素晴らしい機能が備わっています。

まず、GalleryScene.asの_onLoadメソッドを見てください。

protected override function _onLoad():void 
{
  addCommand(
    // 任意のコマンドを記述してください。
    new Prop(_btn_Close, { x:700, y:0 ,sceneId:progression.root.sceneId} ), 
    new AddChild(_page, _btn_Close),
    new Prop(_page, { x:50, y:100 } ),
    //シーン作成用のXMLファイルを読み込み
    new LoadURL(new URLRequest("scenedata.xml")),
    function():void {					
      //シーンの作成(コマンドクラスのlatestDataプロパティで、直近の読み込みデータを参照可能)
      addSceneFromXML(new XML(this.latestData));

      //コマンド登録用のパラレルリスト
      var pList:ParallelList = new ParallelList();
      //削除用の参照を配列に入れておく
      _arr_Btn_Thumbnail = new Array();
      //ボタンの作成
      for ( var i:int = 0; i < numScenes; i++ ) {
        //シーン固有の値をsceneinfo.dataより取得(シーンオブジェクトのscenesプロパティで子シーンの参照の配列を取得可能)
        var xmlData:XMLList = new XMLList( scenes[i].sceneInfo.data );
        //データ形式がXMLListなので、XMLUtilを利用して変換
        var obj:Object = XMLUtil.xmlToObject( xmlData );
        //画像をボタンとして作成(画像クリックで戻る様にする為)、また、ボタンはスプライトに内包する
        var btn_Thumbnail:Btn_Thumbnail_Sprite = new Btn_Thumbnail_Sprite();
        //削除時の為にボタンのインスタンスの参照を保持
        _arr_Btn_Thumbnail.push(btn_Thumbnail);

        //setterへ値をセットする
        btn_Thumbnail.sceneId = scenes[i].sceneId;
        btn_Thumbnail.imageUrl = obj.imageUrl; 
        //位置の決定
        btn_Thumbnail.x = ( 130 * (i % 5) ) + 50;
        btn_Thumbnail.y = (Math.floor(i / 5) * 80) + 30;

        pList.addCommand(
          new AddChild(_page, btn_Thumbnail )
        );
      }
      insertCommand(pList);
    }, 
  new AddChild(progression.container, _page)
  );
}

LoadURLコマンドでxmlファイルを読み込んだ後、シーンを作成する部分が、以下のように1行で済んでいます ※2⁠。

addSceneFromXML(new XML(this.latestData));

指定した書式のXMLファイルを読み込むことによりXMLのデータからシーンを動的に作成してくれるのが、シーンオブジェクトのaddSceneFromXMLメソッドなのです。

XMLファイルの中を見てみましょう。

<?xml version="1.0" encoding="UTF-8" ?>
<prml version="2.0.0" type="text/prml">
  <scene name="image1" cls="myproject.scenes.ImageScene" title="IMAGE1" >
    <imageUrl>images/image1.jpg</imageUrl>
  </scene>
  <scene name="image2" cls="myproject.scenes.ImageScene" title="IMAGE2" >
    <imageUrl>images/image2.jpg</imageUrl>
  </scene>
  <scene name="image3" cls="myproject.scenes.ImageScene" title="IMAGE3" >
    <imageUrl>images/image3.jpg</imageUrl>
  </scene>
  <scene name="image4" cls="myproject.scenes.ImageScene" title="IMAGE4" >
    <imageUrl>images/image4.jpg</imageUrl>
  </scene>
  <scene name="image5" cls="myproject.scenes.ImageScene" title="IMAGE5" >
    <imageUrl>images/image5.jpg</imageUrl>
  </scene>
</prml>

XMLはPRMLと呼ばれる形式で記述します。詳細はProgression公式サイトにリファレンスが掲載されていますので、そちらを参照してくさい。

<scene>タグのnameにはシーン名をclsには追加するシーンクラスを、titleにはブラウザに表示されるタイトルを設定します。<scene>タグ内の要素にはさらに子シーンの構造の追加や、シーン固有のデータを格納できます。

今回は<imageUrl>という画像の場所を設定しています。今回の場合であれば1項目しかないため、そのまま文字列でもかまいませんが、要素が増えた時の事を考慮し、XMLListとして格納しました。

このXMLファイルを読み込み、addSceneFromXMLメソッドを実行するだけで動的にシーンの作成が可能なのです[3]⁠。

試しにシーンをもう一つ増やしてみましょう。以下の<scene>タグをXMLに追加します。

<scene name="image6" cls="myproject.scenes.ImageScene" title="IMAGE6" >
  <imageUrl>images/image5.jpg</imageUrl>
</scene>

パブリッシュして動作させてみてください。画像のサムネールが一つ増えています。クリックするとimage6シーンへ遷移することが分かります。

おすすめ記事

記事・ニュース一覧