facebook twitter hatena line email

「Unity/Csharp/DoTween」の版間の差分

提供: 初心者エンジニアの簡易メモ
移動: 案内検索
(テキストカウントアップ)
(全体文字をx秒で1文字ずつ表示する)
 
(同じ利用者による、間の87版が非表示)
行5: 行5:
  
 
==インストール==
 
==インストール==
 +
===UnityAssets===
 
#unityassetsからdotweenを検索して、
 
#unityassetsからdotweenを検索して、
 
#dotweenのfree ( https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676 ) をダウンロード
 
#dotweenのfree ( https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676 ) をダウンロード
行11: 行12:
 
#OpenDoTweenUtilityPanelを開き
 
#OpenDoTweenUtilityPanelを開き
 
#SetupDotweenボタンを押して、Applyを押す。
 
#SetupDotweenボタンを押して、Applyを押す。
 +
 +
===PackageManager(MyAssets)===
 +
#PackageManagerで、DoTweenを検索
 +
#DoTweenを選択してInstall。
 +
#Plugins/Demigiant/DOTween があることを確認。
 +
 +
===PackageManager(openupm)===
 +
# npm install -g openupm-cli
 +
# openupm search dotween
 +
# openupm add com.demigiant.dotween
 +
なくなってる・・・
  
 
==サンプル==
 
==サンプル==
行21: 行33:
 
     void Start()
 
     void Start()
 
     {
 
     {
         GameObject.Find("Image").transform.DOMove(new Vector3(2f, 3f, 0f), 1f);
+
         GameObject.Find("Image").transform.DOLocalMove(new Vector3(2f, 3f, 0f), 1f);
 
     }
 
     }
 
}
 
}
 
</pre>
 
</pre>
  
 +
==Xだけ動かす==
 +
<pre>
 +
GameObject.Find("Image").transform.DOLocalMoveX(2f, 1f);
 +
</pre>
 
===繰り返し===
 
===繰り返し===
 
無限繰り返し
 
無限繰り返し
 
<pre>
 
<pre>
GameObject.Find("Image").transform.DOMove(new Vector3(2f, 3f, 0f), 1f)
+
GameObject.Find("Image").transform.DOLocalMove(new Vector3(2f, 3f, 0f), 1f)
 
.SetLoops(-1, LoopType.Restart);
 
.SetLoops(-1, LoopType.Restart);
 
</pre>
 
</pre>
 
2回指定
 
2回指定
 
<pre>
 
<pre>
GameObject.Find("Image").transform.DOMove(new Vector3(2f, 3f, 0f), 1f)
+
GameObject.Find("Image").transform.DOLocalMove(new Vector3(2f, 3f, 0f), 1f)
 
.SetLoops(2, LoopType.Restart);
 
.SetLoops(2, LoopType.Restart);
 
</pre>
 
</pre>
 +
4回指定で、2往復となる。
 +
.SetLoops(4, LoopType.Yoyo)
  
 
===遅延動作===
 
===遅延動作===
行49: 行67:
 
https://github.com/Nightonke/WoWoViewPager/blob/master/Pictures/ease.png
 
https://github.com/Nightonke/WoWoViewPager/blob/master/Pictures/ease.png
  
===動きを止める===
+
===動きを止める(キャンセル)===
 
オブジェクト指定
 
オブジェクト指定
 
  DOTween.Kill(this.transform);
 
  DOTween.Kill(this.transform);
 
tweenインスタンスを作って止める
 
tweenインスタンスを作って止める
  Tween tween = GameObject.Find("Image").transform.DOMove(new Vector3(2f, 3f, 0f), 1f);
+
  Tween tween = GameObject.Find("Image").transform.DOLocalMove(new Vector3(2f, 3f, 0f), 1f);
 
  tween.Kill();
 
  tween.Kill();
  
 
参考:https://qiita.com/broken55/items/df152c061da759ad1471
 
参考:https://qiita.com/broken55/items/df152c061da759ad1471
 +
 +
===絶対座標===
 +
DOMoveとする
 +
GameObject.Find("Image").transform.DOMove(new Vector3(2f, 3f, 0f), 1f);
  
 
===ローカル座標===
 
===ローカル座標===
行63: 行85:
  
 
===回転===
 
===回転===
5秒で、90度回転
+
5秒で、x方向に90度回転
  .DORotate(Vector3.up * 90f, 5f)
+
.DORotate(Vector3.right * 90f, 5f, RotateMode.LocalAxisAdd)
 +
 
 +
5秒で、y方向に90度回転
 +
  .DORotate(Vector3.up * 90f, 5f, RotateMode.LocalAxisAdd)
 +
 
 +
5秒で、z方向に90度回転
 +
.DORotate(Vector3.forward * 90f, 5f, RotateMode.LocalAxisAdd)
 +
 
 +
5秒で、z方向に90度回転を、ループで、速度均等に
 +
.DORotate(Vector3.forward * 360f, 5f, RotateMode.LocalAxisAdd).SetLoops(-1, LoopType.Restart).SetEase(Ease.Linear);
 +
 
 +
参考:https://qiita.com/BEATnonanka/items/b4cca6471e77466cec74
 +
 
 +
全方向回転
 +
transform.DORotate(new Vector3(0,0,360), 1, RotateMode.Fast);
 +
参考:https://qiita.com/BEATnonanka/items/b4cca6471e77466cec74
 +
 
 +
===回転2D===
 +
30秒で一回転で、左回り
 +
<pre>
 +
.DOLocalRotate(new Vector3(0, 0, 360f), 30f, RotateMode.FastBeyond360)
 +
.SetEase(Ease.Linear)
 +
.SetLoops(-1, LoopType.Restart);
 +
</pre>
 +
 
 +
右回り
 +
<pre>
 +
imgRenew.transform.DOLocalRotate(new Vector3(0, 0, -360f), 30f, RotateMode.FastBeyond360)
 +
.SetEase(Ease.Linear)
 +
