Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
31. December 2011

 

 

As the title says, the 9th part of our C++ game programming using SFML tutorial is now live. In this chapter we implement a caching solution for dealing with SFML game audio files. Along the way we learn a bit about C++ exception handling as well as touch on the subject of C++ templates. We also implement our second paddle and give it the most basic of artificial intelligence.

 

 

 

As the majority of this chapter is audio related, this image really isn’t all that impressive, but here is our current game in action.  We are very near to a complete game at this point and have covered most of the basics of C++!

 

 

pang9b

 

 

 

 

You can access part 9 by clicking here.  If you haven’t read any of the tutorial yet, you can access the table of contents here.  Again, any and all feedback appreciated.

Programming


22. November 2011

 

 

Continuing the long standing ( and very cool ) tradition of releasing id source code a number of years after being released to market, the Doom3 engine/game source code has been made available on GitHub.

 

 

I have only had the chance to peruse it briefly, but I have to say what I saw was very clean, and shockingly enough C++!  After seeing prior id code, I simply figured it would be straight C for some reason.

 

 

Anyways, I highly recommend you check it out.  Clean, complete, professional quality source code isn’t made available every day, and Carmack really is one of our day’s brilliant minds.  I know I will be doing so in more detail shortly!

 

 

Now I cant wait for someone to port Doom 3 to my toaster…

Programming


20. November 2011

 

 

Handling game time is problem that almost all games have to deal with.  A very good question recently came up in my C++ game from scratch tutorial about why I didn’t normalize the players movements which reminded me of a post on the subject.

 

 

Years ago Shawn Hargreaves of XNA ( and Allegro ) fame blogged about how XNA handles the Update and Render loops.  I simply post it here again because it is one of the most succinct posts I have encountered on the subject.  So, if you are looking into creating a game and need to figure out how to implement the game loop, I recommend you give it a read.

 

By default XNA runs in fixed timestep mode, with a TargetElapsedTime of 60 frames per second. This provides a simple guarantee:

  • We will call your Update method exactly 60 times per second
  • We will call your Draw method whenever we feel like it

 

Digging into exactly what that means, you will realize there are several possible scenarios depending on how long your Update and Draw methods take to execute.

 

The simplest situation is that the total time you spend in Update + Draw is exactly 1/60 of a second. In this case we will call Update, then call Draw, then look at the clock and notice it is time for another Update, then Draw, and so on. Simple!

 

What if your Update + Draw takes less than 1/60 of a second? Also simple. Here we call Update, then call Draw, then look at the clock, notice we have some time left over, so wait around twiddling our thumbs until it is time to call Update again.

 

What if Update + Draw takes longer than 1/60 of a second? This is where things get complicated. There are many reasons why this could happen:

 

  1. The computer might be slightly too slow to run the game at the desired speed.
  2. Or the computer might be way too slow to run the game at the desired speed!
  3. The computer might be basically fast enough, but this particular frame might have taken an unusually long time for some reason. Perhaps there were too many explosions on screen, or the game had to load a new texture, or there was a garbage collection.
  4. You could have paused the program in the debugger.

 

We do the same thing in response to all four causes of slowness:

  • Set GameTime.IsRunningSlowly to true.
  • Call Update extra times (without calling Draw) until we catch up.
  • If things are getting ridiculous and we are too far behind, we just give up.

If you think about how this algorithm deals with the four possible causes of slowdown I listed above, you'll see it handles them all rather well:

  1. Even if the computer is too slow to run Update + Draw inside a single frame, chances are that Update + Update + Draw will fit into two frames. The game may look a little jerky, but it will still play correctly. If the programmer is particularly smart they might even notice that we set IsRunningSlowly, and automatically reduce detail or turn off special effects to speed things up.
  2. If the computer is way too slow (ie. if the Update method alone is too slow to fit into a single frame) there isn't really much we can do, other than set IsRunningSlowly, cross our fingers, and hope the game might do something clever in response to that. Most of the time, though, if you find yourself in this situation you just need a faster computer!
  3. If a particular frame happens to take unusually long, we automatically call Update some extra times to catch up, after which everything carries on as normal. The player may notice a slight glitch, but we automatically correct for this to minimize the impact.
  4. Pausing in the debugger will leave the game a long way behind where the clock says it should be, so our algorithm will give up, accept that it has lost some time, and continue running smoothly from the time execution was resumed.

 

 

Shawn’s blog in general is a very good read, but this this post in particular is one that I seem to keep coming back to.

 

For the record, Pang from the C++ tutorial does not gracefully handle hitting a breakpoint ( it adds a layer of unwanted complexity for learning purposes ), so will do downright stupid things when it hits a breakpoint causing it to pause for a while.  I believe on the next frame it will cause your movement to be really really really far.  It would be as simple as adding if(elapsedTime > someReallyBigValue) startTimeOver() if you really wanted to fix this.

 

 

Sorry for digging up the past, now back to your regular broadcast!

Programming


14. November 2011

 

Chapter 8 of the GFS beginner C++ tutorial, Pang! is now live and can be accessed here.

 

 

This chapter represents a bit of a break from the norm, in that it deals with code design more than it does actual SFML and game implementation.  I actually had a great deal of fun writing this chapter, but the end result is very little usable code.  There is a companion post to this one that illustrates much better use of SFML’s audio classes, that should be up shortly.  That said, I think you could learn a great  deal from this post, it may even alter the way you program!

 

 

