졸업프로젝트

유니티 기본강좌_15. 대화시스템

luminousmoonjj 2021. 11. 25. 23:09

본격적으로 시작하기 전에 Asset 폴더 안에 이미지 폴더를 만들고, 사용할 이미지(png)를 먼저 가져다둬야한다. 

Image 폴더를 만든 뒤에, 사용할 이미지를 드래그 해서 넣어주면 저런식으로 이미지가 들어간다.

이미지를 클릭하게 되면, image inspector창이 뜨는데, 거기서 Texture type을 sprite로 바꿔준다 

Sprite Mode의 single option은 이 이미지를 단일로 사용하겠다는 의미이다. 이 option을 Multiple로 바꿔준 뒤에 apply를 눌러준다. 이후, Sprite Editor를 눌러주면, package manager에서 설치하라는 메시지가 뜬다. 

 

상단 바의 Window > Package Manager에 들어가서 2D Sprite를 찾아서 install 해준다. 그러면 아래 그림과 같이 설치가 된다. 

이렇게 설치를 하고 다시 sprite editor를 클릭하면 

그러면 이런 Sprite Editor 창이 뜨고, 이 창에서 이미지를 쪼개는 등의 편집을 할 수 있게 된다. 

앞서, Sprite Mode의 single option을 Multiple로 바꾸고 apply해준 뒤, Sprite Editor 창에서 

이 slice 탭을 클릭하면, 우리가 원하는 대로 하나의 이미지를 쪼개서 사용할 수 있게 된다. (그러나 이번에는 single mode로 사용할 예정이므로 직접 쪼개주지는 않겠다. Multiple option은 보통 meta asset이나, animation을 쪼갤 때 많이 활용한다.)

 

다시 image inspector 창으로 돌아와서 앞서 바꿔주었던 Sprite Mode의 option을 Multiple에서 single로 다시 바꿔준다. 

Pixels Per Unit: 1미터 당 얼만큼의 픽셀이 들어갈 것인가. (이미지의 사이즈를 조절할 때 사용)

 

[Sprite renderer]

empty 객체를 생성하고, 새로 생성된 객체의 inspector창에서 add component를 눌러서, Sprite Renderer component를 추가해준다. 

그러면 다음과 같은 창이 뜨는데, Sprite에 저 동그란 버튼을 눌러서 이미지를 추가해준다.

이 Renderer창의 기능에 대해 잠시 알아보자면,

- Color: 이미지의 색이나, 투명도 조절(알파값 변경)

- Flip: x축으로 뒤집거나, y축으로 뒤집거나

- Draw Mode: 옵션을 조정하여 타일형태로 이미지를 만드는 등 다양한 형태로 이미지 변경가능

- Sorting Layer, Order in Layer: 우선순위와 관련(숫자가 커질 수록 우선순위가 높아짐) - renderer가 여러 개일 때, 우선순위가 높은 renderer를 먼저 실행하겠다는 것. Sorting layer값이 같으면 Order in Layer값으로 우선순위 결정, Sorting layer값과 Order in Layer값이 둘 다 같으면, hierachy창에 위치하고 있는 순서와 position값에 의해 결정됨.

- Mask Interaction: Mask의 영향을 받을지 여부

-Sprite Sort Point: Sorting Layer, Order in Layer:(우선순위)를 결정할 때, pivot값으로 결정할지, center값으로 결정할지를 정함.

그러면 이렇게 scene에 이미지가 추가된 것을 확인할 수 있다. 

 

Image component와 Sprite Renderer component의 차이점은?

Image component는 canvas 안에 있을 때만 보여지지만 Sprite Renderer component는 카메라에만 보여지면 보여진다. 

 

[Sprite renderer를 이용해서 간단한 대화시스템을 만들어보자]

Scene에 새로운 캔버스를 하나 추가해준다. (오른쪽 마우스 클릭 > UI > Canvas > 이름을 Sprite Canvas로 바꿔준다.)

Canvas를 통해서 UI이미지들을 깔끔하게 정렬시킬 예정.

Sprite Canvas의 Inspector창에서 Render Mode를 Screen Space - Camera로 설정한다. 