.SetLoops(-1, LoopType.Restart);
 +
</pre>
  
 
===色変更===
 
===色変更===
 
5秒で青へ
 
5秒で青へ
 
  Image image = GameObject.Find("Image").GetComponent<Image>();
 
  Image image = GameObject.Find("Image").GetComponent<Image>();
  image.DOColor(Color.brue, 5f).SetEase(Ease.Linear);
+
  image.DOColor(Color.blue, 5f).SetEase(Ease.Linear);
 +
マテリアルを1秒で赤へ
 +
GameObject cubeObj;
 +
cubeObj.GetComponent<MeshRenderer>().material.DOColor(Color.red, 1f);
 +
 
 +
SpriteRendererの色を点滅
 +
Color color = new Color(0.7f, 0.7f, 0.7f, 1f);
 +
objCanvas.GetComponent<SpriteRenderer>().DOColor(color, 0.5f).SetEase(Ease.Linear).SetLoops(-1, LoopType.Yoyo);
  
 
===徐々に透明へ===
 
===徐々に透明へ===
 
透明度を10秒で0%へ
 
透明度を10秒で0%へ
 
  image.DOFade(endValue: 0f, duration: 10f);
 
  image.DOFade(endValue: 0f, duration: 10f);
 +
===透明から表示===
 +
<pre>
 +
Image image = hogeImage.GetComponent<Image>();
 +
image.color = new Color(image.color.r, image.color.g, image.color.b, 0f); // 透明へ
 +
image.DOFade(endValue: 1f, duration: 0.5f); // 透明から表示へ
 +
</pre>
 +
 +
===徐々に透明3Dオブジェクト===
 +
[[unity/3d/透明]] [ショートカット]
 +
 +
<pre>
 +
void TransparentAllUnderObject(GameObject obj)
 +
{
 +
    if (obj.GetComponent<SkinnedMeshRenderer>() != null)
 +
    {
 +
        Material[] materials = obj.GetComponent<SkinnedMeshRenderer>().materials;
 +
        if (materials.Length > 0)
 +
        {
 +
            materials[0].shader = Shader.Find("Custom/SemiTransparent");
 +
            obj.GetComponent<SkinnedMeshRenderer>().materials[0].DOFade(endValue: 0f, duration: 1f);
 +
        }
 +
    }
 +
    if (obj.GetComponent<MeshRenderer>() != null)
 +
    {
 +
        Material[] materials = obj.GetComponent<MeshRenderer>().materials;
 +
        if (materials.Length > 0)
 +
        {
 +
            materials[0].shader = Shader.Find("Custom/SemiTransparent");
 +
            obj.GetComponent<SkinnedMeshRenderer>().materials[0].DOFade(endValue: 0f, duration: 1f);
 +
        }
 +
    }
 +
    Transform transforms = obj.GetComponentInChildren<Transform>();
 +
    if (transforms.childCount > 0)
 +
    {
 +
        foreach (Transform transform in transforms)
 +
        {
 +
            TransparentAllUnderObject(transform.gameObject); // 再帰処理
 +
        }
 +
    }
 +
}
 +
</pre>
 +
参考:https://nn-hokuson.hatenablog.com/entry/2018/01/23/202530
  
 
===拡大縮小===
 
===拡大縮小===
行79: 行180:
 
  obj.transform.DOScaleX(1f, 1.0f);
 
  obj.transform.DOScaleX(1f, 1.0f);
 
  obj.transform.DOScaleY(1f, 1.0f);
 
  obj.transform.DOScaleY(1f, 1.0f);
 +
 +
===振動===
 +
1秒間、強さ5で震える
 +
obj.transform.DOShakePosition(duration: 1f, strength: 5);
 +
1秒間に震える(オプション付き)
 +
obj.transform.DOShakePosition(duration: 1, strength: 5, vibrato: 30, fadeOut: false)
 +
敵にやられたときなど
 +
obj.transform.DOShakePosition(duration: 0.3f, strength: 0.25f, vibrato:30, randomness:1, snapping:false, fadeOut:true);
 +
 +
引数上から順番に
 +
*振動時間
 +
*振動する強さ
 +
*振動数
 +
*手ブレ値
 +
*スナップフラグ
 +
*フェードアウト
 +
 +
iTweenのShakePositionからの移植の場合は、10倍ぐらいの強さにすればよいかも。
  
 
===指定座標の上を移動する===
 
===指定座標の上を移動する===
行96: 行215:
 
     .SetLoops(-1, LoopType.Restart);
 
     .SetLoops(-1, LoopType.Restart);
 
</pre>
 
</pre>
 
===星型に移動する===
 
*root座標のときは、DOPathを使う。
 
 
<pre>
 
Vector3[] movepath = new Vector3[6];
 
movepath[0].Set(0f, 1f, 0f); // 1
 
movepath[1].Set(0.5878f, -0.8090f, 0f); // 5
 
movepath[2].Set(-0.9511f, 0.3090f, 0f); // 9
 
movepath[3].Set(0.9511f , 0.3090f, 0f); // 3
 
movepath[4].Set(-0.5878f, -0.8090f, 0f); // 7
 
movepath[5].Set(0f, 1f, 0f); // 1
 
// 星型頂点 https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10137274530
 
GameObject.Find("Image").transform.DOPath(movepath, 5f, PathType.Linear, PathMode.Sidescroller2D)
 
            .SetLookAt(0.01f)
 
            .SetLoops(-1, LoopType.Restart);
 
</pre>
 
ローカル値を使う場合は、DOLocalPathを使う
 
 
参考:https://qiita.com/BEATnonanka/items/50cacac803f88f5074dd
 
  
 
===曲線でつなぐ===
 
===曲線でつなぐ===
行129: 行228:
 
     .SetLookAt(0.1f)
 
     .SetLookAt(0.1f)
 
     .SetLoops(-1, LoopType.Restart);
 
     .SetLoops(-1, LoopType.Restart);
 +
