いまさらFlash/AIR/ActionScript3関係のTips

2021年になった今でもFlashとAIRとAS3と付き合っている（or付き合うハメになった）人へ捧ぐ。

# Shared Objectへのパス
データの保存先としてよく使われていたFlash cookieことSharedObjectのパス一覧。公式が消えた時用に転載しておきます。

## Flash Projectorの場合
プロジェクターの場合（だったと思うけど昔すぎて忘れた）は、**ブラウザのクッキー削除に巻き込まれるので注意。** ブラウザーでクッキーを全削除したら、関係ないはずのプロジェクター製アプリのセーブデータまで消えるってアレですね！😵

|OS|パス|
|--|--|
|Windows95/98/ME/2000/XP|c:/Documents and Settings/【ユーザー名】/Application Data/Macromedia/Flash Player/#SharedObjects/【ランダムなフォルダ名】/【ホスト名】/【アプリケーションへのパス】/【オブジェクト名】.sol|
|WindowsVista/7/8/10|c:/Users/【ユーザー名】/AppData/Roaming/Macromedia/Flash Player/#SharedObjects/【ランダムなフォルダ名】/【ランダムなフォルダ名】/【ホスト名】/【アプリケーションへのパス】/【オブジェクト名】.sol|
|macOS|/Users/【ユーザー名】/Library/Preferences/Macromedia/Flash Player/#SharedObjects/【Webドメイン名】/【アプリケーションへのパス】/【アプリ名】/【オブジェクト名】.sol|
|Linux/Unix|/home/username/.macromedia/Flash_Player/#SharedObjects/【Webドメイン名】/【アプリケーションへのパス】/【アプリ名】/【オブジェクト名】.sol|

