Flash 輪講第 1 回資料 - KineticFusion

2004/02/24

遠藤侑介

目次

1. KineticFusion とは?

1.1. 概要

KineticFusion とは、swf と XML を相互に変換するソフトウェアです。

swf (Shockwave Flash) とは Macromedia® Flash™ の native format で、RVML (Rich Vector Markup Language) とは XML の一種です。

以下の特徴があります。

新規に swf を作ったり、既存の swf を書き換えたり、画像や音楽などのリソースを抽出したり、非常にさまざまな用途が考えられます。

1.2. 環境設定

http://www.kinesissoftware.com/downloads.html あたりからダウンロードできます。適当にインストールしてください。とってつけたような GUI がありますが、KineticFusion.jar を CLASSPATH に設定してコマンドラインから

java com.kinesis.KineticFusion processFile toXML hoge.swf hoge.xml
java com.kinesis.KineticFusion processFile toSWF hoge.xml hoge.swf

などとすることもできます。

僕は CLASSPATH の設定が面倒だったので KineticFusion.jar を %J2SDK%\jre\lib\ext に入れて、cygwin で

#!/bin/sh
java -Dkinesis.SWFConfigDirectory=`cygpath -wa .` com.kinesis.KineticFusion processFile toSWF $1 `basename $1 xml`swf
#!/bin/sh
java -Dkinesis.SWFConfigDirectory=`cygpath -wa .` com.kinesis.KineticFusion processFile toXML $1 `basename $1 swf`xml

というシェルスクリプトから

./swf2rvml.sh hoge.swf
./rvml2swf.sh hoge.xml

などと実行しています。

java の properties ファイルを適当に用意して KineticFusion のオプション設定を変えることができます。詳しくは こちら 。swf を rvml に展開するときは、環境変数 $TEMP_DIR か properties ファイルのkinesis.flash.repository.directory を適当に設定しておいたほうがいいと思います。さもないと抽出されたリソース群がデフォルトの /temp (windows だと C:\temp) に書き出されてしまいます。

僕は次のような KineticFusion.properties をシェルスクリプトと同じディレクトリに置いています。

kinesis.flash.repository.directory=.
kinesis.actionscript.includePath=.

2. 簡単な実例

とりあえず簡単な swf を作ってみましょう。以下のような RVML の xml ファイルを用意します (ダウンロード) 。ここでは kuma.xml というファイル名とします。

001 <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
002 <!-- <!DOCTYPE Movie SYSTEM "dtd/RVML.dtd"> -->
003 <Movie version="6" sizeShape="kuma" rate="30"
004   backgroundColor="rgb(30, 50, 200)" compressed="No"
005   xmlns="http://www.kineticfusion.org/RVML/1.0">
006   <Title>kuma-</Title>
007   <Repository repositoryType='File' repositoryBase='.' repositoryName='.'>
008     <Image id='kumaImage' imageType='Lossless'
009       resourceType='External' resourceLocation='kuma.png' />
010   </Repository>
011   <Definitions>
012     <ImageShape id="kuma" imageName="kumaImage" />
013   </Definitions>
014   <Timeline>
015     <Frame>
016       <Place name="kuma" depth="1" />
017     </Frame>
018   </Timeline>
019 </Movie>

kuma.xml のあるディレクトリに images サブディレクトリを作成し、その中に kuma.png という png ファイルを用意して

java com.kinesis.KineticFusion processFile toSWF kuma.xml kuma.swf

とすると kuma.swf が作成されます。ブラウザなどで表示すると kuma.png が表示される swf のできあがりです (ダウンロード) 。

3. swf フォーマット

RVML について説明する前に、swf のフォーマットを簡単に説明しておきます。

swf は、Flash のバージョンやフレームレートなどの情報を持つファイルヘッダを除くと、基本的にタグの列だけで成り立っています。タグとはタグ名、タグ長、ペイロードからなるデータの固まりで、大きく、定義タグ、操作タグ、表示タグ、終了タグの 4 種類に分けられます。

