Game Audio Programming Resources

I’m not really musically inclined at all, and I recently did some basic audio programming work for the Noah’s Ark game that involved low-level audio samples and SFML.  Not sure what (if anything) might ultimately come out of that, but I did learn some things about audio within the context of game programming.  Some of my favorite resources that were helpful during this time are below:

Video

Books

Notes from Noah’s Ark Game Refactoring

Recently, I mostly finished a fairly large scale refactoring of code for the Noah’s Ark game.  I’m pretty pleased with how it turned out – the code seems simpler, and I think I’ll be able to more rapidly add features.

Part of the refactoring was motivated by some perceived complexity introduced by some architectural ideas I was trying out – namely, “entities”, “components”, and “systems” – that I’d roughly borrowed from other game engine designs that I’ve read about through the years.

Needless to say, those ideas didn’t seem to be working very well for the game I’m working on.  From various things I’ve learned over the last year, it seemed like there were better solutions to things I was dealing with that would allow replacing a lot of complexity with simplicity.

Will the game’s architecture ultimately return to code similar to what it looked like before the refactoring?  Maybe.  But for now, I think the code is in a much better state than it used to be.  Miscellaneous notes from the refactoring are below.

Making main() Meaningful

Originally, I had a very small amount of code in main():

int exitCode = NoahArkGame::RunGame();
return exitCode;

The bulk of the game logic was contained in a NoahArkGame class.  Part of this was a holdover from when I was using Haaf’s Game Engine before switching over to SFML, but even then, it was largely unnecessary.

So I eliminated this NoahArkGame class and basically moved its logic directly into main().  Why?  Well, using this class (along with some others – “state” and “system” classes) resulted in more indirection that was making things a bit harder to understand, force-fitting certain things into a structure that might not actually be appropriate.  Putting the core game logic in main() meant I could more clearly see the connections necessary between different parts of the code and would make it easier to modify as I discovered new things.

Another interesting idea is that many people often describe a program has having a “main loop.”  Well, if you’re someone new to a code base, where would you expect to find the code for the “main loop”?  Without introducing new constructs that someone would have to learn, the first obvious answer that comes to mind is main().  Anything else is introducing a layer of indirection that has to be jumped through.  I should note that I may not 100% agree with this philosophy, but at the very least, there’s nothing inherently bad about putting a lot of code for the Noah’s Ark game directly in main() for now.  Don’t be afraid of main().

One final note – putting logic directly in main() does have the downside of making it harder to unit test (not that I was planning to do so with the NoahArkGame class either).  But a lot of the pieces orchestrated by the main loop (i.e. actual user input, rendering to screen, etc.) are inherently harder to unit test anyway, so trying to “unit test” the could be a near futile effort anyway.  Just a valid trade-off to consider; there may be more effective ways to test the main loop than unit testing too.

Cleaning Up Tile Map Code

I had a ton of code/classes related to dealing with “tile maps” in the game.  Some of this was intentionally duplicated as I was refactoring smaller parts of the game, but even accounting for that, it was still a messy sea of complexity.

I ultimately eliminated several classes – OverworldMap, ScrollableOverworldMap, TileMapBuilder, TileMapObjectLayer, TileMapTileLayer, ITileMapData, ITileMapLayer, OverworldMapSpecification, SurroundingTileMapLoader, TileMapLayers, TileMapLoader, TiledMapJsonFile – that didn’t really have the best abstractions for useful and intuitive “real-world objects” (in the context of the problems of the game) and thus made the code as a whole more difficult to understand.  That left what seems like a more intuitive collection of classes.

A ton of code was also moved/removed from the TileMap class – it either wasn’t needed anymore or seemed better to place elsewhere for now (to avoid making the TileMap class harder to understand).   I should note that the name of the TileMap class may not best fit the abstraction that it represents, but it isn’t quite clear to me yet exactly what the best class name would be.

Loading All Assets At Startup

I was previously loading assets (i.e. tile map/image files) from disk on-demand, only when needed.  That resulted in some jitteryness/slowdowns during gameplay that required additional complexity to solve.

I did some calculations, and it seemed reasonable to fit basically all of my game assets in memory at once (i.e. 50-60 MB of total usage; my “personal limit” is to keep the game under 100 MB of usage).  Furthermore, most of the assets would be needed in memory basically for the entirety of gameplay anyway, so there isn’t going to be much of a reason to try and free up memory for them.

Therefore, I changed things to just load all assets into memory at startup.  This has the downside of taking about 6-8 seconds (it was 12-14 seconds before I added a tiny bit of multi-threading for tile map loading).  But I’m not too concerned about this since I think I can ultimately have most of this go on in the background during an intro sequence that will be added later.  The good news is that the rest of the code generally doesn’t have to worry about asset loading times.

Making Member Variables Public

Another significant change I made was to make most member variables public instead of private.  This is a common “no-no” in encapsulation/object-oriented guidelines, but I’ve been questioning it lately.

First off, nothing is truly “private” – all there really is is data in the computer’s memory.  Various programming languages do somewhat good jobs at trying to protect these private variables from external access, but this is often just a compilation error.  In C++, you can still easily access private members using pointer offsets.  And some languages don’t even properly support “private” member variables – everything is public, and you have to jump through extraordinary hoops to emulate privacy.

So privacy either doesn’t exist in some programming languages and can be subverted using [often bad] techniques in others.

