はじめに
こんにちは。元 Flasher の皆さんも概ね元気そうでなによりです。
このアドベントカレンダーを見ていると元 Flasher の人達がどんな方向に進んだのかが見えて面白いですね。
Web 界隈で生きている人、3D に行った人、アプリ方面で頑張っている人、アニメーションを描いている人、アートな人、カレー食べてる人、などなど。皆さん色んな方面で活躍していて嬉しく思います。
私はというと、最近は Haxe も触ったりしてますが、まだ Flash を触っている数少ない Flasher の生き残りです。強いて言えばゲーム方面に近いですかね。
さて、今回 Flasher について色々と考えてみようと色々と思案していたのですが、私が語る前に皆さんの記事を見て Flasher とはどんな存在なのか分かったような気がします。Flasher とは空間だけでなく時間も考えることができる人達のことだと。言い換えるなら、 Flasher とはモーション・アニメーションで戦う人達のことだと。
どうしたら気持ちよく見えるのか、どうしたら面白く見えるのか、四六時中そんなことを考えているのでしょうね。そんな職人のような彼らの技術をもって作られた SWF は美しいんです。(タイトル回収)
職人の技術が見えない部分に現れるように、 Flasher の技術もまた、人間には見え難い部分に現れています。
そうです。 SWF というバイナリの中でそれは起きていたのでした。
Flash が重い
そんな相談を受けたのは、つい 1~2 ヶ月ほど前でした。(残念ながら仕事の物なので画像は出せません…)
重いという言葉に込められた意味はいくつかありますが、ここで言う 重い は 描画的に重い という意味の重いでした。その重さは FPS が落ちる形で目に見えてきます。
問題の SWF を見てみると、確かに FPS が大きく落ちていました。
細かな描画があり、シェイプの回転があり、一般的に重くなると言われている、アルファやカラートランスフォームなどが使われてはいました。しかし、この程度ではここまで遅くはならないだろうという程に FPS は落ちていました。(他にはエフェクトやクリッピングマスクなども重くなる原因だったりしますが今回はありませんでした。)
では、何故ここまで重くなってしまったのでしょうか。
重かったらまずは SWF を見る
ほぼ癖になっていますが、私は SWF があったらまずは SWF のバイナリを見ます。重いと言われている SWF を見ると、予想通り目を覆いたくなるような結果が見えてきました。DefineShape
と DefineSprite
が交互に並んだ 美しくないタグリスト です。
これが実際の美しくないタグリストです。
別に DefineShape
や DefineSprite
が悪いわけではありません。これらにはちゃんと役割があり、正しく使って、正しく表現すればいいのです。
ではなぜこの 美しくないタグリスト が良くないのでしょうか。
それを知るためには SWF の基本的な描画の仕組みと DefineShape
、 DefineSprite
等について知る必要があります。
DefineShape と DefineSprite
まずは Define 系です。役割は名前を見ても分かる通りで、これらは Shape や Sprite を定義するものです。DefineShape
には、ベクターデータを描画するさいのアンカーや、塗りの色情報などが格納されています。DefineSprite
は、定義されたりソースを参照して制御することができます。Sprite や MovieClip のように複数の Shape を参照して内包したり、複数の制御タグを持つことができます。制御タグで、Matrix 変換、ColorTransform などで 1 フレーム毎に制御することでアニメーションを実現したりすることもできます。
これらの DefineShape
、DefineSprite
等は、それぞれのタグが読み込まれると FlashPlayer 上で一度ディクショナリに登録され、一意のキャラクタIDを割り振られます。この時点ではまだ描画されません。定義が終了した後、後続の制御タグで、具体的には PlaceObject
タグ1でルートの DisplayList に追加することで描画の準備が行われます。
描画のタイミング
SWF が描画されるタイミングはShowFrame
です。FlashPlayer はShowFrame
タグが見つかるまで、SWF 内の全てのタグを前から処理していきます。この時点で DisplayList が画面にコピーされ、次のフレームまで FlashPlayer はアイドル状態になります。最初のフレームの内容は最初の ShowFrame
タグの前にある全てのタグを実行した累積的な結果であり、2 フレーム目移行の内容も 2 番目以降の ShowFrame
タグまでの累積的な結果です。
当然のことながら、 1 フレームの間にタグが多いほどその描画は重くなっていきます。
美しくないタグリスト
さて、基本がわかったところで問題の美しくないタグリストでは何が起こっているのかを見ていきましょう。
DefineShape
でグラフィックを定義することに問題はありません。問題は無駄なDefineSpriteです。何が無駄かというと、実はこの例のDefineSprite
は、直前のDefineShape
を内包して描画しているだけなんです。そしてルートの DisplayList に追加されるのは、この無駄なDefineSprite
を参照しています。
そうすると、DefineSprite
は毎フレーム ShowFrame
が実行されるので、1フレームに何度も描画が実行されることになり、結果「描画が重い」という話になるわけです。描画の最適化をしていく際にドローコールを減らす工夫をしたりしますが、まさにそれと逆のことがここで起きていました。
どう作ったのか?
「むしろ見てみたいよその fla ファイル」と思う人もいるかもしれませんが、見せるまでも無く荒れ放題でした。よく言えば試行錯誤の後が見て取れました。壊れたトゥイーン、無駄なネスト、○○のコピーのコピーのコピー、過剰なまでのムービークリップ祭。
まるでこの記事のようにいらない情報だらけで乱雑でした。2
Flasher が作り直すと
タグリストはこうなります。
無駄なネストが消え、タグもすっきりしました。スクロールしていくと、DefineSprite
が 1 つあり、その中では上で定義した Shape を参照し、Matrix 変換などをしてアニメーションを実現しています。さらにその下には PlaceObject
で DisplayList に追加する命令と、ShowFrame
があるシンプルなつくりです。
コレが現実的な最適化の範疇ですが、もっと最適化していくと下のようにタグが減ります。
しかしこれはやりすぎというか、時間もかかるのでオススメはしません。
とはいえ、タグリストには職人芸の美しさが滲み出ているのが分かると思います。
Flasher
Flasher の得意分野は SWF の最適化ではありません。しかし、無意識にその構造は最適化されていました。Flasher は本能的に動きに最適化された構造を理解し、それを実現しているのです。それはなにも SWF に限った話ではないと思います。他の分野でも大きく活躍する元 Flasher 達の姿がそれを証明しているではないでしょうか。3
~蛇足
正直ここ以外が蛇足です。
例の構造にならないようにするには、MovieClip
を使いすぎなければ大体大丈夫です。
さいごに
Flash はバイナリレベルまで見てて面白いのに、何故嫌われてしまったんでしょう。
そして私はいったい何になりたいんでしょうか。
きっと VM や CPU やコンパイラになりたいんだと思います。
-
正確には PlaceObject2とか3とかですがそのあたりを説明すると長くなるので省略 ↩
-
あえてそう書きました。
おそらくツールの使い方や、動かしやすい構造を理解していないんです。
思い返せば Flash を始めて触った時(MX 2004 でした)、タイムラインの概念がいまいち理解できずに、グチャグチャの fla ファイルが出来上がりました。最終的に自分の納得できる「見た目」になったので良しとした記憶があります。それはこの fla を作ったデザイナーさんの中でも同じことなのだと思いました。
デザイナーさんは言われたとおりにデザインし、動かしてくれといわれたから動かしたのでしょう。しかし、そこに動かし方の知識はなく、思った見た目の通りにそれを再現してみただけです。Flasher のように構造にまで気を配る人は中々いませんし、それでできてしまうのが Flash の良いところであり、悪いところでもありました。 ↩ -
無理矢理な個人の感想です ↩