C
C#2mo ago
BlandLife

Building Constructors 101

Not to familiar with C# personally but I'm using it with Unity for a project-based class I'm taking. I'm trying to build a state machine, where there's the BaseState interface and StateMachine class. In my StateMachine class I have a constructor that takes a BaseState defaultState parameter. I want it to be able to take classes that implement/inherit from the BaseState interface like IdleState or PatrolState, but I really don't have a clue how to do that.
47 Replies
BlandLife
BlandLifeOP2mo ago
The purpose would be that I can reuse the StateMachine class for different objects of my game and for the variation of states each objects have, I can set a default state is starts with for the game, so for player the default state would be the IdleState
C#
public interface BaseState
{
public abstract void Start();
public abstract void Update();
public abstract void Exit();
}
C#
public interface BaseState
{
public abstract void Start();
public abstract void Update();
public abstract void Exit();
}
C#
using UnityEngine;

public abstract class StateMachine : MonoBehaviour
{
protected BaseState currentState {get; private set;}

// References to states goes here
// e.g public IdleState idleState;

public StateMachine(BaseState defaultState) {
currentState = defaultState;
}

void Start() {
currentState.Start();
}

void Update() {
currentState?.Update();
}

public void TransitionState(BaseState nextState) {
currentState?.Exit();
currentState = nextState;
currentState.Start();
}
}
C#
using UnityEngine;

