NPC 대화 - 선택지

깡통기사·2025년 6월 15일

개요

  • NPC와 대화 시 선택지를 추가한다

목표

  • 대화문 중 선택지를 넣어 다른 대화문으로 넘어가거나, 다른 행동을 할 수 있게 만든다
    (예 : 다른 대화문 출력, 대화 종료, 상점 UI 오픈)
    └ 대화 UI에 선택지 버튼을 만들어 클릭 시 선택지에 따른 결과가 나오게 한다
  • TalkBundle에 선택지 목록을 추가해 TalkManager에서 마지막 인덱스 출력 시 선택지 목록이 나오게 한다

구현

선택지 버튼 프리팹

  • 우선 Button 컴포넌트가 추가된 선택지 버튼 프리팹을 제작한다

대화 UI에 선택지 버튼 자리 만들기

  • 대화 UI에 선택지 버튼이 들어갈 Panel 오브젝트를 추가했다
  • 추가되는 선택지 버튼이 자동으로 정렬되도록 Vertical Layout Group 컴포넌트를 추가했다

TalkBundle 스크립트 수정

using UnityEngine;

[CreateAssetMenu(fileName = "TalkBundle", menuName = "Scriptable Objects/TalkBundle")]
public class TalkBundle : ScriptableObject
{
    [System.Serializable]
    public class TalkData
    {
		///~~~생략~~~
    }

    [System.Serializable]
    public class Choice //선택지
    {
        public string choiceText; //선택지 이름
        public ActionType actionType; //선택지 종류
        public TalkBundle nextTalkBundle; //다음 대화 목록
    }

    public TalkData[] talkdatas; //대화 목록
    public Choice[] choices; //선택지 내용 목록

    public enum ActionType //선택지 종류
    {
        ContinueTalk,
        EndTalk,
    }
}
  • 선택지의 정보를 담고 있는 Choice 클래스 추가

  • 인스펙터에서 선택지를 추가해준다

TalkManager 스크립트 수정

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class TalkManager : MonoBehaviour
{

    [Header("[대화문용]")]
    public TextMeshProUGUI talkText; //대화문 내용 텍스트
    public RectTransform namePanelPosition; //이름 패널 위치
    public TextMeshProUGUI nameText; //이름 텍스트
    public RectTransform portraitPosition; //포트레잇 위치
    public Image portraitImg; //포트에릿 이미지
    public Animator talkPanelAnimator; //대화문 애니메이션
    public GameManager gameManager;  // GameManager 참조
    private TalkBundle currentTalkBundle;  // 현재 대화 번들
    private int currentIndex = 0; //대화 인덱스

    [Header("[선택지용]")]
    public GameObject choicePanel; //선택지 패널
    public Button choiceButtonPrefab; //선택지 버튼 프리팹

    public void StartTalk(TalkBundle talkBundle) //대화 시작
    {
		///~~~생략~~~
    }

    public void NextTalk() //대화문 출력
    {
        int lastIndex = currentTalkBundle.talkdatas.Length - 1; //출력할 대사가 있는지, 없는지 확인용

        // 아직 출력할 대사가 있다면
        if (currentIndex <= lastIndex)
        {
			///~~~생략~~~

            if (currentIndex == lastIndex) //만약 마지막 인덱스라면 선택지 보여주기
            {
                if (currentTalkBundle.choices != null && currentTalkBundle.choices.Length > 0)
                {
                    ShowChoices(currentTalkBundle.choices);
                }
            }

            currentIndex++;  // 다음 대화로 진행
        }
        else
        {
            if (currentTalkBundle.choices == null || currentTalkBundle.choices.Length == 0)
            {
                EndTalk();
            }
        }
    }

    private void ShowChoices(TalkBundle.Choice[] choices) //선택지 보여주기
    {
        choicePanel.SetActive(true); //선택지 패널 활성화
        foreach (Transform child in choicePanel.transform)
            Destroy(child.gameObject); //선택지 패널 초기화

        foreach (var choice in choices) 
        {
            Button btn = Instantiate(choiceButtonPrefab, choicePanel.transform); //선택지 버튼 생성
            btn.GetComponentInChildren<TextMeshProUGUI>().text = choice.choiceText; //선택지 버튼 텍스트
            //선택지 버튼 클릭 시 실행될 함수 등록
            btn.onClick.AddListener(() =>
            {
                choicePanel.SetActive(false);
                HandleChoice(choice);
            });
        }
    }

    private void HandleChoice(TalkBundle.Choice choice) //선택지 버튼 클릭 시 실행되는 함수
    {
        switch (choice.actionType)
        {
            case TalkBundle.ActionType.ContinueTalk:
                //다른 대화문 시작
                StartTalk(choice.nextTalkBundle);
                break;
            case TalkBundle.ActionType.EndTalk:
                //대화문 종료
                EndTalk();
                break;
        }
    }

    private void EndTalk()
    {
		///~~~생략~~~
    }

    public bool IsTalking()
    {
        return gameManager.currentState == GameManager.GameState.Talking;
    }
}
  • 선택지가 존재하면서 마지막 대화문일 경우, 선택지가 등장하도록 한다
  • 선택지가 존재할 경우, 대화가 자동으로 끝나지 않는다
  • ShowChoices()함수로 선택지 버튼 프리팹을 생성하고, 프리팹에 들어가야 할 요소를 부여한다(텍스트, 버튼에 등록된 함수)
  • HandleChoice()함수로 선택지 유형에 따라 선택지 버튼 클릭 시 실행되는 함수를 결정한다

결과

  • TalkBundle에 선택지 목록이 포함된 경우, 선택지 버튼이 생성된다
  • 고른 선택지에 따라 다른 결과가 나온다(다른 대화문 출력, 대화 종료)

0개의 댓글