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() 함수로 진행되도록 되어있습니다.
취소, 완료, 종료를 따로 나눔으로 대화의 결과에 따라 다른 처리를 할 수 있게 해두었습니다.