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. Dismiss Notice

Question Inherited class issues for a state machine

Discussion in 'Scripting' started by abeck12390, Aug 13, 2023.

  1. abeck12390

    abeck12390

    Joined:
    Apr 12, 2023
    Posts:
    3
    I am having trouble with inheritance and I am not sure how to fix it. Sorry I am new to C# and unity and this is my first time posting. I am making a state machine for entities in my game and I have 4 classes. First the base entity controller monobehaviour class and the base entity state class. And then for example a player controller class and player state class that inherit from them. Since each state needs access to the controller I pass the controller to the state in the constructor of the base state class.
    Code (CSharp):
    1.  
    2. public abstract class Entity : MonoBehaviour
    3. {
    4. // Entity base class logic
    5. }
    6.  
    Code (CSharp):
    1.  
    2. public abstract class EntityState
    3. {
    4. protected Entity entity;
    5. public EntityState(Entity entity)
    6. {
    7. this.entity = entity;
    8. }
    9. }
    10.  
    Lets say the player class has access to data like move speed for example
    Code (CSharp):
    1.  
    2. public class Player : Entity
    3. {
    4. private float moveSpeed = 5f;
    5. private PlayerState someState = new PlayerState(this);
    6. }
    7.  
    Code (CSharp):
    1.  
    2. public class PlayerState : EntityState
    3. {
    4. public PlayerState(Entity entity) : base(entity) {}
    5.  
    6. public void DoSomething() { Debug.Log(entity.moveSpeed); }
    7. }
    8.  
    My issue is that I am getting errors when trying to access variables from the player class. I am getting errors like Entity does not have moveSpeed and entity.moveSpeed doesnt exist. I thought this wouldnt happen because Player is a child of Entity. I thought this was happening because PlayerState is storing Player as an Entity and not a player and since Entity doesnt have a variable named moveSpeed I am getting an error. I tried using entity.GetType() to see if the type of entity is Player and it is. So I am not sure what the issue is. I cant keep information like moveSpeed in the entity class because it will be use for many other entities.

    I'm sorry if this is not understandable I can try to elaborate more if needed.
    Thanks for any help!
     
    Last edited: Aug 13, 2023
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,561
    FSM finite state machines:

    I 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.

    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.
     
  3. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    If using Inheritance, the parent class should contain all the variables the child class is using:
    Code (CSharp):
    1. public class Characters : // parent/monoBehaviour
    2. {
    3.    public float speed;
    4.  
    5.    public void FindStuff() { // stuff }
    6. }
    Then the child class can easily call or set it's variables from that:
    Code (CSharp):
    1. public class Player : Characters
    2. {
    3.    void Awake()
    4.    {
    5.       speed = 10.1f;
    6.       FindStuff();
    7.    }
    8. }
    This is assuming you want to use parent classes to group children, for example calling a function that would handle things for any type of sub-class(player, enemies, etc...). Which is a great way to use Inheritance.

    But I'm not exactly sure what your goal is, for wanting Inheritance, in this particular case?
     
  4. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,111
    You are on the right track with this idea though you will have to educate yourself on how TYPES and INHERITANCE / POLYMORPHISM works. The object at runtime is a Player but it is stored in a member of type Entity and thus you can not use it like a Player. You could use a TYPE CAST to overcome this. However, this is not very elegant and you may run into performance issues (BOXING).
     
  5. TheNullReference

    TheNullReference

    Joined:
    Nov 30, 2018
    Posts:
    222
    Just remember that children can know about parents but parents don't know about children. The reason Entity doesn't have a moveSpeed field is because it has no knowledge of the child Player.

    You would need to add the field to the Entity class

    Code (csharp):
    1.  
    2. public class Entity
    3. {
    4.     protected float moveSpeed = 5f;
    5. }
    6.  
    This means that every child of Entity will have a move speed, which might not be ideal.

    You could cast your Entity to Player

    Code (csharp):
    1.  
    2. public class PlayerState : EntityState
    3. {
    4. public PlayerState(Entity entity) : base(entity) {}
    5.  
    6. public void DoSomething() { Debug.Log((Entity as Player).moveSpeed); }
    7. }
    8.  
    but that is also quite ugly. Personally I would probably use a different architecture and use interfaces instead (composition over inheritance).

    Code (csharp):
    1.  
    2. public class Player : IMovable
    3. {
    4.     public float MoveSpeed {get; private set;}
    5. }
    6.  
     
    Bunny83 likes this.
  6. abeck12390

    abeck12390

    Joined:
    Apr 12, 2023
    Posts:
    3
    Ahh that makes sense. Thank you!