Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

Game from Scratch C++ Edition Part 2

 

 

Alright, code time! In this part we are going to setup the general framework for our application. Pang! is going to be state driven, which means at any given time the game is in exactly one state. It is by changing states that we control program flow. It also makes certain tasks like pausing the game trivially simple. On the bright side, it’s all actually pretty easy to understand.

 

 

First off we want to open pang.cpp that Visual C++ automatically generated for us and make a few very small changes.

 

 

// pang.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "Game.h" int _tmain(int argc, _TCHAR* argv[]) { Game::Start(); return 0; }

Click here to download Pang.cpp

 

 

Add lines 6 and 10 to your copy of pang.cpp. Line 6 simply says to include the “Game.h” include file, we will be creating in just a few seconds. Line 10 calls the static method Start() which we are also about to create in a few minutes.

 

 

Optional information

 

But lets look at a couple Microsoftisms before we continue.

 

First, notice that your project already includes a stdafx.cpp file and on line 5 includes stdafx.h? This is Microsoft’s way of supporting precompiled headers.

 

 

What are precompiled headers?

 

Some of the header files you include in your project such as Windows.h or the various SFML .hpp files can become rather large but rarely ever change. To speed up the compilation process, you put all of these header files in stdafx.h and then include stdafx.h as the very first item in every cpp file. It actually makes header management a bit easier and makes the compilation process a whole bunch faster. If you don’t want to use stdafx, you can turn it off as a project setting ( or don’t select “Precompiled Headers” when you create your project ). For the record, with a file extension change, GNU C++ supports stdafx, so portability shouldn’t be an issue.

 

Second, you may notice that main looks different than what you expect. _tmain is a Microsoft provided macro that enables you to support UNICODE if possible or falls back to traditional main if you don’t. If you wish, you can replace _tmain with the more traditional

 

int main(int argc, char** argv)

 

if you prefer. If you aren’t compiling using a compiler other than Visual C++, there really is no point. One last quick note, if you ever see a function prefixed with an underscore such as _tmain, that indicates a vendor specific or non-standard extension that may not be portable cross compilers.

 

 

Now that you’ve made those changes, we need to create Game.cpp and Game.h.

 

 

In Solution Explorer right click Source Files and select Add->New Item… in the dialog that popped up select C++ File (.cpp) , fill in the name as Game.cpp and click Add.

 

 

Now we create the header file using almost exactly the same process. Right click Header Files and select Add-New Item.. , this time selecting Header File (.h) , fill in the name as Game.h and click Add.

 

 

Optional information

 

 
Why didn't we use Add Class?

We could have but the truth is, it is pretty buggy. First and foremost, it reserves all of the MFC datatype names even if you aren't using MFC. Want to see it for yourself, Right click Source Files and choose Add Class and try to add one named MenuItem. Annoying.

 

 

 

Alright, now that we have our two new source files, open up Game.h and enter the following code:

 

#pragma once #include "SFML/Window.hpp" #include "SFML/Graphics.hpp" class Game { public: static void Start(); private: static bool IsExiting(); static void GameLoop(); enum GameState { Uninitialized, ShowingSplash, Paused, ShowingMenu, Playing, Exiting }; static GameState _gameState; static sf::RenderWindow _mainWindow; };
 
 
 
First thing you might notice is that the class is entirely static.  You may be asking yourself, doesn’t that make it global?  Well frankly, yes it does.  Every public member of Game is globally available and this is actually what I want.
 
 
 
The reasons I made it static are:
  • I needed a global interface of some sort
  • I had no need to defer initialization so a Singleton is pretty much a waste of time
  • If Game fails to initialize, there’s no recovering anyways
  • There is going to be exactly one “instance” of this object
  • I find it cleaner

 

 

 

If you wanted, you could make Game a traditional class, instantiated one, passed it around and destroyed it. Personally, I simply find this solution cleaner.  You can think of static functions and member variables like the Highlander of C++ programming, there can be only one and they’ve been there forever.

 

 

 

The rest of the code is fairly straight forward, on line 10 we declare the single public method Start() that we called on line 10 of pang.cpp.  On line 16 we defined an enum type called GameState which represent the various states that our game can be in.  We will cover this a little bit later.

 

 

 

Line 19 and 20 we declare our class’s member variables.  One is an instance of the GameState enum we just defined.  The other is a (poorly named) RenderWindow, perhaps the single most important class in SFML.  We will cover this too in more detail later.

 

 

 

