• 카테고리

    질문 & 답변
  • 세부 분야

    게임 프로그래밍

  • 해결 여부

    미해결

안녕하세요 질문이 있습니다.

24.02.01 14:39 작성 조회수 124

0

안녕하세요 이 강의로 정말 도움을 많이 본 수강생입니다.

Task가 완료된 후 유저가 완료 버튼을 누르면 해당 Task가 지워지면서 보상을 받는 시스템을 만들고 싶어서

TaskDescriptor 스크립트에 DestroySelf함수를 만들어 TASK완료시 버튼을 누르면 해당 TASK가 목록에서 지워지면서 보상을 받게끔 했습니다.

하지만 버튼을 누르면 완료된 TASK가 지워지더라도 씬을 이동하거나 앱을 종료하고 다시 실행하면 지워진 TASK가 complete가 된 상태로 다시 생성되어 있습니다. taskDesriptorPrefab이 만들어지는 QuestTracker에서 작업을 해주면 좋을 것 같아 조건도 달고 별 짓을 다해봐도 소용이 없어 질문드립니다.

어떻게 하면 좋을까요?

답변 1

답변을 작성해보세요.

0

안녕하세요.

먼저 제가 정확히 이해한데로 설명을 드리겠습니다.
수강생분께서는 'Task들에 Quest처럼 개별적으로 보상을 설정하고 Task 완료 Button을 누르면 Task에 설정된 보상을 주고 해당 Task는 삭제하고 싶다'는 것으로 이해했습니다.
Task를 지워도 Load했을 때 그대로 남아있는 이유는 Task UI만 지웠을 뿐 실제 Task는 Quest안에 아직 남아있으므로 Quest를 저장할 시 그 Task도 저장되기 때문입니다.
해당 기능을 구현하는 방법은 여럿 있지만 가장 간단한 방법은 새로운 TaskState를 추가하고, Task가 그 State라면 UI로 표시하는걸 Skip하는 방법입니다. 다만 어떤 방식이라도 원하시는 기능을 구현하시려면 Quest의 Save와 Load에 여러 수정 작업이 필요합니다.

 

#TaskState 수정
public enum TaskState
{
    Inactive,
    Running,
    Complete,
    // !!! New State !!!
    Hidden
}

#EX
// Task 완료 Button을 Click
public void OnTaskCompleteButtonClick()
{
    // Task 보상을 줌
    task.GiveReward();
    // !!! Hidden 상태로 변경 !!!
    task.State = TaskState.Hidden;
}

#QuestTracker::UpdateTaskDescriptos 함수 수정
private void UpdateTaskDescriptos(Quest quest, TaskGroup currentTaskGroup, TaskGroup prevTaskGroup = null)
{
    foreach (var task in currentTaskGroup.Tasks)
    {
        // !!! Task가 Hidden 상태라면 Descriptor로 표시하지 않음 !!!
        if (task.State == TaskState.Hidden)
            continue;

        var taskDesriptor = Instantiate(taskDescriptorPrefab, transform);
        taskDesriptor.UpdateText(task);
        task.onSuccessChanged += UpdateText;

        taskDesriptorsByTask.Add(task, taskDesriptor);
    }
    ...
}

 

다음 Load를 해도 task가 Hidden 상태를 유지하도록 Quest를 Save할 때 Task의 상태도 저장해야하는데요, 꽤 많은 추가, 수정이 필요합니다.

현재 Quest의 Save, Load 방식은 QuestSaveData로 현재 진행 중인 TaskGroup의 번호와 해당 TaskGroup에 속한 Task들의 CurrentSuccessCount를 저장하고,

#Quest::Save
return new QuestSaveData
{
    ...
    taskGroupIndex    = currentTaskGroupIndex,
    taskSuccessCounts = CurrentTaskGroup.Tasks.Select(x => x.CurrentSuccess).ToArray()
}


Load시에 저장된 TaskGroup의 이전 번호들은 모두 Complete처리, 저장된 TaskGroup의 Task들에 저장된 CurrentSuccessCount를 Setting하는 방식입니다.

#Quest::Load
...
for (int i = 0; i < currentTaskGroupIndex; i++)
{
    var taskGroup = taskGroups[i];
    taskGroup.Start();
    taskGroup.Complete();
}

for (int i = 0; i < saveData.taskSuccessCounts.Length; i++)
{
    CurrentTaskGroup.Start();
    CurrentTaskGroup.Tasks[i].CurrentSuccess = saveData.taskSuccessCounts[i];
}

 

원하시는 방식을 구현하시기 위해서는 지금처럼 부분 저장하는게 아닌 완료된 TaskGroup들과 현재 TaskGroup이 가진 Task들의 상태를 저장해야합니다. 다음은 예시 Code입니다.

# TaskGroup에 함수 추가
TaskSaveData[] TaskGroup::ToSavdData()
{
    List<TaskSaveData> taskSaveDatas = new();
    foreach (var task in tasks)
    {
        taskSaveDatas.Add(new TaskSaveData() { state = task.State,
            successCount = task.CurrenctSuccessCount };
    }
    return taskSaveDatas.ToArray();
}

void TaskGroup::LoadFrom(TaskSaveData[] saveDatas)
{
    for (int i = 0; i < saveDatas.Length; i++)
    {
        tasks[i].CurrentSuccess = saveDatas[i].successCount;
        tasks[i].State = saveDatas[i].State;
    }
}

# Quest의 Save, Load Logic 변경
void Quest::ToSaveData()
{
    return new QuestSaveData
    {
        codeName = codeName,
        state = State,
        taskGroupIndex = currentTaskGroupIndex
        # 완료된 TaskGroup들과 현재 TaskGroup의 SaveData들을 저장
        taskGroupSaveDatas = taskGroups.Where(x => x.State == TaskGroupState.Complete ||
          x.State == TaskGroupState.Running).Select(x => x.ToSaveData()).ToList();
    }
}

void Quest::LoadFrom(QuestSaveData saveData)
{
    ...
    for (int i = 0; i < currentTaskGroupIndex; i++)
    {
        var taskGroup = taskGroups[i];
        taskGroup.Start();
        taskGroup.Complete();
        taskGroup.LoadFrom(saveData.taskGroupSaveDatas[i]);
    }

    CurrentTaskGroup.Start();
    CurrentTaskGroup.LoadFrom(saveData.taskGroupSaveDatas[currentTaskGroupIndex]);
}


위 Code는 즉석에서 작성한 이런 식으로 수정하면 될 것 같다는 예시일뿐이므로, 실제 수강생분 게임에 적용하실 때는 수정이 필요할 수도 있습니다.
여럿 수정이 필요하지만 내용 자체는 강의에서 학습한 내용을 기반으로 수정되기 때문에 크게 어렵진 않으실겁니다.
만약 당장 수정하기가 어렵다고 판단되실 경우, Task를 개별적으로 확인해서 보상을 받는 방식은 일반적인 방식은 아니기 때문에 기획적으로 Task를 개별 Quest로 만드는 방식으로 수정하는 것도 고려해보시면 될 것 같습니다.

감사합니다.

문인님의 프로필

문인

질문자

2024.02.04

정말 감사드립니다 선생님

덕분에 시간이 걸리긴 했지만 제가 원하는대로 할 수 있었습니다.

다시한번 바쁜 시간 내셔서 답변 달아주셔서 정말 감사드립니다!