Unity 弧形文本UI

定義腳本CurvedText繼承自Text,重寫OnPopulateMesh函數

protected override void OnPopulateMesh(VertexHelper toFill)             //在Unity生成頂點數據後會調用這個函數,                 
 {                                                                                                            //toFill保存了Mesh的所有信息
            base.OnPopulateMesh(toFill);                                                   //在這個函數中改變頂點座標,達到改變mesh形狀的目的
            CurvedText(toFill);
 }



 private void CurvedText(VertexHelper toFill)
{
            if (!IsActive())    //處於未激活狀態
                return;
            for (int i = 0; i < cachedTextGenerator.lines.Count; i++)     //遍歷所有行
            {
                UILineInfo line = cachedTextGenerator.lines[i];       //當前行
                if (i + 1 < cachedTextGenerator.lines.Count)       //不是最後一行
                {
                    UILineInfo line2 = cachedTextGenerator.lines[i + 1];       //下一行

                    int current = 0;   //一行的第幾個字

                    for (int j = line.startCharIdx; j < line2.startCharIdx - 1; j++)     //遍歷一行所有文字 ,下一行起點爲界限
                    {
                        CurvedText(toFill,j, current++, i ,line2.startCharIdx - 1 - line.startCharIdx);
                    }
                }
                else if (i + 1 == cachedTextGenerator.lines.Count)  //最後一行
                {
                    int current = 0;
                    for (int j = line.startCharIdx; j < cachedTextGenerator.characterCountVisible; j++)  //總字數爲界限
                    {
                        int index = current;
                        CurvedText(toFill, j, current++, i , cachedTextGenerator.characterCountVisible - line.startCharIdx);
                    }
                }
            }
        }



座標變換函數

void CurvedText(VertexHelper helper, int index, int charXIndex, int charYStep , int lineCount)
        {
            UIVertex lb = new UIVertex();   
            helper.PopulateUIVertex(ref lb, index * 4);              //獲取點的信息 index一行的第幾個文字  ,一個文字4個點組成    

            UIVertex lt = new UIVertex();
            helper.PopulateUIVertex(ref lt, index * 4 + 1);          //lb 左下  lt左上  rt 右上 ,rb右下

            UIVertex rt = new UIVertex();
            helper.PopulateUIVertex(ref rt, index * 4 + 2);

            UIVertex rb = new UIVertex();
            helper.PopulateUIVertex(ref rb, index * 4 + 3);

            Vector3 center = Vector3.Lerp(lb.position, rt.position, 0.5f);   //文字的中心點


            float degree = GetAngle(helper, lineCount, text.Split('\n')[charYStep], index - cachedTextGenerator.lines[charYStep].startCharIdx);  //獲取文字旋轉角度
            
            Matrix4x4 move = Matrix4x4.TRS(-center, Quaternion.identity, Vector3.one);  //變化前 座標 旋轉 縮放矩陣

            
            float y = curvedRadius - curvedRadius * Mathf.Cos(degree * Mathf.Deg2Rad);  //根據角度計算 y 座標     curvedRadius文字繞成圓的弧度

            float x = curvedRadius * Mathf.Sin(degree * Mathf.Deg2Rad);   //根據角度計算 x 座標

            Vector3 pos = new Vector3(x, y, 0);

            Vector3 charadir = (new Vector3(0, curvedRadius, 0) - pos).normalized;   //頂點指向圓中心方向
            pos += lb.position.y * charadir * 0.4f;  //向內移動  文字收縮


            Matrix4x4 place = Matrix4x4.TRS(pos, Quaternion.Euler(new Vector3(0,0,degree)), Vector3.one);   //變化後 座標 旋轉 縮放矩陣

            Matrix4x4 transform = place * move;  //變化矩陣 之前矩陣基礎上 旋轉平移 縮放

            lb.position = transform.MultiplyPoint3x4(lb.position);    //根據矩陣旋轉4個頂點
            lt.position = transform.MultiplyPoint3x4(lt.position);
            rt.position = transform.MultiplyPoint3x4(rt.position);
            rb.position = transform.MultiplyPoint3x4(rb.position);

         
            helper.SetUIVertex(lb, index * 4);    //刷新4個頂點
            helper.SetUIVertex(lt, index * 4 + 1);
            helper.SetUIVertex(rt, index * 4 + 2);
            helper.SetUIVertex(rb, index * 4 + 3);
        }



角度計算函數

 private float GetAngle(VertexHelper helper , int charaCount , string tex ,int index)
        {
            float totalangle = 0;

          int startindex = cachedTextGenerator.lines[step].startCharIdx;
            for (int i = 0; i < charaCount; i++)
            {
                UIVertex lb = new UIVertex();
                helper.PopulateUIVertex(ref lb, (i + startindex) * 4);

                UIVertex lt = new UIVertex();
                helper.PopulateUIVertex(ref lt, (i + startindex) * 4 + 1);

                float width = Vector3.Distance(lb.position, lt.position);
                float angle = Mathf.Asin(width / 2 / curvedRadius) * 2 * Mathf.Rad2Deg * curvedFontSpaceScale;
                totalangle += angle;
            }

            totalangle /= 2;

            float getAngle = 0;
            for (int i = 0; i <= index; i++)
            {
                float nowindexangle = 0;

                UIVertex lb = new UIVertex();
                helper.PopulateUIVertex(ref lb,(i + startindex) * 4);

                UIVertex lt = new UIVertex();
                helper.PopulateUIVertex(ref lt,(i + startindex)* 4 + 1);

                nowindexangle = Vector3.Distance(lb.position, lt.position);
                
                if (i == index)
                {
                    getAngle += Mathf.Asin(nowindexangle / 2 / curvedRadius) * Mathf.Rad2Deg * curvedFontSpaceScale;
                }
                else
                {
                    getAngle += Mathf.Asin(nowindexangle / 2 / curvedRadius) * 2 * Mathf.Rad2Deg * curvedFontSpaceScale;
                }
            }
            getAngle -= totalangle;

          if (step != 0)
                 return getAngle / (step * 0.3f + 1);
            return getAngle;
        }

 

效果圖:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章