The one other thing you may have noticed is the #pragma once line.  By their nature, you should be wary of pragma’s, as they are quite often not portable across compilers.  #pragma once guarantees that the code is included only once and takes the place of a traditional include guards. #pragma once is pretty well supported by major compilers, so it should be safe to use.

 

Optional information
 

The Rules of using static in classes

When dealing with static inside your classes there are a few things you need to be aware of.

First off, static methods can only access static member variables.

Second, there is no this pointer in a static method.

Third, you cannot set a static variable in a class constructor.

Fourth, you need to initialize your static variables outside of your class.

Finally, your variables are initialized at runtime.

 

 

That’s about it. They appear more complicated than they really are.

Optional information

What's an enum?


An enum is a user defined type consisting of a set of constants. Put in plainer ( and less accurate English ), it's a way for you to assign a range of labels to a sequence of data. By default, the first value of an enum is assigned 0, but this can be overridden. Before the enum existed, it would generally have been implemented as a series of consts or worse, using #defines.
 
 
If this all seems rather confusing, see here for a much better and much more detailed explanation of enums.  Generally when you have a set list of values that never change in value or composition, you may want to consider using an enum. If you find yourself using a lot of consts and #defines in your code, you should probably look into the enum with more detail.  They are handy and make your code much cleaner to read and maintain.

 

Now open up game.cpp and add the following:

 

#include "stdafx.h" #include "Game.h" void Game::Start(void) { if(_gameState != Uninitialized) return; _mainWindow.Create(sf::VideoMode(1024,768,32),"Pang!"); _gameState = Game::Playing; while(!IsExiting()) { GameLoop(); } _mainWindow.Close(); } bool Game::IsExiting() { if(_gameState == Game::Exiting) return true; else return false; } void Game::GameLoop() { sf::Event currentEvent; while(_mainWindow.GetEvent(currentEvent)) { switch(_gameState) { case Game::Playing: { _mainWindow.Clear(sf::Color(255,0,0)); _mainWindow.Display(); if(currentEvent.Type == sf::Event::Closed) { _gameState = Game::Exiting; } break; } } } } Game::GameState Game::_gameState = Uninitialized; sf::RenderWindow Game::_mainWindow;

Click here to download Game.cpp

 

 

 

 

First and most confusing, take a look at lines 52 and 53.  These are Game’s two member variables.  As a quirk of being static, they need to be instanced manually. That said, since we don’t have a constructor available, this is a convenient time to set a default value Unitialized to _gameState.  This means when Game is created, its _gameState value will start as unitialized, which is useful in a minute.

 

 

 

 

Now take a look at Game::Start().  This currently is the only publically exposed method and is what is called in pang.cpp to get the game started.  Since Game::Start() is available globally we need to be careful that it isn’t called more than once, which would cause all kinds of bad things to happen.  This is why we check to see if the _gameState is currently Unitialized, which it will only be when starting.  If it is unitialized, simply return for now, although throwing some kind of error would be the right behavior.  Considering that when you return from Game::Start() the program exits, returning an error would be pretty redundant.

 

 

 

 

Next up, Game::Start() tells SFML to create the main window at a resolution of 1024x768 at 32bpp colour with the title "Pang!". It then switches the game to the  Playing state.  Next it starts looping over and over until the game is set to an exiting state, calling the critical function Game::GameLoop() each loop through.  When the game is moved to an exiting state, IsExiting() will return true, ending the loop ( and thus exiting the game ).

 

 

 

 

Game::GameLoop() is easily the most important function in the program as this is where everything happens and it will get much more complex as we add features.  Remember, GameLoop is called over and over millions of times, depending on the speed of your computer.  SFML uses a polling based system for events which is why we call GetEvent.  If there is an event, it returns true and assigns it to currentEvent, if there are no new events it returns false.  It is called in a while loop because there can be multiple events in the queue at a time, so it will loop over all available events until there are none left to process.

 

 

 

Next up is a switch statement, which determines what code runs depending on what our current gameState is.  Right now we only handle a single gameState ( Running ) but that will change shortly.  The only thing you need to remember for now is that the game is only ever in a single state at a time.  For now, the running state simply clears the screen to a bright red colour then displays it on screen.  Then it checks to see if there was an event, and if that event was the Closed event ( someone closed the window ), it switches the game state to Exiting which causes isExiting() to return true on the next pass through the game loop, causing our game loop to end.

 

 

 

 

