Once again, thank you for your help, and for putting up with my ignorance-- I'm not very familiar with naming conventions or many common programming practices, but you have helped me learn and pick some of them up. Thank you for setting time aside to respond to my comments, despite your impressively crowded résumé. (: I feel like I'm getting very close to having a new game engine up and running. So far yours is the only tutorial I could find detailing a state-driven kind of engine; all the others I found used singletons. Please put up with me for a little longer, and feel free to tell me exactly where I've screwed up or if I'm using any words wrong.
From what I've read of this, this is what I gather:
- CGame is the game manager. It directs the objects that manipulate the game's resources, such as Graphics, Sound, and Input managers.
- These would supposedly be in class objects owned by a CGame object (CMyGame), accessible by functions defined for CGame.
- CGame doesn't own any CGameState objects-- it owns a StateMachine, which manages the Game States much like the Sound or Graphics managers manage their components.
- CStateFactory is a simple class that creates an object that derives from the virtual base class CGameState (CMainMenu, CGameplay, CPauseScreen, etc.), and returns a pointer to the new object's location for the CStateMachine object to manage.
- CGame calls whatever function that drives the game forward at every iteration through the game loop, which should not contain any game logic such as collisions, whether or not the player is dead, whether or not the room has changed, etc. etc.
- This would supposedly be in, say, CGame's Run() function, which calls the Tick() function of CStateMachine, which would call the Tick() and Draw() function of whatever class derives from CGameState, where the game logic would be executed.
- A pointer to CGame is passed to every CGameState class so that game logic that happens in each CGameState class could trigger a change in states, for instance, pressing the Pause button would call CGame->SetState(gsPause, X), the second parameter being either a simple information (level X, enemy script X) or a pointer to a more complex struct or class holding more information; possibly the player's stats, game world flags, etc.?
- This is possible because INT_PTR/UINT_PTR is a pointer typecasted to an integer, so either the literal numerical address of the pointer or a plain integer are acceptable inputs
- The CGame class would own a member object of the CGameState type, m_sNextState, which has a flag in it of whether the state needs changing or not, bSetNextState. This would be flipped to true if a state calls SetNextState from the CMyGame pointer.
- This is necessary because if the state immediately changed in the middle of whichever CGameState's Tick() function with a more consequential change, such as from a Menu state to a Gameplay state, the rest of the Tick() function wouldn't execute, which may have been important in say, deallocating Menu's resources or playing an animation or tidying up or whatever.
- The CGameState objects would contain other objects like players, enemies, buttons, etc. Only their positions, members, flags, etc. would be manipulated. The job of drawing them is up to the Graphics manager.
- The job of allocating and deleting objects used in CGameStates is up to the CGameStates.
This is all I can think of off the top of my head-- I should have outlined this better, but is this pretty much the gist of it? Please tell me if I'm close to the mark.
I also have more questions, more about the structure rather than the syntax or conventions used but also about terminology:
1) Does the flag for changing the state on the next Tick() necessarily have to be in the m_sNextState object? I feel like it would be a little cluttered for the CGameState class, because it's not up to the CGameState as to when the state changes. I feel like that's more of the job of the CStateMachine, right?
2) What exactly is a script? You have as an example, EnemyScript3.ini as something that would be triggered by fitting 3 in SetNextState's second parameter. I have no idea what to think of scripts or how to implement them in C++.
3) Can you describe what a game engine is, exactly? What would this be in the code? The WinMain() function? The game loop? Some kind of class?
4) Say I have my CGame class all set up. So if I created five enemy objects in my Gameplay state, would I pass a pointer to an object that contains their location, sprite details (animation speed, current frame, etc.) to CGame's Graphics handler, via some function like AddObject()? I looked into it a little and it's been suggested that I use a hash map with a uniquely generated ID for each object of the same type so that they can all be drawn separately. Is this necessary, and does it sound like a good idea, or is there a better way?
Thank you so much for your help and responses.