はじめに
Unityでトゥイーンと言えば、アセットDOTweenが有名です。
Free版でも十分な機能を備えている上に大変使いやすく、個人的にはもはや外せないくらいです。
さて、DOTweenを使って開発しているとたまに出くわす警告(もしくはエラー)があります。
毎回対処するのですが、しばらくするとやり方を忘れてしまうのでメモがてら共有します。
ちなみに警告の状態であれば多分放置してても特に実害はないです。なんか気持ち悪いので消したいという人へ。
警告(エラー)内容
警告の場合
エディタ再生を終了したタイミングで下記の警告が出ます。
DOTWEEN ▶ SAFE MODE ▶ DOTween's safe mode captured [エラー数] errors. This is usually ok (it's what safe mode is there for) but if your game is encountering issues you should set Log Behaviour to Default in DOTween Utility Panel in order to get detailed warnings when an error is captured (consider that these errors are always on the user side).
エラーの場合
Utility Panelで「Safe Mode」のチェックを外していると、エディタ再生中に警告ではなくエラーが出ます。
MissingReferenceException: The object of type '[なんかのコンポーネント]' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
発生する状況
例えば、こんな感じのスクリプトがあったとします。
RectTransformをちょっと動かすだけの単純なコードです。
using DG.Tweening;
using UnityEngine;
[RequireComponent(typeof(RectTransform))]
public class DotweenTest : MonoBehaviour
{
private RectTransform _rectTransform = null;
private void Awake()
{
_rectTransform = GetComponent<RectTransform>();
}
private void Start()
{
// Tween開始
Vector2 start = Vector2.zero;
Vector2 end = new Vector2(0f, -30f);
_rectTransform.anchoredPosition = start;
_rectTransform.DOAnchorPos(end, 10f).SetEase(Ease.OutQuart);
}
}
これを動かし、トゥイーンが終わる前に(シーン遷移などで)アタッチされているゲームオブジェクトが破棄されると上の警告(エラー)が出るようになります。
ゲームオブジェクトはもうないのに、それに対するトゥイーン処理が残り続けているのがマズいみたいですね。
対処方法
(これがトゥイーン完了まで消えない前提で組まれているとかならそのままでもいいかもしれませんが、)一番はゲームオブジェクトが消える際にトゥイーンも一緒に破棄してあげることかなと思います。
具体的にはTweenを覚えておいてOnDisableの中でKillです。
(こいつは何を言っているんだ???…って感じかと思いますが、下記のコードを見て頂ければ一発かと思います。)
using DG.Tweening;
using UnityEngine;
[RequireComponent(typeof(RectTransform))]
public class DotweenTest : MonoBehaviour
{
private RectTransform _rectTransform = null;
private Tween _tween = null;
private void Awake()
{
_rectTransform = GetComponent<RectTransform>();
}
private void Start()
{
// Tween開始
Vector2 start = Vector2.zero;
Vector2 end = new Vector2(0f, -30f);
_rectTransform.anchoredPosition = start;
_tween = _rectTransform.DOAnchorPos(end, 10f).SetEase(Ease.OutQuart);
}
private void OnDisable()
{
// Tween破棄
if (DOTween.instance != null)
{
_tween?.Kill();
}
}
}
補足
上のコードのif判定ですが、エディタ再生終了時のオブジェクト破棄順序次第でDOTweenComponent(画像参照)が先に破棄されると出る後述のエラーを回避するためです。
シングルトンあるある。
Some objects were not cleaned up when closing the scene. (Did you spawn new GameObjects from OnDestroy?)