인프런 커뮤니티 질문&답변
QuestTrackerView.cs 의 foreach 부분을 지울 경우, QuestTrackerUI 가 업데이트 되지 않는 이유는 무엇인가요?
작성
·
302
0
먼저, 좋은 강의 정말 감사드립니다. 모듈화를 처음 접해보아서 조금 어렵긴 하지만, 큰 도움이 되는 강의라고 생각합니다.
강의를 듣고, 다시 코드를 이해하던 중 QuestTrackerView.cs 에서 이벤트에 등록하는 부분이 존재할 경우, foreach 부분이 없어도 자동으로 QuestSystem.cs 에서 onQuestResgistered.Invoke() 에서 등록이 될 것이라고 생각해서 foreach 부분을 주석처리 해도 된다고 생각했는데, 실제로 주석처리를 할 경우 QuestTrackerUI 가 업데이트 되지 않아서 코드 동작 방식이 궁금하여 질문드립니다.

(그림 1: 강의를 따라한 경우 정상적으로 작동하는 모습)
제가 이해한 내용은 다음과 같습니다. 먼저 QuestTrackerView.cs 에서
QuestSystem.Instance.onQuestRegistered += CreateQuestTracker;를 통해 이벤트에 등록합니다.
그 후 QuestSystem.cs 의
onQuestRegistered?.Invoke(newQuest);부분에서 QuestGiver 에 의해 받은 퀘스트가 등록되므로,
QuestTrackerView.cs 의 CreateQuestTracker 가 실행될 것이라고 생각했습니다. 즉,
foreach (var quest in QuestSystem.Instance.ActiveQuests)
{
CreateQuestTracker(quest);
}부분은 필요 없을 것이라고 생각했습니다. 그러나 이 부분을 주석처리하고 실행하니 (즉 아래 코드와 같이 돌리니) UI 가 없데이트 되지 않았습니다.
//QuestTrackerView.cs
private void Start()
{
QuestSystem.Instance.onQuestRegistered += CreateQuestTracker;
//foreach (var quest in QuestSystem.Instance.ActiveQuests)
//{
// CreateQuestTracker(quest);
//}
}
(그림 2 - 주석처리를 하고 게임을 실행한 경우 QuestTrackerUI 가 생기지 않는 모습 )
QuestSystem.cs 의 Register 메소드도
public Quest Register(Quest quest)
{
var newQuest = quest.Clone();
if (newQuest is Achievement)
{
newQuest.onCompleted += OnAchievementCompleted;
activeAchievements.Add(newQuest);
newQuest.OnRegister();
onAchievementRegistered?.Invoke(newQuest);
}
else
{
newQuest.onCompleted += OnQuestCompleted;
newQuest.onCanceled += OnQuestCanceled;
activeQuests.Add(newQuest);
newQuest.OnRegister();
Debug.Log($"is on quest registered true? {onQuestRegistered == null}");
onQuestRegistered?.Invoke(newQuest);
}
return newQuest;
}와 같이, activeQuest.Add(newQuest) 를 통해 activeQuest를 업데이트하고, onQuestRegistered?.Invoke(newQuest)를 합니다.
그렇다면 왜 똑같은 code block 에서 업데이트 되는 activeQuest 를 foreach 로 돌면서 UI 업데이트를 하는 것은 제대로 동작하는데, onQuestRegisterd?.Invoke(newQuest) 에서 UI 업데이트를 하는 것은 정상적으로 작동하지 않는 것인가요?
감사합니다.
답변 1
0
수강해주셔서 감사합니다.
현재 Player에게 Quest를 주고 있는 것은 QuestGiver입니다. QuestGiver의 Start 함수에서 조건문을 확인하고 Quest들을 Register해주고 있습니다. QuestTrackerView에서 QuestSystem의 onQuestRegistered event에 CreateQuestTracker 함수를 연결하고 있는 곳도 역시 Start 함수입니다.
현재 저희가 스크립트 간의 실행 순서를 따로 정해주지 않았기 때문에 QuestGiver의 Start 함수가 먼저 실행될지, QuestTrackerView의 Start 함수가 먼저 실행될지 알 수 없습니다.
만약 운 좋게 QuestTrackerView의 Start 함수가 먼저 실행이된다면 event가 먼저 등록이되고, 이후 QuestGiver의 Start 함수가 실행되어 Quest를 Register할 때 등록한 event가 실행될 겁니다.
하지만 수강생분처럼 QuestGiver의 Start 함수가 먼저 실행될 경우, 이미 Quest가 다 등록된 상태에서 QuestTrackerView가 뒤늦게 event를 등록하기 때문에 event가 실행되지 않습니다. 그렇기 때문에 foreach문을 통해 이미 등록되어 있는 Quest가 있다면 View를 직접 만들어주는 것입니다.
감사합니다.






이해했습니다! 즉, Start 내부에서 여러 함수가 같이 실행될 경우 각 함수가 서로의 변수를 참조할 경우 순서를 보장할 수 없기 때문에 Register 가 먼저 실행될 경우와 event 에 등록하는 부분이 먼저 실행될 것으 모두 고려하여 작성한 코드군요. 설명 감사드립니다.
좋은 강의를 준비해주신 것에 더해 질문을 올린지 약 몇 시간 안에 빠르게 답변주셔서 정말 감사드립니다. 남은 강의도 완강하여 개발중인 게임에 적용해보겠습니다. 앞으로도 좋은 강의 많이 만들어주세요!