Based on Game Dev Experiments’ YT Pokemon series, I was able to implement a method to enable/disable objects based on a specific quest’s status. I thought I would share how I was able to do it along with the results.
First create a new C# script called QuestObject.
using System.Collections;
using System.Collections.Generic;
using RPG.Saving;
using UnityEngine;
namespace RPG.Quests
{
public class QuestObject : MonoBehaviour
{
[SerializeField] Quest questToCheck;
[SerializeField] ObjectActions onStart;
[SerializeField] ObjectActions onComplete;
[SerializeField] string jsonSaveFileName = "save"; // only need if using Brian's Json Saving System
QuestList questList;
private void Start()
{
questList = QuestList.GetQuestList();
questList.OnUpdatedQuest += UpdateQuestObjectStatus;
UpdateQuestObjectStatus();
}
private void OnDestroy()
{
questList.OnUpdatedQuest -= UpdateQuestObjectStatus;
}
public void UpdateQuestObjectStatus()
{
if (onStart != ObjectActions.DoNothing && questList.HasQuest(questToCheck))
{
foreach (Transform child in transform)
{
if (onStart == ObjectActions.Enable)
{
child.gameObject.SetActive(true);
// comment out if using Brian's Json Saving System
// var savable = child.GetComponent<SavableEntity>();
// if (savable != null)
// {
// SavingSystem.instance.RestoreEntity(savable);
// }
// comment out if using Sam's Binary Saving System
var jsonSavable = child.GetComponent<JsonSaveableEntity>();
if (jsonSavable != null)
{
JsonSavingSystem.instance.RestoreEntity(jsonSaveFileName, jsonSavable);
}
}
else if (onStart == ObjectActions.Disable)
child.gameObject.SetActive(false);
}
}
if (onComplete != ObjectActions.DoNothing && questList.HasCompletedQuest(questToCheck))
{
foreach (Transform child in transform)
{
if (onComplete == ObjectActions.Enable)
{
child.gameObject.SetActive(true);
// // comment out if using Brian's Json Saving System
// var savable = child.GetComponent<SavableEntity>();
// if (savable != null)
// {
// SavingSystem.instance.RestoreEntity(savable);
// }
// comment out if using Sam's Binary Saving System
var jsonSavable = child.GetComponent<JsonSaveableEntity>();
if (jsonSavable != null)
{
JsonSavingSystem.instance.RestoreEntity(jsonSaveFileName, jsonSavable);
}
}
else if (onComplete == ObjectActions.Disable)
child.gameObject.SetActive(false);
}
}
}
}
public enum ObjectActions { DoNothing, Enable, Disable }
}
This script has how to use either Sam’s Binary saving system or Brian’s Json saving system to restore the states of the quest objects properly.
Next the following method must be added to the QuestList script. It is called by the QuestObject script to verify whether a quest is complete or not.
public bool HasCompletedQuest(Quest quest)
{
QuestStatus questStatus = GetQuestStatus(quest);
if (questStatus.IsComplete())
return true;
else
return false;
}
Finally depending on which saving system code you are using, the SavingSystem/JsonSavingSystem C# script must be modified.
For the SavingSystem, the following lines must be added:
public static SavingSytem instance { get; private set; }
private void Awake()
{
instance = this;
}
public void RestoreEntity(SavableEntity entity)
{
if (gameState.ContainsKey(entity.UniqueId))
entity.RestoreState(gameState[entity.UniqueId]);
}
For the JsonSavingSytem, the following lines must be added:
public static JsonSavingSystem instance { get; private set; }
private void Awake()
{
instance = this;
}
public void RestoreEntity(string saveFile, JsonSaveableEntity entity)
{
JObject state = LoadJsonFromFile(saveFile);
IDictionary<string, JToken> stateDict = state;
string id = entity.GetUniqueIdentifier();
if (stateDict.ContainsKey(id))
{
entity.RestoreFromJToken(stateDict[id]);
}
}
To get this to work within my project, I created an empty gameObject (I called it QuestObjects) and attached the QuestObject script to it as a component. I prefabbed this gameObject for future use. Based on whether a quest has been started and/or completed, any gameObjects that are children to the QuestObjects prefab can be manipulated based on the status of the quest. For instance, I have a quest that I don’t want the player to be able to kill or collect any quest items before the quest has started. So I placed all these objects under my QuestObjects prefab and set them as inactive.
In the QuestObject script, I just added the quest scriptable object as well as to have the objects enabled when the quest is started. Here is a short video that I hope explains things better.
As you can see from the video (sorry for the quality), before the quest starts, all objects under the QuestObject prefab (Guardian of the Grove) are inactive. Once it is assigned, those objects are made active. Even after saving and reloading the saved scene, the objects are restored to their proper settings. If they have already been killed or picked up, they are reset as such. As you can see, the possibilties are endless.
I hope this helps others who might have been wondering how to do this.