So here it is, our program in action!

 

 

image

 

 

 

 

Granted not that exciting yet, but it has the framework of almost everything a game needs.  Graphics, input and an event loop.  In the next part, we will add a bit more functionality, including a menu and splashscreen.

 

 

 

You can download the complete project source with everything you need to this point right here. 

 

 

 

EDIT 02/27/2012  Massive omission!

 

All this time later, I realized I made a massive omission in this chapter, that if you aren’t following along using the included sample project that it would cause major confusion.  I mentioned earlier about pre-compiled headers and the stdafx files, but I forgot to include them!  Essentially it allows you to include all the various header files you are going to need and precompile them to speed things up.  In a nutshell, you put any #includes in stdafx where the code is large and not going to change.  This means headers like Windows.h or SFML headers are ideal to be located in stdafx.h.

 

This was such a glaring omission because this is what actually causes SFML to be included!   Oops.  The file included below is actually the stdafx.h from a much later chapter, so there are some includes that aren’t needed yet, but shortly will be.  If you are downloading the sample project,  you will notice that your copy is slightly different.

 

So, lets take a look at those two missing files.  First up is stdafx.cpp

// stdafx.cpp : source file that includes just the standard includes // pang.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" // TODO: reference any additional headers you need in STDAFX.H // and not in this file

Click here to download stdafx.cpp

 

 

 

This file simply exists to make sure stdafx.h is called.  Now lets take a look at stdafx.h

 

 

// stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #pragma once #include <stdio.h> // TODO: reference additional headers your program requires here #include <SFML/System.hpp> #include <SFML/Graphics.hpp> #include <SFML/Window.hpp> #include <SFML/Audio.hpp> #include <map> #include <iostream> #include <cassert>

Click here to download stdafx.h

 

 