定義タグDefineShape 、DefineButton 、DefineText など多数図形などを定義して ID を割り振る。フレームに影響は及ぼさない。
操作タグPlaceObject 、RemoveObject など定義された ID を示してフレームに図形を配置、除去などする。
表示タグShowFrame のみ操作タグによって描画されたフレームを表示する。
終了タグEnd のみタグの列の終端を表す。

定義タグで図形を定義し、操作タグでその図形をフレームに配置し、表示タグで現在のフレームを画面に描画する、というパターンが 1 フレームに相当し、これを繰り返すのが基本です。表示タグでフリップ (裏バッファを画面に表示) するようなダブルバッファリングを想像するとわかりやすいと思います。

タグ名効果フレーム画面
フレーム 1DefineShapeID 1 に▲を定義[   ][   ]
PlaceObjectID 1 の図形を画面左に配置[▲  ][   ]
ShowFrame現在のフレームを画面に描画[▲  ][▲  ]
フレーム 2PlaceObjectID 1 の図形を上下反転して画面中央に配置[▲▼ ][▲  ]
DefineShapeID 2 に■を定義[▲▼ ][▲  ]
RemoveObjectID 1 の図形を除去[ ▼ ][▲  ]
PlaceObjectID 2 の図形を画面右に配置[ ▼■][▲  ]
ShowFrame現在のフレームを画面に描画[ ▼■][ ▼■]
フレーム 3PlaceObjectID 2 の図形を 45 度回転して画面右に配置[◆▼■][ ▼■]
ShowFrame現在のフレームを画面に描画[◆▼■][◆▼■]
(繰り返し)
End終端

同じ図形を複数配置したい場合でも、複数の定義タグを置く必要はなく、同じ ID を指定して配置できます。というと、複数配置したのち 1 つだけ除去したい場合にどれを除去するのかわからず困りそうに思えます。ですが実際には配置の際に、配置する図形の depth (Z オーダ) を指定する必要があり、同じ depth に複数の図形を配置することはできないことになっています。除去の際も depth を指定する必要があり、除去すべき図形は一意に定まります。

4. RVML

4.1. 概要

RVML とは、swf を完全に表現できるように設計された XML の一種です。現時点ですべてのバージョンの swf 動画は RVML として表現できます。一部 SVG の概念も取り入れているらしいですがよく調べていません。DTD や XML Schema は http://www.kinesissoftware.com/RVML/1.0 にあります。

詳細なリファレンスは http://www.kinesissoftware.com/Products/KineticFusion/reference.html にあるので、以下では大まかな説明をします。

root となる要素は Movie で、属性に Flash のバージョンや画面サイズ、フレームレート、swf を圧縮するかどうかなどを指定します。Movie 要素の子要素で重要なのは Repository 、Definitions 、Timeline です。Repository では再生中に使用する外部リソース (フォント、画像、音楽、ビデオなど) を指定します。Definitions では再生中に使用するシンボル (後述) を定義します。Timeline は子要素として 1 つ以上の Frame 要素を持ち、各フレームではシンボルを配置したり、移動したり、除去したりできます。複数のフレームがあるときは、各フレームを指定されたフレームレートで順に表示していき、最後のフレームを表示した後に最初のフレームに戻ります。ただし ActionScript (後述) を使用して再生を制御する場合この限りではありません。

4.2. シンボル

シンボルとはシェイプ、フォント、テキストフィールド、テキスト、ボタン、ムービークリップのいずれかのことのようです。Flash の用語は氾濫しているので、はっきりした定義が見つけられませんでした。

僕の探し方が下手なだけかも。FlashMX 2004 30 日間無償トライアル版に付属するマニュアル Using_Flash.pdf には「"シンボル"とは、Macromedia Flash MX 2004 または Macromedia Flash MX Professional 2004 で作成したグラフィック、ボタン、またはムービークリップです。」などと書かれていました。これが定義なら KineticFusion でシンボルは作成できません。