What are the supposed benefits of private members?  Primarily, the intent seems to be to encapsulate/hide implementation details.  There’s certainly some value in that, but just because a piece of data can be thought of as a member of a class, that doesn’t necessarily mean it is an “implementation detail.”  Sometimes, a data member can intuitively be thought of as part of the abstraction presented by a class.  In these cases, it seems to make more sense for that data member to be public – users expect that data to be in the class by virtue of the abstraction it is trying to present.  Trying to hide this and provide public getter/setter methods just results in more code to read/write/maintain and often makes a class harder to use.

Furthermore, most of the “problems” I tend to see in code aren’t actually caused by lack of “private” members – they’re more fundamental design problems.  As code has to get more complex to solve more complex problems, the impact of a public/private member seems to get tinier in the context of these larger design issues.  And if we’re trusting our developers to solve these much more complicated problems, shouldn’t we be trusting them to make responsible decisions when it comes to data access?  In short, the usage of a data member is more of the issue rather than its public/private accessibility.  Good developers should be able to notice code that is potentially accessing a private implementation detail in a negative way and avoid that code entirely.  Rather than treating a symptom of the problem, I’m wondering if perhaps we should focus more on addressing what seems to be the root cause of these problems – mentorship and growth for programmers.  We want programmers to become better people, and not just so that they can craft simple yet exceptional software.

All of that said, I think there is still probably a case for using private members and having public member functions in public API design – you don’t want to cause frustration or unnecessary work for your users if you need to change some implementation detail or data representation.  But for “internal” code that you don’t intend to heavily reuse throughout tons of projects, I question the value of private members.  It’s your code, and you can change it however you see fit.  And if you do need to change something, the compiler (at least in languages like C++) can easily point you to all of the places that need to be changed.

Not Using Classes For Everything

Last but not least, I deleted some classes that were just serving as cruft and making it harder to use/modify code.  In particular, the GraphicsSystem and CollisionSystem classes were eliminated, with the code now existing as free-floating functions in separate files.

I still find [at least what I consider] “object-oriented programming” to be valuable in certain places.  Primarily, allowing a human to work intuitively with “objects” he/she is familiar with is powerful for solving certain kinds of problems.  Classes can also provide a nice home for functionality that can make it easier to find code in a large code base.

However, object-oriented programming certainly is not a silver bullet.  Not every concept is necessarily best represented as an object.  Too many classes can make a code base harder to navigate.  And object-oriented programming can result in too much indirection and structure that could make code harder to understand or change (which can be costly if an object-oriented design is flawed).

Might the free-floating functions eventually end up in a class?  Perhaps.  If I can find a good home for them eventually, that’s something I’d kind of like to do.  But I don’t yet know what that home would be, and right now, free-floating functions makes it easier for me to shape the code into a proper design later.

 

Anyway, that sums up a lot of the major changes I recently made for refactoring code for the Noah’s Ark game (and why).  It’s entirely possible that something I’ve mentioned above is horribly wrong or stupid.  Time will tell, but I think the code is better now than it was before.

Happy coding.

Mini Book Review: Design Patterns Explained

I recently finished reading Design Patterns Explained.  I’m not really going to do a full review of the book, but there were some helpful parts that seemed worth pointing out.

In general, most of the book didn’t seem all that useful.  In particular, the chapters focusing on specific design patterns were the least appealing.  I can see situations where the general approach of a design pattern might be applicable, but specifics of a particular problem at hand likely would dictate a simpler variation of the pattern that could be derived without needing to specifically think about patterns.

However, there were two particular chapters that I liked a lot and thought were really valuable.

The first is chapter 8 “Expanding Our Horizons”.  There is lots of good discussion in this chapter, but the diagram showing how commonality and variability analysis relate to conceptual, specification, and implementation perspectives was a big highlight.  Thinking about a problem from the “conceptual” perspective helps me stay more focused in the problem domain when programming, and the other two perspectives help bridge the gap between the problem domain and crafting solid code.

The next useful chapter was chapter 16 “The Analysis Matrix”.  Extending the ideas behind commonality and variability analysis, this chapter describes a practical, concrete tool that can easily be used to more clearly see commonalities and variations within a problem.  One particular benefit of this approach that I like is that I think it can be helpful to make sure you don’t overdesign flexibility into your program – the variations you actually need are right there in the matrix (table).

There are other chapters in the book that may be useful.  However, most of the topics they cover were covered in the two chapters outlined above, and those two chapters do a great and better job of explaining the topics.

So while most of Design Patterns Explained didn’t seem too useful to me, I highly recommend checking out the two chapters mentioned above if you get the chance.  Definitely at least worth contemplating to see if they might be useful in certain situations.

Handmade Hero and a New Programming Language?

Relatively recently, I found and started watching the Handmade Hero series.  In the series, Casey Muratori is basically coding a complex game from scratch (i.e. using no libraries beyond what is required by an operating system).  You can read more by following the link above.

I’m far behind (and probably will never catch up) due to limited time, but it’s been a great series.  While I have different opinions on some things Casey brings up (and certain items may only apply to different types of software), there is no doubt that he knows his stuff and is far more experienced than me.  I’ve learned some neat tricks from watching, and he has encouraged me to think more critically about certain aspects of programming.  If you’re interested in learning lowish-level programming in a language like C, I highly recommend checking it out.

Watching Handmade Hero also led me to find Jonathan Blow’s videos where he talks about a potential new programming language for games.  His insight into flaws in current programming languages and proposals to fix some of these issues were fascinating, and Jonathan even has a prototype compiler for his new language that seems to work pretty darn well.  I’m looking forward to seeing that new language progress.

Anyway, just wanted to say thanks to both of these guys.  If those topics seem interesting to you, I recommend looking into their programming video series.  Lots of neat learning opportunities.