
[Flags] enum
[Flags] enum은 여러 개의 독립적인 상태를 하나의 정수 변수에 동시에 저장하고 관리할 수 있도록 설계되었습니다. 이는 비트 연산(Bitwise Operation)을 활용합니다.
내부 저장 방식:
각 enum 멤버는 고유한 비트 위치를 나타내는 정수 값(2의 거듭제곱: 1, 2, 4, 8, ...)을 가집니다. 1 << N 연산이 이를 보장합니다.
1 << 0 = 00000001 (1)
1 << 1 = 00000010 (2)
1 << 2 = 00000100 (4)
[Flags] enum 변수에 값을 할당한다는 것은, 내부적으로 이 변수가 여러 비트가 켜진(1) 상태를 나타내는 하나의 정수 값을 가지게 됨을 의미합니다.
0011이면 3이 아닌 0비트와 1비트가 켜졌다고 인식.
일반 enum이면 0001 + 0010 = 0011이지만 숫자 3으로 인식.

<코드 작동 순서>
using System;
/// <summary>
/// NPC의 대화 진행 상태를 나타내는 플래그 열거형입니다.
/// 여러 상태를 동시에 기록할 수 있습니다.
/// </summary>
[Flags]
public enum DialogueFlags
{
None = 0, // 0000 - 아무 대화 안 했을 때
HasSpokenFirstDialogue = 1 << 0, // 0001 - Npc와 첫 만남 대화를 진행 했는지
HasSpokenTrollKill = 1 << 1, // 0010 - 트롤만 처치 후 첫 대화인지
HasSpokenSpiderKill = 1 << 2, // 0100 - 거미만 처치 후 첫 대화인지
HasSpokenCentipedeKill = 1 << 3, // 1000 - 지네만 처치 후 첫 대화인지
HasSpokenTrollSpiderKill = 1 << 4, // 0001 0000 - 트롤, 거미 처치 후 첫 대화인지
HasSpokenSpiderCentipedeKill = 1 << 5, // 0010 0000 - 거미, 지네 처치 후 첫 대화인지
HasSpokenCentipedeTrollKill = 1 << 6, // 0100 0000 - 지네, 트롤 처치 후 첫 대화인지
}
<BossHintNpc.cs>
private static DialogueFlags currentDialogueFlag = DialogueFlags.None; // 현재 대화상태 플래그, 변수 초기화 (0000)
public static DialogueFlags CurrentDialogueFlag { get { return currentDialogueFlag; } }
private IEnumerator HandleDialogueFlow() // 상황에 맞는 대사 출력
{
// 첫 상호작용 대화(한 번만)
if (!HasDialogueFlag(DialogueFlags.HasSpokenFirstDialogue))
{
yield return StartCoroutine(Dialogues(firstDialogue));
SetDialogueFlag(DialogueFlags.HasSpokenFirstDialogue);
}
// 하나의 보스만 처치했을 시(한 번만)
if (isTrollDead && !isSpiderDead && !isCentipedeDead && !HasDialogueFlag(DialogueFlags.HasSpokenTrollKill)) // 트롤 죽인 후
{
yield return StartCoroutine(Dialogues(new string[] { bossKillDialogue[0] }));
SetDialogueFlag(DialogueFlags.HasSpokenTrollKill);
}
else if (isSpiderDead && !isTrollDead && !isCentipedeDead && !HasDialogueFlag(DialogueFlags.HasSpokenSpiderKill)) // 거미를 죽인 후
{
yield return StartCoroutine(Dialogues(new string[] { bossKillDialogue[1] }));
SetDialogueFlag(DialogueFlags.HasSpokenSpiderKill);
}
else if (isCentipedeDead && !isSpiderDead && !isTrollDead && !HasDialogueFlag(DialogueFlags.HasSpokenCentipedeKill)) // 지네를 죽인 후
{
yield return StartCoroutine(Dialogues(new string[] { bossKillDialogue[2] }));
SetDialogueFlag(DialogueFlags.HasSpokenCentipedeKill);
}
if (aliveHintDialogues.Count > 0)
{
int randIndex = Random.Range(0, aliveHintDialogues.Count); // 랜덤 인덱스
string[] selectedDialogue = aliveHintDialogues[randIndex]; // 해당 인덱스 보스대화 선택
yield return StartCoroutine(Dialogues(selectedDialogue));
}
dialogueCoroutine = null;
Player.Instance.playerController.OnInput();
}
private bool HasDialogueFlag(DialogueFlags flag)
{
return (currentDialogueFlag & flag) == flag;
}
// 특정 플래그로 설정하는 메서드
private void SetDialogueFlag(DialogueFlags flag)
{
currentDialogueFlag |= flag;
}
<BossHintNpc 최초 대화 조건>
private static BossDialogueFlags _currentDialogueFlags = BossDialogueFlags.None; // 변수 초기화
currentDialogueFlags는 (0000) 상태.
상호작용하여 대화가 시작되면 if (!HasDialogueFlag(BossDialogueFlags.HasSpokenFirstDialogue)) 조건 확인. (HasSpokenFirstDialogue은 0001)
private bool HasDialogueFlag(BossDialogueFlags flag)
{
return (_currentDialogueFlags & flag) == flag;
}
0000 & 0001 == 0001이 아닌 0000이기 때문에 false를 반환.
그럼 2번 조건이 if(!false)가 되기 때문에 true가 되어 조건문 내부 실행.
대사가 출력이 끝나면
SetDialogueFlag(BossDialogueFlags.HasSpokenFirstDialogue); 실행
private void SetDialogueFlag(BossDialogueFlags flag)
{
_currentDialogueFlags |= flag;
}
_currentDialogueFlags |= flag -> currentDialogueFlags = currentDialogueFlags | flag
_currentDialogueFlags = 0000 | 0001 -> _currentDialogueFlags는 0001이 됨.
그러고 랜덤으로 출력하는 대사를 출력하고 끝.
// 하나의 보스만 처치했을 시(한 번만)
if (isTrollDead && !isSpiderDead && !isCentipedeDead && !HasDialogueFlag(BossDialogueFlags.HasSpokenTrollKill)) // 트롤 죽인 후
{
yield return StartCoroutine(Dialogues(new string[] { bossKillDialogue[0] }));
SetDialogueFlag(BossDialogueFlags.HasSpokenTrollKill);
}
if (!HasDialogueFlag(BossDialogueFlags.HasSpokenTrollKill)) -> HasSpokenTrollKill은 0010
이 조건만 따져보면
(_currentDialogueFlags & flag) == flag -> 0001 & 0010 == 0010
원래 0001 & 0010 == 0000이 맞다.
식이 성립하지 않기 때문에 false 반환.
if (!HasDialogueFlag(BossDialogueFlags.HasSpokenTrollKill))는 현재 if(!false)이기 때문에 내부 코드를 실행
조건문 마지막 코드인 SetDialogueFlag(BossDialogueFlags.HasSpokenTrollKill);
private void SetDialogueFlag(BossDialogueFlags flag)
{
_currentDialogueFlags |= flag;
}
_currentDialogueFlags = _currentDialogueFlags | flag -> _currentDialogueFlags = 0001 | 0010
_currentDialogueFlags = 0011이 된다.
이후 다시 상호작용(대화)를 하면
if (!HasDialogueFlag(BossDialogueFlags.HasSpokenFirstDialogue))의 조건문에 따라
private bool HasDialogueFlag(BossDialogueFlags flag)
{
return (_currentDialogueFlags & flag) == flag;
}
(_currentDialogueFlags & flag) == flag -> 0011 & 0001 == 0001이 성립하기 때문에 이 조건문은 넘어간다.
다음 조건인
if (!HasDialogueFlag(BossDialogueFlags.HasSpokenTrollKill))
(_currentDialogueFlags & flag) == flag -> 0011 & 0010 == 0010이 성립하기 때문에 이 조건문도 넘어간다.
이 두 조건은 넘어가지고 다른 조건문을 검사하기 시작한다.
이런 식으로 작동