プログラミングやる前に先お風呂はいっちゃいなさい

243月/090

先日のリングコマンドの不具合について

どうにも気持ち悪かったんで、先日アップしたリングコマンドの不具合について調べてました。

どうやら、僕がUIComponentにBitmapをaddChildして使う際に行った実装がまずかったみたいです。

UIDecorator.as 

  1. public class UIDecorator extends UIComponent
  2. {
  3.   public function UIDecorator(displayObject:DisplayObject)
  4.   {
  5.     super();
  6.     BindingUtils.bindSetter(bindCenter, this, "centerX");
  7.     BindingUtils.bindSetter(bindCenter, this, "centerY");
  8.     this.displayObject = displayObject;
  9.     super.addChild(this.displayObject);
  10.   }
  11.  
  12.   [Bindable] public var centerX:Number = 0;
  13.   [Bindable] public var centerY:Number = 0;
  14.  
  15.   private function bindCenter(dummy:Number):void
  16.   {
  17.     this.lx = this.lx;
  18.     this.ly = this.ly;
  19.   }
  20.  
  21.   [Bindable]
  22.   public function get lx():Number
  23.   {
  24.     return super.x + centerX;
  25.   }
  26.   public function set lx(value:Number):void
  27.   {
  28.     super.x = value - centerX;
  29.   }
  30.  
  31.   [Bindable]
  32.   public function get ly():Number
  33.   {
  34.     return super.y + centerY;
  35.   }
  36.   public function set ly(value:Number):void
  37.   {
  38.     super.y = value - centerY;
  39.   }
  40.  
  41.   public override function set width(value:Number):void
  42.   {
  43.     super.width = value;
  44.     displayObject.width = value;
  45.   }
  46.   public override function set height(value:Number):void
  47.   {
  48.     super.height = value;
  49.     displayObject.height = value;
  50.   }
  51.  
  52.   public var displayObject:DisplayObject;
  53. }

こんな感じに実装してみた。
これは正解のソースで、本当はコンストラクタの中でdisplayObjectの幅と高さをthisの幅と高さにバインドする処理が入ってました。

で、このバインドを信用していたんだけど、どうもビルドするたびに、このバインドが利いたり利かなかったり・・・。
もう、なんでこんな曖昧なんだ。。バインド。。一気に僕の信用を落としました。

さて、で、これではBitmapをまだaddChildしてないので、ちゃんとBitmapをaddChildするようにコレを継承して、こんなのを作りました。

UIBitmap.as

  1. public class UIBitmap extends UIDecorator
  2. {
  3.   private var _bitmap:Bitmap;
  4.   public function UIBitmap(bitmapData:BitmapData=null)
  5.   {
  6.     super(new Bitmap());
  7.     _bitmap = this.displayObject as Bitmap;
  8.     this.bitmapData = bitmapData;
  9.   }
  10.  
  11.   public function set bitmapData(value:BitmapData):void
  12.   {
  13.     _bitmap.bitmapData = value;
  14.     if (value == null)
  15.       return;
  16.     this.width = value.width;
  17.     this.height = value.height;
  18.   }
  19.   public function get bitmap():Bitmap
  20.   {
  21.     return _bitmap;
  22.   }
  23. }

このソースも正解のソース。
本当はbitmapDataのsetterの中でthisの幅と高さを入れる処理はしてなかった。

まあ、つまり、UIComponentに入れたBitmapのサイズがバインド処理で行うはずなのに行われてなかったというものでした。

おわり。

明日は、MXMLで書くXMLパーサを作った話を書く予定。

183月/090

リングコマンドを作ってみた

先日書いた、MEFrameworkを使いながらリングコマンドを作ってみた。 

53月/095

ゲームプログラミングのためのフレームワークについて本気出して考えてみた3

どうも、DarkOmemeです。

引き続きゲームプログラミングフレームワークについての記事です。

その前に、このゲームプログラミングフレームワークの名前が決まったので発表したいと思います。

「ME Framework」 です。

MEはMXML Extemporeの略です。

Extemporeってのは即興、即席、即座という意味です。

つまり『MXMLで即座に作れる!』という意味をもってME Frameworkという名前にしました。

実は、DarkOmemeのme(目)というダブルミーニングだという話も・・・。

--

昨日の続きです。

昨日説明したように、このME Frameworkはプレイヤーから入力があると、それをCommandという形でコマンドキューにpushします。

このコマンドキューをバックグラウンドで動作しているSingletonなクラスのCommandManagerがEnterframeイベントで逐次一つずつキューからコマンドを読み取って、実行しています。

