【PlayCanvas】スクリプトによるアニメーション制御 ・順再生・逆再生・ループ


PlayCanvasで開閉する自動ドアを作成する。
このようなかたちの1枚ドアを作成する方法を紹介します。

実行リンクはこちらになります
https://playcanv.as/p/GEtlC29v/

3Dモデルのインポート

PlayCanvasにアニメーション付きの3Dモデルをアップロードすると、エディター上に3つのファイルが生成されます。

① (.fbx) ソースファイル
② (.json) JSONに変換された、アニメーションファイル
③ (.json) JSONに変換された3Dモデル

①のソースファイルについては、今後ダウンロードして使用することがないなど、不要の場合は削除してしまっても大丈夫です。

AnimationComponentについて

PlayCanvasのコンポーネントが持っているプロパティ、メソッドの一覧についてはこちらのAPIリファレンスを参考にします。APIリファレンスが更新されていない場合もありますのでconsole.logdebuggerなどを使用してthis.entity.animationの値デバッグをすることもおすすめをします。

今回使用しているプロパティ・メソッドについて

プロパティ名 説明 引数・型
speed アニメーションの速度を指定 数値
playing アニメーションが再生中かどうか 真理値
loop アニメーションをループするか 真理値
activate 起動時にアニメーションを再生するか 真理値
play アニメーションを再生する アニメーション名
getAnimation アニメーション名からアニメーションの詳細を取得 アニメーション名

アニメーションを再生する

プロパティ
speed 0.5
activate false
loop false

エディタで指定をする値

単純なアニメーション、openをゲーム起動時に再生するスクリプトです。

/*jshint esversion: 6, asi: true, laxbreak: true*/

const Door = pc.createScript('door');

// initializeはスクリプトが有効になった際に1度呼び出される
Door.prototype.initialize = function () { 
    //アニメーション名を設定
    const ANIMATION_NAME = "open"

    // AnimationComponentの持っているplay関数を実行
    this.entity.animation.play(ANIMATION_NAME)
};

このスクリプトでは、ゲーム起動時、initializeの関数が呼ばれた際にthis.entity.animation.playとしてopenアニメーションを再生しています。

アニメーションをループ再生する

上記のスクリプトに対してエディター上で速度と、ループの設定をします。

プロパティ
speed 0.5
activate false
loop true

エディタで指定をする値

loopについて

アニメーションのループは出来ました、しかし、PlayCanvas上でループを行うと、順再生のアニメーションが繰り返されるので、順再生のみを使用する場合には、扉を戻すというアニメーションを含むアニメーションを作成する事が必要になります。

アニメーションの逆再生

順再生と逆再生を繰り返す

プロパティ
speed 0.5
activate false
loop false

エディタで指定をする値

スクリプトから逆再生をする方法もあります。アニメーションを逆再生するにはblendTimespeedの値を指定することで逆再生をすることができます。

アニメーションの順再生と逆再生をすることで、扉を開く動作と扉をすることが出来ます

/*jshint esversion: 6, asi: true, laxbreak: true*/
const Door = pc.createScript('door');

/*
  エディタの値
    loop : false
    speed : 0.5
    アニメーション名: open
*/

Door.prototype.initialize = function () {
    this.ANIMATION_NAME = "open"  // アニメーション名を指定
};

Door.prototype.update = function () {
    const {duration, speed ,playing} = this.entity.animation
    // アニメーションが再生中ではなかったら
    if (!playing) {
        // 速度(speed)を0.5 → -0.5 , -0.5 → 0.5に変更をする
        this.entity.animation.speed = -(speed)
        // blendTimeに速度(speed)がマイナスだったらdurationの値を指定する
        const blendTime = this.entity.animation.speed > 0 ? 0 : duration
        // アニメーションを再生
        this.entity.animation.play(this.ANIMATION_NAME, blendTime)
    }
}

イベント発火時、ドアを開け締めするようにする

プロパティ
speed 0.5
activate false
loop false

エディタで指定をする値

アニメーションを再生するエンティティにCOLLISION,RIGID BODYを設定します。

コンポーネント
RIGID BODY Kinematic
COLLISION BOX
/*jshint esversion: 6, asi: true, laxbreak: true*/

const Door = pc.createScript('door');
Door.attributes.add("player", { type: "entity" })

Door.prototype.initialize = function () {
    const ANIMATION_NAME = "open"
    const animation = this.entity.animation.getAnimation(ANIMATION_NAME)
    const duration = animation.duration
    this.isOpen = false
    this.timer = 0

    this.entity.on(`door:open`, () => {
        this.entity.rigidbody.enabled = false
        this.entity.animation.speed = 0.5
        this.entity.animation.play(ANIMATION_NAME)
        this.isOpen = true

    })
    this.entity.on(`door:close`, () => {
        this.entity.rigidbody.enabled = true
        this.entity.animation.speed = -0.5
        this.entity.animation.play(ANIMATION_NAME, duration)
        this.isOpen = false
    })

    this.entity.collision.on("collisionstart", (e) => {
        const { other } = e
        if (other.name === this.player.name && !this.isOpen) {
            this.entity.fire(`door:open`)
        }
    })
};

Door.prototype.update = function(deltaTime){
   if(!this.isOpen) return
   this.timer += deltaTime
   if (!this.entity.animation.playing && this.timer > 3) {
        this.entity.fire(`door:close`)
        this.timer = 0
    }
}


PlayCanvas開発で参考になりそうな記事の一覧です。


入門


その他関連
- PlayCanvasタグの付いた記事一覧

PlayCanvasのユーザー会のSlackを作りました!

少しでも興味がありましたら、ユーザー同士で解決・PlayCanvasを推進するためのSlackを作りましたので、もしよろしければご参加ください!

日本PlayCanvasユーザー会 - Slack