본문 바로가기

Programming/Unity

NGUI 사용 흐르는 문자열 만들기

가. 흐르는 문자열 만들기

 - 사용 조건 : NGUI가 있어야 함.


나. 코드

- NGUI UILabel.cs 파일내에 있는 overflow enum 값에 FlowText 라는 값을 추가해준다.

  해당 옵션이 되어져 있을 경우 글자가 흐르게 할 예정이다.


1
2
3
4
5
6
7
8
    public enum Overflow
    {
        ShrinkContent,
        ClampContent,
        ResizeFreely,
        ResizeHeight,
        FlowText,
    }
cs


 - UILabel.cs 파일 의 OnStart에 해당 라벨이 흐르게 되는 옵션을 가지고 있는지 체크하도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    protected override void OnStart ()
    {
        base.OnStart();
 
        // Legacy support
        if (mLineWidth > 0f)
        {
            mMaxLineWidth = Mathf.RoundToInt(mLineWidth);
            mLineWidth = 0f;
        }
 
        if (!mMultiline)
        {
            mMaxLineCount = 1;
            mMultiline = true;
        }
 
        // Whether this is a premultiplied alpha shader
        mPremultiply = (material != null && material.shader != null &&
                        material.shader.name.Contains("Premultiplied"));
 
#if DYNAMIC_FONT
        // Request the text within the font
        ProcessAndRequest();
#endif
 
        if (overflowMethod == Overflow.FlowText)
        {
            gameObject.GetComponent<UILabel>().CheckTextLength();
        }
    }
cs

※ 용도에 따라 다르게 하겠지만 여러 나라의 언어를 사용 할 예정이였어서 스크립트에서 문자열을 각나라에 맞도록 바    꾸었을 시 문자열 길이가 본래 사이즈보다 초과된다면 흐르게 만들려 했기 때문에 CheckTextLength라는 이름을 하게    되었다.


 - UILabel.cs에 문자열이 바뀌거나 했을 때도 작동할 수 있게 아래를 추가해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public string text
    {
        get
        {
            return mText;
        }
        set
        {
            if (mText == value) return;
 
            if (string.IsNullOrEmpty(value))
            {
                if (!string.IsNullOrEmpty(mText))
                {
                    mText = "";
                    if (overflowMethod == Overflow.FlowText)
                    {
                        gameObject.GetComponent<UILabel>().text = "";
                    }
                    MarkAsChanged();
                    ProcessAndRequest();
                }
            }
            else if (mText != value)
            {
                mText = value;
                if (overflowMethod == Overflow.FlowText)
                {
                    gameObject.GetComponent<UILabel>().text = value;
                }
                MarkAsChanged();
                ProcessAndRequest();
            }
            if (overflowMethod == Overflow.FlowText)
            {
                gameObject.GetComponent<UILabel>().CheckTextLength();
            }
            if (autoResizeBoxCollider) ResizeCollider();
        }
    }
cs


 - 아래 함수도 추가로 UILabel.cs에 넣어준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
public void CheckTextLength()
    {
        if (this.transform.parent != null)
        {
            if (this.transform.parent.name.Contains("FlowTextPanel"))
            {
                ResetPosition();
                return;
            }
            else if (this.transform.parent.parent != null)
            {
                if (this.transform.parent.parent.name.Contains("FlowTextPanel"))
                {
                    ResetPosition();
                    return;
                }
            }
        }
 
        if (this.overflowMethod != Overflow.FlowText)
        {
            return;
        }
 
        if (this.pivot == Pivot.Center || this.pivot == Pivot.Left)
        {
            Vector2 oriSize = new Vector2(this.width, this.height);
            this.MakePixelPerfect();
 
            Vector2 fullSize = new Vector2(this.width, this.height);
            this.overflowMethod = UILabel.Overflow.FlowText;
            this.width = (int)oriSize.x;
            this.height = (int)oriSize.y;
 
            if (oriSize.x < fullSize.x)
            {
                GameObject obj = new GameObject();
                obj.name = "FlowTextPanel";
                LabelFlow flow = obj.AddComponent<LabelFlow>();
                UIPanel uipanel = obj.AddComponent<UIPanel>();
                uipanel.clipping = UIDrawCall.Clipping.SoftClip;
                uipanel.clipSoftness = new Vector2(0, 0);
                uipanel.SetRect(0, 0, this.width, this.height * 1.2f);
                uipanel.clipOffset = new Vector2(this.width / 2f, 0);
                Rigidbody rigid = obj.AddComponent<Rigidbody>();
                rigid.isKinematic = true;
                obj.layer = LayerMask.NameToLayer("UI");
                CommonUtils.SetParent(this.transform.parent, obj.transform);
 
                if (this.pivot != Pivot.Left)
                {
                    this.pivot = Pivot.Left;
                }
                obj.transform.localPosition = new Vector3(this.transform.localPosition.x,
                                                     this.transform.localPosition.y, 0);
 
                GameObject FirstLabel = Instantiate(this.gameObject);
                FirstLabel.gameObject.SetActive(false);
                CommonUtils.SetParent(obj, FirstLabel);
                FirstLabel.gameObject.SetActive(true);
                this.gameObject.SetActive(false);
                CommonUtils.SetParent(FirstLabel, this.gameObject);
                this.gameObject.SetActive(true);
 
                FirstLabel.GetComponent<UILabel>().MakePixelPerfect();
                this.MakePixelPerfect();
 
                flow.Text.Add(FirstLabel.transform);
                flow.Text.Add(this.transform);
                flow.fWidth = this.width;
                flow.ResetPosition();
            }
        }
    }
 
    public void ResetPosition()
    {
        LabelFlow flow = transform.parent.GetComponent<LabelFlow>();
        if (flow == null)
        {
            if (transform.parent.parent != null)
            {
                flow = transform.parent.parent.GetComponent<LabelFlow>();
            }
        }
        if (flow != null)
        {
            flow.ResetPosition();
        }
    }
