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

Question Initializing variables in class's constructor or in class's method

Discussion in 'Scripting' started by CaringKarol, Dec 26, 2022.

  1. CaringKarol

    CaringKarol

    Joined:
    Jan 22, 2018
    Posts:
    28
    I have an abstract class called State that contains a Start() IEnumerator(). Start() runs once immediately after the state machine switches states. Some of my classes that inherit from State contain private variables that need to be initialized immediately after the class is created. I was wondering if it'd be better to initialize those variables inside the class's constructor or initialize those variables in Start().

    Below are two examples that roughly illustrate what I'm asking:

    Code (CSharp):
    1.  
    2. public class SomeState() : State
    3. {
    4. private Rigidbody2D rb;
    5. private bool isFacingRight;
    6.  
    7. public SomeState()
    8. {
    9.       rb = GetComponent<Rigidbody2D>();
    10.       isFacingRight = true;
    11. }
    12.  
    13. public override IEnumerator Start()
    14. {
    15.        //Blah
    16. }
    17. }
    Code (CSharp):
    1.  
    2. public class SomeState() : State
    3. {
    4. private Rigidbody2D rb;
    5. private bool isFacingRight;
    6.  
    7. public SomeState()
    8. {
    9.       //Blah
    10. }
    11.  
    12. public override IEnumerator Start()
    13. {
    14.      rb = GetComponent<Rigidbody2D>();
    15.      isFacingRight = true;
    16.      yield break;
    17. }
    18. }
    Thanks!
     
    Last edited: Dec 26, 2022
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,963
    If
    State
    derives from MonoBehaviour then there is no choice: you may not use constructors for MonoBehaviours. The closest analogy would be Awake()

    If this is your own object then how you do it is really entirely up to you and how you think of the lifetime / lifecycle of these things and who is in charge of owning them.

    In any case, as it APPEARS you are attempting some kind of generic FSM, let me offer this advice:

    This is my position on finite state machines (FSMs) and coding with them:

    https://forum.unity.com/threads/state-machine-help.1080983/#post-6970016

    I'm kind of more of a "get it working first" guy.

    Ask yourself, "WHY would I use FSM solution XYZ when I just need a variable and a switch statement?"

    All generic FSM solutions I have seen do not actually improve the problem space.

    Your mileage may vary.

    "I strongly suggest to make it as simple as possible. No classes, no interfaces, no needless OOP." - Zajoman on the Unity3D forums.

    I also suggest never using the term "state machine." Instead, just think:

    - I have to keep track of some THING(s)
    - That THING might change due to reasons
    - Depending on that THING, my code might act differently

    That's it. That's all it is. Really!! The classic example is a door:

    - track if it is open or closed
    - if it is open, you could close it
    - if it is closed, you could open it
    - if it is open you could walk through it
    - if it is closed you could bump into it

    Wanna make it more complex? Put a latch on one side of the door.
     
  3. CaringKarol

    CaringKarol

    Joined:
    Jan 22, 2018
    Posts:
    28
    Thank you for answering my question. And thank you for your advice! It's changed how I'll be thinking as I continue with my project.
     
  4. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    I'll add some details with respect to the original question:

    You can use constructors in Monobehaviours and ScriptableObjects, in case your State class inherits from them. Unity will try to call a parameterless constructor for your class if it's available. You can also take advantage of this to initialize fields where they are defined. I use it, for example, to make sure a particular field can never be null, even if it doesn't get initialized in other place for some reason. It's also useful for initializing readonly fields.

    That said, sometimes constructors can be called outside of the main thread. For example, Unity creates Monobehaviours and ScriptableObjects in a parallel thread in many cases. Most of the unity API doesn't work outside the main thread, things like GetComponent. So, often, you're better off using things like Awake and OnEnable.

    Now, no matter what kind of objects your states are, I think sometimes it's better to initialize their private fields only once in their lifetime and sometimes it's better to initialize them every time they start. If you are sure the intended value for those fields will never change, it may be optimal to initialize them when they are created. But it may be better to initialize every time the state starts running if a value could change mid game (e.g. if your player starts without a Rigidbody and gets one later).
     
    Last edited: Dec 26, 2022
    Kurt-Dekker and CaringKarol like this.