ひょっとしたら KineticFusion (RVML) の言うシンボルと Flash の言うシンボルで意味が異なるのかも。

シンボルはフレームに配置することでインスタンスになります。同じシンボルから異なるインスタンスを作成することもでき、そういう意味ではシンボルは (通常のオブジェクト指向で言う) クラスに相当するようです。

シンボルのうち特に重要なのはムービークリップで、独立したタイムラインを持っていて、それに従って再生されます (ただしフレームレートは共通) 。例えばルートのムービーが ActionScript によって停止されても、ムービークリップは再生しつづけます。

また RVML はステージ (swf の表示画面) の左上を原点とした pixel 単位の座標系を採用しています (swf フォーマットの仕様は TWIP 単位。20 TWIP = 1 pixel) 。各シンボルも独立した座標系を持ち、配置される際はインスタンスの座標をシンボルの原点に併せて表示されます。

Definitions 要素で定義されたシンボルは Frame 要素中に Place することで配置、Alter することで移動その他表示の変更、Remove することで除去できます。

4.3. ActionScript

ActionScript とは、European Computers Manufacturers Association (ECMA) の定める ECMA-262 仕様に準拠の、オブジェクト指向スクリプト言語です。ECMA-262 仕様が JavaScript を起源としているため、ActionScript は JavaScript と似ています。

ActionScript を利用すると、ルートのムービーやムービークリップの再生、停止、指定したフレームへジャンプ、移動、回転、透明度の変更、表示/非表示切り替えなどや、ユーザのマウスやキーボードからの入力などに対するイベントハンドリング、同一サーバ内の swf やテキストなどのダウンロードや xml 通信など、さまざまなことができます。

ActionScript を持つアクションには、以下の 4 種類があります。KineticFusion は ActionScript 1.0 の機能をすべてサポートしていて、それぞれ以下の要素を使用することで ActionScript を記述できます。

アクションKineticFusion備考
フレームに付属するアクションFrameActions再生ヘッダが当該フレームに到達したとき実行される。
初期化のためのアクションInitClipActionsシンボルがロードされた時に実行される。
ムービークリップに付属するアクションMovieClipActionsムービークリップに対してイベントが発生したときに (それに対応するイベントハンドラがあれば) 実行される。
ボタンに付属するアクションButtonActionsボタンに対してイベントが発生したときに (それに対応するイベントハンドラがあれば) 実行される。

FrameActions 要素は Frame 要素の子要素です。再生ヘッダがこのフレームに到達したときに実行されるのですが、厳密には「再生ヘッダが自分以外のフレームからこのフレームへ入ってきたとき」に実行されるので、自身のフレームへジャンプするような ActionScript を記述しても次のフレームへ進んでしまいます。フレームのループは最低 2 フレームないと行えないようです。また実行のタイミングは、このフレームで行うべき配置、変形、除去などの処理 (Place や Remove 要素など) を行った後、かつ、実際に画面に表示される前です。

あるシンボルを 1 フレーム目で配置、2 フレーム目で何もせず、3 フレーム目で除去、4 フレーム目で ActionScript を利用して 2 フレーム目へジャンプ、とするような状況を考えます。3 フレーム目で除去されているので、このシンボルは最初に 2 フレームほど表示されるだけのように思えますが、実際には 1 フレーム表示して 2 フレーム表示しない、の繰り返しになります。各フレームが表示すべきシンボル一覧を保持しているようなのですが、そうなるという記述を KineticFusion のマニュアルから見つけられませんでした (まだ全部読んでないのですが) 。

InitClipActions 要素は Movie 要素の子要素で、シンボル、とくにムービークリップがロードされたときに 1 度だけ実行されます。FlashMX などでは 1 フレーム目に

#initclip
foo = 1;
bar = 'str';
#endinitclip
などというような ActionScript を記述するらしいです。シンボルの初期化なので何個インスタンスを作ろうとも最初に 1 度だけ実行されます。

