



using UnityEngine;
[CreateAssetMenu(fileName = "TalkBundle", menuName = "Scriptable Objects/TalkBundle")]
public class TalkBundle : ScriptableObject
{
[System.Serializable]
public class TalkData
{
public string Name; //이름 칸
public Sprite Portrait; //포트레이트 칸
public bool IsLeft; //이름, 포트레이트가 왼쪽인지
public string Text; //대화 내용
}
public TalkData[] talkdatas; //대화 내용 목록
}

using UnityEngine;
public class Object_NPC : InteractableObject
{
public TalkBundle talkBundle;
}

using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class TalkManager : MonoBehaviour
{
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; //대화 인덱스
public void StartTalk(TalkBundle talkBundle) //대화 시작
{
currentTalkBundle = talkBundle;
currentIndex = 0;
gameManager.currentState = GameManager.GameState.Talking; // 대화 시작 상태로 변경
talkPanelAnimator.SetBool("IsShow", true); // 대화 UI 올리기
NextTalk(); // 첫 번째 대화 내용 표시
}
public void NextTalk() //대화문 출력
{
int lastIndex = currentTalkBundle.talkdatas.Length - 1; //출력할 대사가 있는지, 없는지 확인용
// 아직 출력할 대사가 있다면
if (currentIndex <= lastIndex)
{
//TalkData의 내용(대화문, 이름, 포트레잇) 받아와서 UI에 표기
var talkData = currentTalkBundle.talkdatas[currentIndex];
nameText.text = talkData.Name;
talkText.text = talkData.Text;
portraitImg.sprite = talkData.Portrait;
//이름 패널, 포트레잇 위치 결정
float xPosition = talkData.IsLeft ? -200f : 200f;
namePanelPosition.anchoredPosition = new Vector2(xPosition, namePanelPosition.anchoredPosition.y);
portraitPosition.anchoredPosition = new Vector2(xPosition, portraitPosition.anchoredPosition.y);
currentIndex++; // 다음 대화로 진행
}
else
{
EndTalk(); //대화 종료
}
}
private void EndTalk()
{
gameManager.currentState = GameManager.GameState.None; // 대화 종료 상태로 변경
currentIndex = 0;
talkPanelAnimator.SetBool("IsShow", false); // 대화 UI 내리기
}
public bool IsTalking()
{
return gameManager.currentState == GameManager.GameState.Talking;
}
}


using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using TMPro;
public class GameManager : MonoBehaviour
{
//게임 상태
public enum GameState { None, Talking,}
public GameState currentState = GameState.None;
public TalkManager talkManager; // TalkManager 참조
public void Action(GameObject scanObj) //상호작용
{
//상호작용한 오브젝트 가져오기
InteractableObject obj = scanObj.GetComponent<InteractableObject>();
//상호작용 함수 실행
switch (obj.interactableType)
{
case InteractableType.NPC:
Object_NPC npc = scanObj.GetComponent<Object_NPC>();
talkManager.StartTalk(npc.talkBundle); //대화 함수 실행
break;
default:
Debug.Log("상호작용 오브젝트입니다");
break;
}
}
public bool IsBusy()
{
return currentState != GameState.None;
}
}
TalkManager 참조, InteractableObject가 NPC일 경우 TalkManager에서 함수를 실행하도록 코드 추가
대화 상태(Talk) 추가
이제 대화 상태일 때 플레이어는 다른 행동(이동, 상호작용)을 하지 못할 것이다

using UnityEngine;
public class PlayerAction : MonoBehaviour
{
/// ~~~ 생략 ~~~
void Update()
{
/// ~~~ 생략 ~~~
//상호작용
if (Input.GetButtonDown("Interact") && scanObject != null && !manager.IsBusy())
{
manager.Action(scanObject);
}
//대화 넘기기
if (Input.GetButtonDown("Submit") && manager.currentState == GameManager.GameState.Talking)
{
manager.talkManager.NextTalk();
}
}

https://www.youtube.com/watch?v=JY-KFx3OsJo&list=PLO-mt5Iu5TeYfyXsi6kzHK8kfjPvadC5u
골드메탈 유니티 기초 강좌 - 탑다운 2D RPG를 따라해 만들었다