Unity Community


Results 1 to 17 of 17

  1. Location
    Ontario, Canada
    Posts
    51

    C# classes that don't have corresponding physical object in world

    Hi there,

    I'm switching to Unity/C# from a DirectX/C++ background and, although I'm pretty comfortable with C# itself now, I'm having a bit of a time getting my head around this new approach to coding in Unity with script components.

    Let's say I have an enemy AI character, that is represented in the world by a simple cube, and has its own script (Enemy.cs). What if, for example, I have a finite state machine system (a whole set of related classes), written in plain ol' C#, that I want my Enemy class to use. I'm having difficulty figuring out how I would model the "has-a" relationship here. The FSM classes have nothing to do with GameObjects and they needn't derive from MonoBehaviour either. How do I integrate this code into the project?

    Many thanks,

    Will
    Last edited by willyfreddy; 11-04-2011 at 05:45 PM.


  2. Location
    California
    Posts
    1,657
    It depends on whether you want to expose your class to the Unity framework on not. If you have a state machine, is it standalone or attachable? If you state machine is standalone a MonoBehaviour will "have-a" state machine as part of the MonoBehaviour class definition. Or if your state machine will be attached directly to a GameObject, and therefore, your MonoBehaviour "is-a" state machine.

    I often make my state machines, using the Open Source Stateless project, a "has-a" of a MonoBehaviour and expose some member variables in the MonoBehaviour that feed in to the state machine.

    It comes down to knowing when to make a class derived from MonoBehaviour and when to make a regular old class derived from UnityEngine.Object which is the equivalent of System.Object in regular .NET.

    The preference of is-a and has-a comes down to how you are structuring your architecture and how you want to expose your particular underlying class implementation.


  3. Location
    Ontario, Canada
    Posts
    51
    Hi Justin,

    Thanks for the response, but I'll admit that I only followed about 73% of it. If you would be willing to spend the time, it would be great if you cache out exactly how both the "have-a" and "is-a" relationships would work, within Unity, with a class (structure) that had originally been written in plain ol' C# for .NET.

    For example, I'll highlight some bits that are iffy to me:

    - "if your state machine will be attached directly to a GameObject, and therefore, your MonoBehaviour "is-a" state machine"
    - "I often make my state machines, [...], a "has-a" of a MonoBehaviour and expose some member variables in the MonoBehaviour that feed in to the state machine."

    Still, speaking more generally, it would be great if you cache out exactly how both the "have-a" and "is-a" relationships would work, within Unity, with a class (structure) that had originally been written in plain ol' C# for .NET.

    Many thanks,

    Will

    p.s. Does every class within a project have to at least derive from UnityEngine.Object? What happens if I utilize a class that doesn't derive from it? (I've included one during testing and it compiled alright).
    Last edited by willyfreddy; 11-04-2011 at 08:58 PM.


  4. Location
    Gold Coast, Australia
    Posts
    3,593
    Quote Originally Posted by willyfreddy View Post
    p.s. Does every class within a project have to at least derive from UnityEngine.Object? What happens if I utilize a class that doesn't derive from it? (I've included one during testing and it compiled alright).
    Nope.

    Unity3d uses 'plain old C#' just fine.

    Have you written many Monobehaviours?


  5. Location
    California
    Posts
    1,657
    Quote Originally Posted by willyfreddy View Post
    Hi Justin,

    Thanks for the response, but I'll admit that I only followed about 73% of it. If you would be willing to spend the time, it would be great if you cache out exactly how both the "have-a" and "is-a" relationships would work, within Unity, with a class (structure) that had originally been written in plain ol' C# for .NET.

    For example, I'll highlight some bits that are iffy to me:

    - "if your state machine will be attached directly to a GameObject, and therefore, your MonoBehaviour "is-a" state machine"
    - "I often make my state machines, [...], a "has-a" of a MonoBehaviour and expose some member variables in the MonoBehaviour that feed in to the state machine."

    Still, speaking more generally, it would be great if you cache out exactly how both the "have-a" and "is-a" relationships would work, within Unity, with a class (structure) that had originally been written in plain ol' C# for .NET.
    No, sorry. That's an awful lot of work to be asking of someone. I am just too busy right now to do a proper write up.

    Quote Originally Posted by willyfreddy View Post
    p.s. Does every class within a project have to at least derive from UnityEngine.Object? What happens if I utilize a class that doesn't derive from it? (I've included one during testing and it compiled alright).
    Sound like you have some more learning to do with the basic C# and the .NET framework based on these last couple of questions. All objects in Unity, even those not explicitly stated, are derived from UnityEngine.Object.
    Last edited by JustinLloyd; 11-04-2011 at 11:34 PM.


  6. Location
    Ontario, Canada
    Posts
    51
    Quote Originally Posted by NPSF3000 View Post
    Nope.

    Unity3d uses 'plain old C#' just fine.

    Have you written many Monobehaviours?
    No, I am brand new to Unity and have only been fiddling with coding for it for a week or so now.


  7. Location
    California
    Posts
    1,657
    Best bet, and I know it may sound flippant, but I suggest one of the many reasonably good introduction to Unity books available.** Any Unity book will get you up to speed very quickly. There are a bunch of very good free tutorials around too, but the quality can be rather hit and miss. A good book with teach you all you need to know about the basics. Obviously you are a programmer, so go for one that is more programming centric with lots of good code in it, rather than the more editing environment/design focused books. Even if the book presents all of its code in UnityScript (a dialect of Javascript/ECMAScript) it doesn't matter as converting between Unityscript and C# is a trivial skill teachable to anyone who can read the other dialect in about 30 minutes.

    **Try and avoid Packt publishing.


  8. Location
    Ontario, Canada
    Posts
    51
    No problem Justin, I understand. I Personally, I think I would understand what you're trying to say quite easily (i.e. the Unity techniques themselves), I'm just having trouble creating contextual examples from your generalized explanations.

    Let me try this alone and hopefully someone can point out the mistakes.

    1) "if your state machine will be attached directly to a GameObject, and therefore, your MonoBehaviour "is-a" state machine"

    I'm guessing an example of this would be something like the following:

    - I have a cube GameObject
    - That GameObject has a script component (i.e. deriving from MonoBehaviour)
    - That script component's class is the state machine

    2) "I often make my state machines, [...], a "has-a" of a MonoBehaviour and expose some member variables in the MonoBehaviour that feed in to the state machine."

    I'm guessing an example of this would be something like the following:

    - I have a cube GameObject
    - That GameObject has a script component (i.e. deriving from MonoBehaviour)
    - That script component's class contains the state machine as a member variable
    - That script component's class contains some other member variables that are made public so the state machine can act on them directly

    What do you guys think? Is that what he meant?

    Cheers,

    Will
    Last edited by willyfreddy; 11-05-2011 at 11:20 AM. Reason: fixing the wording AGAIN - I can't write today for some reason


  9. Location
    Ontario, Canada
    Posts
    51
    Apologies for the bump. I just want to make sure that I'm not way off in my thinking here.

    Cheers,

    Will


  10. Location
    California
    Posts
    1,657
    Sorry, I only do useful posts during the week. Weekends I take off and spend my time trolling the forum posters who are working on an MMO or posting their new MMO a day or two early -- everyone knows that new MMO posts and forming new MMO teams should be posted on Monday so that we have something to laugh at on a Monday morning at the office.

    If you want to make a new MMO thread, or mention that you are making a state machine for an MMO I would be happy to take a few minutes and troll you.


  11. Location
    Ontario, Canada
    Posts
    51
    Fair enough. Now that it's Monday, perhaps you could take a look?

    Cheers,

    Will


  12. Location
    California
    Posts
    1,657
    Name:  kidding_me.jpg