public abstract class StateMachine : MonoBehaviour
{
protected BaseState currentState {get; private set;}

// References to states goes here
// e.g public IdleState idleState;

public StateMachine(BaseState defaultState) {
currentState = defaultState;
}

void Start() {
currentState.Start();
}

void Update() {
currentState?.Update();
}

public void TransitionState(BaseState nextState) {
currentState?.Exit();
currentState = nextState;
currentState.Start();
}
}
Those are the bases
C#
public class PlayerSM : StateMachine
{
[SerializeField] private static InputActionAsset playerActions;
static PlayerIdleState idleState = new PlayerIdleState(playerActions);
public PlayerSM(BaseState defaultState) : base(PlayerIdleState idleState) {}

}
C#
public class PlayerSM : StateMachine
{
[SerializeField] private static InputActionAsset playerActions;
static PlayerIdleState idleState = new PlayerIdleState(playerActions);
public PlayerSM(BaseState defaultState) : base(PlayerIdleState idleState) {}

}
This was my example of a Player state machine that inherits from the StateMachine class
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
BlandLife
BlandLifeOP2mo ago
It doesnt acdtually work btw, but just to show what I had
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
BlandLife
BlandLifeOP2mo ago
Not really sure what would be good practice for C#, why IState, interface state?
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
BlandLife
BlandLifeOP2mo ago
Ah okay
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
BlandLife
BlandLifeOP2mo ago
I settled on interface because I dont really need to implement the functions specifically until im making specific states, but they NEED those classes and need to be written for each state, was that right?
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
BlandLife
BlandLifeOP2mo ago
Ah yeah no, I imagine each state will need all three of those methods to have their own implementation, so setting one implementation in an abstract class would be a waste, and I noticed that with the interface my IDE yells at me for not rewriting them, whereas with abstract class it was fine if I just left the class that inherits from it empty Which I appreciate
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
BlandLife
BlandLifeOP2mo ago
Thanks a lot for the help with that! A bit difficult also needing to figure out some basic C# stuff while still having time to work on other aspects of the game. Still, the main problem I was having was with the constructor for StateMachine
C#
// State machines that inherit from this should accept states that inherit from IState
public StateMachine(IState defaultState) {
currentState = defaultState;
}
C#
// State machines that inherit from this should accept states that inherit from IState
public StateMachine(IState defaultState) {
currentState = defaultState;
}
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
BlandLife
BlandLifeOP2mo ago
Oh really, I had assumed that for the abstract class the difference was that if you didn't place your own implementation it would simply use the implementation from the original
Pobiega
Pobiega2mo ago
What exactly is the problem with that constructor, except that current state doesn't exist?
BlandLife
BlandLifeOP2mo ago
Here's the uh original implementation of a PlayerSM that inherits from StateMachine, before I changed BaseState to IState Not sure if the constructor is even made correctly to be fair Actually, give me one moment to mess around with this before I clarify So i have the StateMachine constructor, and then I want my PlayerSM, and any other state machines that inherit from StateMachine to implement the same constructor, where I pass into defaultState the state that should be default for that state machine, so for a player they should start off as idle, so IdleState, or an enemy default state might be a PatrolState, all of which inherit from IState I'm having troubles translating that idea into actual code rip
Pobiega
Pobiega2mo ago
Constructor inheritance is done via : base(...)
BlandLife
BlandLifeOP2mo ago
Oh I dont need to declare the uh, type do I base(PlayerIdleState idleState) wouldn't work would it
Pobiega
Pobiega2mo ago
No You don't specify the type It specified by the new constructor And has to match the bae constructors requirements
BlandLife
BlandLifeOP2mo ago
so I can make it like this?
C#
public PlayerSM(IState defaultState) : base(idleState) {}
C#
public PlayerSM(IState defaultState) : base(idleState) {}
Pobiega
Pobiega2mo ago
Sorry for shit typing, on the bus and the driver found their license in a cereal packet :p
BlandLife
BlandLifeOP2mo ago
It's all good, I usually have to edit my messages even without the detriments to my own typing lol
Pobiega
Pobiega2mo ago
Well, if idleState is a valid instance at that timr But I can't see how that is
BlandLife
BlandLifeOP2mo ago
I already have it on a previous line static PlayerIdleState idleState = new PlayerIdleState(playerActions); does it need to be static for me to pass it in/
Pobiega
Pobiega2mo ago
Ah
BlandLife
BlandLifeOP2mo ago
? I remember it yelling at me earlier for passing in a non-static field, method, etc.
Pobiega
Pobiega2mo ago
Static means it's associated with the type instead of an instance So it means all players share the same state
BlandLife
BlandLifeOP2mo ago
Ah yes, i think that's generally true Alright thanks, that seems to have gotten it working alright
Pobiega
Pobiega2mo ago
It's prob fine for player But might cause some interesting bugs if you have multiple instances of a given SM
BlandLife
BlandLifeOP2mo ago
I still never did figure out, so for abstract class implementations if I have a class that inherits from it but don't make/override one it's methods it'll just default to the parent's implementation yes? Ah rip, so for numerous enemies it might be an issue? So like, if one enemy goes to patrol state all will?
Pobiega
Pobiega2mo ago
Yes, if your state instance is static
BlandLife
BlandLifeOP2mo ago
rip
Pobiega
Pobiega2mo ago
No, but all enemies in the same state have the same variables Like let's say that your idle state for a monster contains a timer When it reaches 10 the monster enters A search state All your monsters will enter search at the same time Since they share one timer
BlandLife
BlandLifeOP2mo ago
Sounds cool for some mechanic tbh, but yes I can see how generally that'd be a problem LOL
Pobiega
Pobiega2mo ago
Haha yep Easily fixed thou Just remove the static keyword
BlandLife
BlandLifeOP2mo ago
An object reference is required for the non-static field, method, or property 'PlayerSM.idleState'
Pobiega
Pobiega2mo ago
Yeah that sounds roght
BlandLife
BlandLifeOP2mo ago
Keep getting that message when I remove static uh here's the whole file btw
C#
public class PlayerSM : StateMachine
{
[SerializeField] private static InputActionAsset playerActions;
PlayerIdleState idleState = new PlayerIdleState(playerActions);
public PlayerSM(IState defaultState) : base(idleState) {}

}
C#
public class PlayerSM : StateMachine
{
[SerializeField] private static InputActionAsset playerActions;
PlayerIdleState idleState = new PlayerIdleState(playerActions);
public PlayerSM(IState defaultState) : base(idleState) {}

}
Pobiega
Pobiega2mo ago
$paste
MODiX
MODiX2mo ago
If your code is too long, you can post to https://paste.mod.gg/, save, and copy the link into chat for others to see your shared code!
Pobiega
Pobiega2mo ago
Oh that's short
BlandLife
BlandLifeOP2mo ago
Ye real short lol Was doing small stuff to get it generally working so that I can build up the actual state machines after
Pobiega
Pobiega2mo ago
You sure that error is from that file? Not just another place trying to refer to it?
BlandLife
BlandLifeOP2mo ago
C#
public abstract class StateMachine : MonoBehaviour
{
protected IState currentState {get; private set;}

// References to states goes here
// e.g public IdleState idleState;

public StateMachine(IState defaultState) {
currentState = defaultState;
}

void Start() {
currentState.Start();
}

void Update() {
currentState?.Update();
}

public void TransitionState(IState nextState) {
currentState?.Exit();
currentState = nextState;
currentState.Start();
}
}
C#
public abstract class StateMachine : MonoBehaviour
{
protected IState currentState {get; private set;}

// References to states goes here
// e.g public IdleState idleState;

public StateMachine(IState defaultState) {
currentState = defaultState;
}

void Start() {
currentState.Start();
}

void Update() {
currentState?.Update();
}

public void TransitionState(IState nextState) {
currentState?.Exit();
currentState = nextState;
currentState.Start();
}
}
And the statemachine it inherits from But yeah I don't seem to see any other cause for the error aside from that line in the file itself rip, it seems perfectly happy the moment I add in the static keyword I was doing all this bc I couldn't seem to just assign currentState myself in the PlayerSM
Pobiega
Pobiega2mo ago
Brb 30 min Will take a look then
BlandLife
BlandLifeOP2mo ago
C#
public class PlayerSM : StateMachine
{
[SerializeField] private static InputActionAsset playerActions;
static PlayerIdleState idleState = new PlayerIdleState(playerActions);
This.currentState = idleState; // couldn't write any line like this
PlayerSM.currentState = idleState; // or this, since neither exist in the current context, or so it says
public PlayerSM(IState defaultState) : base(idleState) {}

}
C#
public class PlayerSM : StateMachine
{
[SerializeField] private static InputActionAsset playerActions;
static PlayerIdleState idleState = new PlayerIdleState(playerActions);
This.currentState = idleState; // couldn't write any line like this
PlayerSM.currentState = idleState; // or this, since neither exist in the current context, or so it says
public PlayerSM(IState defaultState) : base(idleState) {}

}
All good all good, thanks for the help I think i got it where I want it So I just did away with the constructor in the StateMachine class
C#
using UnityEngine;

public abstract class StateMachine : MonoBehaviour
{
protected IState currentState {get; set;}

void Start() {
currentState.Start();
}

void Update() {
currentState?.Update();
}

public void TransitionState(IState nextState) {
currentState?.Exit();
currentState = nextState;
currentState.Start();
}
}
C#
using UnityEngine;

public abstract class StateMachine : MonoBehaviour
{
protected IState currentState {get; set;}

void Start() {
currentState.Start();
}

void Update() {
currentState?.Update();
}

public void TransitionState(IState nextState) {
currentState?.Exit();
currentState = nextState;
currentState.Start();
}
}
For each class that inherits from StateMachine I'll just make a constructor and assign to the currentState there, like so:
C#
public class PlayerSM : StateMachine
{
// [SerializeField] private static InputActionAsset playerActions;
PlayerIdleState idleState;
public PlayerSM() {
idleState = new PlayerIdleState(this);
currentState = idleState;
}

}
C#
public class PlayerSM : StateMachine
{
// [SerializeField] private static InputActionAsset playerActions;
PlayerIdleState idleState;
public PlayerSM() {
idleState = new PlayerIdleState(this);
currentState = idleState;
}

}
Want results from more Discord servers?
Add your server