MAX2011

Adobe MAX 2011レポート:Stage 3Dを使った2Dゲーム制作

Adobe MAX 2011から「Developing 2D Games on top of Stage 3D」のセッションレポートです。
Stage3Dという名前のせいか、Flash Player 11で搭載されたこの新機能は、3D描画のためのものだと思うかもしれませんが、実は2Dの描画も大変高速になりました。高速になったおかげで、これまで諦めていたいろいろな表現が可能になっています。
3Dの世界を作り込むには、新しい知識をいろいろと身につけなければいけませんが、2Dなら今までの知識の延長で簡単に作れますので、ぜひ挑戦してみてください。
(ソースコードはアドビのガイドラインに沿った書き方ではない部分がありますが、原文のまま掲載します)

これまでの2D描画

これまで、2Dの描画を高速化する手法としては、
・Pixel Blitting(大きなビットマップを用意して、必要な画像をBitmapData.copyPixels()でコピーする手法
・GPUによるベクター描画(renderModeにGPUを指定、AIRのみ)
がありました。解像度は大きくなるばかりなので、CPUを使ってピクセルをスクリーンにプッシュするという方法に未来はありません。

これからの2D描画

Flash Player 11/AIR 3の登場により、Stage3Dを利用できるようになりました。
Stage 3D APIは、低レベルで(コンピューターにより近い位置で)、GPUを使って描画をするAPIです。従来のDisplay Listの下のレイヤーに描画されます。Stage 3Dは、コンピューターに非常に近いAPIなので、単純な矩形を描くだけでもかなり複雑なコードを書く必要があります。
そこで、フレームワークの登場です。面倒な処理は全部フレームワークにまかせて、僕らは表現のところだけ頑張りましょう。

Starling(スターリング)

ここではStarlingというフレームワークを紹介します。(Starlingはたぶんムクドリのことだと思います。)
Starlingは、これまで使ってきたDisplay Listのアーキテクチャに似たフレームワークです。これまでのSpriteの代わりに、StarlingのSpriteを使えばよいという感覚で大丈夫です。
GPUの上に、OpenGL/ES2、DirectXが乗っており、その上にStage3Dがあり、その上でStarlingは動いています。Starlingはコンパクトです。swfの容量は80KBしか増えません。
基調講演でも紹介された「Angry Birds HD」はStarlingを使っているそうです。驚くほどなめらかに動いていました。さりげなく背景に凝ったりもしていて、描画に余裕があることがわかります。
またStarlingを学ぶことで、GPUがどう働いているか理解を深めていくことができます。
StarlingはFreeBSDライセンスです。アドビもこのフレームワークの使用を推奨しています。

どんなコード?

var texture:Texture = Texture.fromBitmap(new embeddedBitmap());
var image:Image = new Image(texture);
quad.pivotX = 50;
quad.pivotY = 50;
quad.x = 300;
quad.y = 150;
quad.rotation = Math.PI/4;
addChild(quad);

細かいところは分からなくても、ああ、結局addChildすればいいのねと、なんとなく読めちゃうのではないかと思います。これがStarlingのよいところです。

表示オブジェクト

使い慣れたものと同じように、StarlingにもDisplayObject、DisplayObjectContainerがあります。また、Button、Sprite、Stage、TextField、Image、MovieClipという表示オブジェクト関連のクラスがあります。これに、Starling独特のQuadというクラスが追加されています。

イベント

Event.ADDED, Event.ADDED_TO_STAGE, Event.REMOVED, Event.REMOVED_FROM_STAGE, Event.TRIGGERED, Event.MOVIE_COMPLETED, Event.FLATTEN, Event.RESIZE, Event.ENTER_FRAME,
ResizeEvent.RESIZE, TouchEvent.TOUCH, KeyboardEvent.KEY_UPとKEY_DOWNがあります。
注意点としては、Timerは使わず、必ずEnterFrameEvent.ENTER_FRAMEを使ってください。

最小のコード

最小のコードはこんな感じです。

package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import starling.core.Starling;
[SWF(width="1280", height="752", frameRate="60", backgroundColor="#002143")]
public class Startup extends Sprite
{
private var mStarling:Starling;
public function Startup()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
mStarling = new Starling(Game, stage);
mStarling.antiAliasing = 1;
mStarling.start();
}
}
}

チェックする点

パフォーマンスを最高にするには、
・アンチエイリアスの品質設定
・エラーチェックを無効にしているか
・リリースビルドで書き出ししているか
をチェックしてください。

Quad(クアッド)

Quadは、テクスチャなしの、色だけの頂点からなる矩形のことです。色の補間はGPUで行われます。

q = new Quad(200, 200);
q.setVertexColor(0, 0x000000);
q.setVertexColor(1, 0xAA0000);
q.setVertexColor(2, 0x00FF00);
q.setVertexColor(3, 0x0000FF);
addChild(q);

単色の場合は、
q.color = 0x00FF00;
とします。

Image(イメージ)

Imageは、テクスチャありのQuadです。「テクスチャ」はビットマップ画像と同じ意味と思ってください。テクスチャは必要になる前に、あらかじめ用意しておくと良いでしょう。圧縮されたテクスチャが使えます。

var sausageBitmap:Bitmap = new Sausage();
var texture:Texture = Texture.fromBitmap(sausage);
var image:Image = new Image(texture);
addChild(image);

色合いは次のように指定します。
image.color = 0xFF0000;
Texture.fromBitmap()は最初に1回だけ行うようにして、for文の中で毎回やらないように気をつけてください。
Dynamic Texture(ダイナミックテクスチャ)
実行時に描いたシェイプをテクスチャとして使う方法です。shape.graphicsのソフトウェアラスタライザを使い、GPUにアップロードする仕組みです。これも、上で説明したように、前もってやっておきましょう。

var buffer:BitmapData = new BitmapData(radius * 2, radius * 2, true, color);
buffer.draw(shape);
var texture:Texture = Texture.fromBitmapData(buffer);
var image:Image = new Image(texture);
addChild(image);

衝突判定

半径を指定して、境界と境界がぶつかっているか判定できます。テクスチャは、BitmapData.hitTestによって判定されます。Box2Dのような物理エンジンと組み合わせることも簡単です。衝突判定が複雑になると、レンダリングパフォーマンスに影響しますので、なるべく単純にしてください。

private function onFrame(event:Event):void
{
point1.x = sausageImage1.x;
point1.y = sausageImage1.y;
point2.x = sausageImage2.x;
point2.y = sausageImage2.y;
if(sausageBitmapData1.hitTest(point2, 255, sausageBitmapData1, point1, 255))
{
trace("touched");
}
}

Buttons(ボタン)

Starlingのボタンはコンテナ(DisplayObjectContainer)です。テクスチャをスキンとして使います。オートスケールなどの機能があります。

var buttonSkin:Bitmap = new ButtonTexture();
var texture:Texture = Texture.fromBitmap(buttonSkin);
var myButton:Button = new Button(texture, "Play");
addChild(myButton);

Sprite(スプライト)

スプライトもコンテナです。標準のSpriteと同様に、もっとも軽いコンテナです。
Flat Sprites(フラットスプライト)
flatten(描画の更新を止める)を使うと、パフォーマンスを向上させることができます。
コンテナの子供がテクスチャを共有していない場合は、劇的なパフォーマンス向上にはなりません。複雑な親子関係があるものをレンダリングする際に有効です。cacheAsBitmapみたいなものです。

container.flatten();
child.scaleX = child.scaleY = 0.5;
container.unflatten();

MovieClip

スプライトがタイムラインに並んだものです。それぞれのフレームに異なるテクスチャがあります。あらゆる操作ができます。(カスタムフレームレート、addFrame、removeFrameAtなど)
MovieClipのネスト(入れ子)はできません(MovieClipはImageをExtendsしています)。フレームスクリプトはサポートしていません。

var frames:Vector. = sTextureAtlas.getTextures("running_");
mMovie = new MovieClip(frames, 40);

Sprite Sheets(スプライトシート)

スプライトシートを使うと、アニメーションのコマ、スキンなど、たくさんのテクスチャをグループにできます。縦横のマスの数は2のべき乗の数でなくてはいけません(1,2,4,8,16,32…)。Stage3Dの制限は、最大2048×2048です。1枚に入りきれないときは、複数のスプライトシートを作ります。将来のFlash(Flash CS6?)にはスプライトシートの作成を行うパネルが付く予定です。

Juggler(ジャグラー)

ムービークリップのアニメーションを行います。StarlingオブジェクトのデフォルトのJugglerを使えます。あまり使用をおすすめできません。ゲームの各パーツ(背景、メニューなど)で使うとよいでしょう。

var frames:Vector. = sTextureAtlas.getTextures("running_");
mMovie = new MovieClip(frames, 40);
Starling.juggler.add(mMovie);

一時停止と再開

