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

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

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">自動ドア <a href="https://twitter.com/hashtag/playcanvas?src=hash&amp;ref_src=twsrc%5Etfw">#playcanvas</a> <a href="https://t.co/mu40UYN2V4">pic.twitter.com/mu40UYN2V4</a></p>&mdash; はが (@Mxcn3) <a href="https://twitter.com/Mxcn3/status/1237006751066509312?ref_src=twsrc%5Etfw">March 9, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

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

### 3Dモデルのインポート

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

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

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

### AnimationComponentについて

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

https://developer.playcanvas.com/en/api/pc.AnimationComponent.html


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

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




## アニメーションを再生する
<img width="600" src="https://i.imgur.com/zRVUWHn.gif" />


|プロパティ|値|
|---|---|
|speed|0.5|
|activate|false|
|loop|false|
*エディタで指定をする値*

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

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

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

// initializeはスクリプトが有効になった際に１度呼び出される
Door.prototype.initialize = function () { 
    //アニメーション名を設定
    const ANIMATION_NAME = "open"
    
    // AnimationComponentの持っているplay関数を実行
    this.entity.animation.play(ANIMATION_NAME)
};

```

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

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

<img width="600" src="https://i.imgur.com/OBAMx53.gif" />

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

|プロパティ|値|
|---|---|
|speed|0.5|
|activate|false|
|loop|true|
*エディタで指定をする値*

#### loopについて

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


## アニメーションの逆再生
<img width="600" src="https://i.imgur.com/cYlH7JH.gif" />


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

|プロパティ|値|
|---|---|
|speed|0.5|
|activate|false|
|loop|false|
*エディタで指定をする値*



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



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

```javascript
/*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)
    }
}

```


## イベント発火時、ドアを開け締めするようにする
<img width="600" src="https://i.imgur.com/wCdU1O9.gif" />

|プロパティ|値|
|---|---|
|speed|0.5|
|activate|false|
|loop|false|
*エディタで指定をする値*

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

|コンポーネント|値|
|---|---|
|RIGID BODY|Kinematic|
|COLLISION|BOX|

```javascript
/*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
    }
}
```



<font color="OrangeRed">
PlayCanvas開発で参考になりそうな記事の一覧です。
</font>
<font color="OrangeRed">
入門

- [PlayCanvas入門- モデルの作成～ゲームに入れ込むまで](https://qiita.com/yushimatenjin/items/2a2c35fe7b1d08f9e361)
- [JavaScriptでスロットを実装する。【PlayCanvas】](https://qiita.com/yushimatenjin/items/e84c42da74df1eb07386)
- [3Dモデルのビューワーを3分で作る【初めてのPlayCanvas】](https://qiita.com/yushimatenjin/items/4b09c9e2076a0b2a6933)
</font>
<font color="OrangeRed">
応用
</font>

- [PlayCanvasのコードエディターでes6に対応する](https://qiita.com/yushimatenjin/items/a61a21c64c1c1a550dd4)
- [Gulpのプラグインを書いたらPlayCanvasでの開発がめちゃくちゃ便利になった](https://qiita.com/yushimatenjin/items/5f0f178e8a4ba4a5ee57)
- [PlayCanvas Editorに外部スクリプトを読み込む新機能が追加されたので開発方法を考える。- Reduxを組み込む](https://qiita.com/yushimatenjin/items/7a64220cceac66843d7d)
</font>
<font color="OrangeRed">
その他の記事はこちらになります。

- [React Native + PlayCanvasを使ってスマートフォンゲームを爆速で生み出す](https://qiita.com/yushimatenjin/items/7c7ad5d35473c11f32f2)
- [PlayCanvasのエディター上でHTML, CSSを組み込む方法](https://qiita.com/yushimatenjin/items/814b4a32db53397219df)
- [【iOS13】新しくなったWebVRの使い方 ](https://qiita.com/yushimatenjin/items/344d86b3d193e0a88567)
</font>

<font color="OrangeRed">
その他関連
- [PlayCanvasタグの付いた記事一覧](https://qiita.com/tags/playcanvas)
</font>


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

[日本PlayCanvasユーザー会 - Slack](https://t.co/IdSRIfJhN5?amp=1)