ゲームプログラミングのためのフレームワークについて本気出して考えてみた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のような感じで記述することでコードの見通しを良くしようというアイディアに基いています。
現在考えている&実装しているのは、以下のものが記述できます。
- 画面状態
- 入力受付状態
- 読み込みデータファイルリスト
- レイヤー構造
- UI
もっと他にも記述できるものはあると思いますが、とりあえず見通しがついているものはこの5つです。
実際のソースコードはこんな感じで記述できたらいいなあと思っています。
SampleGame.mxml
-
<?xml version="1.0" encoding="utf-8"?>
-
<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.*">
-
<me:states>
-
<mx:State name="SenarioPhase">
-
<mx:AddChild position="lastChild">
-
<planes:Plane id="senario" currentInputState="{test}">
-
<planes:inputStates>
-
<io:InputState id="test">
-
<io:horizontal>
-
<commands:TraceCommandA traceText="A" />
-
</io:horizontal>
-
<io:vertical>
-
<commands:TraceCommandB />
-
</io:vertical>
-
<io:keys>
-
<io:Key code="Z">
-
<commands:ReloadCommand />
-
</io:Key>
-
</io:keys>
-
</io:InputState>
-
</planes:inputStates>
-
<planes:layers>
-
<layer:LayerList>
-
<layer:Layer id="system" />
-
<layer:Layer id="foreground" />
-
<layer:Layer id="message" />
-
<layer:Layer id="character" />
-
<layer:Layer id="background" />
-
</layer:LayerList>
-
</planes:layers>
-
</planes:Plane>
-
</mx:AddChild>
-
</mx:State>
-
</me:states>
-
<data:LoadList id="_list" complete="onLoad()">
-
<data:FileInstance id="bitmap" source="images/darkomeme.png" type="image" />
-
</data:LoadList>
-
</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
ゲームプログラミングのためのフレームワークについて本気出して考えてみた2
こんにちわ、DarkOmemeです。
昨日はつい興奮して本題が書けなかったので今日こそ書きたいと思います。
その前に、昨日のアブストラクトをどうぞ。
--
フレームワークなしにゲームプログラミングしていると、以下の事が発生する
- 状態管理ができなくなってくる
- 作りたくない部分ばっかり手間取る
- 修正や機能追加の際に、一体どこをいじればいいのかが分からなくなってくる
--
何コレ?
昨日の内容がたったの3行という。
ま、それはいいとして。
つまり、僕が目指すFlexのゲームプログラミングフレームワークはこんなものを目指すということです。
「簡単に見通しの良いソースが書けて、修正や機能拡張に柔軟なゲームプログラミングフレームワーク」
これを解決するために、色々とゲームというものについて考えてみました。
以下は、ゲームというものの定義およびモデル化です。
--
ゲームというものは、単純化してしまえば『入力』と『反応』だと考えます。
つまり、人間がある『入力』を与えて、それに対して面白い『反応』を返す。
これがゲームというシステムの一番ベースの部分。
但し、電源ゲームに関して言えばもう一つ、次のこともベースとなります。
『仮想競合相手(敵)』もこの二つを行う。
例を挙げるならば、RPG。
モンスターA が あらわれた!
コマンド?
ゆうしゃ の こうげき
モンスターA に 10 のダメージ!
モンスターA の こうげき
ゆうしゃ は 6 のダメージ!
こんなRPGの場合、あるゲームに対して、ゆうしゃ(プレイヤー)とモンスターA(仮想競合相手)がいて、お互いにコマンドを選択し、そのコマンドと自分のパラメータを攻撃計算式に当てはめて結果を出します。
それらの結果から次のコマンドを選び、最終的に自分のライフポイントが0になった方が負け。
コマンドが『入力』で、攻撃計算式の結果が『反応』、そしてその二つをモンスターA、つまり仮想競合相手と行います。
もう一つ例を挙げるとすると、シューティングゲーム。
プレイヤーが画面に登場
敵が画面に登場
プレイヤーが敵から逃げる
敵がプレイヤーを狙って弾を撃つ
敵の弾が画面に登場しプレイヤーの現在座標方向に向かって直進
プレイヤーが弾を撃つ
プレイヤーの弾が画面に登場しプレイヤー上に向かって直進
プレイヤーの弾が敵に当たる
敵のライフポイントが0になる
敵が爆発する
RPGと違って、シューティングゲームはリアルタイムなゲームです。
でも、それだからと言って、この『入力』と『反応』、そして『仮想競合相手』というゲームの定義が揺らぐわけではないと思います。
トランプと同じように、7並べのようなゲームもあれば、スピードのようなゲームもあるということ。
シューティングゲームで入力とは『プレイヤーキャラクターの移動と攻撃』、仮想競合相手の場合も『敵キャラクターの移動と攻撃』。
反応とは『プレイヤーキャラクターの座標変化・攻撃弾が画面に登場し直進、弾が当たる、弾が当たったキャラクターのライフポイントが減る、ライフポイントが0になると爆発する』。
ゲームをこのように、『入力』・『反応』・『それらを操る仮想競合相手』という3つの要素で考えることができるなら、以下の様にモデル化できるんじゃないでしょうか?
--
こんな感じ。
この仮想競合相手とPlayerがコマンドキューにコマンドを追加するタイミングが順番であればRPGのような非リアルタイム型
早い者勝ちであればリアルタイム型のゲームを表現できるというわけです。
と言うことで、DarkOmemeが本気出して考えたゲームプログラミングフレームワークはCommand駆動のフレームワークになります。
(更に続く)
