1
SFML projects / Re: Road to Zero - The Microgrid Management Game
« on: February 18, 2024, 10:59:19 pm »
Hello SFML community!
OK, so here's a more detailed post on the game, with a focus on some of the more interesting implementation aspects.
First of all, I'm sure I'm only scratching the surface of what SFML can do. For example, this particular project is a pretty simple single player game, so I make no use of either SFML/Network or SFML/OpenGL. That said, I suspect that as I take on more and more ambitious projects in the future, I will need to make use of those includes as well.
At this point I mainly use SFML for asset management and IO (it is, after all, a multimedia library). As part of the core of my project, I used SFML to implement an AssetsManager class, which then serves as a component class of the main Game class. Probably nothing earth shattering here, but essentially the AssetsManager class handles the loading and getting of various assets (sounds, fonts, textures, etc.), and then every other object in the game has a pointer to AssetsManager as one of its attributes. The other objects then use that pointer to access AssetsManager's public methods for getting pointers to the various assets being managed. That way, if multiple objects make use of the same asset, then it only needs to be loaded into memory once and is then shared by all using objects. The game just runs in a single thread, so there's no multiple access problems here either.
I take a similar centralized approach for input detection and handling. The main Game class has an sf::Event instance as one of its attributes, and then every other object in the game has a pointer to this instance as an attribute. Ditto for the sf::RenderWindow. I'm guessing this centralized approach is fairly common? Seems a natural way of doing things.
Beyond that, there are two things that I did in this project that were new for me; namely procedural generation, and implementing a centralized message system. Neither rely on SFML, but I think they are nontheless worth mentioning in the context of general game dev.
For the procedural generation (of both Tile types and resource values), I initially tried to use a Markov chain approach (since I wanted like types / resources to be generally clustered, to make assessment easier to infer from); see https://en.wikipedia.org/wiki/Markov_chain. Ultimately, this ended up not working that well, and it introduced the added complexity of needing each tile to keep track of its neighbours (which implies some kind of graph structure). Instead, I made use of some theory from my studies in ocean engineering, where the so-called random amplitude, random phase model is the go-to method for generating realizations of a sea surface (essentially, procedurally generating an ocean wave field). It basically boils down to Fourier series (planar waves) with a deterministic amplitude profile and random phases (and directions); see https://www.researchgate.net/figure/Superposition-od-many-plane-waves-with-random-phase-Originally-from-Pierson-et-al_fig4_273314549 for an illustration. Under this method, I get the "likes clustered" property while at the same time the only input needed is the (x,y) position of each tile (so they don't need to track their neighbours). This also means that I can iterate over the tiles in any random order and still get something that looks like what I'm after. It worked out rather nicely, actually!
For the centralized message system, I again used the "single instance that everyone has a pointer to" approach. That way, each object can send a message to the (in this case) MessageHub class without having to care who is receiving it (kind of a key feature of the observer pattern, which this is one example of). This allowed for the objects in the game to stay pretty loosely coupled while still being able to broadcast information to any other object. In hindsight, not that hard to implement really, but massively helpful. I can see now why this programming pattern is so common in game dev (as far as I'm aware).
Anyways, that's enough blathering on my part. If you're interested and want to get into the nuts and bolts of what I did, the game code (and documentation) is all open source; you can get your hands on it at https://github.com/gears1763-2/RoadToZero.
Cheers!
OK, so here's a more detailed post on the game, with a focus on some of the more interesting implementation aspects.
First of all, I'm sure I'm only scratching the surface of what SFML can do. For example, this particular project is a pretty simple single player game, so I make no use of either SFML/Network or SFML/OpenGL. That said, I suspect that as I take on more and more ambitious projects in the future, I will need to make use of those includes as well.
At this point I mainly use SFML for asset management and IO (it is, after all, a multimedia library). As part of the core of my project, I used SFML to implement an AssetsManager class, which then serves as a component class of the main Game class. Probably nothing earth shattering here, but essentially the AssetsManager class handles the loading and getting of various assets (sounds, fonts, textures, etc.), and then every other object in the game has a pointer to AssetsManager as one of its attributes. The other objects then use that pointer to access AssetsManager's public methods for getting pointers to the various assets being managed. That way, if multiple objects make use of the same asset, then it only needs to be loaded into memory once and is then shared by all using objects. The game just runs in a single thread, so there's no multiple access problems here either.
I take a similar centralized approach for input detection and handling. The main Game class has an sf::Event instance as one of its attributes, and then every other object in the game has a pointer to this instance as an attribute. Ditto for the sf::RenderWindow. I'm guessing this centralized approach is fairly common? Seems a natural way of doing things.
Beyond that, there are two things that I did in this project that were new for me; namely procedural generation, and implementing a centralized message system. Neither rely on SFML, but I think they are nontheless worth mentioning in the context of general game dev.
For the procedural generation (of both Tile types and resource values), I initially tried to use a Markov chain approach (since I wanted like types / resources to be generally clustered, to make assessment easier to infer from); see https://en.wikipedia.org/wiki/Markov_chain. Ultimately, this ended up not working that well, and it introduced the added complexity of needing each tile to keep track of its neighbours (which implies some kind of graph structure). Instead, I made use of some theory from my studies in ocean engineering, where the so-called random amplitude, random phase model is the go-to method for generating realizations of a sea surface (essentially, procedurally generating an ocean wave field). It basically boils down to Fourier series (planar waves) with a deterministic amplitude profile and random phases (and directions); see https://www.researchgate.net/figure/Superposition-od-many-plane-waves-with-random-phase-Originally-from-Pierson-et-al_fig4_273314549 for an illustration. Under this method, I get the "likes clustered" property while at the same time the only input needed is the (x,y) position of each tile (so they don't need to track their neighbours). This also means that I can iterate over the tiles in any random order and still get something that looks like what I'm after. It worked out rather nicely, actually!
For the centralized message system, I again used the "single instance that everyone has a pointer to" approach. That way, each object can send a message to the (in this case) MessageHub class without having to care who is receiving it (kind of a key feature of the observer pattern, which this is one example of). This allowed for the objects in the game to stay pretty loosely coupled while still being able to broadcast information to any other object. In hindsight, not that hard to implement really, but massively helpful. I can see now why this programming pattern is so common in game dev (as far as I'm aware).
Anyways, that's enough blathering on my part. If you're interested and want to get into the nuts and bolts of what I did, the game code (and documentation) is all open source; you can get your hands on it at https://github.com/gears1763-2/RoadToZero.
Cheers!