Discussion:
Base class with member parameterized on type of extending class
rcor via Digitalmars-d-learn
2014-10-19 11:19:37 UTC
Permalink
I'm trying to make a game, and would like to set up the following
hierarchy:
At any time, the game is in one Scene. Each scene has a state
machine that manages States of type T, where T is the type of the
scene (e.g. Overworld, Menu).

abstract class State!T {
void update(T scene, float time, InputManager input);
...
}

class StateMachine!T { //manages states of type State!T }

abstract class Scene {
alias T = // type of class extending Scene
// methods pushState, popState, currentState access
_stateMachine
private StateMachine!T _stateMachine;
}

class MainMenu : Scene {
// I want _stateMachine of type StateMachine!MainMenu
}

class Overworld : Scene {
// I want _stateMachine of type StateMachine!Overworld
}

class MoveToLocation : State!Overworld {
override void update(Overworld world, float time, InputManager
input) {
// access properties of Overworld here
}
}

Within the Scene class, I've tried alias T = typeof(this), but
that appears to be resolved within Scene. This means that any
Scene, such as Overworld, have a state machine of type
StateMachine!Scene rather than StateMachine!Overworld. Since
States are particular to a certain scene and are designed to
manipulate properties specific to that type of scene, this would
involve a lot of casting if States are not parameterized. It
feels like I need something like a class version of the (this T)
syntax used in templates.

This all smells a bit off though, so I wouldn't be surprised if
the answer is that I'm approaching this all wrong, but right now
I'm not seeing it.
Jacob Carlborg via Digitalmars-d-learn
2014-10-20 06:17:42 UTC
Permalink
Post by rcor via Digitalmars-d-learn
I'm trying to make a game, and would like to set up the following
At any time, the game is in one Scene. Each scene has a state machine
that manages States of type T, where T is the type of the scene (e.g.
Overworld, Menu).
abstract class State!T {
void update(T scene, float time, InputManager input);
...
}
class StateMachine!T { //manages states of type State!T }
abstract class Scene {
alias T = // type of class extending Scene
// methods pushState, popState, currentState access _stateMachine
private StateMachine!T _stateMachine;
}
class MainMenu : Scene {
// I want _stateMachine of type StateMachine!MainMenu
}
class Overworld : Scene {
// I want _stateMachine of type StateMachine!Overworld
}
class MoveToLocation : State!Overworld {
override void update(Overworld world, float time, InputManager input) {
// access properties of Overworld here
}
}
Within the Scene class, I've tried alias T = typeof(this), but that
appears to be resolved within Scene. This means that any Scene, such as
Overworld, have a state machine of type StateMachine!Scene rather than
StateMachine!Overworld. Since States are particular to a certain scene
and are designed to manipulate properties specific to that type of
scene, this would involve a lot of casting if States are not
parameterized. It feels like I need something like a class version of
the (this T) syntax used in templates.
This all smells a bit off though, so I wouldn't be surprised if the
answer is that I'm approaching this all wrong, but right now I'm not
seeing it.
You can always make Scene a template class:

abstract class Scene (T)
{
private StateMachine!T _stateMachine;
}

class MainMenu : Scene!(MainMenu) {}

But I'm guessing you like to avoid that if possible.
--
/Jacob Carlborg
rcor via Digitalmars-d-learn
2014-10-20 10:27:50 UTC
Permalink
Post by Jacob Carlborg via Digitalmars-d-learn
abstract class Scene (T)
{
private StateMachine!T _stateMachine;
}
class MainMenu : Scene!(MainMenu) {}
But I'm guessing you like to avoid that if possible.
I would, as I need to keep track of the current scene in a
variable somewhere:

Scene _currentScene; // problematic if Scene is a template

I could just declare the StateMachine separately in every Scene,
but that seems like a lot of duplicate code (I then repeat the
same code for updating the state machine, ect.)
Jacob Carlborg via Digitalmars-d-learn
2014-10-20 11:24:05 UTC
Permalink
I would, as I need to keep track of the current scene in a variable
Scene _currentScene; // problematic if Scene is a template
If the state machine doesn't need to be exposed you can create base
class for Scene which is not templated:

abstract class Scene {} // As it is now minus the state machine

abstract class ConcreteScene (T) : Scene
{
private StateMachine!T _stateMachine;

// other code that need access to _stateMachine
}

class MainMenu : ConcreteScene!(MainMenu) {}

Scene _currentScene = new MainMenu;

"ConcreteScene" might not be the best name of an abstract class.
I could just declare the StateMachine separately in every Scene, but
that seems like a lot of duplicate code (I then repeat the same code for
updating the state machine, ect.)
Or you could use a template mixin:

template StateMachineMixin (T)
{
private StateMachine!T _stateMachine;

// other code that need access to _stateMachine
}

class MainMenu : Scene
{
mixin StateMachineMixin!(typeof(this));
}
--
/Jacob Carlborg
rcor via Digitalmars-d-learn
2014-10-20 11:54:06 UTC
Permalink
Post by Jacob Carlborg via Digitalmars-d-learn
If the state machine doesn't need to be exposed you can create
abstract class Scene {} // As it is now minus the state machine
abstract class ConcreteScene (T) : Scene
{
private StateMachine!T _stateMachine;
// other code that need access to _stateMachine
}
class MainMenu : ConcreteScene!(MainMenu) {}
Scene _currentScene = new MainMenu;
"ConcreteScene" might not be the best name of an abstract class.
Just came up with something similar before I saw this post:

interface IScene { // enter, exit, update, draw }
class Scene!T : IScene {
private StateMachine!T _stateMachine;
void update(float time) {
_stateMachine.update(cast(T) this, time);
}
}
The cast is unfortunate but since it only happens once per update
cycle I'm not that worried about it.
Post by Jacob Carlborg via Digitalmars-d-learn
Post by rcor via Digitalmars-d-learn
I could just declare the StateMachine separately in every
Scene, but
that seems like a lot of duplicate code (I then repeat the
same code for
updating the state machine, ect.)
template StateMachineMixin (T)
{
private StateMachine!T _stateMachine;
// other code that need access to _stateMachine
}
class MainMenu : Scene
{
mixin StateMachineMixin!(typeof(this));
}
Interesting idea, I might give this a try but the first
suggestion seems fine for now. Thanks!

Loading...