I don’t know what your SpawnerManager
looks like, but the DialogueTrigger
could be extended do that for you.
First, create an interface so that it’s easier to work with
public interface IDialogueTrigger
{
void Trigger(string actionToTrigger);
}
Now we’ll need to update PlayerConversant
to look for interfaces instead
// PlayerConversant.cs
private void TriggerAction(string triggerAction)
{
if (triggerAction == null) return;
// find all the monobehaviours on this game object that implement the interface
foreach (var trigger in _currentConversant.GetComponents<MonoBehaviour>().OfType<IDialogueTrigger>())
{
trigger.Trigger(triggerAction);
}
}
Next, our old DialogueTrigger
class must inherit from the interface. It is already implemented so nothing more is needed
public class DialogueTrigger : MonoBehaviour, IDialogueTrigger
{
[SerializeField] string action;
[SerializeField] UnityEvent onTrigger;
public void Trigger(string actionToTrigger)
{
if (actionToTrigger != action) return;
onTrigger.Invoke();
}
}
Now we make a new trigger.
Make a struct to hold the details
public struct SpawnEnemyDetails
{
public GameObject EnemyToSpawn;
public int NumberToSpawn;
public SpawnEnemyDetails(GameObject enemyToSpawn, int numberToSpawn)
{
EnemyToSpawn = enemyToSpawn;
NumberToSpawn = numberToSpawn;
}
}
and a new unity event to pass the details to listeners
[Serializable]
public class SpawnEnemyEvent : UnityEvent<SpawnEnemyDetails> { }
And lastly, the new dialogue trigger
// New dialog trigger
public class SpawnEnemyDialogueTrigger : MonoBehaviour, IDialogueTrigger
{
[SerializeField] string action;
[SerializeField] GameObject enemyPrefab;
[SerializeField] int numberToSpawn;
[SerializeField] SpawnEnemyEvent onTrigger;
public void Trigger(string actionToTrigger)
{
if (actionToTrigger != action) return;
onTriggerSpawn.Invoke(new SpawnEnemyDetails(enemyPrefab, numberToSpawn));
}
}
You will set this up like any other DialogueTrigger
, but it includes fields for the enemy you want to spawn, etc.
Now you just need your SpawnManager
to have a public method that takes the SpawnEnemyDetails
, Add it to the new SpawnEnemyEvent
and use it to do what it needs to do
public class SpawnManager : MonoBehaviour
{
public void SpawnEnemies(SpawnEnemyDetails details)
{
for (var i = 0; i < details.NumberToSpawn; i++)
{
Instantiate(details.EnemyToSpawn);
}
}
}
You could add your EPredicate.HasKilled
or EPredicate.HasKilledClass
to the SpawnEnemyDetails
as well. The downside here is that the configuration lives on the trigger.
My own implementation uses scriptable objects for the actions, but it will look something like this
Edit
I had a quick think about it and it’s not too difficult to put the spawn configuration on the quest instead.
Disregarding all the previous stuff:
Create a new Quest type
[CreateAssetMenu(menuName = "RPG/Quests/New Spawner Quest")]
public class SpawnerQuest : Quest
{
[SerializeField] List<SpawnDetails> spawnDetails = new();
public IEnumerable<SpawnDetails> GetSpawnDetails() => spawnDetails;
[Serializable]
public class SpawnDetails
{
[SerializeField] GameObject objectToSpawn;
[SerializeField] int numberToSpawn;
public GameObject GetObjectToSpawn() => objectToSpawn;
public int GetNumberToSpawn() => NumberToSpawn;
}
}
Then create a QuestGiver
component that expects this type of quest
public class SpawnerQuestGiver : MonoBehaviour
{
[SerializeField] SpawnerQuest questToGive = null;
public void GiveQuest()
{
var questList = GameObject.FindWithTag("Player").GetComponent<QuestList>();
questList.AddQuest(questToGive);
var spawner = GetComponent<TestSpawner>();
foreach (var detail in questToGive.GetSpawnDetails())
{
spawner.SpawnEnemies(new SpawnEnemyDetails(detail.GetObjectToSpawn(),
detail.GetNumberToSpawn()));
}
}
}
It’s the same as any other quest giver (I omitted the ‘items to give’ bits, but you don’t have to), but now the quest can tell it what type of object (can be a sword, too) to spawn, etc.
This is the new quest