コードのどこからでも、デフォルトのメインジャグラーを使って可能です。Starling.current.start()とStarling.current.stop()は使わないでください。ゲームのメイン部分を構成するクラスとは別のクラスで、それぞれにジャグラーを作ってください。stageクラスにenterframeイベントのリスナー関数を作成し、そこでアニメーションを進めるようにしてください。

private function onFrame(event:EnterFrameEvent):void
{
if(paused)
alertBox.advanceTime(event.passedTime);
else
battle.advanceTime(event.passedTime);
if(paused)
dashboard.advanceTime(event.passedTime);
}

Texture Atlas(テクスチャアトラス)

スプライトシートよりよいです。似たエレメントを1つの大きなテクスチャにまとめることができます。最小のアップロードと、少ないテクスチャ切り替えで済みます。縦横のマスの数は2のべき乗の数でなくてはいけません(1,2,4,8,16,32…)。テクスチャアトラスごとに、似たオブジェクトをまとめてください。
一番下のレイヤーに背景の要素をまとめたテクスチャアトラスを、次のレイヤーにプレイフィールドのテクスチャアトラスを、次のレイヤーにダッシュボードのテクスチャアトラスを描くといいでしょう。

Dynamic Texture Atlas(ダイナミックテクスチャアトラス)

Dynamic Texture Atlas Generatorは、Starlingの拡張機能としてあります。Flashのムービークリップをテクスチャアトラスに変換します。すごい!
それぞれのフレームをラスタライズして、テクスチャを作ってくれます。ゲームの初期化には少し時間がかかるでしょう。初期化の時間とswfのサイズのバランスです。

リソース、それはスプライトの命

使い終わったオブジェクトはdisposeしましょう。
removeEventListers(), removeChild(child, dispose), removeFromParent(true)を使ってリスナーを削除してください。
disposeを呼び出せば、リスナーは削除され、GPUのバッファーからも消えます。テクスチャオブジェクトでは、GPUメモリからテクスチャが消えます。

Native overlay(ネイティブオーバーレイ)

GPUは万能ではありません。textinputをネイティブオーバーレイしたいときは、Starling.current.nativeOverlayを使います。

var textInput:flash.text.TextField = new flash.text.TextField();
textInput.type = TextFieldType.INPUT;
Starling.current.nativeOverlay.addChild(textInput);

Text(テキスト)

Textは必要でしょう。しかも速いやつ。TextFieldとBitmapFont APIがあります。
TextFieldは、レンダリングのためにネイティブのTextFieldを使い、その後GPUにアップロードします。
BitmapFontはビットマップグリフを使います(グリフのスプライトシート)
ゲームのローカライズに便利なオートスケール機能がついています
Particles(パーティクル)
パーティクルはゲームに命を与えます。すごく速い(batching)。1回のコールで描画します。頂点の位置は、CPUで補間されます。

パーティクルの作り方:

http://blog.onebyonedesign.com/flash/particle-editor-for-starling-framework/

プロファイリング

MrDoob StatsクラスがStarlingにポートされています。

Starlingの資料(英語)

www.bytearray.org/?p=3371
からダウンロードできます。(107ページのPDF、無料)
以上、全然60分に収まっていなかったセッションの内容をすべてお伝えしました。
2D描画が高速になって、簡単に使えるフレームワークが登場したことから、簡単に本格的なゲームが、極めて短い時間で作れる時代が来ました。ゲームだけではなく、ウェブサイトのコンテンツ、インタラクティブな展示型コンテンツにも使えると思います。
ぜひStarlingを使って、GPUを使った高速な2Dの表現を試してみてください。モバイル向けのStage 3Dは来年リリースされる予定です。未来はすぐそこまで来ていますよ。
10/11訂正:
スターリンじゃなくて、スターリングと読むのが正しそうです。お詫びして訂正いたします。


Author

  • Shuichi Ishikawa
    Shuichi IshikawaShuichi
    Ishikawa
  • MikasaHideyuki
    Hideyuki MikasaHideyuki
    Mikasa
Shuichi Ishikawa
執行役員/インタラクションデザイングループ

フロントエンド開発からクラウドサーバー構築まで、新しいことに興味がありすぎて時間が足りない制作部門リーダー。Adobeインフルエンサー。九州芸術工科大学→ドリームキャスト→サーバーサイド→フロントエンド→執行役員→早稲田大学大学院→Kinect v2

好きな飛行機
B787-8
好きな空港
SXM
好きな航空路
Y28
Hideyuki Mikasa
オーサリングエンジニア

mikasa's text