Sprites
If I decide to go with the rendering system, what would be the best way to store and send sprites? I suppose that I need to make a sprite resource manager. If so, how is the best way to send them to the render system without coupling things too much? Or perhaps the sprite resource manager should reside in the render system itself?
I faced this problem recently. Look, there are three things:
- Bitmaps
- Textures
- Sprites/Tiles
First, you will have a resource manager, and it is concerned with loading bitmaps. You then need to get texture objects (which belong to the rendering system):
- Sometimes you want to copy bitmap to a texture directly. That is the common case.
- Then, sometimes, you want to create bitmaps in memory instead of loading them from the resource manager, and then copy those to textures. Although, you probably will not need to do that (it can be useful when you are rolling your own GUI).
- Occasionally you want to copy only parts of the bitmap to textures. That is the rare case, in fact, I do think you will be doing it at all.
Finally, a texture could have multiple sprites/tiles that you can render separately by using texture coordinates. That all happens inside the rendering system, completely hidden from the rest of the solution.
Note: You can decide to have a fixed size for all sprites set at the start of the rendering system. Having all the sprites be of that size will save passing the size of the sprites each time. On the other hand, it is not a bad idea to have a similar solution to display overlays of custom size. Although, I guess the GUI can do that.
Now, your game object will have to tell the rendering system what sprite from what texture they use when you create it or when it changes (for animation). Yet, they are not responsible for loading those sprites/tiles. The convention is that there is an error texture (usually a magenta and black checkers pattern) used when the requested texture is not available.
Usually you want to have only a handful of textures loaded and you want to load them when initializing the scene/map/scenario/room. Bitmaps are there to facilitate that. If you need to build an atlas at run time, you can do that with bitmaps. Hopefully you do not need that and you can just load a few bitmaps from the resource manager that has all the sprites/tiles you need.
GUI
Between GUI and Render. The TGUI library introduces a TGUI Window class that inherits from SFML one, and can be used as one. In my case, it will be a part of the rendering system. Hovewer, the GUI system will need to have a pointer to the Window to register GUI widgets.
The initialization of the window is neither.
Just because the rendering system does a lot of SFML calls does not mean that every SFML call belongs in the rendering system.
Instead, handling the window is its own thing. Mold the event loop into the game loop, and it will call both the rending and the GUI system, and also all other systems.
Animation
Between Gameplay and Render. Where applicable, Actor class will have a AnimatedSprite, which i will implement on my own. It will be a part of the Gameplay system, and will have a pointer to the sprite in resource manager (in the rendering system); it will just cut it depending on animation/frame. In some cases, when animations are not required, the Actor class will just have pointer to a normal sprite. To get those pointers a function in resource manager will be called from the Gameplay system.
As I was saying the game object needs to tell the rendering system about its sprite. However, I would avoid pointers across systems. Instead of a pointer, use an id that serves as index in a table.
You will have multiple sprites in the same texture, and you can change which one is the current sprite of a game object. That is one way to do animation. There is no cutting for that, the rendering system will be rendering a different part of the texture, that is all.
No resource manager is involved either. You load the textures before hand. Remember that multiple game objects could use the same textures. You do not want each game object loading the same texture, that is wasted effort.
Also, I was saying sprites/tiles, because it is very similar to a way to do the terrain of the map. In fact, that can be animated too (water animation, for example). However, the map will give an array of sprite ids to render instead of the single sprite id from the game object. Perhaps not what you want... you can always have a custom painted map.
Which brings me to: the camera. Yes, camera. It will be exposed by the rendering system for control, however figuring what is in view is responsability of the rendering system. You might want to send to the GPU only things that are nearby the camera.
In fact, having a way to query things that are nearby a position is a good idea for physics. Will you have physics? I guess for collisions with terrain obstacles. Oh, another use is for AI. You might want enemies to react when the player is nearby.
Now, the camera is not exactly a game object, and it is not exactly a system. However, having some sort of system or module dedicated to handle the camera is a good idea. You may want to move it in predefined paths for cinematics, also there are planty of ways to handle the camera in a 2D game, and none of that logic belongs in any particular visible object nor in the rendering system. It would be a camera manager or something like that (camera operator? cinematographer?).
I am assuming you will be writing shaders, and loading textures to the GPU. That is why rendering parts of a texture is completely hidden from the rest of the system (it is shader logic). Again, no cuttig required.
I said above that changing which one is the current sprite is a way to the animation. I am implying that there is another way. You can have the game object tell the rendering system about all the sprites of the current animation, and the rendering system can loop them. In fact, the shader code can loop them. Just remember to pass the time as a uniform and in the shader compute which one is the current sprite for the time. That way, animating a screen full of water tiles does not require to pass a bunch of sprite ids each frame.