Instead this post introduces the concept of design patterns and illustrates a way to de-couple  your code, so you don’t end up littered with global and manager classes.  It covers a concept that I have never seen covered by a game tutorial before, but then, there might be a good reason for that! Winking smile

 

 

So give it a read and let me know what you think.  Would you like to see more posts like this, or would you like me to focus on more implementation specific aspects?

Programming


9. November 2011

 

 

Along with many others, I don’t really recommend C++ as someone’s first language for various reasons.  Sometimes concrete examples aren’t easy to come by off the tip of your tongue, so I figured the next time I encountered one of those things that make C++ so beginner unfriendly, I would post it.  Not the obvious stuff like memory leaks, dealing with the linker or exceptionally cryptic template errors, but the more benign stuff that add up to frustrate new and experienced users.  If you are a veteran C++ coder, you will probably spot the problem in a second or two, but this is the kind of thing that will trip up a beginner completely and is a complete nightmare to solve.

 

 

Consider the following C++ header file:

 

#pragma once #include "SFML/Audio.hpp" class SoundFileCache { public: SoundFileCache(void); ~SoundFileCache(void); const sf::Sound& GetSound(std::string) const; const sf::Music& GetSong(std::string); private: static std::map<std::string, sf::Sound> _sounds; static std::map<std::string, sf::Music> _music; }; class SoundNotFoundExeception : public std::runtime_error { public: SoundNotFoundExeception(std::string const& msg): std::runtime_error(msg) {} }

 

 

Pretty straight forward stuff right?  Two class declarations, nothing really funky going on.  Now consider the following implementation:

 

#include "StdAfx.h" #include "SoundFileCache.h" SoundFileCache::SoundFileCache(void) {} SoundFileCache::~SoundFileCache(void) {} const sf::Sound& SoundFileCache::GetSound(std::string soundName) const { std::map<std::string,sf::Sound>::iterator itr = _sounds.find(soundName); if(itr == _sounds.end()) { sf::SoundBuffer soundBuffer; if(!soundBuffer.LoadFromFile(soundName)) { throw new SoundNotFoundExeception( soundName + " was not found in call to SoundFileCache::GetSound"); } sf::Sound sound; sound.SetBuffer(soundBuffer); _sounds.insert(std::pair<std::string,sf::Sound>(soundName,soundBuffer)); } else { return itr->second; } } const sf::Music& SoundFileCache::GetSong(std::string soundName) { //stub }

 

 

Again, pretty standard code, ignore the fact GetSound and GetSong don’t return values, they aren’t the issue here.

 

 

Now consider the error:

 

error C2533: 'SFMLSoundProvider::{ctor}' : constructors not allowed a return type

 

 

If you are new to the expression ctor, it basically just shorthand for constructor. For the record, it’s Visual Studio Express 2010 and if you double click that error, it brings you to this line:

 

SoundFileCache::SoundFileCache(void) {}

 

 

So… what’s the problem?  By the error, it is quite obvious that the constructor doesn’t in fact return a value, so the message is clearly not the problem.

 

 

What then is the problem?  I’ll show you after this brief message from our sponsors… Smile

 

 

 

 

 

 

Welcome back… figured it out yet?  If not, I don’t blame you, the warning sure as hell didn’t help.  Here then is the offending code:

 

class SoundNotFoundExeception : public std::runtime_error { public: SoundNotFoundExeception(std::string const& msg): std::runtime_error(msg) {} } <-- Missing semicolon

 

So, forgetting a semi colon ( something you will do A LOT! ) results in a message that your constructor cannot return a value.  Now, once you’ve been coding C++ for a while this kind of stuff becomes pretty much second nature.  Getting nonsensical error messages?  Check your header for a missing include guard or semi colon become pretty much the norm.  But for a new developer, this is the beginning of a complete train wreck.

 

 

 

Think about if for a second, you just developed some of your first code, the error says you are returning something you aren’t, the compiler is pointing at your constructor and now you need to figure out just WTF is going on..  What do you do?  Many run off to a forum and post the error verbatim and hope for an answer ( which they will probably get, learning nothing in the process ). Hopefully you Google it using exact quotes, but even then you get forum answers like this where you have a bunch of other new developers fixating on the error message itself and leading the developer down a wild goose chase.  Fortunately a moderator stepped in and gave a proper explanation, but that doesn’t always happen.  Even worse, it is a legit error, you really can’t return from a ctor, so if you encounter it again in the future you may actually have a real problem but find yourself instead on a missing semi-colon hunt!

 

 

 

How would this work in Java, C#, Python or Ruby?  Well it wouldn’t, as no other modern language I can think of use header files any more.  For good reason too, they add a level of complexity for very little positive return.  It could be argued that separating interface from implementation is “a good thing”, but even that is munged up by the fact you can actually have you implementation in your header file.  Also don’t get me wrong, other languages have their faults too, just wait till you get forced to go on your first Java XML configured error hunt, you will be begging for C++ errors again!

 

 

 

This is just a classic example of the little things experienced developer forget the pain of experiencing in the first place!  As I said, once you’ve got a bit of experience this kind of stuff becomes second nature, but while you are learning this kind of error is absolutely horrific.  It’s little things like this that add up and make it so hard to recommend new developers start with C++.  When I say it isn’t pointers and memory management that make C++ difficult, I mean it.  It’s crap like this.

Programming


GFS On YouTube

See More Tutorials on DevGa.me!

Month List