That’s actually about right.
The State and StateMachine classes are abstractions (quite literally marked abstract, they can’t be created directly). We inherit from these classes for the unique functionality that is required. Rather than having both PlayerStateMachine and EnemyStateMachine handle the life cycle methods and switching, we let the abstract parent state handle these things.
So our StateMachine maintains a variable currentState that holds the current State that the StateMachine is running. Any class that inherits from State can go here.
PlayerTestState inherits from PlayerBaseState
PlayerBaseState inherits from State. Therefore, currentState can be a PlayerTestingState (or more useful as we go along, any of the many other states we’ll be creating throughout the course).
In the converse, the PlayerBaseState is hanging on to a reference to the StateMachine that owns it. Since we know that Player states will only be used within a PlayerStateMachine, we can use the PlayerStateMachine type as our reference. This allows us access to the public variables in the PlayerStateMachine.