はじめに
PlayCanvasに Template という機能が実装されています。
これによりEntityやコンポーネントなどを組み合わせたものをアセットとして保存できるようになり、別シーンでも同じ構成物をいちいち作る必要がありません。
またTemplateをインスタンス化することもできるので、シーンにベースEntityを置いておく必要がなくなりました。
まずはインスタンス化
まずは手短にインスタンス化を行います。
var Generator = pc.createScript('generator');
Generator.attributes.add('tmpl', {type: 'asset', assetType: 'template'});
Generator.prototype.initialize = function() {
if( this.tmpl ){
// インスタンス化
var instance = this.tmpl.resource.instantiate();
// インスタンスを子Entityに設定
this.app.root.addChild( instance );
}
};
インスタンス化と子Entity化はワンセットです。
子Entity化を忘れると表示もされず、メモリの彼方へと消えます。(そして自動開放される)
これであとは座標を変えたりして調整すればいいのですが、そこで注意が必要です。
Rigidbodyを持ったTemplateをインスタンス化
コリジョンを持ったEntityをTemplate化することも勿論あると思います。
先程と同じ手順でインスタンス化し{X:0, Y: 10, Z: 0}の座標に設置して、自由落下させようとしたとします。
var Generator = pc.createScript('generator');
Generator.attributes.add('tmpl', {type: 'asset', assetType: 'template'});
Generator.prototype.initialize = function() {
if( this.tmpl ){
var instance = this.tmpl.resource.instantiate();
this.app.root.addChild( instance );
instance.setLocalPosition( 0, 10, 0 );
}
};
ザックリと実装するならばこんな感じでしょうが、これは正常に動作しません。
これを実行すると、インスタンス化したEntityは指定した座標に設置されず、更に他のコリジョンを持つEntityと衝突すると下記のエラーが出ます。
Uncaught RuntimeError: memory access out of bounds
コンソールを開いて確認するとAmmoが警告を吐いてるので、Rigidbodyを持ったTemplateをインスタンス化直後に座標系を弄ると駄目なようです。(無論、回転も駄目)
対処
ひとまず正常に動作する方法を探した結果、以下の3つの方法が動作するのを確認しました。
Rigidbodyをインスタンス化後にaddする
Templateを作成する時にRigidbodyを外しておき、インスタンス化時にaddComponentでRigidbodyを追加する方法。
細かいパラメータ(反発係数など)を後からセットする手間を考えると現実的じゃない。
Generator.prototype.initialize = function() {
if( this.tmpl ){
var instance = this.tmpl.resource.instantiate();
this.app.root.addChild( instance );
instance.setLocalPosition( 0, 10, 0 );
instance.addComponent('rigidbody');
}
};
RigidbodyをDisable状態でTemplateにする
Template作成時に、Rigidbodyの状態をDisableにしてからTemplateにする方法。
インスタンス化時にEnableにしてあげればよい。
Generator.prototype.initialize = function() {
if( this.tmpl ){
var instance = this.tmpl.resource.instantiate();
this.app.root.addChild( instance );
instance.setLocalPosition( 0, 10, 0 );
if( instance.rigidbody ){
instance.rigidbody.enabled = true;
}
}
};
rigidbody.teleport()を使用する
そもRigidbodyの機能に依存する方法。
座標だけを変える必要があるならば、この方法が採用できる。
Generator.prototype.initialize = function() {
if( this.tmpl ){
var instance = this.tmpl.resource.instantiate();
this.app.root.addChild( instance );
if( instance.rigidbody ){
instance.rigidbody.teleport(0, 10, 0 );
}
}
};
おわりに
こんなん書いてどうするんだと思うかもしれませんが、これを上手く書くとプロジェクト自体を落とせます。
進捗が正常に更新される前に落とされたら最悪プロジェクト自体が死ぬ可能性があるので、共有を…といった感じ。