MovieClipActions 要素は Place 要素で、ムービークリップのインスタンスに対してイベントハンドラを設定します。例えば、enterFrame というイベントはフレームが更新されるたびに発生するイベントで、

onClipEvent(enterFrame)
{
  _x++;
}

と書けば 1 フレーム毎にこのムービークリップが 1 pixel 右に進みます。ほかにも load 、unload 、mouseMove 、mouseDown 、mouseUp 、keyDown 、keyUp 、data 、setParameters などといったイベントがあるらしいですがまだ調べていません。

ButtonActions は Button の子要素で、ボタンのシンボルに対してイベントハンドラを設定します。おおよそ MovieClipActions と同じようですが、onClipEvent ではなく on と書くらしいです。イベントの集合も異なって press 、release 、releaseOutside 、rollOver 、rollOut 、dragOver 、dragOut 、keyPress らしいですがこちらもまだ調べていません。

ActionScript のライブラリについては、FlashMX 2004 30 日間無償トライアル版に付属するマニュアル FL_ActionScript_Ref.pdf が (あたりまえですが) 詳しいです。このトライアル版はインストールしなくてもマニュアルが読めるので (アーカイブの中にインストーラと共に pdf 群が圧縮されている) 入手しておいて損はないと思います。

5. 実例

5.1. 複数フレームある例

すこし長めですが (ダウンロード) 、

001 <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
002 <!-- <!DOCTYPE Movie SYSTEM "dtd/RVML.dtd"> -->
003 <Movie version="6" width="130" height="180" rate="30"
004   backgroundColor="rgb(30, 50, 200)" compressed="No"
005   xmlns="http://www.kineticfusion.org/RVML/1.0">
006   <Title>kuma-</Title>
007   <Repository repositoryType='File' repositoryBase='.' repositoryName='.'>
008     <Image id='kumaImage' imageType='Lossless'
009       resourceType='External' resourceLocation='kuma.png' />
010   </Repository>
011   <Definitions>
012     <ImageShape id="kuma" imageName="kumaImage" />
013   </Definitions>
014   <Timeline>
015     <Frame>
016       <Place name="kuma" depth="1">
017         <Transform translateX="32" translateY="45" />
018         <RGBAColorTransform multAlpha="1.0" />
019       </Place>
020     </Frame>
021     <Frame>
022       <Alter name="kuma" depth="1">
023         <Transform translateX="29" translateY="41" scale="1.1" />
024         <RGBAColorTransform multAlpha="0.9" />
025       </Alter>
026     </Frame>
027     <Frame>
028       <Alter name="kuma" depth="1">
029         <Transform translateX="26" translateY="36" scale="1.2" />
030         <RGBAColorTransform multAlpha="0.8" />
031       </Alter>
032     </Frame>
033     <Frame>
034       <Alter name="kuma" depth="1">
035         <Transform translateX="23" translateY="32" scale="1.3" />
036         <RGBAColorTransform multAlpha="0.7" />
037       </Alter>
038     </Frame>
039     <Frame>
040       <Alter name="kuma" depth="1">
041         <Transform translateX="19" translateY="27" scale="1.4" />
042         <RGBAColorTransform multAlpha="0.6" />
043       </Alter>
044     </Frame>
045     <Frame>
046       <Alter name="kuma" depth="1">
047         <Transform translateX="16" translateY="23" scale="1.5" />
048         <RGBAColorTransform multAlpha="0.5" />
049       </Alter>
050     </Frame>
051     <Frame>
052       <Alter name="kuma" depth="1">
053         <Transform translateX="13" translateY="18" scale="1.6" />
054         <RGBAColorTransform multAlpha="0.4" />
055       </Alter>
056     </Frame>
057     <Frame>
058       <Alter name="kuma" depth="1">
059         <Transform translateX="10" translateY="14" scale="1.7" />
060         <RGBAColorTransform multAlpha="0.3" />
061       </Alter>
062     </Frame>
063     <Frame>
064       <Alter name="kuma" depth="1">
065         <Transform translateX="6" translateY="9" scale="1.8" />
066         <RGBAColorTransform multAlpha="0.2" />
067       </Alter>
068     </Frame>
069     <Frame>
070       <Alter name="kuma" depth="1">
071         <Transform translateX="3" translateY="5" scale="1.9" />
072         <RGBAColorTransform multAlpha="0.1" />
073       </Alter>
074     </Frame>
075     <Frame>
076       <Alter name="kuma" depth="1">
077         <Transform translateX="0" translateY="0" scale="2.0" />
078         <RGBAColorTransform multAlpha="0" />
079       </Alter>
080     </Frame>
081   </Timeline>
082 </Movie>

