본문 바로가기
유니티 게임 개발/오류&개발TIP

[TIP #2] 유니티에 c# MessageBox 구현하기 (코루틴 이용한 메시지박스)

by 헝탱 2017. 2. 3.
반응형


안녕하세요.


오늘은 c# 비주얼 스튜디오에서 MessageBox라는 기능을


유니티에서도 사용하는 부분인데요.


윈도움 폼을 사용했던 분들은 많이 사용하게 되는 기능입니다.


저도 유니티에서 해볼려고 별짓을 다 해봤는데...


결론은 제 실력이 부족해서인지 "왠만한 기술력 가지고는 안된다" 라는 결론을


도출해서 편법을 사용해 구현을 했습니다.


원래는 델리게이트, 콜백함수 이런 개념이라는데


비동기 구현 방식이라 강제로 현재의 상태를 유지하고


리턴을 받아야 하는 방식의 구현을 하기 위해서는


적합하지도 않고 평소에 쓸일이 별로 없어서 좀 난해 했습니다.


또 정확히 알아보니 제가 원하는 구현 느낌이랑 달랐습니다.


제가 생각하는 그림은 이런 것이였습니다.



그래서 여기저기 돌아본 결과 2중 코루틴을 사용하면 


이런한 방식을 구현 할 수 있습니다.


검색하다 여기 들어오셨다면 콜백이나 메시지박스로 검색해서 들어오셨을 텐데


델리게이트나 콜백에 대한 답변은 이글에서 얻으실 수 없습니다.


또한 콜백이나 델리게이트는 유니티에서 막강한 코루틴이 있기 떄문에


힘들여 구현할 필요 없다고 생각됩니다.


리턴만 잘쓰면 코루틴만으로 사용 가능하리라 봅니다.


관련된 내용을 설명 해드리면 전제조건이 2가지가 있습니다.


(1). 코루틴을 2중으로 사용해야 한다.

(2). 반환값으로 사용된 변수가 필요하다.


이 조건에 맞춰 우선 사용한 소스코드를 보여드리면



 1  메시지 박스 셋팅


우선은 셋팅 방법에 대한 소스를 보여드리겠습니다.


아래의 소스 중 3~7은 사실 필요한 부분은 아니나 나중에 최종 그림에서


프로세스를 설명하기 위해 추가로 넣어놨습니다.


1
2
3
4
5
6
7
8
9
10
11
12
    public IEnumerator MessageBox(string Title, string Text, bool YesNoType, Transform initPath)
    {
        //메시지 박스 프리팹 가져와서 텍스트를 넣음
        GameObject MsgBox = LoadPrefeb("MessageBox""Function/MessageBox", initPath);
        MsgBox.GetComponent<clsYesNoMsgeBox>().Title = Title;
        MsgBox.GetComponent<clsYesNoMsgeBox>().Text = Text;
        MsgBox.GetComponent<clsYesNoMsgeBox>().YesNoType = YesNoType;
        while (!MsgBox.GetComponent<clsYesNoMsgeBox>().userBtnChk)
        {
            yield return new WaitForSeconds(0.1f); //계속 확인하는 용도
        }
    }
cs


Line 4~7 : 프리팹을 로드하고 정보를 넘겼습니다.


YesNoType : 확인 취소창으로 할것인지 일반 확인 창으로 할것인지 정하는 변수 입니다.


Line 8~10 : 프리팹으로 만든 객체의 UserBtnChk라는 변수가 변하는지 0.1초바다 확인하는 변수입니다.

(위의 설명한 라인보다는 해당 부분의 라인이 중요합니다.)


저는 그리고 객체가 따로 돌게 하기 위해서 ClsYesNoMsgBox라는 C# 클래스를 하나 더 만들어서


아래와 같이 적었습니다.


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
public class clsYesNoMsgeBox : MonoBehaviour {
 
    TimeManager Time;
    
    public string Title, Text;
    public bool YesNoType;
    public bool userBtnChk = false;
    public bool userSelBtn;
 
    // Use this for initialization
    void Start()
    {
        //타임매니저를 불러옴
        Time = GameObject.Find("stu_time").GetComponent<TimeManager>();
        Time.TimePlay = false;
 
        //텍스트 객체화
        this.transform.FindChild("Title").GetComponent<Text>().text = Title;
        this.transform.FindChild("Text").GetComponent<Text>().text = Text;
 
        //YesNo타입 메시지 박스
        if (YesNoType)
        {
            this.transform.FindChild("YesNobtn").gameObject.SetActive(true);
            this.transform.FindChild("OKbtn").gameObject.SetActive(false);
        }
        else
        {
            this.transform.FindChild("YesNobtn").gameObject.SetActive(false);
            this.transform.FindChild("OKbtn").gameObject.SetActive(true);
        }
    }
 
    public void YesBtnClick()
    {
        Time.TimePlay = true;
        userBtnChk = true;
        userSelBtn = true;
    }
 
    public void NoBtnClick()
    {
        Time.TimePlay = true;
        userBtnChk = true;
        userSelBtn = false;
    }
    public void OKbtnClick()
    {
        Time.TimePlay = true;
        userBtnChk = true;
        userSelBtn = true;
    }
}
cs


LINE 10 ~ 32 : 시작이 되면 여러가지 검사한 후에 넘겨져온 데이터를 셋팅 합니다.


그리고 프리팹 내에서 버튼을 눌러 이벤트가 발생하면 


34~39, 41~46, 47~52의 함수들이 불러와져서 프리팹의 객체 값이 변하고 


앞에서 있던 UserBtnChk가 읽어져 While을 빠져나오게 했습니다.


여기까진 엄청 일반적인 코루틴의 모습입니다.



 2  메시지 박스 사용


여기 부터는 이중 코루틴의 핵심이며 중요한 부분입니다.


우선 사용한 부분에 대한 소스코드를 발췌하면 아래와 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
//메시지창을 띄워서 알려주기                        
string msgtext = "건물 " + (GM.Floor.Count + 1+ "층을 증축 하시겠습니까?";
yield return StartCoroutine(Func.MessageBox("구매확인", msgtext, true, BtnFlow._instance.UIpanel.transform));
GameObject msgboxobj = GameObject.Find("MessageBox").gameObject;
if (GameObject.Find("MessageBox").GetComponent<clsYesNoMsgeBox>().userSelBtn)
{
    //메시지박스에서 YES혹은 확인을 누른경우 이쪽을 돌게됨
    break;
}
else
{
    //아니요를 누른 경
}
cs


메시지를 띄워서 알려주는 부분입니다.


여기서 3번째 줄을 주목하셔야 합니다.


yield return StartCoroutine(Func.MessageBox("구매확인", msgtext, true, BtnFlow._instance.UIpanel.transform));


당연히 yield return을 사용하기 위해서는 해당 코드가 있는 함수는


반환자가 "IEnumerator"로 선언이 되어 있어야 하구요.


핵심은 여기서 코루틴의 코루틴이고 리턴을 함수 호출로 받습니다.


그말은 현재 IEnumerator함수를 돌고 있는데 


처음 만난 startcorutine을 지나서 다음으로 넘어가기 위해서는


위의 줄이 마무리가 되야 합니다.


IEnumerator로 선언된 함수에서 yield return new WaitForSeconds()을 적으면


해당 시간이 지나야 다음줄로 넘어가는 성질을 이용한 부분입니다.


그래서 앞에서 보여준 2개의 코드 뭉치들에서 결론이 나야 3번째 줄을 지날 수 있고


아래의 5번째 줄에 있는 IF문을 읽고 검출해서 다음 단계로 넘어갈 수 있는 프로세스 입니다.


그림으로 간단하게 설명해드리면 아래와 같습니다.



잘 설명된 그림인지는 모르겠지만


다른 프로세스 쪽은 정상적으로 돌고 


A함수가 B에 의해서 강제로 정지가 된 상태이구요.


B는 C의 상태를 계속 확인(유저의 조작)하고 있고


C는 유저가 조작하지 않는 한 변화가 생기지 않습니다.


A는 C를 조작하지 않는 한 멈춰있는다 라는 조건이 성립이 됩니다.


이런 방식으로 메시지 창이 뜨면 유저가 선택하기 전까지 


계속 기다리는 기능이 구현이 됩니다.



 3  사용된 예시 & 코루틴


이러한 기능으로 만들고 있는 게임의 장면 일부를 보여드리겠습니다.


상황은 아니요를 누르면 진행이 안되고 예를 누르면 진행이 됩니다.



하드코딩을 해도 해당 기능을 충분히 구현 가능합니다.


하지만 매번 같은 코드를 적기에 너무 비효율적인것 같아


객체지향적인 느낌으로 구현한 내용입니다.


누군가에게는 도움이 되었으면 합니다.


해당 기능은 지극히 제 개인적으로 고생했던 부분이라


한번 정리 했습니다.


그리고 코루틴이 뭔지 모른다 하시는 분들은


제가 검색하다가 영감을 얻은 글입니다.


개인적으로 코루틴의 예제와 설명을 아주 잘한 글이라고 생각합니다.


http://rapapa.net/?p=621


코루틴을 모르시는분들은 개념부터 확인하시고


개념을 아시는 분들은 다른글 보지말고 이걸로 예제 연습하세요.


쉬운글을 지향하고 있어 이해가 안가거나 어려운 부분은 댓글로 남겨주세요.

반응형

댓글