【PlayCanvas(JavaScript)】ランダムな値をTweenに渡してループさせる

##PlayCanvas

>PlayCanvasは、デスクトップとモバイルブラウザ向けに作られた
WebGL/HTML5ゲームエンジンです。豊富な機能を揃えた3Dエンジンと
クラウドホスティングされた開発環境およびツールセットを備えています。

引用元：[PLAYCANVAS](https://playcanvas.jp/)

超初歩的な使い方は下記にまとめました。
【参考リンク】：[【PlayCanvas(JavaScript)】PlayCanvasを触ってみた](https://qiita.com/OKsaiyowa/items/3d63942334a76f734d0d)


今回はTweenを試すので`tween.js`を下記リンクから頂戴します。
[playcanvas-tween](https://github.com/playcanvas/playcanvas-tween#usage)

##デモ
ライトのレンジを**ランダムな間隔でランダムな大きさに変化**させています。
踊っている人はまったく関係ないです。
![PlayCanvasQiita1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/e7c0b69a-7a45-90c7-880f-03eb0ce637c7.gif)

Tweenで**ランダムな値を渡してループ**させることに少々苦労したのでメモ残します。

**JavaScript初心者**なので酷いこと書いてるかもしれません。
どうか優しくしてやってください。

##コード

下記全文です。

```javascript:適当なEntityにアタッチ
//宣言
var LightTween = pc.createScript('lightTween');

//アトリビュート　Editor画面にGUIで参照を設定可能に
LightTween.attributes.add('pointLightEntity', {type: 'entity', title: 'Point Light Entity'});

LightTween.prototype.initialize = function() {
    //初期化時Tweenの処理を担うメソッド呼び出す
    this.lightRandomFlash();
};

//ライトのレンジをランダムに変化
LightTween.prototype.lightRandomFlash = function(){
    //"this"を別の変数に持っておく
    var self = this;
    
    //＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
    //　ライトの範囲をTweenで変化させる
    //＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
    
    //実行中のTween停止
    if(tweenLightRange){
        tweenLightRange.stop();
    }
    
    //単発でTween実行
    var tweenLightRange = this.app
    .tween(this.pointLightEntity.light).to({range: getRandomInt(3,8)},  getRandomInt(1,3), pc.SineOut)
    .yoyo(true)
    .on('complete', function () {
        //完了時、再帰的にメソッド呼び出し
        self.lightRandomFlash();
    })
    .start();
};

//ランダムな値生成
function getRandomInt(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return (Math.floor(Math.random() * (max-min)) + min);
}

```

結論から言うと、**Tweenをループさせず再帰的に何度も呼び出し**ています。
疑似的にループに見せているだけです。

というのも、tween.jsのループ処理は最初に定義したtween以降の処理をループさせるからです。
ランダムな値を渡そうとしても最初に渡した値で二回目以降の処理は固定されます。
(認識間違っていたらコメントください、、)

ですので、下記手順で実行しています。
**①HogeTweenを動かす処理を記述したメソッドを呼び出す
②HogeTweenが動いているかチェックし、動いていたら止める
③HogeTweenにランダムな値を渡して動かす
④HogeTweenの完了時に再度HogeTweenを動かす処理を記述したメソッドを呼び出す
⑤ ②に戻る**

##this
`JavaScript`の`this`が自分の予想した`this`を指していなかったようでかなり混乱しました。

【参考リンク】：[JavaScriptの「this」は「4種類」？？](https://qiita.com/takeharu/items/9935ce476a17d6258e27)

tweenのメソッドチェーンの中でコールバックに処理を登録できる
`.on('hoge',function)`というのがあります。

**このコールバックの中で`this`を使用した場合、`this`の中身はtween**になります。

その**直前のメソッドチェーンの中で呼び出した際の
`this`の中身は`lightTween`というScriptのインスタンス**です。

```JavaScript:問題の箇所
 var tweenLightRange = this.app
    .tween(this.pointLightEntity.light).to({range: getRandomInt(3,8)},  getRandomInt(1,3), pc.SineOut)
    .yoyo(true)
    .on('complete', function () {
        //このthisは中身がtweenなのでエラーとなる
        this.lightRandomFlash();
    })
    .start();
```

ですので、tweenの中で`lightTween`のインスタンスを使用するには
**一度変数にインスタンスを保持させる**必要がありました。

```JavaScript
    //"this"を別の変数に持っておく
    var self = this; 

    var tweenLightRange = this.app
    .tween(this.pointLightEntity.light).to({range: getRandomInt(3,8)},  getRandomInt(1,3), pc.SineOut)
    .yoyo(true)
    .on('complete', function () {
        //selfは`lightTween`のインスタンスを指す
        self.lightRandomFlash();
    })
    .start();
```

【参考リンク】：[What is the purpose of writing “self = this”?](https://forum.playcanvas.com/t/what-is-the-purpose-of-writing-self-this/14833)


##おわりに
もう少しJavaScriptと仲良くならないとPlayCanvas使うのは大変だなと思いました。

体系的に基礎から学べるサイトとかご存じの方教えてください。

---
[ユーザーコミュニティ](https://playcanvas.jp/joincommunity/)にてご回答いただいた方ありがとうございました！

##参考リンク
[Math.random()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random)