[Solved] Is there a better way to do this?

For the past little while, I’ve been trying to create a flexible and abstract system that allows objects to listen to events and perform some actions depending on some conditions.
This is the code I wrote:

Code

 public class AttachableTrigger<TEvent, TObject> : Trigger<TEvent> where TEvent : Event
            {
                public TObject Container { get; set; }
                public new Func<TEvent, TObject, bool> Condition { get; set; }
                public new List<Action<TEvent, TObject>> Actions { get { return _actions; } }
                private readonly List<Action<TEvent, TObject>> _actions = new List<Action<TEvent, TObject>>();

                public new void Run(TEvent e)
                {
                    if (IsDisabled) return;
                    if (Container == null) return;
                    if (Condition != null && !Condition(e, Container)) return;

                    Execute(e);
                }

                public new void Execute(TEvent args)
                {
                    foreach (var action in _actions) action(args, Container);
                }
            }

Usage

  var t = new AttachableTrigger<StatChangedEvent, Shell>();
  t.Condition = (e, s) => { return e.StatType == StatType.Health && s.GetComponentInShelled<Profile>().Stats[StatType.Health].Current <= 0;};
  Action<StatChangedEvent, Shell> a = (e, s) => {DoThis(s.transform.position); DoThat(s.gameObject.name = "Hi";};
  t.Actions.Add(a);

The pros of the above are that it can be added / removed / modified any time, and lets an object listens to the same event but only perform actions for the triggers’ whose conditions are met.
The con is that it’s not serializable and that I haven’t seen anything like it before or any “design patterns” of this, so I’m wondering if there is another way for me to allow objects to respond differently based on some conditions?

I actually made something like this due to requirements.
So what I had was that Trigger contains a list of TriggerEvent objects, .such that OnTriggerEnter would run it’s respective TriggerEvent execute function.
Each TriggerEvent object would contain a list of Logic objects, which encapsulates a list of Condition objects to check and a list of Action objects to perform.

The reason for such a design is such that the all these custom objects are made serializable using an external format that can be fed in during runtime for initialization. Of course, there is alot of usage of System.Reflection.

1 Like

Sounds interesting, especially the part about using serialization. Can you tell me a bit more how you achieved this? Did you just create a bunch of “Condition” classes and serialize them or did you do something else?

Yup. So I had a ICondition interface and a bunch of Condition classes that stems out of it. Same with Actions.

1 Like

That’s basically what I’ve been doing lol.

I’d like to point out that delegates can already be combined, so the List<Action<…>> is sort of redundant.

You could just make it:

public Action<TEvent, TObject> Actions;

And then when adding actions you’d:

t.Actions += (e, s) => {DoThis(s.transform.position); DoThat(s.gameObject.name = "Hi";};
1 Like

Cool didn’t know that. Thanks for pointing it out. :slight_smile: