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

Best approach on enums and classes

Discussion in 'Scripting' started by Zukas, May 13, 2015.

  1. Zukas

    Zukas

    Joined:
    Dec 17, 2013
    Posts:
    40
    I'm making class which would hold info for possible action, it looks like this so far.
    Code (CSharp):
    1. public enum ActionType{Trade, Quest, Rest, Work}
    2.     public class Action
    3.     {
    4.         ActionType actionType;
    5.         string actionName;
    6.         string actionDescription;
    7.     }
    Thing is, I want to have each ActionType to have it's own exclusive variables that wont be needed for other ActionTypes, but I don't want to stuff all of them into one class as it will get messy over time. Is there any possible way I might not be aware of, or just how you'd personally do it to keep it as organized as possible? My scripts tend to get really messy later on in projects.
     
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Make each action it's own class that inherits from Action

    Code (csharp):
    1.  
    2. public abstract class Action
    3. {
    4.     public string Name { get; protected set; }
    5. }
    6.  
    7. public class Trade : Action
    8. {
    9.  
    10. }
    11.  
    12. public class Quest : Action
    13. {
    14.  
    15. }
    16.  
     
    Kiwasi and Zukas like this.
  3. Zukas

    Zukas

    Joined:
    Dec 17, 2013
    Posts:
    40
    Guess I'll have to read about inheritence, thanks!
     
  4. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    If you plan to have a gazillion of these you may think about scalability vs performance as well...
    If you're going to be creating and destroying them a lot you may think about using a struct instead of a class so it will be a value type and not allocate on the heap, however you lose the ability to do inheritance.
     
  5. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    If you're just talking about properties, it might be worthwhile to look at Interfaces as well. Rather than inherit, you can implement the interface. You can also implement multiple interfaces (but not inherit multiple classes). This would allow you to mix and match.
     
  6. Zukas

    Zukas

    Joined:
    Dec 17, 2013
    Posts:
    40
    Thanks for the input, looked into interfaces aswell, but they wont need any mixing and matching so I believe I wont need them. Though I see where I can possibly use them in future, will truly come in handy!
     
  7. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Sure thing. The thing to keep in mind is this:

    BaseClass -> ChildClass
    ** ChildClass will always be of type BaseClass and share functionality

    Interface -> Class
    ** Class will implement the members in Interface and the functionality is always up to me.

    So, the base class allows you to code once and reuse, while the interface essentially defines a contract. Here's a scenario where this might be useful:

    Code (csharp):
    1.  
    2. interface IEnvironmentObject
    3. {
    4.   //This doesn't have anything, it's a marker (explained later)
    5. }
    6.  
    7. interface IInteractive
    8. {
    9.    void Action();
    10. }
    11.  
    12. interface IDestructible
    13. {
    14.    void Destroy();
    15. }
    16.  
    Now consider the following scenarios:

    Code (csharp):
    1.  
    2. public class ClassA : IEnvironmentObject, IInteractive
    3. ...
    4.  
    ClassA will always have an Action method and something can be done with it

    Code (csharp):
    1.  
    2. public class ClassB : IEnvironmentObject, IDestructible
    3. ...
    4.  
    ClassB is IDestructible and will always have a Destroy method.

    Code (csharp):
    1.  
    2. public class ClassC : IEnvironmentObject, IInteractive, IDestructible
    3. ...
    4.  
    Class C is both IInteractive and IDestructible. It will have both Action and Destroy methods.

    Also as a quick note, you can use both inheritance and implementation. If your base class implements interfaces, the child classes will get them too. Your child classes can inherit a base class and implement an interface giving it the base functionality AND the additional contracts.

    Now consider the following for where this is useful:

    Code (csharp):
    1.  
    2. var envObjects = new List<IEnvironmentObject>();
    3.  
    4. envObjects.Add(new ClassA());
    5. envObjects.Add(new ClassB());
    6. envObjects.Add(new ClassC());
    7.  
    8. foreach(var obj in envObjects)
    9. {
    10.    if(obj is IInteractive)
    11.    {
    12.         (obj as IInteractive).Action();
    13.    }
    14.  
    15.    if(obj is IDestructible)
    16.    {
    17.         (obj as IDestructible).Destroy();
    18.    }
    19. }
    20.  
    So, we used IEnvironmentObject as a marker interface... this allowed us to put all of those classes in a single list. Then we looped through every class in the list. If the class implements IInteractive, we cast it to IInteractive and call the Action method. If it's IDestructible, we cast it to IDestructible and call the Destroy method.

    The result is:
    envObjects[0] is a ClassA instance - Action exists and gets called.
    envObjects[1] is a ClassB instance - Destroy exists and gets called.
    envObjects[2] is a ClassC instance - Action and Destroy both get called.

    The usefulness of the Interface approach is that you can essentially add attributes to completely unrelated objects. ClassA could be a button or switch, ClassB could define a tree and ClassC could define a psychotic mongoose. They are completely different types of objects so they don't belong in the same inheritance tree, but interfaces give them the ability to share attributes. the drawback is that you have to code Action and Destroy individually for each of those classes but in many cases that's probably desirable as they will behave differently.
     
    Zukas likes this.
  8. Zukas

    Zukas

    Joined:
    Dec 17, 2013
    Posts:
    40
    Another door of endless coding possibilities opens for me, thanks! The example you gave me finally made some cogs in my head turn on why I should use interface.

    So, I believe in my case, it would better be to make multiple classes for each type of action, and just implement IAction interface. Then I can store all these actions in list of IAction variables.. I'll try to fiddle around with it and let you know how it goes.
     
  9. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Sure. :). I wasn't trying to convince you one way or the other, just showing you some options and differences. Use whichever route makes the most sense for your code :)
     
  10. Zukas

    Zukas

    Joined:
    Dec 17, 2013
    Posts:
    40
    I know, but this now seems way better and I feel bad for not using this previously, it's really good functionality. Thanks once again!
     
    Dustin-Horne likes this.