그러면 창이 다음과 같이 바뀌는데, Render Camera에 Main Camera를 넣어주고, Plane Distance를 1로 설정해준다.

그러면 카메라 앞에 이렇게 canvas가 생성된 것을 확인할 수 있다. 

Game Object의 이름을 Standing CG로 바꾸고, Sprite Canvas 안에 넣어준다. (아래 그림 참조)

그리고 Standing CG의 Transform 값을 위의 그림과 같이 조절해준다. (Scale은 본인이 사용하는 이미지 크기에 알맞게 조절해준다.)

이후 게임탭에서, 위치를 조절해서, 이미지가 왼쪽 모서리에 위치할 수 있도록 조절해준다. 

 

Standing CG를 복사해서 Dialog Bar를 만들어준다. (copy,paste한 뒤에 rename해준다.)

dialog bar의 inspector창에서 sprite에 crop(대화창 이미지- 어떤 이미지를 쓸지는 본인자유)를 넣어주고, position과 scale값을 조절해서 아래와 같은 화면이 되도록 한다.

추가적으로 crop이미지의 알파값을 조절해서, 위와 같이 되도록 했다. (본인이 보여주고 싶은대로 조절하면 됨)

 

이제 새로운 text를 생성해준다. (오른쪽 마우스 클릭 > UI > Text) hirerachy는 아래 그림과 같이 설정해주면 된다.

이후 text의 inspector창에 들어가서

다음의 두 옵션을 모두 Overflow로 바꿔준다. 이후 text의 position을 조절해서, text가 적절한 위치에 올 수 있도록 해준다.

위에서 설명한 모든 요소들을 가지고, 본인이 원하는 식으로 화면을 설정해준뒤, 

텍스트에 내용을 입력하면, 이런식으로 text에 넣고싶은 말을 입력하면, 화면에 다음과 같이 출력된다. 

 

이렇게 유니티 엔진에서 직접 수정하지 말고, script를 이용해서 동작하도록 코드를 작성해보자.

 

새로운 script를 만든다. (Assets>Script폴더에 new script 파일을 만들어준다.)

그리고 유니티엔진에서, 스페이스바를 누를때마다 대화가 진행되도록 하는 코드를 작성한다. (각 코드에 대한 설명은 주석참조)

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;//Text field를 사용할 수 있도록 하는 header

[System.Serializable] //직접 만든 class에 접근할 수 있도록 해줌. 
public class Dialogue {
    [TextArea]//한줄 말고 여러 줄 쓸 수 있게 해줌
    public string dialogue;
    public Sprite cg; // 교체될 이미지

}
public class dialog : MonoBehaviour
{
    //SerializeField : inspector창에서 직접 접근할 수 있도록 하는 변수임.
    [SerializeField] private SpriteRenderer sprite_StandingCG; //캐릭터 이미지(YK)를 제어하기 위한 변수
    [SerializeField] private SpriteRenderer sprite_DialogueBox; //대사창 이미지(crop)를 제어하기 위한 변수
    [SerializeField] private Text txt_Dialogue; // 텍스트를 제어하기 위한 변수

    private bool isDialogue = false; //대화가 진행중인지 알려줄 변수
    private int count = 0; //대사가 얼마나 진행됐는지 알려줄 변수

    [SerializeField] private Dialogue[] dialogue;

   
    public void ShowDialogue()
    {
        ONOFF(true); //대화가 시작됨
        count = 0;
        NextDialogue(); //호출되자마자 대사가 진행될 수 있도록 
    }

    private void ONOFF(bool _flag)
    {
        sprite_DialogueBox.gameObject.SetActive(_flag);
        sprite_StandingCG.gameObject.SetActive(_flag);
        txt_Dialogue.gameObject.SetActive(_flag);
        isDialogue = _flag;
    }

    private void NextDialogue() { 
        //첫번째 대사와 첫번째 cg부터 계속 다음 cg로 진행되면서 화면에 보이게 된다. 
        txt_Dialogue.text = dialogue[count].dialogue;
        sprite_StandingCG.sprite = dialogue[count].cg;
        count++; //다음 대사와 cg가 나오도록 
    
    }
 

