Flash as3からhaxe+openfl化で直面したエラー群

過去にflash(as3)で作成したそこそこ巨大なプロジェクト(子供向けの教材)をhtml5に移植する仕事を請け負ったが、移植には、haxe+openFLを選択した。

あまり世の中に情報がなかったので、その移植の中で直面した問題を、どう解決したのかを残していきます。

 

 

・以下、ターミナルから、lime test html5 で実行した時のもの。
(openfl test html5 でも同じっぽい)


※また、-debug を付けて実行すると、エラーが起きた時に、どこの行で起きているかまで出してくれるので、基本的に開発中は付けた方がいいと思う。

f:id:suzuki_kuni:20190105001830p:plain

上記は付けた時の状態。付けないと、上記がjsにコンバートされた後の状態での場所になって、全くよくわからないため。

また、その-debugをつけていると、コンバート後のjsと元のhaxeとのマッピングファイルも作成されるので、ブラウザでのブレイクポイントありのステップ実行デバッグが可能となる。

具体的には、haxeのコードに、js.Lib.debug();を入れて実行すると、chromeでは、標準でマッピングがあればそちらを見るようになっているようなので、自分の環境では、そこの行を実行された時に、問題なくデバッガーが起動した。
(もし起動しなければ、chromeの設定がonになっていない可能性もあるので、
https://gist.github.com/jakebellacera/336c4982194bcb02ef8a
を見て確認する)

f:id:suzuki_kuni:20190108183524p:plain
※また、-v をつけてビルドすると、ビルド中の詳細を出力してくれる。

 
・as3hxという、ある程度自動的に置き換えてくれる物があるので、それにまず通した。


・またその際、改行コードは、CR改行だとかなり変になることがあったのでLFに変換してから行った(当方mac環境)


・as3hxは、hxのライブラリ群もあって、それを使うように置き換えることもするので、最終的に動かしたいものにはそのライブラリも入れておく。

f:id:suzuki_kuni:20181223110556p:plain

 

・AS3HX WARNING というのが自動変換で付くことがあるが、そこは確認して修正した方が良い。こちらでは、objectとしてなんでも入れてしまっているような変数があって、そこに対して出ていた。

・また、自動的に、
Reflect.field(this, LABEL_ONE)
みたいに、Reflect.fieldで置き換えられる箇所があるが、返り値がDynamicなので、
これに対してのプロパティアクセスは、型の情報がないのでnullが返ってきてしまう。
getChildByNameに変更したのち、castする必要が出てくる。
(Reflect.fieldの返り値をそのままcastすればいいのではと思ったが、それではダメかも?getChildByNameで取得した上でcastしないと、想定の動きにならなかった。詳細までは調べきれず…)

自動変換の後、Reflect.fieldで一度検索して、全部コードを確認した方がいいと思われる。

 


・if (object == _mc.btn_OK)
//次の画面に行く{

 

みたいにコメントを巻き込んで、カッコを下に改行して変換してしまうことがあり、ビルドするとエラーが起こっていた。

 

