Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

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

Discussion in 'Scripting' started by Deleted User, May 3, 2015.

  1. Deleted User

    Deleted User

    Guest

    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 (CSharp):
    1.  public class AttachableTrigger<TEvent, TObject> : Trigger<TEvent> where TEvent : Event
    2.             {
    3.                 public TObject Container { get; set; }
    4.                 public new Func<TEvent, TObject, bool> Condition { get; set; }
    5.                 public new List<Action<TEvent, TObject>> Actions { get { return _actions; } }
    6.                 private readonly List<Action<TEvent, TObject>> _actions = new List<Action<TEvent, TObject>>();
    7.  
    8.                 public new void Run(TEvent e)
    9.                 {
    10.                     if (IsDisabled) return;
    11.                     if (Container == null) return;
    12.                     if (Condition != null && !Condition(e, Container)) return;
    13.  
    14.                     Execute(e);
    15.                 }
    16.  
    17.                 public new void Execute(TEvent args)
    18.                 {
    19.                     foreach (var action in _actions) action(args, Container);
    20.                 }
    21.             }

    Code (CSharp):
    1.   var t = new AttachableTrigger<StatChangedEvent, Shell>();
    2.   t.Condition = (e, s) => { return e.StatType == StatType.Health && s.GetComponentInShelled<Profile>().Stats[StatType.Health].Current <= 0;};
    3.   Action<StatChangedEvent, Shell> a = (e, s) => {DoThis(s.transform.position); DoThat(s.gameObject.name = "Hi";};
    4.   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?
     
    Last edited by a moderator: May 3, 2015
  2. pws-devs

    pws-devs

    Joined:
    Feb 2, 2015
    Posts:
    63
    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.
     
    Deleted User likes this.
  3. Deleted User

    Deleted User

    Guest

    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?
     
  4. pws-devs

    pws-devs

    Joined:
    Feb 2, 2015
    Posts:
    63
    Yup. So I had a ICondition interface and a bunch of Condition classes that stems out of it. Same with Actions.
     
    Deleted User likes this.
  5. Deleted User

    Deleted User

    Guest

    That's basically what I've been doing lol.
     
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    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:

    Code (csharp):
    1.  
    2. public Action<TEvent, TObject> Actions;
    3.  
    And then when adding actions you'd:

    Code (csharp):
    1.  
    2. t.Actions += (e, s) => {DoThis(s.transform.position); DoThat(s.gameObject.name = "Hi";};
    3.  
     
    Deleted User likes this.
  7. Deleted User

    Deleted User

    Guest

    Cool didn't know that. Thanks for pointing it out. :)