[Unity] DOTweenでの各ループ終了時にCallback処理を挟みたい

## 環境
- Unity5.5.2f
- DOTween v1.1.600

## 結論
`Tween.OnStepComplete` を使おう

## 背景
- 例えば、以下のようなゲージ増加のTweenを用意する
- `OnComplete` を使用することで終了時に `Debug.Log` が実行される

```c#
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Image))]
public class DOTweenTest : MonoBehaviour
{
    private void OnEnable()
    {
        this.GetComponent<Image>()
            .DOFillAmount(1.0f, 1.0f)
            .OnComplete(() => Debug.Log("completed"))
            .Play();
    }
}
```

![tween1.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/3a0c9a3a-d76c-b77b-f333-c6935fcda034.gif)

- これにループ処理を挟み、ゲージが貯まる度に挙動を挟みたい
- まずは以下のコードを実行してみる

```c#
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Image))]
public class DOTweenTest : MonoBehaviour
{
    private void OnEnable()
    {
        this.GetComponent<Image>()
            .DOFillAmount(1.0f, 1.0f)
            .OnComplete(() => Debug.Log("completed"))
            .SetLoops(-1, LoopType.Restart)
            .Play();
    }
}
```

![tween2.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/e2b66fd6-70e7-be27-3a43-818f6d48b4df.gif)

- 上記のケースでは `OnComplete` での処理が実行されない
- これは渋谷ほととぎす通信さんの [今一番個人的にアツいUnityのTweenエンジン『DOTween』の罠〜ループ編〜](http://www.shibuya24.info/entry/2016/10/08/141314) で言及されている「永久ループ時はComplete状態に至らないのでOnCompleteは実行されない」という挙動に沿うものだ

## Sequence.AppendCallback
- 次に試したのがSequenceでの対応
- Sequenceに関しては以下の記事にまとめた
  - [[Unity] DOTweenのSequenceを使ってアニメーションを結合する](http://qiita.com/lycoris102/items/6a9e1e39bfa69880eaba)
- ループさせる挙動自体にコールバックを仕込むことで対応する

```c#
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Image))]
public class DOTweenTest : MonoBehaviour
{
    private void OnEnable()
    {
        Sequence sequence = DOTween.Sequence()
            .Append(this.GetComponent<Image>().DOFillAmount(1.0f, 1.0f))
            .AppendCallback(() => Debug.Log("completed"))
            .SetLoops(-1, LoopType.Restart)
            .Play();
    }
}
```

![tween4.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/70ebdfc0-289a-f7b8-7aaa-e086593cdc46.gif)

- 挙動的には問題なさそうである
- 但しこれもやはり問題があり `SetLoops(-1, LoopType.Yoyo)` に対応できていないということだ
  - `LoopType.Yoyo` は処理を折り返し実行する関数 (ヨーヨーみたいに)
- 手元で実行すると往路での `Debug.Log` は呼ばれるが、復路では呼ばれないことが確認出来た

```c#
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Image))]
public class DOTweenTest : MonoBehaviour
{
    private void OnEnable()
    {
        Sequence sequence = DOTween.Sequence()
            .Append(this.GetComponent<Image>().DOFillAmount(1.0f, 1.0f))
            .AppendCallback(() => Debug.Log("completed"))
            .SetLoops(-1, LoopType.Yoyo)
            .Play();
    }
}
```

![tween5.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/b388a0a1-b86a-3028-c414-9dd1de0bcb3a.gif)

## Tween.OnStepComplete
- http://dotween.demigiant.com/documentation.php
- DOTween側で何かしら関数用意してそうだなぁと思ってドキュメント読んでいたら `OnStepComplete` を発見した
- `a single loop cycle` が完了したときに発火してくれるコールバック
- まさにこれだ！ということで試してみる

```c#
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Image))]
public class DOTweenTest : MonoBehaviour
{
    private void OnEnable()
    {
        this.GetComponent<Image>()
            .DOFillAmount(1.0f, 1.0f)
            .OnStepComplete(() => Debug.Log("completed!"))
            .SetLoops(-1, LoopType.Yoyo)
            .Play();
    }
}
```

![tween3.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/70937d05-a7af-9bda-a3b1-b41de70ea1b9.gif)


- 意図通りの挙動になった！