if (object == _mc.btn_OK){
//次の画面に行く

 

というように普通に修正。


haxeの基本的なことになってしまうと思うが、if文で、
if(obj){ //objが存在していたら(falseでなければ)
みたいな判定は出来ない。やりたければ、
if(obj != null){
みたいに、nullかどうかをきちんと見る必要がある。
(あくまで判定はbool型である必要があるということだと思う)

 

・Arrayは、Array<Dynamic>と宣言が置き換えられるが、Dynamicではなく、きちんと型を指定出来るのであれば、しておいたほうがコンパイルの段階でエラーを出してくれるので、トータルで見たらメリットは大きい。出来れば変換後の段階でやっておきたい。
特に、swfファイルが絡んでくると、どこでエラーが起こっているのかを探すのが本当に大変なので…


・また、Dynamic型だと、例えばas3では何も型を指定しなくても、MovieClipが来るという想定で、型指定をObjectか、もしくは何も指定しなくとも、引数で受け取り、関数内で、mc.name = "aaa" みたいにプロパティに問題なくアクセスできるが、haxeでDynamic型を指定してしまうと、Reflect.fieldのところでも書いたが、実際にオブジェクトがMovieClipでnameプロパティを持っていようと、アクセスした際にnullを返してしまう。
これはMovieClipにcastしてからアクセスすれば問題ない。

面倒だが、Dynamicのところは問題を起こしがちなので、一度全て検索して、型を指定していった方がいい。

 


・new Menu → new Menu()
明確なclass指定にしないとだめだった。
(というか知らなかったが、as3では関数指定のカッコいらないということなのか…?)


flash.events.InvokeEvent
が無い。
(というか、AIR関連の、ローカルのファイルをいじるようなやつとかもないので、消すなりしないとだめ)


tweenerの置き換え必要
haxe版も合ったようだがリンク切れになってしまっている…。
TweenXなどのライブラリがあるのでそういったのに置き換える。

もしくは、<haxelib name="actuate" />というhaxelibライブラリがActuate.tweenというのを持っているようなので、それでもいいのかもしれない。
(また、同様に恐らく、png生成などのadobeのライブラリ群もないので、置き換える必要があると思われる)

 

・swfファイルも扱える(リンゲージ設定でクラスを指定し、それをhaxe側でnewすることで生成が可能)が、基本クラスの情報は失われる。

持っていけるのは、あくまで、階層の構造、素材とフレームアニメーションのみ。(シェイプトゥイーンアニメーションも持っていけない。最初と最後のフレームだけ出て、間は出ない。とはいえ上記が持っていけるだけでも、かなり凄いことだと思うし衝撃的だったが…)


なので、flashではよく基本クラスで素材の共通的な動きをまとめるとかやるが、それはどのように持っていくか考えないといけない。

自分の場合は、色々調査したのだが、結局、ビルド後に生成されるhxファイルの継承を一括で書き換えることにした。

 

具体的には、
Export/html5/haxe/_generated/
以下に、swfファイル内でリンゲージ設定が行われているオブジェクトのhxが書き出されるが、一律、extendsがMovieClipになっている。

ここを、flashの方で基本クラスにしているものに書き換えて、もう一度ビルドすれば問題なく動作するようになった。

(※既に作らているファイルは再度生成はしないため。ただしもちろん、swfを書き出し直したりした際は再度作られることとなるので、再度の書き換えが必要。これを毎回やるのは無理なので、別途、flashの方で基本クラスをMovieClip以外に指定しているものを全部リストに書き出して、

ed -i '' 's/extends MovieClip/extends framework.ui.NumberMovieClip/' Export/html5/haxe/_generated/s01_02/Button_OK.hx

というような、コンソールから変換できる命令を作り、それを、flaの方に変更があって書き出しなおすたびに(とはいえ、flaが変更されることはほぼないが)一括で実行するようにして管理した。

本当は、haxeのマクロなどを使って、ビルドシステムの中に組み込みたかったのだが…時間もないのでこの方法までで断念した)

 

 

 

・Animateでは、

f:id:suzuki_kuni:20181229105614p:plain

をoffにしないと、

Export/html5/haxe/_generated/debug_fla/Inner_6.hx:12: character 19 : Invalid character 0xE3

みたいな、日本語関係文字コードのエラーっぽい物が出てだめだった。また、ここをoffにしないと、どのみち、mcとして扱えない模様(画像は出るが、stopなどの命令が効かなくなる)

最近のAnimateでは新規にファイルを作るとここがデフォルトonのようなので確認したほうがいい。


・swc→swfに変更
(厳密に言えば、swcでもhaxeからの利用は出来るのだが、結局中のswfを取り出さないといけないなど、swfにしたほうが早そうだったので)


中のライブラリで日本語になってしまっている箇所は、英語に置き換えが必要。
また、頭を大文字にしないとだめっぽい?(ただ、全てではない?クラスとして認識されるものだけそうすればいいのかも)

具体的には、

Error: Could not process argument debug_fla.シンボル1_4

invalid character: ?

みたいなエラーが出た。
この場合、実際にExport/html5/haxe/_generated/debug_flaに、シンボル1_4.hxというファイルができているが、その中を見ると、どのflaファイルが元になっているかわかるので、そこを修正する。
(一見、上のエラーだけで、debug.flaにあるはずだと思うが、例えば、違うswcをライブラリパスからのリンクで読んでいる時など、そうではない場合もある

 

また、
--macro:1: character 0 : Package "taisen_animation_fla.enemy2_win_result_29" was not found in any of class paths
みたいなエラーが出てきたら、flashのライブラリのそのアイテム
上記の場合、taisen_animation.flaにある、enemy2_win_resultというアイテムの頭を大文字にする。
(というか、ライブラリ全てに対して、頭を大文字にするとか、頭に固定の大文字をつけるみたいな機能拡張のスクリプトを書けば良いのかも)

 

・flaの中のリンゲージ設定で、頭が大文字だとだめ。
haxeからは、ここに指定があるとスクリプトファイルとして書き出され、スクリプトから参照できるようになるが、haxeのパッケージ名としては最初大文字では通らないので、コンパイル時にエラーが出る)
小文字にする必要がある。

f:id:suzuki_kuni:20181227200324p:plain

その際に一括で変換するには、
http://feb19.jp/blog/archives/000237.php
に、リンゲージ設定の文字列を全て調整できる機能拡張がある。
/Users/xxxxxxx/Library/Application Support/Adobe/Animate CC 2019/ja_JP/Configuration/Commands
に、

Add Prefix to Linkage.jsfl
Add Prefix to Linkage.xml

Remove Prefix from Linkage.jsfl
Remove Prefix from Linkage.xml

を入れAnimateを再起動すると、「コマンド」に出てくる。
上記の例だと、Remove Prefixで1文字消して("S"が消える)、
Add Prefixで小文字のsを頭に追加、ということが一括でできるのでかなり便利。

 


・Dictionaryに型を設定する。
<Dynamic,Dynamic>とかでもいいが、前述の色々なDynamicの問題もあり、明確に型を指定した方が好ましい。

var aaa : Dictionary = new Dictionary();

var aaa : Dictionary<Dynamic,Dynamic> = new Dictionary();
(もしくはMapにしてしまうのでもいいと思う)


flash内に、btn$S01_03
みたいな名前が付いているmcがあり、「$」がコンパイル通らないので、
btn_S01_03に変更。


・Numberを、IntかFloatかにきちんと変更する。
(自動変換だと、Floatにされてしまう模様。Numberは浮動小数点数持てますからね…挙動的には正しい)
Float should be Intというエラーが出る。


・aaa["bbbb" + i].play();
みたいな、文字列で子のmcにアクセスしている部分は、
aaa.getChildByName("bbbb" + i).play();
に置き換える。


同様に、mcA.childMc.gotoAndStop(1);
みたいにしている箇所は、flashでは暗黙的にエラーを出さないでいてくれるが、
haxeではエラーになる。
mcA.getChildByName("childMc").gotoAndStop(1);
みたいにする必要がある。


・openfl.display.DisplayObject should be flash.display.MovieClip
MovieClipにcastする。


・Unknown identifier : arguments
http://mmmpa.hatenablog.com/entry/2014/12/22/Haxe_で無名関数を_arguments.callee_でアレしようと思ったらダメだ
arguments.calleeの置き換えが必要。


・Too many arguments
private var tmpStatus_ : Array<Dynamic> = new Array<Dynamic>(10)

private var tmpStatus_ : Array<Dynamic> = new Array<Dynamic>()

 

・as3で、
var className:String = getQualifiedClassName(someMC);
という箇所は、
var className : String = Type.getClassName(someMC);
というように自動変換されるが、そこから更に、
var className : String = Type.getClassName(Type.getClass(someMC));
というようにしないとコンパイル通らなかった。

 

・同様にas3で、
var c:Class = Class(getDefinitionByName(className));
という箇所は、
var c : Class<Dynamic> = cast*1, Class);
というように自動変換されるが、
var c : Class<Dynamic> = Type.resolveClass(className);
でokだった。


・ブラウザ起動まで行くものの、
var symbol = swfLite.symbols.h[29];var symbol = swfLite.symbols.h[29];
undefined is not an object (evaluating 'swfLite.symbols')

というエラーが起動時に出て止まってしまった…。色々調べたところ、
private static var _soundPanel : SoundPanel = new SoundPanel();

private var _soundPanel : SoundPanel = new SoundPanel();
というように変えたら大丈夫だった。

このSoundPanelの中では、swfファイルのオブジェクトを継承して使っており、
staticでswfファイルの中身を見るようなものはだめなのかも…?(検証してませんが…)

 

また何かあればこちらに書いていきます。

*1:Type.resolveClass(className

GoogleVRForUnityのinstant previewが始まらない…

起動はしているものの、connectの種類を選択してくれ、その後unity側でstartを押してくれという画面から進まなかったが、

 

answers.unity.com

 

に書いてあるとおり、カメラに「MainCamera」タグを付けていなかったのが原因で、付けたところプレビューできるようになりました。

【Laravel5.0/php5.4】Symfony\Component\Debug\Exception\FatalErrorException Uncaught TypeError: Argument 1 passed to App\Exceptions\Handler::report()

Laravel5.0で、

php artisan migrate:refresh --seed
を実行すると、

 

[Symfony\Component\Debug\Exception\FatalErrorException]                      
  Uncaught TypeError: Argument 1 passed to App\Exceptions\Handler::report() must be an instance of Exception, instance of Error given, called in xxx/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php on line 73 and defined in xxx/app/Exceptions/Handler.php:25

 

というエラーが…。
composer dump-autoloadしても直らず。


結局、php my adminからテーブルを一旦消して、作り直して、再度
php artisan migrate:refresh --seed
の実行で問題がなくなった。

vue.jsとaxiosで、edge/IE11で問題が…

vue.jsとaxiosでpostするようなものを作っていた所、edge、IE11で動かず、それを解決したのでその手順をまとめた。

 

 

postのパラメーターを作るのに、axiosだと、

let params = new URLSearchParams();

params.append('postData', 'aaaaaa');

というようなURLSearchParamsを使ってpostdataを作るサンプルが多くあるが、

なんとそもそも、edge、IE11ではURLSearchParamsが使えない。

(※edgeでは次期バージョンから使えるようになる、みたいな情報もあったが…)

 

なので、

github.com

のような、polyfillを読み込むようにして、使えるようにした所、まず、edgeではそれだけで問題なくなった。

 

※polyfillとは…というのはこちらが詳しかった。

qiita.com

 

 

IE11向けには、まだ対応が必要で、まず、promiseが無いので、

こちらも同様に、

teratail.com

などにあるpolyfillを読み込むようにする。

 

その他に、以下のような形で、アローファンクションを使っていたら、やはりIE11では使えないので、

axios.post('', params).
then(res => {

})

以下のように書き換える必要がある。

axios.post('', params).
then(function(res){

})

 

※さらにその場合、thisのスコープが変わるので、thenの後のブロックでthisを使うような場合は、大元から、thisを変数に取っておいて、使うようにしないといけなくなる。

var num = 1;

var self = this;

axios.post('', params).
then(function(res){

  console.log(self.num); //これはok

  console.log(this.num); //これはスコープが既に違ってしまっているのでng

})

 

また、postの際、urlを省略すると、通常、自分が読み込まれているページにpostされるはずだが、IE11ではだめで、空のまま実行すると、object DOMExceptionが起こってしまった。

なので、普通に、自分のurlをlocation.hrefを指定することで、IE11でも問題なく動くようになった。

axios.post(location.href, params).
then(function(res){

})

 

以上で、edge、IE11でも問題なく、vue.jsとaxiosが使えるようになった。

mamp+laravel+sublime text3でのphpのxdebug

 

 

www.aipacommander.com

 

上記を参考にさせてただいた所、特に難しいこと無くデバッグ実行が出来た。

 

php.iniには、上記サイトに記載がある、

 

[xdebug]
zend_extension="/Applications/MAMP/bin/php/php7.1.6/lib/php/extensions/no-debug-non-zts-20160303/xdebug.so"
xdebug.profiler_output_dir="/tmp/xdebug/"
xdebug.profiler_enable=On
xdebug.remote_enable=On
xdebug.remote_host="localhost"
xdebug.remote_port=9000
xdebug.remote_handler="dbgp"
xdebug.idekey="sublime.xdebug"

 

をこちらの環境に、zend_extensionの部分だけ調整(コメントアウトを外すだけだが)して入れ(※ちなみに上記ポート9000というのは、webサーバが動いているポートとは関係ない模様。下記の、webサーバのポートにしないとだめかと思って最初8888を入れてしまったが動作しなかった)、

 

sublime textのプロジェクトには、

"settings":{
"xdebug": {
"url": "http://localhost:8888/"
}
}

を書き足すだけでokだった。(自分の環境では、mampApacheのポート設定が8888になっている)

 

これでこちらの環境では、特に階層関係なく、ブレイクポイントをセットした箇所に引っかかるようになってくれた。

Adobe AIR windows向け 64bit書き出し

Adobe AIR windows向け 64bit書き出しが、ベータ版では出来るようになっていた。

 

forums.adobe.com

 

AIR 64-Bit on Windows - Testers needed « Starling Forum

 

ただ、数ヶ月経つのにまだ正式版には採用されないところを見ると、まだ実際のプロジェクトに使えるまで時間はかかるのかもしれませんね…

 

 

Adobe AIRは今のところ32bitアプリしか書き出せず、1.5GB程度メモリを使うと落ちたり、落ちなくても、画像が点滅しだしたりと言った、不安定になるという制限がある(※とはいえこれは、32bitアプリでは正しい挙動で、windowsからmaxでも2GBまでしか使えないという制限が設けられている模様。↓の説明が詳しい)

forums.adobe.com

 

これが倍まで使えるようになると、かなり制作が楽になるだが…。