【Cocos2d-JS】cc.loader の拡張

リソースデータAに自前のデータBを依存していて、
データAをプリロード時にデータBも一緒にプリロードしたいです。
データAをインスタンス化してからデータBをプリロードしてもいいですが、
処理が複雑になってしまうです。

あるいは、同時時複数リソースを使用するデータが、
毎回パスを構築してプリロードするのもコード量が増える。

どう対処するかと
cc.loaderのソースとにらめっこしたら
cc.loader.register(...) を発覚しました。

cc.loader.register

cc.loader.registerを使って特定の拡張子でカスタムローダーを登録できます

cc.loader.register(['ext'], {
  load: function (realUrl, url, resource, cb) {
    /*....*/
    cb(); // ロードが終わったらコールバックを実行します
  }
});

spine データには json / atlas / png 3つのファイルが必要です。
毎回この3つのファイルを配列して cc.loader.load してもいいですが、

.spine 拡張子を定義して一気にこの3つのファイルをロードする

cc.loader.register(['spine'], {
  load: function (realUrl, url, resource, cb) {
    let urls = [];
    urls.push(url.replace('.spine', '.atlas'));  // atlas
    urls.push(url.replace('.spine', '.png'));  // png
    urls.push(url.replace('.spine', '.json'));  // json
    cc.loader.load(urls , (error, datas)=>{
      // datas を使ってさらに依存しているデータを読み込む
      cb();
    });
  }
});

使い方

cc.loader.load("res/assets/model.spine");

このように *.spine 拡張子をロードする場合、
登録したカスタムローダーが実行され、
必要なデータがロードされます。

【Unity】Unity WebGLのIME入力

UnityのWebGL対応でIME入力はほぼ必要ですが
検索したら、大体以下の公式リポジトリにたどり着きます。
GitHub - unity3d-jp/WebGLNativeInputField: WebGLでIME入力を可能にします

実はこの対応はあまり好みではないです。
なぜなら
ブラウザのダイアログオーバーレイなどにしちゃうと
ゲームから離れシステムっぽくなってしまうです。
フォントも選択できないしね。


それで、UnityのWebGLIME入力プラグインを書きました。

サンプルページ
kou-yeung.mygamesonline.org

unitypackage

ダウンロード

使い方

上記のunitypackageをimportし、
InputFieldのGameObjectにWebGLInputをAddComponentするだけです。
面倒な設定など必要ありません。

【javascript】function.bind()でハマった。

タイトル通り、javascriptの function.bind()でハマった。