まあ、このバックグラウンドの仕組みはあまり利用者が意識しなくてもいいようにしておきたいですね。

--

さて、今日の話は【MXMLで何を記述するか?】です。

僕がFlexのMXMLに感じている特徴としては、静的な情報を表現するのに向いている、ということです。
MXMLで一応、処理のフロー(?)も書くこともできるんですが、なんとなくいまいちだと思います。
(たとえば、Effectを定義する場合、回転→ブラー+フェードみたいな処理の流れは書ける)

やっぱり、もっと常に一定な情報を記述できた方がいいのではないかと考えます。
イメージとしてはHTML。
基本的な枠組みはHTMLで記述して、動的な処理についてはJavaScriptに任せてしまう、という思想。
今回考えているフレームワークもこんなHTMLのような感じで記述することでコードの見通しを良くしようというアイディアに基いています。

現在考えている&実装しているのは、以下のものが記述できます。

  1. 画面状態
  2. 入力受付状態
  3. 読み込みデータファイルリスト
  4. レイヤー構造
  5. UI

もっと他にも記述できるものはあると思いますが、とりあえず見通しがついているものはこの5つです。
実際のソースコードはこんな感じで記述できたらいいなあと思っています。

SampleGame.mxml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <me:GameApplication xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:me="me.rkome.da.front.*" layout="absolute" backgroundColor="#000000" width="640" height="480" currentState="SenarioPhase" xmlns:planes="me.rkome.da.planes.*" xmlns:io="me.rkome.da.io.*" xmlns:commands="me.rkome.da.commands.*" xmlns:data="me.rkome.da.data.*" xmlns:layer="me.rkome.da.layer.*">
  3.   <me:states>
  4.     <mx:State name="SenarioPhase">
  5.       <mx:AddChild position="lastChild">
  6.         <planes:Plane id="senario" currentInputState="{test}">
  7.           <planes:inputStates>
  8.             <io:InputState id="test">
  9.               <io:horizontal>
  10.                 <commands:TraceCommandA traceText="A" />
  11.               </io:horizontal>
  12.               <io:vertical>
  13.                 <commands:TraceCommandB />
  14.               </io:vertical>
  15.               <io:keys>
  16.                 <io:Key code="Z">
  17.                   <commands:ReloadCommand />
  18.                 </io:Key>
  19.               </io:keys>
  20.             </io:InputState>
  21.           </planes:inputStates>
  22.           <planes:layers>
  23.             <layer:LayerList>
  24.               <layer:Layer id="system" />
  25.               <layer:Layer id="foreground" />
  26.               <layer:Layer id="message" />
  27.               <layer:Layer id="character" />
  28.               <layer:Layer id="background" />
  29.             </layer:LayerList>
  30.           </planes:layers>
  31.         </planes:Plane>
  32.       </mx:AddChild>
  33.     </mx:State>
  34.   </me:states>
  35.   <data:LoadList id="_list" complete="onLoad()">
  36.     <data:FileInstance id="bitmap" source="images/darkomeme.png" type="image" />
  37.   </data:LoadList>
  38. </me:GameApplication>

一つずつ説明します。

1.画面状態(Planeタグ)

これはME Frameworkで最も大きな枠組みです。
このタグを一つの画面と見立てて、これらを親コンテナにaddしたりremoveする事で、画面が切り替わります。

ME Frameworkは基本的に画面単位で状態を記述します。

ゲーム、例えばRPGにはタイトル画面・オプション画面・ゲーム画面・戦闘画面・エンディング画面・スタッフロール画面という風に画面によってゲームのルールが変わります。

これはそれらを一つの単位として扱うためのタグです。

また、このタグの要素として、他の静的な情報をタグで記述していきます。

2.入力受付状態(InputStateタグ)

これは、入力の状態を記述するタグです。

PlaneのinputStatesプロパティに直接、複数の入力受付状態を記述することができます。

これはつまり、キーボード入力と入力によってコマンドキューに追加されるキューの紐付けを行います。

SampleGame.mxmlのtestというInputStateの場合、左右キーを押すとTraceCommandAコマンドが発行され、上下キーを押すとTraceCommandBコマンドが発行され、Zキーを押すとReloadCommandコマンドが発行されるという事が記述されています。

方向キーについては、horizontal,verticalの他に上下左右を現すmoveと、それぞれ一つのキーに対応したup,down,left,rightがあります。

