Adobe Animateで作ったCreateJS形式コンテンツをWebGL再生したい

# はじめに

Flash、ついに終わりますね（悲しみ）

3年前、同じようなコンセプトで[こんなもの](https://qiita.com/tawatawa/items/1ed67517f91c1cbfc489)を作ったんですが、
Adobe Animateのバージョンが上がり、書き出されるコンテンツの構造が変わっていたりするので

Creap.jsの進化版
**Adobe Animate製CreateJSコンテンツを、[pixi.js](https://www.pixijs.com/)で再生するプラグイン**
[pixi-animate-player](https://github.com/tawaship/pixi-animate-player)

を改めて作ってみました。

目指すのはCreap.jsと同様

- アニメーションをAnimateで作りたい
- でも動作速度は改善したい

です。

## ドキュメントとサンプル

https://tawaship.github.io/pixi-animate-player/

# 使いかた

## 用意するもの

- CreateJS 1.0.0
- pixi.js 5.3.2
- pixi-animate-player 2.1.2
- Adobe Animateでパブリッシュしたコンテンツ一式

## ファイルの読み込み
~~~html
<script src="https://code.createjs.com/1.0.0/createjs.min.js"></script>
<script src="pixi.5.3.2.min.js"></script>
<script src="pixi-animate-player.min.js"></script>
<script src="content/content.js"></script> <!-- Adobe Animateでパブリッシュしたコンテンツ一式のjsファイル -->
~~~

1. 最初にpixi.js及びCreateJS（順不同）
2. 次にpixi-animate-player
3. 最後にcontent/content.js

という順で読み込むようにしてください。

## 実行
~~~javascript
var player = new PIXI.animate.Player(
    "[conposition id]", // "lib.properties.id" in Animate content.
    "[root class name]", // Root class name of Animate content.
    "[content directory path]", // Directory path of Animate content.
    {
        useSynchedTimeline: true,
        useMotionGuide: false
    },
    {
        antialias: true
    } // Options of PIXI.Application.
);

player
    .prepareAsync({
        crossOrigin: false
    })
    .then(function() {
        player.play();
    });
~~~

- **[conposition id]**
content.js内で`lib.properties.id`として定義されている32文字くらいの文字列。

- **[root class name]**
`root`に該当する`MovieClip`クラス名。
Animateが勝手に付けるので、大体はflaファイルと同名になっているはず。
（content.flaであれば `content`）

- **[content directory path]**
「Adobe Animateでパブリッシュしたコンテンツ一式ディレクトリ」の
**HTMLから見た相対パス**、または**絶対パス**のいずれか。
絶対パスを使用、かつアセットが別サーバにある場合は、`player.prepareAsync`の引数の`crossOrigin`を`true`にする。


プラグイン自体に`Promise polyfill`は含めていないので、
必要があれば別途読み込んでください。

## パフォーマンス

[ここ](https://tawaship.github.io/pixi-animate-player/samples/20.02/)の`Benchmarks`を見てもらえると分かりますが、
ざっくりと**重い処理になればなるほど効果が高い**といって差し支えないかなと思います。

例として、私のPCでのFPSは

|| CreateJS| pixi-animate-player(webGL) | pixi-animate-player(canvas) |
|-----------|------------|------------|------------|
| 100インスタンス | 60 | 60 | 60 |
| 1000インスタンス | 52 | 60 | 56 |
| 1000インスタンス(着色) | 42 | 58 | - |
| 5000インスタンス | 12 | 25 | 14 |

のような感じで、基本的にはwebGLの力での高速化が大きく、
加えてpixi.jsのレンダリング処理の最適化も若干利いているという感じでしょうか。

本来pixi.jsであれば、[5000インスタンス程度ではFPSは下がらない](https://tawaship.github.io/pixi-animate-player/samples/20.02/5000_scripts/pixi/)んですが、
**タイムライン＋入れ子**という構造が処理に強く影響しているような印象です。


# 仕組み

ここからは内部構造についてちょっと。
使えればいいよって方は読み飛ばしてください。

## 処理フロー

CreateJSの処理フローはざっくりと

1. アセットのプリロードやらをして
2. ティッカーが回って
3. プロパティが変化して
4. レンダリングされて
5. 2に戻る

![animate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126740/c9583ea5-9a65-0cbe-9cb3-7466c8b7c01a.png)

のような形です。

pixi-animate-playerでは、このフローが

1. CreateJSのアセットのプリロードやらをしつつpixi.jsの準備をして
2. CreateJSのティッカーが回って
3. CreateJSのプロパティが変化すると同時にpixi.jsのプロパティも変化して
4. pixi.jsでレンダリングされて
5. 2に戻る

![core.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126740/0d1b63b6-6af0-5d1e-0b68-adbce841ec25.png)

のようになっています。

ユーザスクリプト（flaファイル上でタイムラインに実装するスクリプト）は、
そのほとんどが**描画内容を変化させるため**に実装しているものですので、
最終的な描画内容が確定するまではCreateJSに任せてしまい、
レンダリングだけpixi.jsで横取りすればいいや、という考え方です。

本来はCreateJSを完全にエミュレートした方が処理量が少なくなるのですが、
全てのクラスを完全に実装しない限り、ユーザスクリプトに対応しきれない部分があったので
このような形を採っています。

唯一、ユーザのインタラクションイベント（タップなど）だけは、
イベントを受けるのがpixi.jsのオブジェクトになるため、ひと手間加えた処理をしています。

## プラグインの構造

上記フローを実現するために

- `createjs.DisplayObject`継承クラスのインスタンス1つ(**以下A**)につき
`PIXI.DisplayObject`継承クラスのインスタンスを1つ(**以下B**)、対になるように生成、
(e.g. `createjs.MovieClip` -> `PIXI.Container`)

- Aのプロパティが変化すると同時に、Bの対応するプロパティを変化させる
(e.g.`A.scaleX` -> `B.scale.x`)

- Bが受けたインタラクションを、Aに対するインタラクションとして処理する
(e.g. ユーザアクション -> `B.emit('pointerdown')` -> `A.dispatchEvent('mousedown')`)
※これはイメージで、実際には登録されたハンドラを実行しているだけ

といったことをしています。

# おわりに

端末の性能も向上してきたので、Animate製CreateJSコンテンツそのまま再生でも問題ないかもなーと思いつつ
どこかで何かの役に立てばいいなと。

~~AnimateからのwebGL書き出しはいつになったらスクリプト対応するんですかね？~~

みんなもAnimate使ってね！