衣替え
今年も早いもので衣替えのシーズンとなってきましたが、夏場に購入した制汗シートが未だに消費しきれず、無理に使って風邪をひきそうになった皆さんこんにちは。秋なのに"氷結"タイプとか何の修行だよ。
DOTweenPro
さて、以前記事でも紹介しましたが、近頃DOTweenProがアップデートされてTextMeshに対して文字単位にアニメーションを行えるようになりました。
この文字単位のアニメーションには当然ながら平行移動(DOOffsetChar)の機能も含まれているので、これを使用すれば文字を好きな位置へ移動させることが出来ます。
なので、これまでは編集した画像を用意するしかなかった「円状に並んだ文字列」というUIもDOOffsetCharを使えば動的に実装できるかもしない、そう考えたわけです。
円状に配置させるには
各文字の円周上の座標は、文字列の中心を原点とすれば簡単に算出することができるので、各文字の位置から円周上の位置への移動ベクトル(オフセット量)を計算できれば文字を円状に配置させることができます。
この移動ベクトルは「文字列の中心から円周上の位置へのベクトル」と「文字列の中心から文字の位置へのベクトル」との差分となります。
しかし、「文字列の中心から文字の位置へのベクトル」に関しては正確なベクトルを得るすべは現在のところありません。
最初はGetCharOffsetメソッドで取得できるかと思っていたのですが、これは「各文字の初期位置からのオフセット量」を取得するメソッドらしく、文字列の中心位置からのオフセット量が取得できるわけではありませんでした。
よって暫定としてTextMeshのRecttransformからTextMeshの幅を文字数で割ったものを基準として算出します。
このためTextMeshの幅は文字列が一列で表示できるギリギリの幅を設定しておく必要があります。
まぁ、そのように設定してもフォントによっては各文字の幅は均等でないため、必ずしも正確な「文字列の中心から文字の位置へのベクトル」が算出できるわけではありません。あくまで暫定のベクトルになります。
まぁ、それなりに・・・
実際に実装してみた結果はこんな感じになります。奇麗な円ではありませんが、それなりに表示させることはできました。
ソースはこんな感じ、Y座標最高点を開始位置にして時計回りに配置したかったので円周位置は90度から減算させて計算しています。また、移動に合わせてDORotateCharを使って文字を回転させています。
private List<Vector3> GetCirclePosList(float cirRad, int chNum) { List<Vector3> retList = new List<Vector3>(); float radInc = 360.0f / (float)chNum; for (int iCnt = 0; iCnt < chNum; iCnt++) { float curShita = 90.0f - (radInc * iCnt); float modx = cirRad * Mathf.Cos(curShita * Mathf.Deg2Rad); float mody = cirRad * Mathf.Sin(curShita * Mathf.Deg2Rad); retList.Add(new Vector3(modx, mody, 0)); } return retList; } public void CircleTextAnim() { RectTransform TargeTextRect = TargeTextMesh.GetComponent<RectTransform>(); float TextMeshWidh = TargeTextRect.sizeDelta.x; DOTweenTMPAnimator tmproAnimator = new DOTweenTMPAnimator(TargeTextMesh); int chNum = tmproAnimator.textInfo.characterCount; float radInc = 360.0f / (float)chNum; List<Vector3> cirOffsetList = GetCirclePosList(CircleRadius, chNum); int halfIndex = chNum / 2; float wordInt = (TextMeshWidh / 2.0f) / halfIndex; for (int i = 0; i < tmproAnimator.textInfo.characterCount; ++i) { float xOffset = 0.0f; if (i <= halfIndex) { xOffset = -1 * (halfIndex - (i + 0.5f)) * wordInt; } else { xOffset = ((i - halfIndex) + 0.5f) * wordInt; } // X方向のオフセット Vector3 currCharOffset = new Vector3(xOffset, 0.0f, 0.0f); // 円周位置 Vector3 cirOffset = cirOffsetList[i]; // オフセットベクトル取得 Vector3 modOffset = cirOffset - currCharOffset; // 文字単位のオフセット tmproAnimator.DOOffsetChar(i, modOffset, 2.0f); // 文字単位の回転 tmproAnimator.DORotateChar(i, new Vector3(0.0f, 0.0f, -1 * radInc * i), 2.0f); } }
ちなみに円状に配置した後にDOOffsetCharでオフセット量にゼロ(=Vector3.zero)を指定すると元の位置へ戻すことができます。DORotateCharも同様にします。