それ以外のキーについてはkeys以下にKeyタグを使って記述します。使えるキーはA-Z、0-9、Enter、Space、BackSpaceのみです。
もちろん、他にも対応させてもいいんですが、ゲームにそこまで多くのキー入力は必要ないと思って対応してません。
Shiftくらいは対応してもいいかもしれません。

3.読み込みデータファイルリスト(LoadListタグ)

これはPlaneタグの要素として記述する必要はありません。
場合によっては別のファイルに書いておいてもいいかもしれません。

何かと言うと、これはゲームを表現するのに必要な外部読み込みデータのリストをひとまとめにしておけるタグです。

実装では内部的にBulkLoaderというライブラリを使っており、type属性で指定している値は、BulkLoaderで使用する値そのものです。

SampleGame.mxmlの_listはloadという関数を持っているので、任意のタイミングで_list.load()と呼び出すことで、このタグで記述されたファイルリストのsourceから逐次ダウンロードなどしてデータを読み込みます。
読み込みが完了するとonLoad()という関数が呼ばれるように設定してあります。

これは、画面毎に決まった素材をロードする時に、このように記述しておくことで、一覧性がかなり向上するんじゃないかと思います。

デフォルトのロード画面をPlaneクラスにあらかじめ持たせておくようにフレームワークを設計すれば、このLoadListをPlaneに渡すだけで、画面遷移が起こった時点でロード画面を自動的に表示してロードが完了すると、Planeクラスに記述された動的なスクリプトが実行されるようにすることも可能だと考えています。

うーん、素敵だ。

ロード画面は多少カスタムできれば、別にいちいちPlaneタグを使って用意する程の画面じゃないよね?

4.レイヤー構造(LayerListタグ)

これは、レイヤーの階層を定義するタグです。

※ちなみに、ここからの話は絵に描いた脳内彼女です。

恐らく、あまり動的にゲームの表示レイヤーというものは変化しないはずなので、こんな感じで定義します。

もちろん、あらかじめ表示されるものが決まっている場合は、Layerタグの子要素としてオブジェクトを配置することもできるようにします。

実際は、ここで定義されたレイヤーのidを使って、それぞれのレイヤーに動的にオブジェクトを配置していく事になると思います。

上に書いてあるものが最も上(手前)に表示され、下に書いてあるものが最も下(奥)に表示されます。
それぞれのレイヤーに呼びかけて、SampelGame.mxmlで言うと、characterレイヤーだけ子オブジェクトを全部removeするなんて事もできるようにする予定です。

レイヤー間の移動など、レイヤー全体を通して行う処理に関してはLayerListクラスが担当することになると思います。

5.UI

これは、正直まだあまり考えていません。

よく使うようなUIをFlexのカスタムコンポーネントとして作っておいて、レイアウトなんかをデザインビューなんかで確認できれば最高だなあと思っているんですが、Flex Builderのデザインビュー機能はこれがなかなか曲者です。

どれくらい曲者かと言うと、簡単に言えば、ナナフシという虫から生命を取ったようなくらいです。

棒切れです。

カスタムコンポーネント開発においては、全然まだ使えるレベルじゃないという噂です。(実際使いこなしている方をお見受けしたことはありません

なので、これは結構長い間保留になるかと思います。

まあ、作るのが確定しているものとしては、とりあえずメッセージボックスとゲージコンポーネントくらいでしょうか。

メッセージボックスは文章を流れる様に表示する、ストーリー記述には必須のコンポーネントです。

ゲージコンポーネントはプログレスバーみたいに数値を棒グラフ状に表現できるコンポーネントとして用意します。

ここら辺はFlexのSkin機能を使って、簡単にデザインを変更できるようにしておきたいなあ。

--

と、長く書いてきましたが、以上が現段階で考えている&実装しているME Frameworkです。

イメージ掴めましたか?

ゲーム開発で是非とも使ってみたい、使ってみたいとは思わないがこんな機能が欲しい、物申す!などなんでもいいのでご意見をお聞かせ下さい。

一応、このゲームフレームワークが完成したら、spark projectにコミットしようかと考えています。

まだまだ、構想としては色々考えていますが、時間の関係などで今日はとりあえずここまでです。

SampelGame.mxmlで記述されたプログラムは近々このブログにアップする予定です。

そんな感じで、DarkOmemeが本気出してゲームプログラミングフレームワークについて考えてみた、はこれにて。

以降はME Frameworkの記事として適当にやったことや、構想などを書いて行ければとか思ってます。

--

あー、疲れた。

もう寝よう。

あれ、3:46 amだって。。明日も明日として仕事なのに、お前は一体なにをや(ry