gist.github.com
[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

function.bind() で、文字列を分岐しようとしていますが、
default に分岐してしまったのです。

原因は

thisArg として渡されるプリミティブ値はオブジェクトに変換されます

Function.prototype.bind() - JavaScript | MDN

それで、

switch文は厳密等価演算子 === を使用している比較する

switch - JavaScript | MDN

ということは、
String( "STR" ) === "STR" のように比較するため、
defaultに分岐しました。

// 1.  bind する時に パラメータとして渡して使うか
func.bind(null, str)();

// 2.  toString() を使う
switch(this.toString()) {...} 

で変更すれば正しく分岐されます。

【Unity】今年度報告した不具合

仕事でUnityを触ると、たまり不具合に遭遇しますね。
今年度は4件報告しました。

1件目:List.LastIndexOf(...) の挙動がおかしい
FogBugz

C#
List が空きの状態で List.LastIndexOf(T)を呼びと -1 を返されますが、
Unityの場合、例外をスローします
throw [ArgumentOutOfRangeException: Argument is out of range.]

Unityからの回答

This is fixed in the new scripting runtime.
Given that we are rapidly migrating to this new scripting runtime and
deprecating the old one it is unlikely that this issue will be resolved in that version.

2件目:LayoutGroupとAnimatorController組み合った場合の不具合です
FogBugz

LayoutGroupにAnimatorControllerを使ってAnchor Position Animationを設定すると、
アニメーションが再生しなくても無条件で、Anchor Position 終了時の座標になってしまう

Unityからの回答

I have been able to reproduce your issue and after some investigation,
I have found out, that the issue is already fixed in upcoming 2018.2 beta version,
so you can just update your version and you won't be encountering this issue anymore.

3件目:シェーダーのTangent.w はUnityのバージョンによって異なる
FogBugz

これはUnityかわで再現できましたが、いつ修正するか不明です。

4件目:長方形のテクスチャ + Mip Maps有効の状態だと正しく描画されない
FogBugz

超限定のAndroidバイスで再現する不具合です。
OSも4.4系なので、発生しても無視してもいいと思いますが、
一応報告しました。

Unityからの回答

This issue is not present in Unity 2019.1 beta and 2019.2 alpha. However it's present in 2017.4 LTS, therefore I've sent it for resolution with our developers.

2017.4 LTSでは再現するので、いつか修正されるでしょう。

この最近、cocos2dの仕事を受けているためしばらくUnityから離れますわ〜

【Unity】Hybrid ECS から Pure ECS へ

前回 でMeshInstanceRendererを使って描画できました。
PositionComponent とか RotationComponent とかも使ってPure ECS を少し理解が深まったので、
GameObject.Instantiate(...) でオブジェクトを生成ではなく、
Pure ECSらしく書き換えを行いたいです。

まずは調査!!

var manager = World.Active.GetOrCreateManager<EntityManager>();
var archetype = manager.CreateArchetype(...); // Position とか Rotationとか
var entity = manager.CreateEntity(archetype);
var look = ... // MeshInstanceRenderer
manager.AddSharedComponentData(entity, look);

以上の意味は自分なりに解釈すると、

EntityManager に Archetype を指定し Entity を生成し、
MeshInstanceRenderer を Entity に追加する
これで MeshInstanceRenderer は Entity の情報 ( Position , Rotationなど )で描画してくれる
あとは やりたいことを ComponentSystem とか JobComponentSystem を使って更新する

かなぁ~(間違ったらコメントで指摘していただければと・・・

オブジェクトの生成部分を変更する

オブジェクトは GameObject.Instantiate(...) ではなく
EntityManager から生成するため、Managerクラスを書き換えます

gist.github.com

MeshInstanceRendererComponent など設定して実行すると
f:id:kou_yeung:20181109142013g:plain

今まで通り描画されますが、回転しないよね。

回転スクリプト( Move.cs ) を変更する

gist.github.com
変更点は ※ を参照してください。

あとは Entity の Archetype に Move を追加するだけ

var archetype = manager.CreateArchetype(new ComponentType[]
{
    typeof(Position),
    typeof(Rotation),
    typeof(Move),      // ※ 追加する
});

f:id:kou_yeung:20181109143408g:plain
動きました!!
200FPS 以上になりました。

もう一歩先へ

Archetype はハードコーディングなのが不満です!!
どう解決するかなぁと思い、「そうだ、ComponentDataWrapper があるじゃないか!」

やりたいこと、
Prefab に アタッチしてる ComponentDataWrapper<T> の T 型を取得すればいいじゃない?(w)

書いた。
gist.github.com

GameObjectにアタッチした ComponentDataWrapperBase のコンポーネントを取得し
そのコンポーネントの基底クラスのジェネリック型パラメーターを取得する。

それと、MeshInstanceRendererComponent など SharedComponent が存在するかもしれないので
IsSharedComponent == true のものは取り除けばいいです

ついでに、CreateMeshInstanceRenderer() メソッドも提供し
MeshFilter や MeshRenderer から動的MeshInstanceRendererを生成すればスッキリです。

あとは、Manager のオブジェクト生成部分を書き換えればいい
gist.github.com

プログラム変更なしで、Archetype の調整ができました!!

まぁ

まだ検証段階なので、
Prefab から Archetype を取得するのが本当にいいのかも疑問ですが。。
結果的に ECS が理解を深まったからいいや~