Sorry for the delay. Iâve been too busy to give a proper answer to properly clarify.
I would first recommend watching the event messaging system live traning video. a large portion of my code is almost i direct copy. I like it since its easy to add new events in the future without even having to touch the event manager. also it can give you a better understanding of the dictionary.
below if just a rough draft of the event system Iâm talking about. I actually spent more time trying to think of better names than job, task and action than I did typing it out.
using UnityEngine;
using UnityEngine.Events;
using System.Collections;
using System.Collections.Generic;
public abstract class EventStateData{}
public delegate void Job<GameObject, EventStateData>(GameObject go,out EventStateData eventstateData);
public delegate void GlobalEffect<EventStateData, GlobalEffectCallback>(out EventStateData eventstateData,Job<GameObject, EventStateData> job);
public class EventManager : MonoBehaviour
{
public class GlobalEffect: UnityEvent<EventStateData,Job<GameObject, EventStateData>>{}
public class Trigger: UnityEvent<GameObject>{}
private Dictionary <string, Trigger> triggers;
private GlobalEffect globalEffect;
private static EventManager eventManager;
public static EventManager instance
{
get
{
if (!eventManager)
{
eventManager = FindObjectOfType (typeof (EventManager)) as EventManager;
if (!eventManager)
{
Debug.LogError ("There needs to be one active EventManger script on a GameObject in your scene.");
}
else
{
eventManager.Init ();
}
}
return eventManager;
}
}
void Init ()
{
if (triggers == null)
{
triggers = new Dictionary<string, UnityEvent>();
}
}
void OnDestroy()
{
for (int i = triggers.Count - 1; i >= 0; i--)
{
triggers [i].RemoveAllListeners ();
}
triggers.Clear ();
globalEffect = null;
}
public static void AddToEffects(GlobalEffect<EventStateData, Job<GameObject, EventStateData>> action)
{
instance.globalEffect += action;
}
public static void RemoveFromEffects(GlobalEffect<EventStateData, Job<GameObject, EventStateData>> action)
{
instance.globalEffect -= action;
}
public static void InvokeGlobalEffect(out EventStateData stateData, Job<GameObject, EventStateData> job)
{
if (instance.globalEffect != null)
{
instance.globalEffect(out stateData, callback);
}
}
public static void StartListening (string eventName, UnityAction listener)
{
Trigger thisEvent = null;
if (instance.triggers.TryGetValue (eventName, out thisEvent))
{
thisEvent.AddListener (listener);
}
else
{
thisEvent = new UnityEvent ();
thisEvent.AddListener (listener);
instance.triggers.Add (eventName, thisEvent);
}
}
public static void StopListening (string eventName, UnityAction listener)
{
if (eventManager == null) return;
Trigger thisEvent = null;
if (instance.triggers.TryGetValue (eventName, out thisEvent))
{
thisEvent.RemoveListener (listener);
}
}
public static void Trigger (string eventName,GameObject source)
{
Trigger thisEvent = null;
if (instance.triggers.TryGetValue (eventName, out thisEvent))
{
thisEvent.Invoke (source);
}
}
}
public sealed class Card: MonoBehaviour
{
public CardProperties properties { get; set; }
void OnEnable()
{
properties = GetComponent<CardProperties>();
EventManager.AddToEffects (Participate);
EventManager.Trigger ("OnCardEnabled");
}
void OnDisable()
{
EventManager.RemoveFromEffects (Participate);
}
public void Cast()
{
//validate that you can cast card, ten cast it
EventManager.Trigger ("OnCardCast", gameObject);
}
void Participate(out EventStateData eventstateData,GlobalEffectCallback<GameObject, EventStateData> job)
{
job(gameObject,out eventstateData);
}
}
// when a black card is cast, Card Owner gains life equal to black cards in play
public sealed class BlackChaliceEnchanment:MonoBehaviour
{
public CardProperties properties { get; set; }
public class EnchantmentData:EventStateData
{
public int BlackCardsInPlay;
}
void OnEnable()
{
properties = GetComponent<CardProperties>();
EventManager.StartListening ("OnCardCast", WhenACardIsCast);
}
void OnDisable()
{
EventManager.StopListening ("OnCardCast", WhenACardIsCast);
}
void WhenACardIsCast(GameObject source)
{
if (source.GetComponent<BlackCard> () == null)
{
return; //source is not a black card enchantment doesn't trigger
}
EnchantmentData data = new EnchantmentData ();
data.BlackCardsInPlay = 0;
EventManager.InvokeGlobalEffect(out data,GlobalEffect);
properties.currentOwner.Life += data.BlackCardsInPlay;
}
void GlobalEffect(GameObject gameObject,out EventStateData eventstateData)
{
BlackCard blackCard = gameObject.GetComponent<BlackCard> ();
if (blackCard == null)
return;
if (blackCard.properties.IsInPlay)
{
EnchantmentData data = eventstateData as EnchantmentData;
data.BlackCardsInPlay++;
}
}
}
Similar to my code, and since I know how Trading cards can get⌠I would try to make your classes SUPER modular so if a card is a black card, then the game object should have a BlackCard component script and a Card component script. the Enchantment card in my example would have a Card Component, a BlackChaliceEnchantment Component, a Enchantment Component, and maybe a BlackCard Component as well . Looking for a card that is either Red or Black? well you may invent a card that is both Red and Black (the card will have both components) and so it should pop up for the current set of cards, last seasonâs cards, and possibly any future cards.
These classes may also benefit by not holding any state (immutible), or as best as possible, and instead reference a single script that will store the state (CardProperties) which all the components can share with which will also reduce inconsistent data (bug example: one component may say the card is tapped, another says its not). it also abstracts the data from the components which will make adding a feature or fixing a bug only require you to change 1-2 files instead of 10-20, even 100-200 depending on how many card types you can think up.