[Unity] TextMeshProで生成したテキストをDOTween(Pro)を使って動かす

この記事は [Unity アセット真夏のアドベントカレンダー 2017](https://atnd.org/events/89521) の8/19の記事となります。

昨日は [baba_s](https://twitter.com/baba_s_) さんによる [「Hierarchy を拡張する多機能アセット「PRO Hierarchy + Memory Monitoring + Navigator for Selecting」紹介」](http://baba-s.hatenablog.com/entry/2017/08/18/100000) でした。

## 実行環境
- Unity 2017.2.0b5
- DOTween v1.1.600
- DOTweenPro v0.9.685
- TextMeshPro 1.0.55.xx.0b12

## はじめに
自分は普段ゲーム上で動きをつけるとき、 [DOTween](https://www.assetstore.unity3d.com/jp/#!/content/27676) を愛用しています。
DOTween自体に関しては、過去に以下のような記事を書きました。

- [[Unity] DOTweenを使ってUI要素を点滅させる](http://qiita.com/lycoris102/items/fe148d2c6803742c6f4d)
- [[Unity] DOTweenのSequenceを使ってアニメーションを結合する](http://qiita.com/lycoris102/items/6a9e1e39bfa69880eaba)
- [[Unity] DOTweenで自動再生させない](http://qiita.com/lycoris102/items/b639235ea613cbd31308)
- [[Unity] DOTweenでの各ループ終了時にCallback処理を挟みたい](http://qiita.com/lycoris102/items/41c0eaf373cfedd9d873)

さて、DOTweenを普段使用している人は多いと思いますが、DOTweenProはどうでしょうか。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/102664/6aedcf68-98b0-cb30-ed64-f266d56a5639.png)

[DOTweenPro](https://www.assetstore.unity3d.com/jp/#!/content/32416) は $16.20 で販売しているアセットです。
[Unityエッセンシャルパック](http://response.unity3d.com/jp-essecials-pack)の2Dにも含まれていました。
今回は DOTween と DOTweenPro の違いの話、Unity側への統合を踏まえ、最近無料化された TextMeshPro と組み合わせた演出の話を記載しようと思います。

## DOTweenProについて
DOTweenに出来なくて
DOTweenProに出来ることは、例えば以下のようなものがあります。

### ビジュアルアニメーションエディタ (DOTweenAnimation)
- コードを記載しなくてもTweenを適応することができます。
- 複数の `DOTweenAnimation` をアタッチすることで `Sequence` 相当の役割を持つことも可能です。

![dotween_inspector.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/5b37b722-0a7a-3725-9ab7-3b5da203e3ac.gif)

### ビジュアル進路エディター (DOTweenPath)
- パスを指定することで、そのパスを経由するようにオブジェクトを動かすことができます。

![dotween_path.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/5602a294-d3a0-8faa-5a93-b072077c5e29.gif)

## TextMeshProについて
![image.png](https://qiita-image-store.s3.amazonaws.com/0/102664/74312f44-5cad-322f-7aab-fb3ee45758fd.png)

[TextMeshPro](https://www.assetstore.unity3d.com/jp/#!/content/84126) はUnity標準のuGUIに比べ、よりリッチなスタイリングが可能で、かつズームしても滑らかに表示させることのできるテキストを作成することができるアセットです。

例えば、滑らかなアウトラインを適応することが出来たり
カーニング(文字間隔)を設定できたり
Materialを適応させたりすることが出来ます。

![textmeshpro.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/06ff8865-df7a-db83-baa2-cac1285fcf94.gif)


以下の資料が詳しいです。
[【Unity道場 2017】TextMesh Pro を使いこなす！](https://www.slideshare.net/UnityTechnologiesJapan/text-meshprounity)

## TextMeshProで生成したテキストにTweenを適応する
DOTweenProのもう一つの特徴として、TextMeshPro用の拡張メソッドの提供があります。
http://dotween.demigiant.com/documentation.php#textMeshProShortcuts
具体的にいくつか例を見て行きましょう。

### 文字の大きさを変更する
`.DOScale()` か `.DOFontSize()`を使用します。
`.DOScale()` を使用した場合、文字のレイアウト(改行)は崩れません。

```csharp:TweenTextMeshProSample
using UnityEngine;
using DG.Tweening;
using TMPro;

[RequireComponent(typeof(TextMeshProUGUI))]
public class TweenTextMeshProSample : MonoBehaviour
{
	void Start()
	{
		this.GetComponent<TextMeshProUGUI>()
			.DOScale(1.2f, 1.0f)
			.SetLoops(-1, LoopType.Yoyo)
			.Play();
	}
}
```

![textmeshpro_scale.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/f186e456-41d5-597c-9ba7-ba7e49a2813e.gif)

`.DOFontSize()` を使用した場合、文字の描画領域はそのままにフォントサイズが変更されるので、 `Warpping & Overflow` における設定に準拠して挙動が変わります。以下は `Truncate` を指定して、描画領域に納める例です。描画領域の外に出た文字列が切り取られています。

```csharp:TweenTextMeshProSample
using UnityEngine;
using DG.Tweening;
using TMPro;

[RequireComponent(typeof(TextMeshProUGUI))]
public class TweenTextMeshProSample : MonoBehaviour
{
	void Start()
	{
		TextMeshProUGUI text = this.GetComponent<TextMeshProUGUI>(); 
        text.DOFontSize(text.fontSize * 1.5f, 1.0f)
			.SetLoops(-1, LoopType.Yoyo)
			.Play();
	}
}
```

![textmeshpro_fontsize.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/8724cbb7-1f40-a886-c793-9035ce6dd001.gif)

### 文字をフェードイン/アウトさせる
文字全体をフェードイン/アウトさせるのであれば `.DOFade()` を使用します。

```csharp:TweenTextMeshProSample
using UnityEngine;
using DG.Tweening;
using TMPro;

[RequireComponent(typeof(TextMeshProUGUI))]
public class TweenTextMeshProSample : MonoBehaviour
{
	void Start()
	{
		this.GetComponent<TextMeshProUGUI>()
			.DOFade(0.0f, 1.0f)
			.SetLoops(-1, LoopType.Yoyo)
			.Play();
	}
}
```

![textmeshpro_fade.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/ccc78c21-bf57-3d9d-47bd-17e7395111fa.gif)

文字の塗り(Face)箇所だけフェードイン/アウトさせるのであれば `.DOFaceFade()` を使用します。

```csharp:TweenTextMeshProSample
using UnityEngine;
using DG.Tweening;
using TMPro;

[RequireComponent(typeof(TextMeshProUGUI))]
public class TweenTextMeshProSample : MonoBehaviour
{
	void Start()
	{
		this.GetComponent<TextMeshProUGUI>()
			.DOFaceFade(0.0f, 1.0f)
			.SetLoops(-1, LoopType.Yoyo)
			.Play();
	}
}
```

![textmeshpro_facefade.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/003675c6-782b-99ae-77dd-a9e09a1033fa.gif)

文字の枠(Outline)箇所だけフェードイン/アウトさせるのであれば、 `.DOOutlineColor()` でα値を変更します。


```csharp:TweenTextMeshProSample
using UnityEngine;
using DG.Tweening;
using TMPro;

[RequireComponent(typeof(TextMeshProUGUI))]
public class TweenTextMeshProSample : MonoBehaviour
{
	void Start()
	{
		TextMeshProUGUI text = this.GetComponent<TextMeshProUGUI>();
		Color transparentColor = text.outlineColor;
		transparentColor.a = 0.0f;
		
		text.DOOutlineColor(transparentColor, 1.0f)
			.SetLoops(-1, LoopType.Yoyo)
			.Play();
	}
}
```

![textmeshpro_outlinefade.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/712bc69d-dbdd-07d3-e0bb-998754f6884c.gif)

### 文字を1文字ずつ表示/変更させる
文字を1文字ずつ表示させるのであれば `.DOMaxVisibleCharacters` を使います。
TextMeshProは `maxVisibleCharacters` プロパティに設定された値の文字数のみ、文字が描画されます。事前に0を代入し、未表示な状態にした上で、現在入力されている文字数をTweenで受け渡します。

```csharp:TweenTextMeshProSample
using UnityEngine;
using DG.Tweening;
using TMPro;

[RequireComponent(typeof(TextMeshProUGUI))]
public class TweenTextMeshProSample : MonoBehaviour
{
	void Start()
	{
		TextMeshProUGUI text = this.GetComponent<TextMeshProUGUI>();
		text.maxVisibleCharacters = 0;	
		text.DOMaxVisibleCharacters(text.text.Length, 3.0f).Play();
	}
}
```

![textmeshpro_maxcharacter.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/f930f073-aa72-027d-3f97-a298ba8a8ac7.gif)

`.DOText()` を使用することで現状表示されている文字を1文字ずつ、指定した文字列に置き換えることが可能です。上の1文字ずつ出現する処理も、初期文字列を空文字にすることで実現できます。
(この辺りは `UI.Text.DOText()` と同じ挙動)

```csharp:TweenTextMeshProSample
using UnityEngine;
using DG.Tweening;
using TMPro;

[RequireComponent(typeof(TextMeshProUGUI))]
public class TweenTextMeshProSample : MonoBehaviour
{
	[Multiline]
	public string FromText;
	
	[Multiline]
	public string ToText;
	
	void Start()
	{
		TextMeshProUGUI text = this.GetComponent<TextMeshProUGUI>();
		text.text = this.FromText;
		text.DOText(this.ToText, 3.0f).Play();
	}
}
```

![textmeshpro_text.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/384420cc-c163-5a91-cffa-11a8ee891378.gif)

### 文字間隔を広げる
文字間隔の調整は DOTweenPro での拡張メソッド群に含まれていないので、独自に拡張メソッドを記載します。
(これは無償版のDOTweenでも対応可能)

```csharp:TextMeshProExtesion
using DG.Tweening;
using TMPro;

public static class TextMeshProExtesion
{
    public static Tween DOCharacterSpacing(this TextMeshProUGUI textMeshProUgui, float amount, float duration)
    {
        return DOTween.To(() => textMeshProUgui.characterSpacing, x => textMeshProUgui.characterSpacing = x, amount, duration);
    }
}
```
```csharp:TweenTextMeshProSample
using UnityEngine;
using DG.Tweening;
using TMPro;

[RequireComponent(typeof(TextMeshProUGUI))]
public class TweenTextMeshProSample : MonoBehaviour
{
	void Start()
	{
		this.GetComponent<TextMeshProUGUI>()
			.DOCharacterSpacing(30, 2.0f)
			.SetLoops(-1, LoopType.Yoyo)
			.Play();
	}
}
```

![textmeshpro_spacing.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/f216ff15-679f-76c9-3982-5ef5e36fd0cb.gif)

### UI.Maskと組み合わせて金属感を出す
TextMeshPrpはuGUIにも対応しています (TextMeshProUGUI)。
こちらは [UI.Graphic](https://docs.unity3d.com/jp/540/ScriptReference/UI.Graphic.html) を継承しているため、 [Maskコンポーネント](https://docs.unity3d.com/jp/530/Manual/script-Mask.html) を適応することが可能です。TextMeshProで生成したテキストに光沢のようなImageを重ね、それをDOTweenで動かすことで、金属のような見栄えを作ることが出来ます。
(これは無償版のDOTweenでも対応可能)

![textmeshpro_mask.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/76c5a900-0a95-7732-8ac5-7f199fb40a56.gif)

## 最後に
![textmeshpro_sample.gif](https://qiita-image-store.s3.amazonaws.com/0/102664/f2b43243-2d6f-6472-4ceb-48ccaaf54392.gif)

上記の動きを組み合わせて、こんな感じの演出を作ることができました。
(もっといい感じのものを作るセンスが欲しかった)

明日の [Unity アセット真夏のアドベントカレンダー 2017](https://atnd.org/events/89521) は [SASE](https://twitter.com/SaseKubrick) さんの [「【Unity】Pixel Art風な見た目にするアセット Stylizer - Extended」](http://qiita.com/Sase/items/bac0526b5602288bc674) です！

---

<div><img src="http://unity-chan.com/images/imageLicenseLogo.png" alt="ユニティちゃんライセンス"><p>この作品は<a href="http://unity-chan.com/contents/license_jp/" target="_blank">ユニティちゃんライセンス条項</a>の元に提供されています</p></div>