    // Update is called once per frame
    void Update()
    {
        //spacebar 누를 때마다 대사가 진행되도록. 
        if (isDialogue) //활성화가 되었을 때만 대사가 진행되도록
        {
            if (Input.GetKeyDown(KeyCode.Space)) {
                //대화의 끝을 알아야함.
                if (count < dialogue.Length) NextDialogue(); //다음 대사가 진행됨
                else ONOFF(false); //대사가 끝남
            
            }
        }

    }
}


위의 함수 중, ONOFF함수에 대한 함수를 아래 코드처럼 두 함수로 나누어서 작성할 수도 있다. (그러나 합쳐서 작성하는 것이 더 간결하고 보기 좋음)


//버튼을 클릭할 때만 이미지가 보이게 만들어준다. (활성화/비활성화)로 조절
    public void ShowDialogue() {
        sprite_DialogueBox.gameObjcet.SetActive(true); //활성화가 되었을 때 보여지도록 한다.
        sprite_StandingCG.gameObjcet.SetActive(true);
        txt_Dialogue.gameObject.SetActive(true);

        //대화가 시작되었으니까 아래와 같이 설정해준다. 
        count = 0;
        isDialogue = true;
        NextDialogue(); //호출되자마자 대사가 진행될 수 있도록 
    }

    public void HideDialogue()
    {
        sprite_DialogueBox.gameObjcet.SetActive(false); 
        sprite_StandingCG.gameObjcet.SetActive(false);
        txt_Dialogue.gameObject.SetActive(false);
        isDialogue = false;
       
    }

 

새로운 canvas를 생성하고, 그 안에 위와 같이 button을 하나 생성해준다. 그러면 화면에 다음과 같이 보인다. 

그리고 버튼을 원하는 위치로 옮기고 크기를 조절해준다. 

Button 안에는 다음과 같은 text가 존재하는데, 저걸 클릭해서, button에 적힌 text를 수정해줄 수 있다. 

다음과 같이 설정해주었다. 

그리고 canvas에다가 앞서 만든 script를 넣어준다. (canvas 클릭 후 canvas의 inspector창으로 script drag해주면 됨.)

그러면 canvas의 inspector창에 다음과 같은 component가 추가됨을 확인할 수 있다. 

Sprite_Standing CG, Sprite_Dialogue Box, Txt_dialogue에 각각 해당되는 것을 드래그하여 넣어준다. 

앞서 만든 이 각각의 것을 드래그하여 넣어주는 것이다. 그렇게 해주면 아래와 같이 된다. 

우리는 총 4개의 대화가 진행되도록 할 것임으로, Dialogue의 size를 4로 설정해준다. 

그러면 이렇게 밑에 4개의 element가 형성되는데, 각각에 본인이 원하는 대사와 cg(맨 처음에 가지고 왔던 이미지들 중 택1)를 적어넣어주면 된다. 

 

이제 앞서만든 button에다가 On Click함수를 추가해준다.

button의 inspector창에 들어가서, On Click 부분의 +버튼을 눌러준뒤, 각가의 옵션을 위의 그림과 같이 바꿔준다. (canvas 드래그 해서 넣어주고, 함수 선택해준다.)

 

위의 3개의 component를 비활성화해주고(체크해제) play버튼을 클릭하여 실행한다.

 

그러면 아래 영상과 같이 동작하는 것을 확인할 수 있다. 처음에 대화시작을 누르고 스페이스바를 누를때마다, 대화가 진행되며, 마지막 대화가 끝나면 대화가 끝난것을 인식하고, 스페이스바를 더 눌러도 대화가 더이상 진행되지 않는 것을 확인할 수 있었다. 그리고 다시 대화시작 버튼을 눌러주면 대화가 처음부터 다시 시작되는 것이 성공적으로 구현된 것을 확인할 수 있다. 

 

대화시스템 작동영상

우리의 게임에서, npc와의 대화기능이 많이 활용될 예정이므로, 본 대화시스템 요소기술은 프로젝트 진행시에 굉장히 중요하며 유용한 내용이 될 것이라 생각된다.