Views: 442
Size:  26.8 KB
    You have called my bluff. Well played Sir, well played.


    Name:  challenge_accepted.jpg
Views: 444
Size:  26.7 KB



    Because of the simplicity of the examples, please do not fall in to the trap of thinking "yeah, but you could make that example be the other type because of reason X." The examples are simple, but if you scale up the complexity, you can easily choose the wrong solution. What got you to here, won't get you to there.


    If you are making a simple state machine, you may desire to derive your state machine from MonoBehaviour itself, e.g.:


    Code:  
    1.  [FONT=&quot]public class StateMachineBehaviour : MonoBehaviour
    2. {
    3. [COLOR=#2B91AF]  IDictionary[/COLOR]<TState, [COLOR=#2B91AF]StateRepresentation[/COLOR]> _stateConfiguration = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]Dictionary[/COLOR]<TState, [COLOR=#2B91AF]StateRepresentation[/COLOR]>();[/FONT]
    4.   [COLOR=#2B91AF][FONT=&quot]  IDictionary[/FONT][/COLOR][FONT=&quot]<TTrigger, [COLOR=#2B91AF]TriggerWithParameters[/COLOR]> _triggerConfiguration = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]Dictionary[/COLOR]<TTrigger, [COLOR=#2B91AF]TriggerWithParameters[/COLOR]>();[/FONT]
    5.  
    6.   [COLOR=blue][FONT=&quot]  public[/FONT][/COLOR][FONT=&quot] [COLOR=#2B91AF]StateConfiguration[/COLOR] Configure(TState state)
    7. {[/FONT]
    8.   [FONT=&quot]// blah blah
    9. }[/FONT]
    10.  
    11.   [COLOR=blue][FONT=&quot]  public[/FONT][/COLOR][FONT=&quot] [COLOR=#2B91AF]StateConfiguration[/COLOR] Permit(TTrigger trigger, TState destinationState)
    12.   {
    13.     // blah blah
    14.   }[/FONT]
    15.  
    16.   [COLOR=blue][FONT=Consolas]public[/FONT][/COLOR][FONT=Consolas] [COLOR=blue]void[/COLOR] Fire(TTrigger trigger)
    17.   {[/FONT]
    18.   [FONT=Consolas]    // fire a state transition here based on the permissions ruleset[/FONT]
    19.   [FONT=Consolas]  }[/FONT]
    20.  
    21.   [FONT=&quot]}[/FONT]
    And then implement a state machine that will do what you need based off of that:
    Code:  
    1.  [FONT=&quot]public class [/FONT][COLOR=#2B91AF][FONT=Consolas]SensorDevice [/FONT][/COLOR][FONT=&quot]: StateMachineBehaviour
    2. {
    3. [/FONT][FONT=Consolas]  [COLOR=blue]protected[/COLOR] [COLOR=blue]enum[/COLOR] [COLOR=#2B91AF]States[/COLOR][/FONT]
    4.   [FONT=Consolas]  {[/FONT]
    5.   [FONT=Consolas]    Uninitialised,[/FONT]
    6.   [FONT=Consolas]    Initialising,[/FONT]
    7.   [FONT=Consolas]    Reinitialise,[/FONT]
    8.   [FONT=Consolas]    Reading,[/FONT]
    9.   [FONT=Consolas]    ShuttingDown,[/FONT]
    10.   [FONT=Consolas]  }[/FONT]
    11.  
    12.   [FONT=Consolas]  [COLOR=blue]protected[/COLOR] [COLOR=blue]enum[/COLOR] [COLOR=#2B91AF]Triggers[/COLOR][/FONT]
    13.   [FONT=Consolas]  {[/FONT]
    14.   [FONT=Consolas]    Initialise,[/FONT]
    15.   [FONT=Consolas]    ReadData,[/FONT]
    16.   [FONT=Consolas]    Shutdown,[/FONT]
    17.   [FONT=Consolas]    Unplugged,[/FONT]
    18.   [FONT=Consolas]    StartOver,[/FONT]
    19.   [FONT=Consolas]    FailInitialisation[/FONT]
    20.   [FONT=Consolas]  }[/FONT]
    21.  
    22.  
    23.   [FONT=Consolas]  // set up our state machine[/FONT]
    24.   [FONT=&quot]void Awake()
    25. [/FONT][FONT=&quot]{[/FONT]
    26.   [FONT=&quot]    // because of Unity's parameterless constructors we have to do some behind the scenes magic to get a generic type that can handle our states and triggers
    27. [/FONT][FONT=Consolas]    InitialiseMachine<[COLOR=#2B91AF]States[/COLOR], [COLOR=#2B91AF]Triggers[/COLOR]>([COLOR=#2B91AF]States[/COLOR].Uninitialised);[/FONT]
    28.  
    29.   [FONT=Consolas]    Configure([COLOR=#2B91AF]States[/COLOR].Uninitialised)[/FONT]
    30.   [FONT=Consolas]      .PermitReentry([COLOR=#2B91AF]Triggers[/COLOR].Shutdown)[/FONT]
    31.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].Initialise, [COLOR=#2B91AF]States[/COLOR].Initialising);[/FONT]
    32.  
    33.   [FONT=Consolas]    Configure([COLOR=#2B91AF]States[/COLOR].Initialising)[/FONT]
    34.   [FONT=Consolas]      .OnEntry(() => StateEntry_Initialising())[/FONT]
    35.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].FailInitialisation, [COLOR=#2B91AF]States[/COLOR].Reinitialise)[/FONT]
    36.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].Shutdown, [COLOR=#2B91AF]States[/COLOR].ShuttingDown)[/FONT]
    37.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].ReadData, [COLOR=#2B91AF]States[/COLOR].Reading);[/FONT]
    38.  
    39.   [FONT=Consolas]    Configure([COLOR=#2B91AF]States[/COLOR].Reinitialise)[/FONT]
    40.   [FONT=Consolas]      .OnEntry(() => StateEntry_Reinitialise())[/FONT]
    41.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].Shutdown, [COLOR=#2B91AF]States[/COLOR].ShuttingDown)[/FONT]
    42.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].Initialise, [COLOR=#2B91AF]States[/COLOR].Initialising);[/FONT]
    43.  
    44.   [FONT=Consolas]    Configure([COLOR=#2B91AF]States[/COLOR].Reading)[/FONT]
    45.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].Shutdown, [COLOR=#2B91AF]States[/COLOR].ShuttingDown)[/FONT]
    46.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].Unplugged, [COLOR=#2B91AF]States[/COLOR].Reinitialise);[/FONT]
    47.  
    48.   [FONT=Consolas]    Configure([COLOR=#2B91AF]States[/COLOR].ShuttingDown)[/FONT]
    49.   [FONT=Consolas]      .OnEntry(() => StateEntry_ShuttingDown())[/FONT]
    50.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].StartOver, [COLOR=#2B91AF]States[/COLOR].Uninitialised);[/FONT]
    51.   [FONT=&quot]}[/FONT]
    52.  
    53.   [FONT=&quot]  protected void StateEntry_Initialising()[/FONT]
    54.   [FONT=&quot]  {[/FONT]
    55.   [FONT=&quot]    // initialiise the sensor device upon state entry[/FONT]
    56.   [FONT=&quot]  }[/FONT]
    57.  
    58.   [FONT=&quot]  protected void StateEntry_ReInitialise()[/FONT]
    59.   [FONT=&quot]  {[/FONT]
    60.   [FONT=&quot]    // reinitialise the sensor device upon state entry[/FONT]
    61.   [FONT=&quot]  }[/FONT]
    62.  
    63.   [FONT=&quot]  protected void StateEntry_ShuttingDown()[/FONT]
    64.   [FONT=&quot]  {[/FONT]
    65.   [FONT=&quot]    // shut down the sensor device[/FONT]
    66.   [FONT=&quot]  }[/FONT]
    67.  
    68.   [FONT=&quot]}[/FONT]
    69.  
    70.   [FONT=&quot]// and some basic code to interact with the state machine[/FONT]
    71.   [FONT=&quot]public class UserInterface : MonoBehaviour[/FONT]
    72.   [FONT=&quot]{[/FONT]
    73.   [FONT=&quot]  void OnGUI()[/FONT]
    74.   [FONT=&quot]  {[/FONT]
    75.   [FONT=&quot]    if (GUI.Button(new Rect(25, 25, 200, 50), "Initialise") == true)[/FONT]
    76.   [FONT=&quot]    {[/FONT]
    77.   [FONT=&quot]      SensorDevice device = GetComponent<SensorDevice>();[/FONT]
    78.   [FONT=&quot]      device.Fire(Triggers.Initialise);[/FONT]
    79.   [FONT=&quot]    }[/FONT]
    80.  
    81.   [FONT=&quot]    if (GUI.Button(new Rect(25, 100, 200, 50), "Shutdown") == true)[/FONT]
    82.   [FONT=&quot]    {[/FONT]
    83.   [FONT=&quot]      SensorDevice device = GetComponent<SensorDevice>();[/FONT]
    84.   [FONT=&quot]      device.Fire(Triggers.Shutdown);[/FONT]
    85.   [FONT=&quot]    }[/FONT]
    86.   [FONT=&quot]  }[/FONT]
    87.   [FONT=&quot]}[/FONT]
    This obviously is the is-a composition.

    You could just as well implement your state machine as an interface, in which case your declaration would become:

    Code:  
    1.  [FONT=&quot]public class [/FONT][COLOR=#2B91AF][FONT=Consolas]SensorDevice [/FONT][/COLOR][FONT=&quot]: MonoBehaviour, IStateMachine
    2. {
    3. }
    4. [/FONT]
    But whilst this is-a is correct, it would lead to a lot of duplication for anything but the most simplest of state machines. Also, because of how Unity handles construction of new objects, and hence scripts, you have to do some fancy footwork to make a class that can be generic.

    By now, all the programmers on the forum already like:
    Name:  now_what.jpg
Views: 435
Size:  29.0 KB
    "S.O.B. made a mistake but I can't find!"


    You are also exposing a lot of the internal workings of your state machine to scripts that may not need to know about it, and if you are in a team of many people, or you take a break from your code if you are solo, you or they may end up, one day, on pulling strings in your state machine that your state machine doesn't want to be pulled on. You can obviously wrap your triggering firing mechanisms in yet more isolating functions and abstract it away, but again, more duplicated code for each state machine you make.

    Let's try the same idea with a has-a composition, e.g.:
    Code:  
    1.  [FONT=&quot]public class [/FONT][COLOR=#2B91AF][FONT=Consolas]SensorDevice [/FONT][/COLOR][FONT=&quot]: MonoBehaviour
    2. {
    3. [/FONT][FONT=Consolas]  [COLOR=blue]protected[/COLOR] [COLOR=blue]enum[/COLOR] [COLOR=#2B91AF]States[/COLOR][/FONT]
    4.   [FONT=Consolas]  {[/FONT]
    5.   [FONT=Consolas]    Uninitialised,[/FONT]
    6.   [FONT=Consolas]    Initialising,[/FONT]
    7.   [FONT=Consolas]    Reinitialise,[/FONT]
    8.   [FONT=Consolas]    Reading,[/FONT]
    9.   [FONT=Consolas]    ShuttingDown,[/FONT]
    10.   [FONT=Consolas]  }[/FONT]
    11.  
    12.   [FONT=Consolas]  [COLOR=blue]protected[/COLOR] [COLOR=blue]enum[/COLOR] [COLOR=#2B91AF]Triggers[/COLOR][/FONT]
    13.   [FONT=Consolas]  {[/FONT]
    14.   [FONT=Consolas]    Initialise,[/FONT]
    15.   [FONT=Consolas]    ReadData,[/FONT]
    16.   [FONT=Consolas]    Shutdown,[/FONT]
    17.   [FONT=Consolas]    Unplugged,[/FONT]
    18.   [FONT=Consolas]    StartOver,[/FONT]
    19.   [FONT=Consolas]    FailInitialisation[/FONT]
    20.   [FONT=Consolas]  }[/FONT]
    21.  
    22.   [FONT=Consolas]  [COLOR=blue]protected[/COLOR] [COLOR=#2B91AF]StateMachine[/COLOR]<[COLOR=#2B91AF]States[/COLOR], [COLOR=#2B91AF]Triggers[/COLOR]> m_stateMachine;[/FONT]
    23.  
    24.  
    25.   [FONT=Consolas]  // set up our state machine[/FONT]
    26.   [FONT=&quot]void Awake()
    27. [/FONT][FONT=&quot]{[/FONT]
    28.   [FONT=&quot]    // no such problem with making a generic class now[/FONT]
    29.   [FONT=Consolas]    m_stateMachine = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]StateMachine[/COLOR]<[COLOR=#2B91AF]States[/COLOR], [COLOR=#2B91AF]Triggers[/COLOR]>([COLOR=#2B91AF]States[/COLOR].Uninitialised);[/FONT]
    30.  
    31.   [FONT=Consolas]    m_stateMachine.Configure([COLOR=#2B91AF]States[/COLOR].Uninitialised)[/FONT]
    32.   [FONT=Consolas]      .PermitReentry([COLOR=#2B91AF]Triggers[/COLOR].Shutdown)[/FONT]
    33.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].Initialise, [COLOR=#2B91AF]States[/COLOR].Initialising);[/FONT]
    34.  
    35.   [FONT=Consolas]    m_stateMachine.Configure([COLOR=#2B91AF]States[/COLOR].Initialising)[/FONT]
    36.   [FONT=Consolas]      .OnEntry(() => StateEntry_Initialising())[/FONT]
    37.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].FailInitialisation, [COLOR=#2B91AF]States[/COLOR].Reinitialise)[/FONT]
    38.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].Shutdown, [COLOR=#2B91AF]States[/COLOR].ShuttingDown)[/FONT]
    39.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].ReadData, [COLOR=#2B91AF]States[/COLOR].Reading);[/FONT]
    40.  
    41.   [FONT=Consolas]    m_stateMachine.Configure([COLOR=#2B91AF]States[/COLOR].Reinitialise)[/FONT]
    42.   [FONT=Consolas]      .OnEntry(() => StateEntry_Reinitialise())[/FONT]
    43.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].Shutdown, [COLOR=#2B91AF]States[/COLOR].ShuttingDown)[/FONT]
    44.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].Initialise, [COLOR=#2B91AF]States[/COLOR].Initialising);[/FONT]
    45.  
    46.   [FONT=Consolas]    m_stateMachine.Configure([COLOR=#2B91AF]States[/COLOR].Reading)[/FONT]
    47.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].Shutdown, [COLOR=#2B91AF]States[/COLOR].ShuttingDown)[/FONT]
    48.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].Unplugged, [COLOR=#2B91AF]States[/COLOR].Reinitialise);[/FONT]
    49.  
    50.   [FONT=Consolas]    m_stateMachine.Configure([COLOR=#2B91AF]States[/COLOR].ShuttingDown)[/FONT]
    51.   [FONT=Consolas]      .OnEntry(() => StateEntry_ShuttingDown())[/FONT]
    52.   [FONT=Consolas]      .Permit([COLOR=#2B91AF]Triggers[/COLOR].StartOver, [COLOR=#2B91AF]States[/COLOR].Uninitialised);[/FONT]
    53.  
    54.   [FONT=&quot]}[/FONT]
    55.  
    56.   [FONT=&quot]  protected void StateEntry_Initialising()[/FONT]
    57.   [FONT=&quot]  {[/FONT]
    58.   [FONT=&quot]    // initialiise the sensor device upon state entry[/FONT]
    59.   [FONT=&quot]  }[/FONT]
    60.  
    61.   [FONT=&quot]  void StateEntry_ReInitialise()[/FONT]
    62.   [FONT=&quot]  {[/FONT]
    63.   [FONT=&quot]    // reinitialise the sensor device upon state entry[/FONT]
    64.   [FONT=&quot]  }[/FONT]
    65.  
    66.   [FONT=&quot]  void StateEntry_ShuttingDown()[/FONT]
    67.   [FONT=&quot]  {[/FONT]
    68.   [FONT=&quot]    // shut down the sensor device[/FONT]
    69.   [FONT=&quot]  }[/FONT]
    70.  
    71.   [FONT=&quot]  // let's make some functions to expose just those bits of our state machine we want to show to the rest of the world[/FONT]
    72.   [FONT=&quot]  public void InitialiseSensor()[/FONT]
    73.   [FONT=&quot]  {[/FONT]
    74.   [FONT=Consolas]    m_stateMachine.Fire([COLOR=#2B91AF]Triggers[/COLOR].Initialise);[/FONT]
    75.   [FONT=Consolas]  }[/FONT]
    76.  
    77.   [FONT=&quot]  public void ShutdownSensor()[/FONT]
    78.   [FONT=&quot]  {[/FONT]
    79.   [FONT=Consolas]    m_stateMachine.Fire([COLOR=#2B91AF]Triggers[/COLOR].Shutdown);[/FONT]
    80.   [FONT=Consolas]  }[/FONT]
    81.  
    82.   [FONT=&quot]// and some basic code to interact with the state machine[/FONT]
    83.   [FONT=&quot]public class UserInterface : MonoBehaviour[/FONT]
    84.   [FONT=&quot]{[/FONT]
    85.   [FONT=&quot]  void OnGUI()[/FONT]
    86.   [FONT=&quot]  {[/FONT]
    87.   [FONT=&quot]    if (GUI.Button(new Rect(25, 25, 200, 50), "Initialise") == true)[/FONT]
    88.   [FONT=&quot]    {[/FONT]
    89.   [FONT=&quot]      SensorDevice device = GetComponent<SensorDevice>();[/FONT]
    90.   [FONT=&quot]      device.InitialiseSensor();[/FONT]
    91.   [FONT=&quot]    }[/FONT]
    92.  
    93.   [FONT=&quot]    if (GUI.Button(new Rect(25, 100, 200, 50), "Shutdown") == true)[/FONT]
    94.   [FONT=&quot]    {[/FONT]
    95.   [FONT=&quot]      SensorDevice device = GetComponent<SensorDevice>();[/FONT]
    96.   [FONT=&quot]      device.ShutdownSensor();[/FONT]
    97.   [FONT=&quot]    }[/FONT]
    98.   [FONT=&quot]  }[/FONT]
    99.   [FONT=&quot]}[/FONT]
    The empirical difference between the two architectural approaches is one of encapsulation. Is-a is the subsumption of the inherited class, it is a specialization of a more generic abstraction, e.g. Granny Smith (very specific) is-a Apple (specific) is-a Fruit (generic) is-a Food (very generic) is-a Object (very, very generic). In .NET but not in C++, you can only usually be, i.e. is-a, one particular type of object at any particular level of inheritance, though of course, interfaces to a degree can further generalize or make a narrower specificity through their own definitions, but interfaces do not provide concrete behaviour, only a behavioural contract, vis C++ and multiple inheritance.

    By which point in time, most non-programmers' eyes have glazed over and they are thinking:
    Name:  mother_of_god.jpg
Views: 449
Size:  43.0 KB

    On the opposite, has-a is a composition, where one object belongs to another object, Orchard has-a Apple Tree (many trees probably) has-a Apple (many apples on the tree), but the Orchard can also has-a Orange Citrus Tree has-a Orange (many oranges).

    The architectural choices between is-a and has-a can often be subtle and the art is knowing in which case you should use each technique and there is actually a lot of overlap between choosing either option which then becomes a series of trade-offs. General rule of thumb is "expose as little as possible, minimise your code."

    Unity, as stated, throws in its own little wrinkle because of the way object construction is done, making it difficult to make generic MonoBehaviours.

    I think I did a pretty good job of explaining all that!
    Name:  fuck_yeah.jpg
Views: 437
Size:  35.8 KB
    Last edited by JustinLloyd; 11-08-2011 at 01:44 AM.


  13. Location
    California
    Posts
    1,657
    Has-a and is-a: making programmers speak like a LOLCAT

    Name:  fhc6wm6l.jpg
Views: 588
Size:  78.2 KB
    But I have many flavours!


    Name:  c9ave6jo.jpg
Views: 664
Size:  62.5 KB
    But I can only ever be ten ninjas, but sometimes I can have an interface or two that changes me in to a special kind of killer ninja with a contract.

    Let me know if anything needs clarification


    Name:  y_u_no_let.jpg
Views: 422
Size:  42.7 KB
    Last edited by JustinLloyd; 11-08-2011 at 01:44 AM.


  14. Location
    California
    Posts
    1,657
    Of course, C++ makes the whole is-a and has-a choice a little fuzzier because of the multiple inheritance ability.

    Name:  u_jelly.jpg
Views: 513
Size:  94.7 KB


  15. Location
    USA
    Posts
    2,532
    I can't believe I've had to do this twice in one week...



  16. Location
    Ontario, Canada
    Posts
    51
    Wow, Justin, I certainly never expected such a detailed response. Regardless, I think you did a great job of explaining it and, yes, I followed it completely.



    Thanks again.

    Will


  17. Posts
    298
    This is probably one of the greatest posts I have read on these forums.

    Unity Forums:
    Y U NO LET ME +1 JUSTIN!?!?!1!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •