top of page

미로스 - 4. 퀘스트나 미션등의 요소를 기획하여 게임 플레이 이벤트를 설계 구현, 결과에 대한 보상성 포함

  • 작성자 사진: 100 powerun
    100 powerun
  • 2024년 11월 27일
  • 3분 분량

최종 수정일: 2월 13일

퀘스트는 다음 아래와 같은 부모 클래스를 사용합니다.

부모 클래스는 스크립터블 오브젝트로 생성되며 이후 enum Type에 따라 자식 class를 생성하여 세부 분류로 나뉘게 됩니다.

 public enum Type
 {
    Find = 0,
    Hunt,
    Talk,
    Arrive
 };
 public enum RewardType
 {
     Item=0,
     Money
 };

 [Tooltip("퀘스트 타입분류")]
 public Type type;


 [Tooltip("보상 타입분류")]
 public RewardType rewardType;
 [Tooltip("보상 아이템, 보상타입이 아이템일 경우에만 적용됨")]
 public ItemObject rewardItem;
 [Tooltip("보상 수량")]
 public int rewardQuantity;

 [TextArea,Tooltip("퀘스트 타이틀")]
 public string questTitle;
 [TextArea, Tooltip("퀘스트 타이틀")]
 public string texts;
 [TextArea, Tooltip("퀘스트 진행창에 표시될 텍스트")]
 public string request;
 public abstract void QuestStart();

 /// <summary>
 /// 퀘스트 클리어 가상화 함수
 /// 내용 : 공통 보상처리
 /// </summary>
 public virtual void Clear()
 {
     Debug.Log("퀘스트 클리어~~~~");   
            
    QuestManager.instance.ClearQuest(int.Parse(this.name.Substring(0,1)));
    switch (rewardType)
    {
        case RewardType.Item:
            {
                if (rewardItem != null)
                {
                    InventoryManager.Instance.ObtainItem(rewardItem, rewardQuantity);
                }
                      //GameObject.Find("Player").GetComponent<PlayerInventory>().inventory[rewardItem.itemtype].ObtainItem(rewardItem, 1);
                    break;
                }
            case RewardType.Money:
                {
                    //재화 보상처리
                    Managers.Game.Gold += rewardQuantity;

                    break;
                }
        }
    }

스크립터블 오브젝트로 생성하는 만큼 우선 퀘스트라면 기본적으로 들어가야 할 요소들을 넣을 수 있게 만듭니다. 주된 요소로는 퀘스트 타이틀, 내용, 퀘스트 진행 창에 나타날 이름, 보상 처리등이 있습니다. 이곳에서의 보상 처리는 아이템과 재화 총 2가지의 보상 방식이 있습니다.



스크립터블 오브젝트로 생성된 퀘스트는 인스팩터에서 세부 사항을 수정하거나 추가할 수 있습니다.


퀘스트 수행의 예시로 사냥을 들어보자면

public class HuntQuest : Quest
{
    public int monsterId = 0;
    public int huntGoal;
    public int curHuntCnt=0;

    public override void Clear()
    {
        base.Clear();
        //특수보상 처리
    }
    public void KillMonster(int id)
    {
        if (monsterId == id)
        {
            curHuntCnt++;
            QuestManager.instance.questWindow.GetComponent<CurrentQuestWindow>().CheckQuest(this);
            if (huntGoal == curHuntCnt)
            {
                this.Clear();
            }
        }
    }
    public override void QuestStart()
    {
        curHuntCnt = 0;
    }
}

이 게임내에 있는 모든 몬스터들은 퀘스트와 관련된 ID값을 가지는데 만약 플레이어가 몬스터를 잡았을 때 해당 ID가 몬스터와 일치한다면 카운트를 증가시키게 됩니다.


맨 아래의 퀘스트 스타트는 퀘스트를 처음 받았을 때 퀘스트가 이전 진행 상황과 겹치지 않도록 0으로 초기화 시켜주는 역할을 합니다.


맨 아래에 id를 생성한것이 보이는데 이 id가 해당 몬스터를 쓰러트렸을 때 쌓이게 되며 이 id를 가진 몬스터를 특정수를 처치하게 되면 퀘스트가 클리어 되는 방식입니다.


public void KillMonster(int id)
    {
        if (monsterId == id)
        {
            curHuntCnt++;
            QuestManager.instance.questWindow.GetComponent<CurrentQuestWindow>().CheckQuest(this);
            if (huntGoal == curHuntCnt)
            {
                this.Clear();
            }
        }
    }

이곳이 바로 몬스터의 id를 파악하는 곳으로, 만약 조건이 맞는다면 CurrentQuestWindow에서 현재 퀘스트의 진행도를 갱신 시킵니다.


public class CurrentQuestWindow : MonoBehaviour
{
    private GridLayoutGroup glg;
    public GameObject questSlot;

    List<GameObject> slots = new List<GameObject>();


    private void Awake()
    {
        glg = GetComponent<GridLayoutGroup>();

    }

    public void AddQuest(Quest quest)
    {
        Debug.Log("addCheck");
        GameObject slot = Instantiate(questSlot);
        slot.transform.parent = this.transform;
        slots.Add(slot);
        
        slot.GetComponent<Qslot>().SetTitle(quest.questTitle);
        slot.GetComponent<Qslot>().SetRequest(quest.request);
        slot.GetComponent<Qslot>().quest = quest;
        CheckQuest(quest);
    }
    public void CheckQuest(Quest quest)
    {
        GameObject slot = null;
        for (int i = 0; i < slots.Count; i++)
        {
            if (slots[i].GetComponent<Qslot>().quest == quest)
            {
                slot = slots[i];
                break;
            }
        }
        if (slot== null) return;

        if (quest.type == Quest.Type.Hunt)
        {
            HuntQuest q = (HuntQuest)quest;
            slot.GetComponent<Qslot>().current.text = q.curHuntCnt + " / " + q.huntGoal; 
        }
        else
        {
            slot.GetComponent<Qslot>().current.text ="";
        }
    }

    public void ClearQuest(Quest quest){

        for (int i = 0; i < slots.Count; i++)
        {
            if (slots[i].GetComponent<Qslot>().quest == quest)
            {
                Destroy(slots[i].gameObject);
                slots.RemoveAt(i);
                return;
            }
        }

    }

}

위에는 수락한 퀘스트를 관리하는 스크립트로 퀘스트를 승낙하였을 때 AddQuest로 현재 진행중인 퀘스트를 추가합니다. 아래의 Qslot들은 모두 캔버스와 관련된 스크립트 입니다. 이후 퀘스트를 진행하는것은 위의 HunQuest에 있던 KillMonster안의 CheckQuest에서 관리하게 되는데

 if (quest.type == Quest.Type.Hunt)
        {
            HuntQuest q = (HuntQuest)quest;
            slot.GetComponent<Qslot>().current.text = q.curHuntCnt + " / " + q.huntGoal; 
        }

만약 퀘스트의 종류가 사냥이라면 오른쪽에 사냥해야하는 몬스터 표시와 처치한 몬스터를 표시하는 캔버스 작업과 캔버스를 불러오기 전 퀘스트의 정보를 가져오는 변수로 이루어져 있습니다.


몬스터 잡기 전


몬스터를 잡은 후


시연 영상에서도 설명했 듯 구현한 시스템의 한계로 퀘스트 완료시 보상이 자동으로 들어오는구조로 되여있습니다.



Kommentare


bottom of page