</pre>
 +
 +
===幅を伸ばす===
 +
<pre>
 +
RectTransform rectTransform = underLineObj.GetComponent<RectTransform>();
 +
rectTransform.sizeDelta = new Vector2(0, rectTransform.sizeDelta.y);
 +
rectTransform.DOSizeDelta(new Vector2(800, rectTransform.sizeDelta.y), 1);
 
</pre>
 
</pre>
  
行159: 行265:
 
<pre>
 
<pre>
 
var sequence = DOTween.Sequence();
 
var sequence = DOTween.Sequence();
sequence.Append(this.transform.DOMove(new Vector3(1f, 3f, 0f), 1f);
+
sequence.Append(this.transform.DOMove(new Vector3(1f, 3f, 0f), 1f));
sequence.Append(this.transform.DOMove(new Vector3(2f, 4f, 0f), 1f);
+
sequence.Append(this.transform.DOMove(new Vector3(2f, 4f, 0f), 1f));
 
sequence.Play();
 
sequence.Play();
 
</pre>
 
</pre>
行166: 行272:
 
<pre>
 
<pre>
 
var sequence = DOTween.Sequence();
 
var sequence = DOTween.Sequence();
sequence.Append(this.transform.DOMove(new Vector3(1f, 3f, 0f), 1f);
+
sequence.Append(this.transform.DOMove(new Vector3(1f, 3f, 0f), 1f));
sequence.Append(this.transform.DOMove(new Vector3(2f, 4f, 0f), 1f);
+
sequence.Append(this.transform.DOMove(new Vector3(2f, 4f, 0f), 1f));
 
sequence.Join(this.transform.DOScale(Vector3.one * 3f, 1f)); // 1つ前と同時に実行
 
sequence.Join(this.transform.DOScale(Vector3.one * 3f, 1f)); // 1つ前と同時に実行
 +
sequence.Join(this.transform.DORotate(new Vector3(0, 0, 360f), 1f, RotateMode.FastBeyond360)); // 1つ前と同時に実行
 
sequence.Play();
 
sequence.Play();
 
</pre>
 
</pre>
 +
 +
移動しながら、徐々に表示されるように
 +
<pre>
 +
hogeText.color = new Vector4(hogeText.color.r, hogeText.color.g, hogeText.color.b, 0f);
 +
var sequence = DOTween.Sequence();
 +
sequence.Append(hogeObj.transform.DOLocalMoveY(10, 0.1f));
 +
sequence.Join(hogeText.DOFade(endValue: 1f, duration: 0.15f));
 +
sequence.Play();
 +
</pre>
 +
 +
上に移動しながら、文字が消える
 +
<pre>
 +
TextMeshPro textPro = hogeObj.GetComponent<TextMeshPro>();
 +
textPro.color = new Color(textPro.color.r, textPro.color.g, textPro.color.b, 1);
 +
Color color = new Color(textPro.color.r, textPro.color.g, textPro.color.b, 0f);
 +
sequence = DOTween.Sequence();
 +
sequence.Append(hogeObj.transform.DOLocalMoveY(4f, 1f));
 +
sequence.Join(textPro.DOColor(color, 1f));
 +
sequence.Play();
 +
</pre>
 +
 +
or
 +
<pre>
 +
Text text = obj.GetComponent<Text>();
 +
Color color = new Color(1f, 1f, 1f, 0f);
 +
Sequence sequence = DOTween.Sequence();
 +
sequence.Append(obj.transform.DOLocalMoveY(obj.transform.localPosition.y + 200f, 0.5f));
 +
sequence.Join(DOTween.ToAlpha(
 +
    () => text.color,
 +
    color => text.color = color,
 +
    0f,
 +
    0.5f
 +
).SetEase(Ease.InCubic));
 +
sequence.Play();
 +
</pre>
 +
 +
===sequenceで待機する===
 +
sequence.AppendInterval(0.5f); // 待機
  
 
===テキストカウントアップ===
 
===テキストカウントアップ===
 
<pre>
 
<pre>
int start = 10;
+
int now = 10;
 
int end = 1000;
 
int end = 1000;
DOTween.To(() => end, (n) => end = n, 1000, 1)
+
int sec = 1;
     .OnUpdate(() => text.text = end.ToString("#,0"));
+
DOTween.To(() => now, (n) => now = n, end, sec)
 +
    .SetEase(Ease.Linear) // 線形
 +
     .OnUpdate(() => text.text = now.ToString("f2")); // 小数第2位まで
 
</pre>
 
</pre>
  
 
参考:http://halcyonsystemblog.jp/blog-entry-524.html
 
参考:http://halcyonsystemblog.jp/blog-entry-524.html
 +
 +
===スライダーアニメーション===
 +
<pre>
 +
float now = 0;
 +
float end = 1;
 +
float sec = 1;
 +
DOTween.To(() => now, (n) => now = n, end, sec)
 +
    .SetEase(Ease.Linear) // 線形
 +
    .OnUpdate(() => {
 +
      enemyBossHpSlider.value = now;
 +
    })
 +
    .OnComplete(() => {
 +
      Debug.Log("complete");
 +
    });
 +
</pre>
 +
 +
===DOTweenのキャンセル===
 +
<pre>
 +
float now = 0;
 +
float end = 1;
 +
float sec = 1;
 +
Tween tween = DOTween.To(() => now, (n) => now = n, end, sec)
 +
    .SetEase(Ease.Linear) // 線形
 +
    .OnUpdate(() => {
 +
      enemyBossHpSlider.value = now;
 +
    })
 +
    .OnComplete(() => {
 +
      Debug.Log("complete");
 +
    });
 +
tween.Kill(); // キャンセル
 +
</pre>
 +
 +
===数秒遅延===
 +
<pre>
 +
DOVirtual.DelayedCall(2f, () =>
 +
{
 +
  // 2秒後実行
 +
});
 +
</pre>
 +
 +
===完了するまで処理を待機する===
 +
UniTaskなどを使ってasyncを使う。
 +
<pre>
 +
async void BasicAsync()
 +
{
 +
    await GameObject.Find("Image").transform.DOMove(new Vector3(3f, 3f, 0f), 2f)
 +
        // .SetEase(Ease.InExpo)
 +
        .SetEase(Ease.Linear)
 +
        .AsyncWaitForCompletion();
 +
    Debug.Log("完了");
 +
}
 +
</pre>
 +
====sequenceの場合====
 +
await sequence.AsyncWaitForCompletion();
 +
 +
===元シーン削除でTweenを削除する方法===
 +
<pre>
 +
transform
 +
    .DOMoveX(2, 2)
 +
    .SetLink(gameObject);
 +
</pre>
 +
参考:https://baba-s.hatenablog.com/entry/2020/03/02/151500
 +
 +
==自作テンプレモーション==
 +
 +
===テレビのように開く===
 +
<pre>
 +
this.transform.localScale = new Vector3(0f, 0f, 0f);
 +
var sequence = DOTween.Sequence();
 +
sequence.Append(this.transform.DOScale(new Vector3(1f, 0.005f, 1f), 0.2f).SetEase(Ease.InOutCubic));
 +
sequence.Append(this.transform.DOScale(new Vector3(1f, 1f, 1f), 0.2f).SetEase(Ease.InOutCubic));
 +
sequence.Play();
 +
</pre>
 +
===テレビのように閉じる===
 +
<pre>
 +
this.transform.localScale = new Vector3(1f, 1f, 1f);
 +
var sequence = DOTween.Sequence();
 +
sequence.Append(this.transform.DOScale(new Vector3(1f, 0.005f, 1f), 0.2f).SetEase(Ease.InOutCubic));
 +
sequence.Append(this.transform.DOScale(new Vector3(0f, 0f, 0f), 0.2f).SetEase(Ease.InOutCubic));
 +
sequence.Play();
 +
</pre>
 +
 +
===星型に移動する===
 +
*root座標のときは、DOPathを使う。
 +
 +
<pre>
 +
Vector3[] movepath = new Vector3[6];
 +
movepath[0].Set(0f, 1f, 0f); // 1
 +
movepath[1].Set(0.5878f, -0.8090f, 0f); // 5
 +
movepath[2].Set(-0.9511f, 0.3090f, 0f); // 9
 +
movepath[3].Set(0.9511f , 0.3090f, 0f); // 3
 +
movepath[4].Set(-0.5878f, -0.8090f, 0f); // 7
 +
movepath[5].Set(0f, 1f, 0f); // 1
 +
// 星型頂点 https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10137274530
 +
GameObject.Find("Image").transform.DOPath(movepath, 5f, PathType.Linear, PathMode.Sidescroller2D)
 +
            .SetLookAt(0.01f)
 +
            .SetLoops(-1, LoopType.Restart);
 +
</pre>
 +
ローカル値を使う場合は、DOLocalPathを使う
 +
 +
参考:https://qiita.com/BEATnonanka/items/50cacac803f88f5074dd
 +
 +
===敵にダメージを与えたときにランダムに振動===
 +
enemyTransform.DOShakePosition(duration: 0.1f, strength: 0.1f, vibrato: 1, randomness: 1, snapping: false, fadeOut: false);
 +
 +
===敵にダメージを与えたときにランダムに振動===
 +
<pre>
 +
float knockbackDistance = 0.5f; // ノックバックの距離
 +
// プレイヤーの方向を計算
 +
Vector3 directionToPlayer = playerObj.transform.position - enemy.transform.position;
 +
directionToPlayer.Normalize(); // ベクトルの正規化
 +
 +
// ノックバックの方向を計算(プレイヤーの方向とは逆)
 +
Vector3 knockbackDirection = -directionToPlayer;
 +
 +
// ノックバック後の座標を計算
 +
Vector3 knockbackPosition = enemy.transform.position + knockbackDirection * knockbackDistance;
 +
 +
// ノックバック後の座標のY成分が今よりも下にいかないように(床貫通対策)
 +
if (knockbackPosition.y < enemyObj.transform.position.y)
 +
{
 +
    knockbackPosition.y = Mathf.Max(knockbackPosition.y, enemy.transform.position.y);
 +
}
 +
 +
enemyTransform.DOMove(knockbackPosition, 0.04f)
 +
    .SetLoops(2, LoopType.Yoyo).SetEase(Ease.OutQuad);
 +
</pre>
 +
ゼンゼロっぽく。すぐに元の位置に戻す。
 +
 +
===力を加える場合は、DotweenじゃなくRigidbodyを使う===
 +
<pre>
 +
float knockbackDistance = 3.5f; // ノックバックの距離
 +
// プレイヤーの方向を計算
 +
Vector3 directionToPlayer = playerObj.transform.position - enemyObj.transform.position;
 +
directionToPlayer.Normalize(); // ベクトルの正規化
 +
 +
// ノックバックの方向を計算(プレイヤーの方向とは逆)
 +
Vector3 knockbackDirection = -directionToPlayer;
 +
 +
// Rigidbodyコンポーネントを取得
 +
Rigidbody rb = enemyObj.GetComponent<Rigidbody>();
 +
 +
// ノックバックの方向を力として加える
 +
rb.AddForce(knockbackDirection * knockbackDistance, ForceMode.Impulse);
 +
</pre>
 +
 +
===縮小してきて震える===
 +
<pre>
 +
messageObj.transform.localScale = new Vector3(20f, 20f, messageObj.transform.localScale.z);
 +
Vector3 initPosition = messageObj.transform.localPosition;
 +
var sequence = DOTween.Sequence();
 +
sequence.Append(messageObj.transform.DOScale(Vector3.one, 0.2f).SetEase(Ease.OutBack));
 +
sequence.Append(messageObj.transform.DOShakePosition(duration: 0.2f, strength: 50f, vibrato: 30, fadeOut: false).SetDelay(0.2f));
 +
sequence.Play().OnComplete(() =>
 +
{
 +
      messageObj.transform.localPosition = initPosition;
 +
});
 +
</pre>
 +
 +
===ffっぽいダメージ===
 +
<pre>
 +
var sequence = DOTween.Sequence();
 +
sequence.Append(imageObj.transform.DOLocalMoveY(100f, 0.1f).SetEase(Ease.OutSine));
 +
sequence.Append(imageObj.transform.DOLocalMoveY(0f, 0.1f).SetEase(Ease.InSine));
 +
sequence.Append(imageObj.transform.DOLocalMoveY(60f, 0.1f).SetEase(Ease.OutSine));
 +
sequence.Append(imageObj.transform.DOLocalMoveY(0f, 0.2f).SetEase(Ease.OutBounce));
 +
sequence.Play();
 +
</pre>
 +
 +
===スタンプを押してる感じ===
 +
<pre>
 +
clearImageObj.transform.localScale = Vector3.one * 5f;
 +
var sequenceClear = DOTween.Sequence();
 +
sequenceClear.Append(clearImageObj.transform.DOScale(Vector3.one, 0.2f).SetEase(Ease.OutBack));
 +
sequenceClear.Join(clearImageObj.transform.DOShakePosition(duration: 0.2f, strength: 50f, vibrato: 30, fadeOut: false));
 +
sequenceClear.Play();
 +
</pre>
 +
 +
===全体文字をx秒で1文字ずつ表示する===
 +
<pre>
 +
totalDuration = 2f; // 全体を2秒で表示
 +
textMeshPro.text = ""; // 初期化
 +
float timePerChar = totalDuration / text.Length; // 各文字にかける時間を計算
 +
Sequence sequence = DOTween.Sequence();
 +
for (int i = 0; i < text.Length; i++)
 +
{
 +
    int index = i; // クロージャ内でのiを保持
 +
    sequence.AppendCallback(() => {
 +
        textMeshPro.text = text.Substring(0, index + 1);
 +
    }).AppendInterval(timePerChar);
 +
}
 +
sequence.Play();
 +
</pre>
 +
 +
==サンプルモーション==
 +
ボタンフェードイン表示
 +
<pre>
 +
obj.transform.localScale = Vector3.zero;
 +
obj.transform.DOScale(1f, 1f).SetEase(Ease.OutBounce);
 +
</pre>
 +
参考:https://unity-yuji.xyz/dotween-good-game-ui/
 +
 +
上下移動サンプル
 +
<pre>
 +
obj.transform
 +
            .DOMoveY(obj.transform.position.y  - 0.1f, duration: 1f)
 +
            .SetEase(Ease.Linear)
 +
            .SetLoops(-1, LoopType.Yoyo)
 +
            .Play();
 +
</pre>
 +
参考:https://qiita.com/azumagoro/items/d97a07cff212a664461b
 +
 +
==外部サイトサンプルモーション==
 +
DOTweenで作成したモーション17個を含むプロジェクトを公開
 +
https://game-ui.net/?p=975
 +
 +
==The type 'TweenerCore<,,>' is definedエラーが出る場合==
 +
詳しいエラーは以下の通り
 +
The type 'TweenerCore<,,>' is defined in an assembly that is not referenced. You must add a reference to assembly 'DOTween, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
 +
PCを再起動で直った。

2024年9月22日 (日) 13:44時点における最新版

目次

dotweenとは

アニメーションライブラリ

参考:https://qiita.com/broken55/items/df152c061da759ad1471

インストール

UnityAssets

  1. unityassetsからdotweenを検索して、
  2. dotweenのfree ( https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676 ) をダウンロード
  3. installし、
  4. importする
  5. OpenDoTweenUtilityPanelを開き
  6. SetupDotweenボタンを押して、Applyを押す。

PackageManager(MyAssets)

  1. PackageManagerで、DoTweenを検索
  2. DoTweenを選択してInstall。
  3. Plugins/Demigiant/DOTween があることを確認。

PackageManager(openupm)

  1. npm install -g openupm-cli
  2. openupm search dotween
  3. openupm add com.demigiant.dotween

なくなってる・・・

サンプル

x=2、y=3のrootから見た座標に1秒後に移動する。

using DG.Tweening;
using UnityEngine;
public class SampleScene : MonoBehaviour
{
    void Start()
    {
        GameObject.Find("Image").transform.DOLocalMove(new Vector3(2f, 3f, 0f), 1f);
    }
}

Xだけ動かす

GameObject.Find("Image").transform.DOLocalMoveX(2f, 1f);

繰り返し

無限繰り返し

GameObject.Find("Image").transform.DOLocalMove(new Vector3(2f, 3f, 0f), 1f)
.SetLoops(-1, LoopType.Restart);

2回指定

GameObject.Find("Image").transform.DOLocalMove(new Vector3(2f, 3f, 0f), 1f)
.SetLoops(2, LoopType.Restart);

4回指定で、2往復となる。

.SetLoops(4, LoopType.Yoyo)

遅延動作

5秒待ってから動作

.SetDelay(5f);

Easeの動き

.SetEase(Ease.Linear); // 線形
.SetEase(Ease.OutSine); // 最初速く後ゆっくり
.SetEase(Ease.InExpo); // 最初ゆっくり後速く

https://github.com/Nightonke/WoWoViewPager/blob/master/Pictures/ease.png

動きを止める(キャンセル)

オブジェクト指定

DOTween.Kill(this.transform);

tweenインスタンスを作って止める

Tween tween = GameObject.Find("Image").transform.DOLocalMove(new Vector3(2f, 3f, 0f), 1f);
tween.Kill();

参考:https://qiita.com/broken55/items/df152c061da759ad1471

絶対座標

DOMoveとする

GameObject.Find("Image").transform.DOMove(new Vector3(2f, 3f, 0f), 1f);

ローカル座標

DOLocalMoveとする

GameObject.Find("Image").transform.DOLocalMove(new Vector3(2f, 3f, 0f), 1f);

回転

5秒で、x方向に90度回転

.DORotate(Vector3.right * 90f, 5f, RotateMode.LocalAxisAdd)

5秒で、y方向に90度回転

.DORotate(Vector3.up * 90f, 5f, RotateMode.LocalAxisAdd)

5秒で、z方向に90度回転

.DORotate(Vector3.forward * 90f, 5f, RotateMode.LocalAxisAdd)

5秒で、z方向に90度回転を、ループで、速度均等に

.DORotate(Vector3.forward * 360f, 5f, RotateMode.LocalAxisAdd).SetLoops(-1, LoopType.Restart).SetEase(Ease.Linear);

参考:https://qiita.com/BEATnonanka/items/b4cca6471e77466cec74

全方向回転

transform.DORotate(new Vector3(0,0,360), 1, RotateMode.Fast);

参考:https://qiita.com/BEATnonanka/items/b4cca6471e77466cec74

回転2D

30秒で一回転で、左回り

.DOLocalRotate(new Vector3(0, 0, 360f), 30f, RotateMode.FastBeyond360)
.SetEase(Ease.Linear)
.SetLoops(-1, LoopType.Restart);

右回り

imgRenew.transform.DOLocalRotate(new Vector3(0, 0, -360f), 30f, RotateMode.FastBeyond360)
.SetEase(Ease.Linear)
.SetLoops(-1, LoopType.Restart);

色変更

5秒で青へ

Image image = GameObject.Find("Image").GetComponent<Image>();
image.DOColor(Color.blue, 5f).SetEase(Ease.Linear);

マテリアルを1秒で赤へ

GameObject cubeObj;
cubeObj.GetComponent<MeshRenderer>().material.DOColor(Color.red, 1f);

SpriteRendererの色を点滅

Color color = new Color(0.7f, 0.7f, 0.7f, 1f);
objCanvas.GetComponent<SpriteRenderer>().DOColor(color, 0.5f).SetEase(Ease.Linear).SetLoops(-1, LoopType.Yoyo);

徐々に透明へ

透明度を10秒で0%へ

image.DOFade(endValue: 0f, duration: 10f);

透明から表示

Image image = hogeImage.GetComponent<Image>();
image.color = new Color(image.color.r, image.color.g, image.color.b, 0f); // 透明へ
image.DOFade(endValue: 1f, duration: 0.5f); // 透明から表示へ

徐々に透明3Dオブジェクト

unity/3d/透明 [ショートカット]

void TransparentAllUnderObject(GameObject obj)
{
    if (obj.GetComponent<SkinnedMeshRenderer>() != null)
    {
        Material[] materials = obj.GetComponent<SkinnedMeshRenderer>().materials;
        if (materials.Length > 0)
        {
            materials[0].shader = Shader.Find("Custom/SemiTransparent");
            obj.GetComponent<SkinnedMeshRenderer>().materials[0].DOFade(endValue: 0f, duration: 1f);
        }
    }
    if (obj.GetComponent<MeshRenderer>() != null)
    {
        Material[] materials = obj.GetComponent<MeshRenderer>().materials;
        if (materials.Length > 0)
        {
            materials[0].shader = Shader.Find("Custom/SemiTransparent");
            obj.GetComponent<SkinnedMeshRenderer>().materials[0].DOFade(endValue: 0f, duration: 1f);
        }
    }
    Transform transforms = obj.GetComponentInChildren<Transform>();
    if (transforms.childCount > 0)
    {
        foreach (Transform transform in transforms)
        {
            TransparentAllUnderObject(transform.gameObject); // 再帰処理
        }
    }
}

参考:https://nn-hokuson.hatenablog.com/entry/2018/01/23/202530

拡大縮小

obj.transform.DOScale(new Vector3(1f, 1f, 0f), 1.0f);
obj.transform.DOScaleX(1f, 1.0f);
obj.transform.DOScaleY(1f, 1.0f);

振動

1秒間、強さ5で震える

obj.transform.DOShakePosition(duration: 1f, strength: 5);

1秒間に震える(オプション付き)

obj.transform.DOShakePosition(duration: 1, strength: 5, vibrato: 30, fadeOut: false)

敵にやられたときなど

obj.transform.DOShakePosition(duration: 0.3f, strength: 0.25f, vibrato:30, randomness:1, snapping:false, fadeOut:true);

引数上から順番に

  • 振動時間
  • 振動する強さ
  • 振動数
  • 手ブレ値
  • スナップフラグ
  • フェードアウト

iTweenのShakePositionからの移植の場合は、10倍ぐらいの強さにすればよいかも。

指定座標の上を移動する

  • 2Dの場合は、PathMode.Sidescroller2Dを追加する。
  • SetLookAtは、傾きが変わるx秒前に正面の向きを変える
Vector3[] movepath =
{
    new Vector3(0f,0f,0f),
    new Vector3(0f,100f,0f),
    new Vector3(100f,100f,0f),
    new Vector3(100f,0f,0f),
    new Vector3(0f,0f,0f)
};
GameObject.Find("Image").transform.DOLocalPath(movepath, 5f, PathType.Linear, PathMode.Sidescroller2D)
    .SetLookAt(0.1f)
    .SetLoops(-1, LoopType.Restart);

曲線でつなぐ

Vector3[] movepath =
{
    new Vector3(0f,0f,0f),
    new Vector3(200f,-100f,0f),
    new Vector3(400f,-300f,0f),
};
GameObject.Find("Image").transform.DOLocalPath(movepath, 0.5f, PathType.CatmullRom, PathMode.Sidescroller2D)
    .SetEase(Ease.Linear)
    .SetLookAt(0.1f)
    .SetLoops(-1, LoopType.Restart);

幅を伸ばす

RectTransform rectTransform = underLineObj.GetComponent<RectTransform>();
rectTransform.sizeDelta = new Vector2(0, rectTransform.sizeDelta.y);
rectTransform.DOSizeDelta(new Vector2(800, rectTransform.sizeDelta.y), 1);

完了したら関数実行

パターン1

GameObject.Find("Image").transform.DOPath(movepath, 5f, PathType.Linear, PathMode.Sidescroller2D).OnComplete(CallbackComplete);
}
void CallbackComplete()
{
    Debug.Log("CallbackComplete");
}

パターン2

GameObject.Find("Image").transform.DOPath(movepath, 5f, PathType.Linear, PathMode.Sidescroller2D).OnComplete(() =>
{
    Debug.Log("CallbackComplete");
});

コールバック一覧

.OnComplete(Callback);
.OnStart(Callback);
.OnUpdate(Callback);
.OnKill(Callback);

複数動作をつなげる

var sequence = DOTween.Sequence();
sequence.Append(this.transform.DOMove(new Vector3(1f, 3f, 0f), 1f));
sequence.Append(this.transform.DOMove(new Vector3(2f, 4f, 0f), 1f));
sequence.Play();

複数同時実行をつなげる

var sequence = DOTween.Sequence();
sequence.Append(this.transform.DOMove(new Vector3(1f, 3f, 0f), 1f));
sequence.Append(this.transform.DOMove(new Vector3(2f, 4f, 0f), 1f));
sequence.Join(this.transform.DOScale(Vector3.one * 3f, 1f)); // 1つ前と同時に実行
sequence.Join(this.transform.DORotate(new Vector3(0, 0, 360f), 1f, RotateMode.FastBeyond360)); // 1つ前と同時に実行
sequence.Play();

移動しながら、徐々に表示されるように

hogeText.color = new Vector4(hogeText.color.r, hogeText.color.g, hogeText.color.b, 0f);
var sequence = DOTween.Sequence();
sequence.Append(hogeObj.transform.DOLocalMoveY(10, 0.1f));
sequence.Join(hogeText.DOFade(endValue: 1f, duration: 0.15f));
sequence.Play();

上に移動しながら、文字が消える

TextMeshPro textPro = hogeObj.GetComponent<TextMeshPro>();
textPro.color = new Color(textPro.color.r, textPro.color.g, textPro.color.b, 1);
Color color = new Color(textPro.color.r, textPro.color.g, textPro.color.b, 0f);
sequence = DOTween.Sequence();
sequence.Append(hogeObj.transform.DOLocalMoveY(4f, 1f));
sequence.Join(textPro.DOColor(color, 1f));
sequence.Play();

or

Text text = obj.GetComponent<Text>();
Color color = new Color(1f, 1f, 1f, 0f);
Sequence sequence = DOTween.Sequence();
sequence.Append(obj.transform.DOLocalMoveY(obj.transform.localPosition.y + 200f, 0.5f));
sequence.Join(DOTween.ToAlpha(
    () => text.color,
    color => text.color = color,
    0f,
    0.5f
).SetEase(Ease.InCubic));
sequence.Play();

sequenceで待機する

sequence.AppendInterval(0.5f); // 待機

テキストカウントアップ

int now = 10;
int end = 1000;
int sec = 1;
DOTween.To(() => now, (n) => now = n, end, sec)
    .SetEase(Ease.Linear) // 線形
    .OnUpdate(() => text.text = now.ToString("f2")); // 小数第2位まで

参考:http://halcyonsystemblog.jp/blog-entry-524.html

スライダーアニメーション

float now = 0;
float end = 1;
float sec = 1;
DOTween.To(() => now, (n) => now = n, end, sec)
    .SetEase(Ease.Linear) // 線形
    .OnUpdate(() => {
       enemyBossHpSlider.value = now;
    })
    .OnComplete(() => {
       Debug.Log("complete");
    });

DOTweenのキャンセル

float now = 0;
float end = 1;
float sec = 1;
Tween tween = DOTween.To(() => now, (n) => now = n, end, sec)
    .SetEase(Ease.Linear) // 線形
    .OnUpdate(() => {
       enemyBossHpSlider.value = now;
    })
    .OnComplete(() => {
       Debug.Log("complete");
    });
tween.Kill(); // キャンセル

数秒遅延

DOVirtual.DelayedCall(2f, () => 
{
   // 2秒後実行
});

完了するまで処理を待機する

UniTaskなどを使ってasyncを使う。

async void BasicAsync()
{
    await GameObject.Find("Image").transform.DOMove(new Vector3(3f, 3f, 0f), 2f)
        // .SetEase(Ease.InExpo)
        .SetEase(Ease.Linear)
        .AsyncWaitForCompletion();
    Debug.Log("完了");
}

sequenceの場合

await sequence.AsyncWaitForCompletion();

元シーン削除でTweenを削除する方法

transform
    .DOMoveX(2, 2)
    .SetLink(gameObject);

参考:https://baba-s.hatenablog.com/entry/2020/03/02/151500

自作テンプレモーション

テレビのように開く

this.transform.localScale = new Vector3(0f, 0f, 0f);
var sequence = DOTween.Sequence();
sequence.Append(this.transform.DOScale(new Vector3(1f, 0.005f, 1f), 0.2f).SetEase(Ease.InOutCubic));
sequence.Append(this.transform.DOScale(new Vector3(1f, 1f, 1f), 0.2f).SetEase(Ease.InOutCubic));
sequence.Play();

テレビのように閉じる

this.transform.localScale = new Vector3(1f, 1f, 1f);
var sequence = DOTween.Sequence();
sequence.Append(this.transform.DOScale(new Vector3(1f, 0.005f, 1f), 0.2f).SetEase(Ease.InOutCubic));
sequence.Append(this.transform.DOScale(new Vector3(0f, 0f, 0f), 0.2f).SetEase(Ease.InOutCubic));
sequence.Play();

星型に移動する

  • root座標のときは、DOPathを使う。
Vector3[] movepath = new Vector3[6];
movepath[0].Set(0f, 1f, 0f); // 1
movepath[1].Set(0.5878f, -0.8090f, 0f); // 5
movepath[2].Set(-0.9511f, 0.3090f, 0f); // 9
movepath[3].Set(0.9511f , 0.3090f, 0f); // 3
movepath[4].Set(-0.5878f, -0.8090f, 0f); // 7
movepath[5].Set(0f, 1f, 0f); // 1
// 星型頂点 https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10137274530
GameObject.Find("Image").transform.DOPath(movepath, 5f, PathType.Linear, PathMode.Sidescroller2D)
            .SetLookAt(0.01f)
            .SetLoops(-1, LoopType.Restart);

ローカル値を使う場合は、DOLocalPathを使う

参考:https://qiita.com/BEATnonanka/items/50cacac803f88f5074dd

敵にダメージを与えたときにランダムに振動

enemyTransform.DOShakePosition(duration: 0.1f, strength: 0.1f, vibrato: 1, randomness: 1, snapping: false, fadeOut: false);

敵にダメージを与えたときにランダムに振動

float knockbackDistance = 0.5f; // ノックバックの距離
// プレイヤーの方向を計算
Vector3 directionToPlayer = playerObj.transform.position - enemy.transform.position;
directionToPlayer.Normalize(); // ベクトルの正規化

// ノックバックの方向を計算(プレイヤーの方向とは逆)
Vector3 knockbackDirection = -directionToPlayer;

// ノックバック後の座標を計算
Vector3 knockbackPosition = enemy.transform.position + knockbackDirection * knockbackDistance;

// ノックバック後の座標のY成分が今よりも下にいかないように(床貫通対策)
if (knockbackPosition.y < enemyObj.transform.position.y)
{
    knockbackPosition.y = Mathf.Max(knockbackPosition.y, enemy.transform.position.y);
}

enemyTransform.DOMove(knockbackPosition, 0.04f)
    .SetLoops(2, LoopType.Yoyo).SetEase(Ease.OutQuad);

ゼンゼロっぽく。すぐに元の位置に戻す。

力を加える場合は、DotweenじゃなくRigidbodyを使う

float knockbackDistance = 3.5f; // ノックバックの距離
// プレイヤーの方向を計算
Vector3 directionToPlayer = playerObj.transform.position - enemyObj.transform.position;
directionToPlayer.Normalize(); // ベクトルの正規化

// ノックバックの方向を計算(プレイヤーの方向とは逆)
Vector3 knockbackDirection = -directionToPlayer;

// Rigidbodyコンポーネントを取得
Rigidbody rb = enemyObj.GetComponent<Rigidbody>();

// ノックバックの方向を力として加える
rb.AddForce(knockbackDirection * knockbackDistance, ForceMode.Impulse);

縮小してきて震える

messageObj.transform.localScale = new Vector3(20f, 20f, messageObj.transform.localScale.z);
Vector3 initPosition = messageObj.transform.localPosition;
var sequence = DOTween.Sequence();
sequence.Append(messageObj.transform.DOScale(Vector3.one, 0.2f).SetEase(Ease.OutBack));
sequence.Append(messageObj.transform.DOShakePosition(duration: 0.2f, strength: 50f, vibrato: 30, fadeOut: false).SetDelay(0.2f));
sequence.Play().OnComplete(() =>
{
      messageObj.transform.localPosition = initPosition;
});

ffっぽいダメージ

var sequence = DOTween.Sequence();
sequence.Append(imageObj.transform.DOLocalMoveY(100f, 0.1f).SetEase(Ease.OutSine));
sequence.Append(imageObj.transform.DOLocalMoveY(0f, 0.1f).SetEase(Ease.InSine));
sequence.Append(imageObj.transform.DOLocalMoveY(60f, 0.1f).SetEase(Ease.OutSine));
sequence.Append(imageObj.transform.DOLocalMoveY(0f, 0.2f).SetEase(Ease.OutBounce));
sequence.Play();

スタンプを押してる感じ

clearImageObj.transform.localScale = Vector3.one * 5f;
var sequenceClear = DOTween.Sequence();
sequenceClear.Append(clearImageObj.transform.DOScale(Vector3.one, 0.2f).SetEase(Ease.OutBack));
sequenceClear.Join(clearImageObj.transform.DOShakePosition(duration: 0.2f, strength: 50f, vibrato: 30, fadeOut: false));
sequenceClear.Play();

全体文字をx秒で1文字ずつ表示する

totalDuration = 2f; // 全体を2秒で表示
textMeshPro.text = ""; // 初期化
float timePerChar = totalDuration / text.Length; // 各文字にかける時間を計算
Sequence sequence = DOTween.Sequence();
for (int i = 0; i < text.Length; i++)
{
    int index = i; // クロージャ内でのiを保持
    sequence.AppendCallback(() => {
        textMeshPro.text = text.Substring(0, index + 1);
    }).AppendInterval(timePerChar);
}
sequence.Play();

サンプルモーション

ボタンフェードイン表示

obj.transform.localScale = Vector3.zero;
obj.transform.DOScale(1f, 1f).SetEase(Ease.OutBounce);

参考:https://unity-yuji.xyz/dotween-good-game-ui/

上下移動サンプル

obj.transform
            .DOMoveY(obj.transform.position.y  - 0.1f, duration: 1f)
            .SetEase(Ease.Linear)
            .SetLoops(-1, LoopType.Yoyo)
            .Play();

参考:https://qiita.com/azumagoro/items/d97a07cff212a664461b

外部サイトサンプルモーション

DOTweenで作成したモーション17個を含むプロジェクトを公開 https://game-ui.net/?p=975

The type 'TweenerCore<,,>' is definedエラーが出る場合

詳しいエラーは以下の通り

The type 'TweenerCore<,,>' is defined in an assembly that is not referenced. You must add a reference to assembly 'DOTween, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

PCを再起動で直った。