cs


 - LabelFlow.cs 파일을 만들어 아래 내용을 추가해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
public class LabelFlow : MonoBehaviour
{
    public float ScrollSpeed =30f;
    public float WGap = 5f;
    public float fWidth = 0.0f;
    public List<Transform> Text = new List<Transform>();
    Vector3 OriPos = Vector3.zero;
    bool IsActive = true;
    float fTime = 0.0f;
 
    void OnDisable()
    {
        IsActive = false;
    }
 
    void Update()
    {
        if(!IsActive)
        {
            ResetPosition();
        }
        if (fWidth != Text[0].GetComponent<UILabel>().width)
        {
            fWidth = Text[0].GetComponent<UILabel>().width;
            ResetPosition();
        }
        if ((fTime += Time.deltaTime) >= 0.01f)
        {
            if (Text[0].localPosition.x <= 
                -OriPos.x - Text[0].GetComponent<UILabel>().width - WGap)
            {
                Transform temp = Text[0];
                Vector3 pos = Text[0].localPosition;
                pos.x += Text[0].GetComponent<UILabel>().width + WGap;
                CommonUtils.SetParent(Text[0].parent, Text[1]);
                Text[1].localPosition = pos;
                Text.Remove(Text[0]);
                Text.Add(temp);
                CommonUtils.SetParent(Text[0], Text[1]);
                Text[1].transform.localPosition = Text[0].localPosition + 
                    new Vector3(Text[0].GetComponent<UILabel>().width + WGap, 0, 0);
            }
            
            Vector3 temppos = Text[0].localPosition;
            temppos.x -= ScrollSpeed * Time.deltaTime;
            Text[0].localPosition = temppos;
        }
    }
 
    public void ResetPosition()
    {
        Text[0].localPosition = OriPos;
        Text[1].transform.localPosition = Text[0].localPosition + 
            new Vector3(Text[0].GetComponent<UIWidget>().localSize.x + WGap, 0, 0);
        IsActive = true;
    }
 
    public void ChangeText(string _text)
    {
        foreach(Transform label in Text)
        {
            UILabel uilabel = label.GetComponent<UILabel>();
            if ( label.name.Contains("Clone"))
            {
                uilabel.text = _text;
            }
            uilabel.MakePixelPerfect();
        }
    }
}
 
cs


다. 문자열이 흐르는 조건

 1. 게임이 실행되고 스크립트 상에서 문자열을 변경하였는데 OverFlow값이 FlowText이고 문자열의 길이가

    라벨의 크기 보다 클 경우.

 2. 게임이 실행 되었을 때 문자열의 길이가 라벨의 크기보다 클 경우.


 - 위 두 경우에 문자열이 흐르게 되었다.


라. 주의

 - 해당 코드를 사용하는 UI는 프리팹으로 만들어 진 것을 스폰시켜서 사용하는 방법을 할것.

   그렇게 하지 않으면 라벨 앞에 생성된 클립핑용 패널까지 저장될 수 있음.

 - 언어가 변경되어 텍스트 길이가 줄어들 시 UI를 파괴했다가 다시 생성하는 것을 추천 않그럴 경우

   위와 마찬가지로 생성된 클립핑 패널과 문자열 흐르는 것이 멈추지 않음.


마. 결과

 - 실행 과 동시에 보라색 클립핑용 패널이 생성되는 것을 볼 수 있다.