参考:[Adobe Flash Platform * 共有オブジェクト](https://help.adobe.com/ja_JP/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7d80.html)

## AdobeAIRの場合
|OS|パス|
|--|--|
|Windows10|C:/Users/【ユーザー名】/AppData/Roaming/【アプリ名】/Local Store/#SharedObjects/【オブジェクト名】.sol|


# サイズや角度計算はあくまでシンボルベース
タイムライン上にシンボル置いて、プロパティでサイズとか角度設定して、更にそっから必要があればプログラムで弄るという作り方が多いと思います。
画面上で見えちゃってるので、ついつい感覚を引っ張られがちですが、内部的にはシンボル（≒クラス）でnewしてプロパティの値で自動的に上書きしてるに過ぎない（想像）ので、プログラム書く際はシンボルベースで計算すること。特に角度（.rotation）関係でやらかしがち。.rotation=0はステージに置かれた状態ではなくシンボルの状態！（標語）

# 実はコレクション操作メソッドあります。
JSやJavaで普及が進みつつあるコレクション操作メソッド。実はAS3でも[forEach/filter/some/everyがArray,Vectorの組み込みメソッドとして用意](https://help.adobe.com/ja_JP/FlashPlatform/reference/actionscript/3/Array.html)されており、同じように使うことできます。
省略記法が無いので毎回function句と引数3つとも書く必要があったりと現代から見ると面倒ですけどね。また.flatとか.reduceとかもありませんが、AS3もJSと同じくprototypeベースなのでやろうと思えば~~汚染~~拡張できるっぽいです。

# DisplayObject.localToGlobal()の注意点
部品の入れ子とかしてるといかにも使えそうなこのメソッド。現在値ではなくシンボルベースで計算されるため、シンボルから拡大縮小してると正しくない値が返ってくる。なんということだ……

# カスタムクラスにはfor inが効かない
>オブジェクトが sealed クラス（ビルトインクラスおよび**ユーザー定義クラス**を含む）のインスタンスである場合、**そのプロパティに対して繰り返し処理を実行することはできません。**繰り返し処理を実行できるのは、ダイナミッククラスのプロパティのみに対してです。ダイナミッククラスのインスタンスの場合であっても、繰り返し処理を実行できるのは、動的に追加されるプロパティのみに対してです。

[公式](https://help.adobe.com/ja_JP/as3/learn/WSf00ab63af761f1702761490412937d6fc9b-7fc8.html#WSf00ab63af761f1702761490412937d6fc9b-7fc6)より引用。ちらっとしか書いてないので読み飛ばしてしまいそうですが、使えません。特にtoString/toJSONやクローン系メソッド作る際は気合:muscle:でやるしかないですね……

# リンケージについて
||親|子|孫|
|---|---|---|---|
|リンケージ欄の表記|（なし）|基本クラス|クラス|
|リンケージ欄の位置|（なし）|**下**|**上**|
|コンストラクタの動作順|3|2|1|
|典型的な運用|MovieClip|.asファイル用意してメインでコーディング|自動生成|

まず実際の継承関係とリンケージの設定欄が上下逆になっているので混乱しないよう注意。また生成する際はあくまで「孫クラス」（リンケージ設定の「クラス」）の名前でnewすること。普段メインで弄ってるのが子クラスにあたるのでそのまま書いてハマりがち。孫クラスを自動生成させるセオリーについては参考先を参照のこと。
参考：[[AS3] クラスを複数のMovieClipシンボルに設定したい](http://f-site.org/articles/2008/01/17053315.html)

# 自動宣言オンの時のリンケージの挙動
ゴリゴリとクラス書きたい場合は自動宣言オフにしろと言われてますが、フレームアクションベースで作られてて拡張する場合等、作業量的に無理な場合もあるかと思います。でなんやかんやと規模大きくなって継承とかしだすと、大概**「継承した定義 ***（名前空間 public）にコンフリクトが存在します」**というエラーに遭遇することになります。
自動宣言オフにしたら大抵解決するのと、内部挙動が絡むので、あんまり深く突っ込まれてこなかった（自分調べ）このハマりポイントですが、経験則上、納得できる**仮説**が組み上がったので置いときます。

+ 自動宣言＝子要素のインスタンスを「public var 【インスタンス名】」として自動で追加する機能である。
+ **自動宣言が行われるクラスは自動生成したクラスの親クラスで固定である**
    + この為、更に祖父クラスを作成して継承させた場合でも、**親クラスで宣言されるため、当然祖父クラスから自動宣言した部品にはアクセスできない**。
    + 自動宣言＝「一々宣言しなくても自由にステージ上の部品に参照できる機能」という曖昧な認識だと、**自作の祖父クラスからも自由にアクセスできることを期待してしまい**、コンフリクトにハマってしまう。
    + また関連して **親子関係にあるクラスを両方ともリンケージ設定してステージ上に置くとハマります**（親子クラス両方でステージ上の部品が自動宣言され、子クラス側が重複になる）。ありがちなパターンは独自ボタンとかウィンドウとか基本的な部品をリンケージして作ってて、バリエーションが必要になった時に安易に継承して作っちゃった場合ですかね。
        + 親クラス側は全て.getChildAt()や.getChildByName()等で参照取るとかしたら回避できると思いますが（未検証）、自動宣言のメリットが……。

参考:[「継承した定義 ***（名前空間 public）にコンフリクトが存在します」理由](http://d.hatena.ne.jp/kkotaro0111/20130424/1366814506)

# 【重要】再生ヘッド操作系メソッドをコンストラクタ内で使ってはいけない
見た目を切り替えるのにフレーム切り替えを利用するのってよくあると思うんですが、コンストラクタでやるのは絶対やめといた方がいいです。[リファレンスに載ってる](https://help.adobe.com/ja_JP/FlashPlatform/reference/actionscript/3/flash/display/MovieClip.html#gotoAndStop())んですが
> このムービークリップの指定されたフレームに再生ヘッドを送り、そこで停止させます。**この処理は、フレーム内のすべての残存アクションが実行を完了した後に行われます。**フレームに加えてシーンを指定する場合は、scene パラメーターを指定してください。

太字部分、要するに遅延処理しますよと言ってるのがミソ。コンストラクタで行うと、**実際にフレーム移動が行われるまで**（生成が完了してないので）**そのインスタンスは他のインスタンスからアクセスできません。** 未定義(undefined)扱いとなるうえ、親-子関係で子の生成が遅延すると、**連鎖して親の生成も遅延します。**

例えば親部品-子部品-孫部品の3層構造で全てリンケージしてる場合だと、孫部品コンストラクタ→子部品コンストラクタ→親部品コンストラクタ→（親部品フレームアクション→子部品フレームアクション→孫部品フレームアクション）と処理されるので、遅延した場合、生成が想定より相当遅くなり、参照が取れなかったり、処理順がめちゃくちゃになるわのスパゲティ化します。**地獄だぁ…… :scream:**
フレームアクションをほとんど使ってない場合はまだ何とかなるかもしれませんが、中途半端にクラスを導入（MVCで言うところのCはメインタイムラインのフレームアクションで、末端のVはリンケージしたクラスで～みたいな運用とか）して混在してたり、部品の入れ子やクラス継承してるとホントにエグいです。
対策としてはフレーム切り替え系は別メソッドに切り出してフレームアクションの最終部分で纏めて呼ぶとか、生成専用フレームを作り、次フレームで操作するとかですかね。どちらも対処療法的で微妙ですが……

## [ボタン]シンボルに自動再生のムービークリップを置かない方がいい？
[ボタン]シンボル（内部的には[SimpleButton](https://help.adobe.com/ja_JP/FlashPlatform/reference/actionscript/3/flash/display/SimpleButton.html)クラス）で、アップのフレームに自動再生のムービークリップ（点滅アニメーション）を置いてあるシンボルがありまして、それにリンケージを設定した所、見事に生成が遅延しました。原理的にはおそらく同じですね……。ちなみにフレームを削って1Fにしてもダメで、ムービークリップからグラフィックに変える必要がありました。うーん。

# 隣接するキーフレームの同名インスタンスの扱いについて
キーフレームごとに全部画面上の全インスタンスは再生成されると思いきや、同レイヤー＆隣接したキーフレーム＆インスタンス名が同名ならば、フレーム移動時に再生成は行われない。
(例:1F目と2F目をキーフレームに設定し、1F目にシンボルを置いて、2Fにも座標を変えて同シンボルを置く。名前が同じならばフレームを切り替えてもステージから排除されず、参照等も生きてる)
ただしダイナミックテキストの場合、同名でもフレーム切り替え時に中身のテキストが消えてしまうので注意。多分再生成してるんでしょうね。

# クラシックトゥイーンについて
クラシックトゥイーンを含むMovieClipは、最終フレームから（トゥイーン関係ない）フレームに移る際に全部再生成されるので注意。trace取ってるとコンストラクタが2回呼び出されるように見えたりします。

# キーボードが日本語入力状態の時に、半角英数入力に戻してもキーコードが変わらない
FlashPlayerがアクティブ状態でキーボードが入力されると、内部メモリにバッファとして溜まる場合があり、メモ帳等を開いてクリックすると吐き出されます。これをして空にしないとIMEの変換モードを変えてもFlashPlayerが正常に認識してくれない模様。

# サウンド周りの注意点
サウンドドライバが使えない状態（？）の時に音鳴らそうとするとエラーが出るのですが、エラーメッセージが分かり辛い（サウンド関係の組み込みクラスが未定義とかだったはず）のでハマりがち。**ありがちなのがPCとモニタorスピーカーを結ぶ線が抜けてたパターン。** しょうもないですが、これで時間取られた日には……:sob: 
そもそも音が出ないぐらいで例外を投げて、キャッチしない限りアプリごと落ちるのはやりすぎではないかと思えてきたんですが、指摘するには10年以上遅いですね……

# 大きなファイルを読み込む時の注意点
[プログレスバーのコンポーネント](https://help.adobe.com/ja_JP/FlashPlatform/reference/actionscript/3/fl/controls/ProgressBar.html)を使っていたんですが、**バーが0のまま動かず、いきなり満タンになるけど、途中の進行状況はPROGRESSイベントでちゃんと拾えてる**という謎現象が発生して、これまたちょっとハマりました。:sweat:
これはバグではなく、FLASHの仕様です。**大きなファイル読み込んでステージに追加する処理でCPUを食っちゃって、フレームレートが下がってフレームが進まず、バーの表示が更新されない**のが原因です。この現象に対しては[FileStreamクラス](https://help.adobe.com/ja_JP/FlashPlatform/reference/actionscript/3/flash/filesystem/FileStream.html)を使い、非同期読み込みするのが一応の対策となります。ただしこれが使えるのはAIRかつローカルファイル限定です:pensive:

## 参考
[ProgressEvent on android not work](https://github.com/Gamua/Starling-Framework/issues/722)
[Adobe AIR progress event traces value but wont allow me to update a text field during load progress](https://stackoverflow.com/questions/25792910/adobe-air-progress-event-traces-value-but-wont-allow-me-to-update-a-text-field-d)
[Actionscript - Loading a file freezes application](https://stackoverflow.com/questions/20026231/actionscript-loading-a-file-freezes-application)

# Flash Projector（プロジェクター）って何？
AIRのご先祖様的存在で **AS2／AS3両対応。** ブラウザで走ってるFlashのエンジンをスタンドアローン化してオフライン環境で動かせるよう、単体ファイルとして書き出したもの。AIRのようにネイティブの機能を触ったりすることはできません。
2015年～2017年（ごめんなさい自信ないです）あたりで一旦書き出し設定が無くなり、Adobe AIRだけになった時期もありましたが、現在は復活しています。
ちなみに近年は、[プーさんのホームランダービー](https://kids.disney.co.jp/etc/disney-game/01_swf/3018/index.html)等のスタンドアローンタイプのFlashゲームをローカル保存して動かす手段として微妙に紹介されてたりします。~~ロビン相手に30本まで行ったところで挫折したので、もういいです。~~

# Adobe AIRって何？
[Adobe AIRとは？](https://www.adobe.com/jp/products/air/faq.html)を御覧ください。
AS3専用。未だにほとんど存在しない**Windows/macOS/iOS/Android/Linuxの5大OS対応**を成し遂げており（Linuxは長らくサポート対象から外されていましたが、Harman傘下でサポートが復活しました）、ネイティブの機能も触れる等、クロスプラットフォームとしては頑張ってました。
ただ基本的にFlashベースのため、その衰退と足並みを揃えており、2019年5月をもって[HARMAN社に移管](https://av.watch.impress.co.jp/docs/news/1187719.html)され、HARMAN社のリリースしたバージョン（ver33以降）の商用利用に関しては有料化してしまいました。~~オワコン~~

# Adobe AIRについて相談したい
Adobeの[公式フォーラム](https://community.adobe.com/t5/air/ct-p/ct-air?page=1&sort=latest_replies&filter=all&tabid=all)もしくは、GithubにHarmanが運営する[サポートリポジトリ](https://github.com/airsdk/Adobe-Runtime-Support)があり、issueやdiscussionで相談することができます。言うまでもないですが英語です。

# Adobe Animateのパブリッシュ設定の「AIRの設定」ウィンドウの正体
パブリッシュ設定の「ターゲット」でAdobe AIRを選択すると、右横に🔧アイコンが出てきて、そこをクリックするとAIRの設定ウィンドウが開きます。**このウィンドウの正体は、「【出力名】-app.xml」という設定ファイルに対するエディタ**となります。さり気なく自動生成されてるファイルですね。
何故これをわざわざ強調するかというと、**設定ウィンドウからは設定できないけど、XMLに直書きすることで反映可能な項目が結構ある**からなんです。iOS向けの最小インストールバージョンの指定とかが代表ですね。


# バージョンごとの細かい挙動ネタ
## stage.stageWidth/Heightの不具合（？）
scaleMode = StageScaleMode.SHOW_ALLでは、画面サイズ変更時？（条件未確定／画面最大化時は必ず発生）に、stage.stageWidthやstage.stageHeightの値がSWFファイルの元のサイズではなくウィンドウサイズになる上、座標の基準もおかしくなる（？）不具合があり、AIRで実行時に支障がある。昔あったバグが再発してる？
参考：[F-site | [AS3] Stage.stageWidth/Stage.stageHeightの戻り値がウィンドウサイズで変わる](
http://f-site.org/articles/2006/09/28203339.html)

## FlashPlayer9-11あたりのfscommandのバグ
複数使った場合、**複数回分の全ての引数が一意（ユニーク）じゃないと動作しない**という信じられない欠陥があります:flushed:
2個目の引数のtrue,falseは被るしかないので、どう対策するかというと、

```ActionScript
    fscommand("fullscreen", "true");
    fscommand("trapallkeys", "True");//頭のTを大文字にしてユニーク化
    fscommand("showmenu", "false");
    fscommand("allowscale", "truE");//尾のEを大文字にしてユニーク化
```

このように単語の中の大文字小文字を切り替えることでtrue,falseと認識させつつ、ユニークにするのがセオリーの模様。そら[incredible...とかi can't believe that worked...って言われるわ。](https://stackoverflow.com/questions/1762328/bug-flashplayer-10-projector-not-going-into-fullscreen-depending-on-swf-html-pl) え、今時FP11.4使わないって？~~AS2のプロジェクタで動かしてる製品がまだあるんですよ！:fearful:~~