This file simply consists of includes for all the various header files that we are going to need through-out the project.  This prevents you from having to include them in all your various files ( you get them included when you added #include “stdafx.h” at the top of your file ).  More importantly, it prevents the compiler from having to process the contents over and over, which can speed compilation up a fair bit.

 

 

Sorry for the omission…

 

 

Back to Part One Forward to Part Three




blog comments powered by Disqus


Month List

Popular Comments

Unreal Engine 4.12 Preview 3 Released
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


12. May 2016

 

Epic have just released another update on Unreal Engine, this time it’s UE 4.12 Preview 3.  Note once again, this is a preview release, so you should expect bugs and shouldn’t use it for production code.  There be dragons!   The single biggest new feature of this preview is the addition of experimental Vulkan support.  Of course this release also has loads of bug fixes including:

Fixed! UE-30343 Project fails to compile after adding child class of AIController (C++)
Fixed! UE-30120 Investigate Crash during Garbage Collection in travel mode with InitProperties() optimization
Fixed! UE-29351 Crash attempting to PIE in QAGame after deleting BP_QAPawn
Fixed! UE-30062 (Regression) BP editor - SCS component tree display is not updated after Undo/Redo of component attachment.
Fixed! UE-30253 Cubes do not react to projectiles in Nativized First Person Code Template
Fixed! UE-30196 Unable to package a copy of project with Nativize Blueprints enabled
Fixed! UE-30235 Mac QAGame fails to package with nativization
Fixed! UE-29888 Hot Reloading an up to date project in Xcode causes the build to fail
Fixed! UE-30150 Crash undoing the selection of an actor while in Mesh Paint mode.
Fixed! UE-28172 Opening asset editor with Ctrl down (including hotkey use) causes editor to act like ctrl still pressed
Fixed! UE-30309 Tabbing to a new row in the details panel selects the blank space to the left of the section
Fixed! UE-30201 Open a copy of a project, results in illegal characters and incorrect filepath warnings when packaging
Fixed! UE-29345 Crash occurs exiting the editor after enabling mesh paint mode and PIEing
Fixed! UE-30218 Build Step Async Step Infinite Loop
Fixed! UE-30318 Crash on mesh reimport after converting brushes to static mesh
Fixed! UE-27087 Crash when pasting MaterialFunctionCall expressions into the material editor between projects
Fixed! UE-30186 SplineComponent has issues shipping
Fixed! UE-30332 "show collision" console command does not render the collision capsule on character
Fixed! UE-30093 Animations created from recorded gameplay are in default pose
Fixed! UE-30039 Crash when removing cloth apb's assigned to asset
Fixed! UE-30100 Destructible meshes can render incorrectly during PiE with Accurate velocities from Vertex Deformation enabled
Fixed! UE-25634 Crash undoing when using component whitelist
Fixed! UE-30142 Landscape3 in ContentExamples Landscape crashes when using erosion tool
Fixed! UE-30400 Sun Temple Fails to launch on PowerVR SGX540 Tablets
Fixed! UE-29569 bReceiveCSMFromDynamicObjects needs a better name, tooltip and to be in a Mobile section
Fixed! UE-29807 Major corruption in ProtoStar in Vulkan PC with VULKAN_ENABLE_PIPELINE_CACHE=1
Fixed! UE-29557 iOS - Packaged Windows BP Template Crashes on Metal Devices
Fixed! UE-30047 Materials that use 5 unique textures do not compile for ES2
Fixed! UE-30331 CompressFileToWorkingBuffer may fail due to block size overhead
Fixed! UE-30258 Packaging for HTML5 in DebugGame fails BuildSettings not cached
Fixed! UE-26057 4.12 regression: UE4Editor-PS4Tracker.dll is always out of date
Fixed! UE-30381 Fatal error in GarbageCollection.cpp file when launching ShooterGame on Xbox One.
Fixed! UE-26495 Crash opening editor on Linux
Fixed! UE-30325 Ads not appearing on full Shipping Distribution Android package of Match3
Fixed! UE-30402 Error in Vulkan.Build.cs check in
Fixed! UE-30401 Add fallback to third party Windows Vulkan SDK for Android if other options not available
Fixed! UE-28862 Xbox One: Cant type in console command
Fixed! UE-30383 Disable MRT on A7 devices for GPU particles
Fixed! UE-30297 iOS from Mac Quick Launch fails at cook on the fly
Fixed! UE-30340 Fix num instances not getting reset after draw indirect calls on PS4
Fixed! UE-30130 [CrashReport] Vulkan Preview Crashes When Running Vulkan Preview PIE
Fixed! UE-30151 Vulkan UI should be gated by Experimental
Fixed! UE-30231 Engine crashes on Android device after being paused for a while
Fixed! UE-30271 Fix bsd_signal linking error for NDK11 and android-21
Fixed! UE-29263 Flying Pawn renders incorrectly while flying on XboxOne
Fixed! UE-30230 Textures aren't getting initialized correctly on PS4
Fixed! UE-30222 Remove glMapBufferOES and glUnmapBufferOES link warnings for Android builds
Fixed! UE-30277 GitHub 2354 : Fix for Git Source Control not working anymore in 4.12, master
Fixed! UE-30190 Adjusting Default Light Settings for Atmospheric Fog causes Crash
Fixed! UE-29150 UT EDITOR: CRASH: Crash occurs when launching Editor on MAC
Fixed! UE-30121 Experimental GPU defragging is enabled by default for PS4
Fixed! UE-29234 Crash when building lighting on Mac with M_EyeRefractive in the scene
Fixed! UE-30208 Ensure taking high resolution screenshot
Fixed! UE-30223 Skylight reflections not rendering correctly on translucent materials
Fixed! UE-30354 CrossCompilerTool does not compile
Fixed! UE-29824 Texture group LOD Bias might be applied several time
Fixed! UE-30115 Indirect Lighting Transition is delayed one frame.
Fixed! UE-29454 M_Water_Drops_Master material failing to compile
Fixed! UE-30112 Standalone Game presents with black bar
Fixed! UE-30266 In Elemental, the lava drip has parts that appear to be cut off
Fixed! UE-30304 In Vehicle Game, the buggy hits collision at the start of the track
Fixed! UE-30246 Content Examples Material_Nodes lighting needs to be rebuilt
Fixed! UE-30386 Dragging Shot_002 down a row causes the shot not to spawn in MasterSequence
Fixed! UE-30367 Crash Auto Saving after using material track
Fixed! UE-30360 Crash converting to spawnable when object is missing
Fixed! UE-30344 Master sequence settings have no bounds
Fixed! UE-29321 Adding a material track sets material to MaterialInstanceDynamic_#
Fixed! UE-30404 Modifications to Android OnCreate delegates
Fixed! UE-29264 Get Screen Percentage does not return values in –game

 

As always this release is available from the game launcher.

GameDev News

blog comments powered by Disqus

Month List

Popular Comments