🎮

Unityの定番アセット"UI Gradient"で発生する、time parameterエラー対策

2024/10/30に公開

https://assetstore.unity.com/packages/tools/gui/ui-gradient-133992

Asset Storeで販売されている定番アセットの UI Gradient で、特定の条件を満たすと

Evaluate: time parameter is not a valid number

というエラーが発生するのですが、発生条件と回避方法を調査しました。

発生条件

  • UIGradientを適用しているRectTransformの、縦ないしは横のサイズが0
  • グラデーションの回転角が、RectTransformのサイズが0になっている方向と一致
  • GradientTypeをComplexLinearに設定

上記の条件を全て満たしてしまうと発生します。
それでは、コードを見ていきます。

UIGradient.cs
#if UNITY_2018_1_OR_NEWER
    Vector2 normalizedPosition = ((Vector2)vert.position - rectTransform.rect.min) / (rectTransform.rect.max - rectTransform.rect.min);
#else

まず、UIGradient.csの230行目で、例えばRectTransformの幅が0になっていると、

rectTransform.rect.max - rectTransform.rect.min

でxが0になり、Vector2同士の割り算でゼロ除算が行われ、normalizedPosition.xにNaNが代入されます。

UIGradient.cs
normalizedPosition = RotateNormalizedPosition(normalizedPosition, this.angle);

次に、236行目でグラデーションの方向に合わせ、normalizedPositionが回転します。
この時、例えばグラデーションの角度が90度に設定されていると、先ほどのnormalizedPositionは、yにNaNが移ります。

UIGradient.cs
else if (gradientType == UIGradientType.ComplexLinear)
{
    gradientColor = linearGradient.Evaluate(normalizedPosition.y);
}

250行目でlinearGradient.EvaluateをnormalizedPosition.yに対して行っていますが、この時に先ほどの回転でNaNになっているnormalizedPosition.yへEvaluateを行おうとするため、

Evaluate: time parameter is not a valid number

というエラーが発生する…といった機序になります。

対策

運用でカバーする方法と、コードを変更して対応する方法の二種類がありそうです。

運用でカバーする方法

何らかの理由でコードを変更できない場合、以下の2点に気をつけて運用でカバーする感じになりそうです。

  • RectTransformの幅が0にならないようにする
  • RectTransformでStretch(青矢印のやつ)を使用している場合、親のサイズに気をつける
  • アニメーション等で伸縮させる場合は、サイズが0にならないように気を付ける

コードを変更する方法

236行目の RotateNormalizedPosition 前でxとyに対してNaNチェックを行い、NaNだった場合に0fを代入します。

UIGradient.cs
#if UNITY_2018_1_OR_NEWER
    Vector2 normalizedPosition = ((Vector2)vert.position - rectTransform.rect.min) / (rectTransform.rect.max - rectTransform.rect.min);
#else
    Vector2 size = rectTransform.rect.max - rectTransform.rect.min;
    Vector2 normalizedPosition = Vector2.Scale((Vector2)vert.position - rectTransform.rect.min, new Vector2(1f / size.x, 1f / size.y));
#endif

+   normalizedPosition.x = float.IsNaN(normalizedPosition.x) ? 0f : normalizedPosition.x;
+   normalizedPosition.y = float.IsNaN(normalizedPosition.y) ? 0f : normalizedPosition.y;
    normalizedPosition = RotateNormalizedPosition(normalizedPosition, this.angle);

以上です。
本来、ゼロ除算される前に値を見てあげたほうが丁寧かと思いますが、Assetのアップデートなどでコードが変わってしまうことを考慮し、なるべく行数が少ない方が再修正時のコストが低いと判断して今回はこの形にまとめています。
もし丁寧にやるなら、normalizedPositionの変数宣言前に、rectTransformの各値をキャッシュしてバリデーションしたり、キャッシュされた値を使ってnormalizedPositionを作るなどする必要がありそうです。

同様のエラーに困っている方の参考になれば幸いです。

Discussion