본문 바로가기
C#

[C#][Unity 2D] npc와 대화 시스템 구현

by teamnova 2022. 12. 15.

안녕하세요

오늘은 대화시스템을 예제를 진행해보겠습니다.

 

더보기

환경은 다음과 같습니다.

유니티 버전 - 2021.3.4f1

또한, 앞의 유니티 2D 예제 포스팅들에서 이어집니다.

 

 

먼저, 계층구조에서 UI - 패널을 생성합니다.

 

그 다음 같이생성된 canvas의 Scaler에서 스케일 모드 수정과 해상도를 변경해줍니다.

패널의 이름을 변경해주고 앵커 프리셋을 게임 대화상자가 나올 위치대로 잡아줍니다. 저는 botton - center로 하겠습니다.

패널의 크기를 적당한 크기로 조절해줍니다. 게임탭을 보면서 적절하게 조정하시면 됩니다.

그리고 지금은 넣지는 않지만 추후에 npc의 이미지를 넣을 수 있는 이미지ui를 추가하겠습니다. (UI - 이미지)

추가적으로 npc의 이름과 대화 내용을 넣을 텍스트를 같이 생성하겠습니다. (UI - 레거시 - 텍스트)

생성후 적절한 크기로 조정과 위치를 잡아줍니다.

 

npc의 이름과 이미지를 넣어서 정의할 Actor 스크립트와 Dialogue를 정의할 DialogueContainer를 생성합니다.

//Actor.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(menuName = "Data/Dialogue/Actor")]
public class Actor : ScriptableObject
{
    public string Name;
    public Sprite portrait;
}
//DialogueContainer.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(menuName = "Data/Dialogue/Dialogue")]
public class DialogueContainer : ScriptableObject
{
    public List<string> line;
    public Actor acotr;
}

 

그 다음, 다이얼로그 시스템을 컨트롤하기 위해 패널에서 DialogueSystem이라는 스크립트를 생성해서 컴포넌트 추가해줍니다.

정의한 SerializeField 들에 Name 과 Text를 넣어줍니다.

//DialogueSystem.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class DialogueSystem : MonoBehaviour
{
    [SerializeField] Text targetText;
    [SerializeField] Text nameText;

    DialogueContainer currentDialogue;
    int currentTextLine;

    private void Update(){
        if(Input.GetMouseButtonDown(0)){
            PushText();
        }
    }

    private void PushText(){
        currentTextLine += 1;
        if(currentTextLine >= currentDialogue.line.Count){
            Conclude();
        } else{
            targetText.text = currentDialogue.line[currentTextLine];
        }
    }

    public void Initialize(DialogueContainer dialogueContainer){
        Show(true);
        currentDialogue = dialogueContainer;
        currentTextLine = 0;
        targetText.text = currentDialogue.line[currentTextLine];
    }

    private void Show(bool v){
        gameObject.SetActive(v);
    }

    private void Conclude(){
        Show(false);
        Debug.Log("Dialogue test // Stickcode post ");
    }
}

 

이제 계층구조의 Gamemanager에서 Gamemanager스크립트를 수정하겠습니다.

DialogueSystem 필드를 추가하고 넣어주겠습니다.

//GameManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager instance;
    private void Awake(){
        instance = this;
    }

    public GameObject player;
    public DialogueSystem dialogueSystem; //추가한 코드
}

 

이제, 앞에서 스크립트로 정의한 asset menu를 이용하겠습니다.

마우스 오른쪽 클릭 - 생성 - 데이터 - Dialogue - Dialogue 와 Actor를 각각 생성하겠습니다.

Actor에서 이름을 정의합니다. 이미지를 넣으실 거면 같이 넣으시면됩니다.

 

그리고 DIalogue 에서 출력할 대화를 Line- 요소에 입력하고 Actor 필드를 앞에 먼저 생성한 Actor로 지정합니다.

각 요소 번호는 페이지라고 생각하시면 됩니다.

 

 

 이제 대화를 할 상대 npc를 넣어줍니다. 기존에 사용하던 오브젝트나 이미지 등 상관없이 넣으시면됩니다.

새로 넣거나 사용할 기존 오브젝트에 collider가 없다면 boxCollider2D 를 추가해주시고, 캐릭터와 상호작용을 위해 TalkInteract라는 스크립트를 생성해서 새 컴포넌트로 추가해줍니다.

(TalkInteract는 기존 포스팅된 예제에서 정의한 Interat를 상속하는 스크립트 입니다. 앞의 예제를 참고해주세요!)

그리고 스크립트에서 정의한 Dialogue에 앞에서 생성한 Dialogue를 지정합니다. (생성-데이터 - Dialogue로 생성한 파일)

//TalkInteract.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TalkInteract : Interactable{

    [SerializeField] DialogueContainer dialogue;
    public override void Interact(Character character)
    {
        Debug.Log("대화성공");
        GameManager.instance.dialogueSystem.Initialize(dialogue);
    }
}

 

이제 실행하면 됩니다.