kuma.png が拡大しつつ薄くなって消えていくのを繰り返します (ダウンロード) 。

2 の簡単な実例 から変わったところは、Movie 要素の属性と、Frame が増えたことです。

Movie 要素の属性は shapeSize (画面サイズを指定したシンボルのサイズに合わせる) ではなく直接 pixel で指定しました (最大 2 倍まで拡大するため)。

Place 要素ではただ配置するだけでなく、子要素に Transform 要素を指定し、表示位置をずらしています。RGBAColorTransform 要素では透明度 1.0 (全く透明でない) を指定しています。

その後のフレームの Alter は、すでに配置されているシンボルの表示方法を変更する要素で、少しずつ拡大しながら (scale 属性) 透明度を下げて (より透明になるように) います。

5.2. ActionScript の例

次は ActionScript を使用して回転させてみます (ダウンロード) 。

001 <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
002 <!-- <!DOCTYPE Movie SYSTEM "dtd/RVML.dtd"> -->
003 <Movie version="6" width="130" height="180" rate="30"
004   backgroundColor="rgb(30, 50, 200)" compressed="No"
005   xmlns="http://www.kineticfusion.org/RVML/1.0">
006   <Title>kuma-</Title>
007   <Repository repositoryType='File' repositoryBase='.' repositoryName='.'>
008     <Image id='kumaImage' imageType='Lossless'
009       resourceType='External' resourceLocation='kuma.png' />
010   </Repository>
011   <Definitions>
012     <ImageShape id="kuma" imageName="kumaImage" />
013     <MovieClip id="kuma_movieclip">
014       <Timeline>
015         <Frame>
016           <Place name="kuma" depth="3">
017             <Transform translateX="-32" translateY="-45" />
018           </Place>
019         </Frame>
020       </Timeline>
021     </MovieClip>
022   </Definitions>
023   <Timeline>
024     <Frame>
025       <Place name="kuma_movieclip" depth="1">
026         <Transform translateX="64" translateY="90" />
027         <MovieClipActions><![CDATA[
028 onClipEvent( enterFrame )
029 {
030   if((this._rotation = this._rotation + 30) >= 360) this._rotation -= 360;
031 }
032 ]]></MovieClipActions>
033       </Place>
034     </Frame>
035   </Timeline>
036 </Movie>

kuma.png が回転し続けます (ダウンロード) 。

Definitions に MovieClip を追加して、kuma を表示するだけのムービークリップ kuma_movieclip を定義しました (13 行目の MovieClip) 。ここでムービークリップの原点を kuma の中心にあわせておきます (17 行目の Transform) 。

Timeline では 1 つのフレームだけを用意して、kuma の代わりに kuma_movieclip を画面中心に (16 行目の Transform) 配置して、27 行目の MovieClipActions で ActionScript を記述しています。

MovieClip インスタンスは _rotation というプロパティを持ち、毎フレームこれに適当な角度を足すことで回転させることができます (ちなみに角度はラジアンではなく度) 。

ActionScript は CDATA を使用して記述するのが KineticFusion に推奨されています。

