How to get started with game programming on Windows 8
Tags:
Windows 8,DirectX,C++
may 05 2012 11:40 by Johan Lindfors
I've been a passionate game developer for way too many years now
and when XNA was introduced (and Managed DirectX before that) I was
mighty impressed with the abstractions created and how easy it was
to create both simple and advanced games with managed code for Xbox
360, Windows and later the Windows Phone platform. I was equally
depressed when it was announced (or actually wasn't announced) that
XNA so far hasn't been considered a solution for building games on
Windows 8. But I can understand some of the reasoning behind the
strategy, and I totally appreciate the efforts being made in
creating the latest release of DirectX with it's support for Hull
Shader, Compute Shader, Tesselation and all other goodies that we
can leverage. And I've always considered game development to be the
primary reason for me to keep my skills in C++ up to date so going
native when building games for Windows 8 is for me an accepted
challenge instead of a show stopper! But I also understand that not
all have the same background in C++ and native development and
hence this post on how to get started quite rapidly to build 2D
games for Windows 8 with something that might look quite familiar
if you have an XNA background.
But it's going to be quite a ride for one who haven't done C++
development in Visual Studio earlier, so here we go:
Before you get started this post requires you to have the
following installed and running:
- Windows 8 Consumer Preview
- Visual Studio 2011
First, we are going to use
something called the DirectX Tool
Kit or simply DirectXTK to mimic the behavior of the
SpriteBatch. The DirectXTK includes a native implementation of the
SpriteBatch created by the amazing Shawn Hargreaves who
also have implemented native versions of the configurable effects
as well as a SpriteFont component to render text. I hope to look
into those in future posts. Download the DirectXTK and open and
build the solution file "DirectXTK_11_Metro.sln" in Visual Studio
2011. Hopefully everything runs smoothly and you now have the
binaries to get started.
Now create a new Direct3D Application in Visual Studio and name
it appropriately. This project template is a bit too much for the
purpose but still it's the easiest way to get started in my opinion
without bothering with the plumbing in getting a Direct3D Metro
application created. There is some documentation on the
Windows Dev Center around that topic and I hope to be able to
write about it to in the future. What you need to worry about is
the two files CubeRenderer.h and CuberRenderer.cpp.
But first we need to make sure we can use the library we created
in the previous step. Right click on the project in the solution
explorer and select properties. Then find the Configuration
Properties | Linker | Input section of the property pages window.
In the "Additional Dependencies" you need to make sure that the
DirectXTK.lib is included. Hit the combo-box down arrow and edit
the configuration. On a new line in the "Additional Dependencies"
dialog, insert the entire path (including the .lib-filename) to the
libray. In my case this is: "c:ProjectsWindows
8DirectXDirectXTKBinMetroWin32DebugDirectXTK.lib". Hit OK to
close the dialog.
Now we also must include some other files from
the DirectXTK and that is also done in the Property Pages window.
We highlight the Configuration Properites | C/C++ section and in a
similar manner as above we make sure that the "Additional Include
Directories" include the path to the Inc-folder that was included
in the DirectXTK download. In my case I add the following:
"c:ProjectsWindows 8DirectXDirectXTKInc", close the dialog and
now it's time to delete some code!
Begin by cleaning up the CubeRenderer.h to the following:
#pragma once
#include <wrl.h>
#include <memory>
#include "Direct3DBase.h"
#include <DirectXMath.h>
ref class CubeRenderer : public Direct3DBase
{
public:
CubeRenderer();
~CubeRenderer();
virtual void CreateDeviceResources() override;
virtual void Render() override;
void Update(float timeTotal, float timeDelta);
private:
};
And the CubeRenderer.cpp can be cleaned as much as follows:
#include "pch.h"
#include "CubeRenderer.h"
#include <DirectXMath.h>
using namespace Microsoft::WRL;
using namespace Windows::Foundation;
using namespace Windows::UI::Core;
using namespace DirectX;
CubeRenderer::CubeRenderer()
{
}
CubeRenderer::~CubeRenderer()
{
}
void CubeRenderer::CreateDeviceResources()
{
Direct3DBase::CreateDeviceResources();
}
void CubeRenderer::Update(float timeTotal, float timeDelta)
{
}
void CubeRenderer::Render()
{
// clear
m_d3dContext->OMSetRenderTargets(
1,
m_renderTargetView.GetAddressOf(),
m_depthStencilView.Get()
);
const float midnightBlue[] = { 0.098f, 0.098f, 0.439f, 1.000f };
m_d3dContext->ClearRenderTargetView(
m_renderTargetView.Get(),
midnightBlue
);
m_d3dContext->ClearDepthStencilView(
m_depthStencilView.Get(),
D3D11_CLEAR_DEPTH,
1.0f,
0
);
}
Now we need two variables in this sample, one texture to draw
and one instance of the SpriteBatch. We define them as follows in
CubeRenderer.h:
private:
ID3D11ShaderResourceView* texture;
std::unique_ptr<DirectX::SpriteBatch> spriteBatch;
Don't forget that you also need to add the following #include
line above:
#include "SpriteBatch.h"
Now we create instances of these variables and then it's off to
render them. We turn to the CubeRenderer.cpp and update the method
CreateDeviceResources() as follows:
void CubeRenderer::CreateDeviceResources()
{
Direct3DBase::CreateDeviceResources();
spriteBatch = std::unique_ptr<DirectX::SpriteBatch>(new DirectX::SpriteBatch(m_d3dContext.Get()));
DX::ThrowIfFailed(
CreateWICTextureFromFile(m_d3dDevice.Get(),m_d3dContext.Get(),L"Assets//Logo.png",NULL,&texture,NULL)
);
}
It's unfortunately different syntaxes for the creation of the
instances. The one line that might require the most explanation is
the line that creates the texture. We're leveraging another feature
from the DirectXTK library, and hence we also must add the
following line of code to the file, preferably among the other
#include-directives:
#include "WICTextureLoader.h"
The CreateWICTextureFromFile loads the specified file and
creates the instance for us, let's just keep that in mind, because
there's some advanced possibilities with the WICTextureLoader that
I won't go into here.
The last piece of code we need to add will look the most
familiar to us XNA-developers. Add the following three lines of
code to the end of the Render() method:
spriteBatch->Begin();
spriteBatch->Draw(texture, XMFLOAT2(0,0));
spriteBatch->End();
Now you should be able to build and run this simple sample and
get a very simple image rendered on screen. And most likely you
also have a very tiny base for further development to get you
started in porting games from XNA and C# to native DirectX and
C++.