RPGツクール素材メモ とかティラノスクリプトの話とか

同人RPGの制作で役立ちそうなスクリプト・プラグイン素材を書き留めておく

spineランタイムのメモ(スロットの表示・非表示、画像切り替え、trackでアニメ合成、効果音再生)

spineをただアニメ再生するだけじゃなく、ランタイムとしてゲーム中に操作してやる。
これで一本ゲームを作ったので、メモ。
環境はJavaScriptpixi.js

becomegame.booth.pm

スロットの表示・非表示自体はできない?
画像の非表示はその下の画像(メッシュ)をsetAttacment(null)する。
(再表示はnullの前に予め取得して、保存しておく)
また画像切り替えも同じsetAttacment()。

私が実際に書いたコードだとこんな感じ↓

非表示:

if(animation.skeleton.findSlot(s_n).getAttachment() != null)mesh_backup.set(s_n , animation.skeleton.findSlot(s_n).getAttachment());
animation.skeleton.findSlot(s_n).setAttachment(null);

表示(もしくはメッシュ、画像変更):

const mesh_name = mesh_backup.get(s_n);
animation.skeleton.findSlot(s_n).setAttachment(mesh_name);

実はスロットのRGBAでもそれっぽい事は出来るけど、透明度が絡むアニメをしようとする時に困る。

let a = (mode == "show") ? 1.0 : 0.0;
animation.skeleton.findSlot(s_n).color.a = a;

みたいな感じ。

複数のアニメから一つのアニメの合成メモ。
spineは概念的にtrackという配列ぽい物を持っており、それに複数のアニメを入れて再生するとブレンドしたアニメが生成される。
spineのtrackにも直にアクセス出来るようだが、今回は自前で配列を持って管理して、
setAnimation(...);
の引数の一番目がトラック番号指定という事で、対応させた。

let anime_track = [0,0,0,0,0,0,0];
function trapAnime(type , lv){
    if(anime_track.every(v => v == 0)){ // waitアニメーション解除(でないと表示おかしい感じに)
        animation.state.addEmptyAnimation(0, 1.5, 0);
    }
    const index = anime_track.indexOf(0); // 空きトラックを探す
    anime_track[index] = 1;
    const track = animation.state.setAnimation(index ,name , false);
}

アニメ再生速度はtimeScaleで変更。
setAnimationはセットした各々のtrackを返す……という事で、こうなった↓

function waitAnimation(){ // 待機アニメ(感じると速くなる)
    let track;
    if(eroLv() <= 2){
        track = animation.state.setAnimation(0 ,"wait2", true);
        track.timeScale = 1.0 + getHp() / 50;
    }else{
        track = animation.state.setAnimation(0 ,"wait1", true);
        track.timeScale = 1.0 + (getHp()-50) / 50;
    }
}

効果音再生。listenerのeventプロパティがコールバックになっているので、ここでイベントを拾って対応。

const track = animation.state.setAnimation(0 ,name, loop);
// *このlistenerはJavaScriptデフォのオブジェクト{}でやってて(インターフェイスが合ってるので)動くけど、本来はListenerオブジェクトを使うっぽい?
track.listener = {
    event : function(track_entry , event){ // イベント(SE用の名前が渡される)
        if(eroLv() >= event.intValue)preloadPlaySound(event.stringValue);
    }
}