5.3. 音楽の再生

最後に音楽を再生してみます (ダウンロード) 。sounds サブディレクトリを作成して、その中に何らかの mp3 を用意してください。ここでは TAM Music Factory の効果音素材から soft-001.mp3 を使用させていただいています。

001 <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
002 <!-- <!DOCTYPE Movie SYSTEM "dtd/RVML.dtd"> -->
003 <Movie version="6" sizeShape="kuma" rate="30"
004   backgroundColor="rgb(30, 50, 200)" compressed="No"
005   xmlns="http://www.kineticfusion.org/RVML/1.0">
006   <Title>kuma-</Title>
007   <Repository repositoryType='File' repositoryBase='.' repositoryName='.'>
008     <Sound id="bgm" format="MP3"
009       resourceType="External" resourceLocation="soft-001.mp3" />
010     <Image id='kumaImage' imageType='Lossless'
011       resourceType='External' resourceLocation='kuma.png' />
012   </Repository>
013   <Definitions>
014     <ImageShape id="kuma" imageName="kumaImage" />
015   </Definitions>
016   <Timeline>
017     <Frame>
018       <PlaceSound name="bgm">
019         <SoundInfo uniquePlay="Yes" stopPlaying="No" loopCount="1" />
020       </PlaceSound>
021       <Place name="kuma" depth="1" />
022     </Frame>
023   </Timeline>
024 </Movie>

停止した kuma.png を表示されながら soft-001.mp3 が 1 度だけ再生されます (ダウンロード) 。

音楽は Definitions でシンボル定義することなく、Repository を直接指定して PlaceSound 要素で再生します。子要素の SoundInfo では再生の方式を指定しています (uniquePlay : すでに同じ音楽が再生されていたら再生しない/音を重ねて再生する、stopPlaying : すでに同じ音楽が再生されていたらすでに再生されていた方を止める/止めない、 loopCount : 再生繰り返し回数) 。

音楽だけシンボル定義を介さないのは、swf の仕様でも音楽を特別扱いしているためだと思います。音楽データは一般に巨大なので、swf の一箇所にまとめて格納してしまうと、低速な回線ではストリーミング再生している際、音声データの箇所で再生が止まってしまうおそれがあります。このために swf では、mp3 の断片を細かく切って各フレームのデータの間にちりばめることができます。(推測ですが) このような理由で他のシンボルに比べて幾分複雑な仕様になっているため、扱いにくくなっているのだと思います。

このほかにも KineticFusion のサイトには RVML の実例 がたくさんあるので、これとリファレンスを見ながら使い方を把握していくことになると思います。

6. 関連ソフトウェア

swf を出力または解析するような関連ソフトウェアを軽く紹介します。すべてフリーソフト (のはず) です。

6.1. Ming

Ming はおそらく swf を出力するライブラリとして最も有名なものです。C で書かれたライブラリなので、swf を出力する場合はこのライブラリを使用するプログラムコードを書くことになります。java 、C++ 、PHP 、Perl 、Ruby 、Python などから Ming ライブラリを使用するインターフェイスが提供されているようです。既存の swf を解析したり書き換えたりすることはできません。多分。

半年前に少しいじったきりなので今どうなってるのかはよく知りません。

6.2. sswf

sswf は独自言語のテキストファイルと swf を相互変換するソフトウェアです。この独自言語は RVML より swf のフォーマットに近く煩雑です。また現時点では ActionScript のコンパイラ、逆コンパイラは実装されていないので、ActionScript のバイトコードを手で書き下さなければなりません。処理系が不安定です。このサイトの swf の仕様書 は、少し古く Flash 6 までのものですがとてもまとまっています。

6.3. Flasm

Flasm は ActionScript バイトコードのアセンブラ、逆アセンブラです。基本的には既存の swf を逆アセンブルして、改造してアセンブルし直す、という使い方しかできません。

7. 参考文献

mailto: mame AT tsg.ne.jp