digitalmars.D.learn - Base class with member parameterized on type of extending class
- rcor (40/40) Oct 19 2014 I'm trying to make a game, and would like to set up the following
- Jacob Carlborg (10/47) Oct 19 2014 You can always make Scene a template class:
- rcor (7/14) Oct 20 2014 I would, as I need to keep track of the current scene in a
- Jacob Carlborg (24/30) Oct 20 2014 If the state machine doesn't need to be exposed you can create base
- rcor (12/38) Oct 20 2014 Just came up with something similar before I saw this post:
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.
Oct 19 2014
On 2014-10-19 13:19, rcor wrote: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.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
Oct 19 2014
On Monday, 20 October 2014 at 06:17:42 UTC, Jacob Carlborg wrote: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.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.)
Oct 20 2014
On 2014-10-20 12:27, rcor wrote:I would, as I need to keep track of the current scene in a variable somewhere: Scene _currentScene; // problematic if Scene is a templateIf 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
Oct 20 2014
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.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.Interesting idea, I might give this a try but the first suggestion seems fine for now. Thanks!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)); }
Oct 20 2014