Dialogue System 은 IDalogueSystem 과 IDialogue 의 두 개의 인터페이스로 구성되어 있습니다.

public interface IDialogueSystem
{
    public delegate void DialogueSystemEventHandler(IDialogueSystem dialogueSystem);

    public IDialogue StartDialogue { get; }
    public IDialogue CurrentDialouge { get; }
    public bool IsPlaying { get; }

    public void PlayDialogue(IDialogue dialouge);
    public void NextDialogue(IDialogue dialouge = null);
    public void CancelDialogue();
    public void FinishDialogue();

    public event DialogueSystemEventHandler OnStartedDialogue;
    public event DialogueSystemEventHandler OnFinishedDialogue;
    public event DialogueSystemEventHandler OnCanceledDialogue;
    public event DialogueSystemEventHandler OnEndedDialogue;
}
public interface IDialogue
{
		public string DialogueText { get; }
		public IDialogue NextDialogue { get; }
}

IDialogueSystem 과 IDIalogue 는 본 프로젝트와 상관없이 다른 프로젝트에 적용할 수 있게 모듈화시켜 재사용하고 있습니다.

또, 기본형을 Interface 의 형태로 만들어 추후 변경 및 확장이 용이하게 구성하였습니다.

public class DialogueSystemComponent : BaseMonoBehaviour, IDialogueSystem
{
	  [Header(" [ Dialouge System Component ] ")]
	  [Header(" Unity Events ")]
	  [SerializeField] private ToggleableUnityEvent _onStartedDialogue;
	  [SerializeField] private ToggleableUnityEvent _onCanceledDialogue;
	  [SerializeField] private ToggleableUnityEvent _onFinishedDialogue;
	  [SerializeField] private ToggleableUnityEvent _onEndedDialogue;
	
	  private IDialogue _startDialogue;
	  private IDialogue _currentDialouge;
	  private readonly Queue<IDialogue> _nextDialogues = new();
	
	  private bool _isEnded = false;
	
	  public bool IsPlaying => _currentDialouge is not null;
	  public IDialogue StartDialogue => _startDialogue;
	  public IDialogue CurrentDialouge => _currentDialouge;
	
	  public event IDialogueSystem.DialogueSystemEventHandler OnStartedDialogue;
	  public event IDialogueSystem.DialogueSystemEventHandler OnFinishedDialogue;
	  public event IDialogueSystem.DialogueSystemEventHandler OnCanceledDialogue;
	  public event IDialogueSystem.DialogueSystemEventHandler OnEndedDialogue;
	
	  public void PlayDialogue(IDialogue dialogue)
	  {
	      if (_isEnded)
	      {
	          _nextDialogues.Enqueue(dialogue);
	      }
	      else
	      {
	          if (_startDialogue is null)
	          {
	              _startDialogue = dialogue;
	          }
	
	          _currentDialouge = dialogue;
	
	          Invoke_OnStartedDiaogue();
	      }
	  }
	
	  public void NextDialogue(IDialogue dialogue = null)
	  {
	      if(dialogue is not null)
	      {
	          PlayDialogue(dialogue);
	      }
	      else if (_currentDialouge is not null)
	      {
	          if (_currentDialouge.NextDialogue is not null)
	          {
	              PlayDialogue(_currentDialouge.NextDialogue);
	          }
	          else
	          {
	              FinishDialogue();
	          }
	      }
	      else
	      {
	          return;
	      }
	  }
	
	  public void CancelDialogue()
	  {
	      _isEnded = true;
	
	      Invoke_OnCanceledDialogue();
	
	      EndDialogue();
	  }
	
	  public void FinishDialogue()
	  {
	      _isEnded = true;
	
	      Invoke_OnFinishedDiaogue();
	
	      EndDialogue();
	  }
	
	  private void EndDialogue()
	  {
	      Invoke_OnEndedDiaogue();
	
	      _startDialogue = null;
	      _currentDialouge = null;
	
	      _isEnded = false;
	
	      if(_nextDialogues.Count > 0)
	      {
	          PlayDialogue(_nextDialogues.Dequeue());
	      }
	  }
	
	  private void Invoke_OnStartedDiaogue()
	  {
	      Log($"{nameof(OnStartedDialogue)}");
	
	      _onStartedDialogue?.Invoke();
	      OnStartedDialogue?.Invoke(this);
	  }
	  private void Invoke_OnCanceledDialogue()
			  ...
	  private void Invoke_OnFinishedDiaogue()
			  ...
	  private void Invoke_OnEndedDiaogue()
			  ...
}

IDialougeSystem 을 상속 받아 만들어둔 DialogueSystemComponent 입니다.

이처럼 IDialogueSystem 을 상속받은 기본적인 컴포넌트를 미리 제작해두어 추후 재사용이 쉽도록 하고 있습니다.

...
public void PlayDialogue(IDialogue dialogue)
{
    if (_isEnded)
    {
        _nextDialogues.Enqueue(dialogue);
    }
    else
    {
        if (_startDialogue is null)
        {
            _startDialogue = dialogue;
        }

        _currentDialouge = dialogue;

        Invoke_OnStartedDiaogue();
    }
}
...

PlayDialogue(IDialogue) 에서 다음 IDialogue 를 받아 대화를 시작하고, 만약 지금 종료중에 있다면, IDialogue 를 Queue 에 넣어 대기 시키도록 구성했습니다.

public void NextDialogue(IDialogue dialogue = null)
	  {
	      if(dialogue is not null)
	      {
	          PlayDialogue(dialogue);
	      }
	      else if (_currentDialouge is not null)
	      {
	          if (_currentDialouge.NextDialogue is not null)
	          {
	              PlayDialogue(_currentDialouge.NextDialogue);
	          }
	          else
	          {
	              FinishDialogue();
	          }
	      }
	      else
	      {
	          return;
	      }
	  }

NextDialogue(IDialogue) 함수는 다음으로 이어질 IDialogue 를 받아 대화를 이어나가고, 만약 IDialogue 가 없으면 현재 재생중인 IDialogue 의 NextDialogue 를 받아 대화를 이어나갑니다. 만약 다음 대화도 Null 이라면 대화를 종료합니다.

...
public void CancelDialogue()
{
    _isEnded = true;

    Invoke_OnCanceledDialogue();

    EndDialogue();
}

public void FinishDialogue()
{
    _isEnded = true;

    Invoke_OnFinishedDiaogue();

    EndDialogue();
}
private void EndDialogue()
{
    Invoke_OnEndedDiaogue();

    _startDialogue = null;
    _currentDialouge = null;

    _isEnded = false;

    if(_nextDialogues.Count > 0)
    {
        PlayDialogue(_nextDialogues.Dequeue());
    }
}
...

CancelDialogue() 와 FinishDialogue() 함수는 둘 모두 대화를 종료하기 위한 함수입니다. 두 함수 모두 EndDailogue() 함수로 진행되도록 되어있습니다.

취소, 완료, 종료를 따로 나눔으로 대화의 결과에 따라 다른 처리를 할 수 있게 해두었습니다.