You are on page 1of 52

Windows Phone 8 2D Game Development For Beginners

Cao Phong Developer Tech Support Manager Nokia, Vietnam

Content
Setting up a basic framework with XNA Setting up a basic framework with Direct3D: DirectX TK Direct3D (native) Direct3D with XAML and XAML with Direct3D app

Porting XNA to Asha Touch

XNA vs Direct3D
XNA Pros: - Simple setup and easy to use - Legacy support - Can be quickly ported to Asha Touch Direct3D Pros: - Best performance - Leverage on WP8 APIs: In-app purchase, NFC, Bluetooth - Native code support - Flexibility to add nice game effects Cons: - Requiring quite a lot steps to set up at the beginning - Fairly complex to use

Cons: - Unable to use WP8 APIs: In-app purchase, NFC, Bluetooth - Lack of native code support

XNA
Choose project template

Main loop
protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); // TODO: Add your update logic here base.Update(gameTime); }

protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here base.Draw(gameTime); }

Fill Rectangle
Texture2D Rectangle Color m_pRectTexture = null; m_rect; m_color; public void FillRect(int color, int x, int y, int w, int h) { if (m_pRectTexture == null) { m_pRectTexture = new Texture2D(GraphicsDevice, 1, 1); m_pRectTexture.SetData<Color>(new Color[] { Color.White }); } m_rect.X = x; m_rect.Y = y; m_rect.Width = w; m_rect.Height = h; m_color.A m_color.R m_color.G m_color.B = = = = (byte)((color (byte)((color (byte)((color (byte)((color & & & & 0xFF000000) >> 24); 0x00FF0000) >> 16); 0x0000FF00) >> 8); 0x000000FF));

spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque); spriteBatch.Draw(m_pRectTexture, m_rect, m_color); spriteBatch.End(); }

Draw Image
public Texture2D LoadImage(String file) { try { Stream fs = TitleContainer.OpenStream(file); Texture2D img = Texture2D.FromStream(GraphicsDevice, fs); fs.Close(); fs = null; return img; } catch (Exception e) { // Handle error return null; } } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // Draw a rectangle (color=red, x=50, y=100, w=100, h=50) FillRect(0xFF0000, 50, 100, 100, 50); // Draw an image (x=10, y=10) spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied); spriteBatch.Draw(imgGirl, new Vector2(10, 10), Color.White); spriteBatch.End(); base.Draw(gameTime); }

Direct3D
DirectX TK (Toolkit)
There is a collection of helper classes united under the name of DirectX Tool Kit [4] - or in short DirectX TK - started by Shawn Hargreaves. This library contains convenience classes that help write code that uses Direct X. It also contains a tool called MakeSpriteFont that can create fonts to be used in game.

Download link: http://directxtk.codeplex.com/releases/view/98986

Direct3D
Choose project template

Fill Rectangle
void GameRenderer::FillRect(int color, int x, int y, int w, int h) { // Create Texture CD3D11_TEXTURE2D_DESC texDesc( DXGI_FORMAT_R8G8B8A8_UNORM,// DXGI_FORMAT 1,// width 1,// height 1,// arraySize 1,// mipLevels D3D11_BIND_SHADER_RESOURCE// bindFlags ); D3D11_SUBRESOURCE_DATA colorData = { 0 }; Microsoft::WRL::ComPtr<ID3D11Texture2D> texture; int a[] = {0xFF000000 | ((color & 0xFF) << 16) | (((color & 0xFF00) >> 8) << 8) | ((color & 0xFF0000) >> 16)}; // argb => abgr colorData.pSysMem = &a; colorData.SysMemPitch = sizeof(a); colorData.SysMemSlicePitch = 0; m_d3dDevice->CreateTexture2D(&texDesc, &colorData, texture.GetAddressOf()); Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> view; m_d3dDevice->CreateShaderResourceView(texture.Get(), 0, &view); // Draw In a Rectangle RECT rect = {x, y, x + w, y + h}; // left, top, right, bottom spriteBatch->Begin(); spriteBatch->Draw(view.Get(), rect, Colors::White); spriteBatch->End(); }

DirectDraw Surface (DDS)


DirectDraw Surface file format Filename extension: DDS Data compressed with the lossy S3 Texture Compression (S3TC) algorithm Support phone GPUs and consoles (PSP, PS3, Xbox 360) Converting images to .dds files DirectXTex library: http://directxtex.codeplex.com/SourceControl/changeset/22746 NVIDIA Texture Tools: https://developer.nvidia.com/nvidia-texture-tools-adobe-photoshop https://developer.nvidia.com/content/texture-tools-208-64-bit Easy2Convert PNG to DDS: http://www.easy2convert.com/png2dds/

Draw Image
1. Declare texture in GameRenderer.h:
ID3D11ShaderResourceView* m_catTexture;

2.

Include DDS loader header in GameRenderer.cpp:


#include <DDSTextureLoader.h>

Load resource

3.

Load texture in CreateDeviceResources method:


void GameRenderer::CreateDeviceResources() { Direct3DBase::CreateDeviceResources(); spriteBatch = std::shared_ptr<SpriteBatch>(new SpriteBatch(m_d3dContext.Get())); DX::ThrowIfFailed(CreateDDSTextureFromFile(m_d3dDevice.Get(), L"Assets\\CatTexture.dds", NULL, &m_catTexture, NULL)); m_loadingComplete = true; }

Draw Image
void GameRenderer::Render(float timeTotal, float timeDelta) { 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); // Only draw once the resources are loaded (loading is asynchronous). if (!m_loadingComplete) { return; } m_d3dContext->OMSetRenderTargets(1, m_renderTargetView.GetAddressOf(), m_depthStencilView.Get()); // Fill a rectangle FillRect(0xFF0000, 50, 100, 100, 50); // Draw an image (x=10, y=10) spriteBatch->Begin(); spriteBatch->Draw(m_catTexture, XMFLOAT2(10, 10)); spriteBatch->End(); }

Direct3D App
Choose project template

3D Coordinate Systems
Left-handed versus Right-handed

DirectX: usually uses Left-handed coordinate system OpenGL: usually uses Right-handed coordinate system

HLSL (High Level Shader Language)


The language used to write shaders for GPUs in DirectX

SimpleVertexShader.hlsl
VertexShaderOutput main(VertexShaderInput input) { VertexShaderOutput output; float4 pos = float4(input.pos, 1.0f); // Transform the vertex position into projected space. pos = mul(pos, model); pos = mul(pos, view); pos = mul(pos, projection); output.pos = pos; // Pass through the color without modification. output.color = input.color; return output; }

SimplePixelShader.hlsl
float4 main(PixelShaderInput input) : SV_TARGET { return float4(input.color,1.0f); }

DirectX Math and HLSL


Matrix OpenGL GLSL DirectX Math HLSL (by default) Solutions: Transpose matrices before sending to HLSL Use the #pragma pack_matrix directive in shaders:
#pragma pack_matrix( row_major )

Vector Column vectors Column vectors Row vectors Row vectors

Column-major Column-major Row-major Column-major

DirectX Primitives
Point Lists Line Lists Line Strips

Triangle Lists

Triangle Strips

Face and Vertex Normal Vectors


Each face in a mesh has a perpendicular unit normal vector The vector's direction is determined by the order in which the vertices are defined and by whether the coordinate system is right- or left-handed The face normal points away from the front side of the face In Direct3D, only the front of a face is visible A front face is one in which vertices are defined in clockwise order.

Direct3D App (Cont.)


Use row-major in HLSL so that you dont need to transpose matrices from DirectX Math 1. Add directive in vertex shader: SimpleVertexShader.hlsl #pragma pack_matrix( row_major ) 2. Remove all transpose matrices in CubeRenderer.cpp:
void CubeRenderer::Update(float timeTotal, float timeDelta) { (void) timeDelta; // Unused parameter. XMVECTOR eye = XMVectorSet(0.0f, 0.7f, 1.5f, 0.0f); XMVECTOR at = XMVectorSet(0.0f, -0.1f, 0.0f, 0.0f); XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); XMStoreFloat4x4(&m_constantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up))); XMStoreFloat4x4(&m_constantBufferData.model, XMMatrixTranspose(XMMatrixRotationY(timeTotal * XM_PIDIV4) )); }

void CubeRenderer::CreateWindowSizeDependentResources() { Direct3DBase::CreateWindowSizeDependentResources(); float aspectRatio = m_windowBounds.Width / m_windowBounds.Height; float fovAngleY = 70.0f * XM_PI / 180.0f; if (aspectRatio < 1.0f) { fovAngleY /= aspectRatio; } XMStoreFloat4x4(&m_constantBufferData.projection, XMMatrixTranspose(XMMatrixPerspectiveFovRH(fovAngleY, aspectRatio,0.01f,100.0f))); }

Direct3D App
Apply orthographic projection for our 2D game framework with Left-handed coordinate system
void CubeRenderer::CreateWindowSizeDependentResources() { Direct3DBase::CreateWindowSizeDependentResources(); XMStoreFloat4x4( &m_constantBufferData.projection, XMMatrixOrthographicOffCenterLH ( 0, // ViewLeft m_windowBounds.Width, // ViewRight m_windowBounds.Height, // ViewBottom 0, // ViewTop -1.0f, // NearZ 1.0f // FarZ ) ; }

Direct3D App
Update view matrix with Left-handed coordinate system
void CubeRenderer::Update(float timeTotal, float timeDelta) { (void) timeDelta; // Unused parameter. XMVECTOR eye = XMVectorSet(0.0f, 0.0f, -1.0f, 0.0f); XMVECTOR at = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); XMStoreFloat4x4(&m_constantBufferData.view, XMMatrixLookAtLH(eye, at, up)); XMStoreFloat4x4(&m_constantBufferData.model, XMMatrixIdentity()); }

Direct3D App
Disabling Z buffer in 2D mode to enable back-to-front rendering
// Initialize the Direct3D resources required to run. void Direct3DBase::Initialize(CoreWindow^ window) { m_window = window; CreateDeviceResources(); CreateWindowSizeDependentResources(); D3D11_DEPTH_STENCIL_DESC depthDisabledStencilDesc; ID3D11DepthStencilState* depthDisabledStencilState; depthDisabledStencilDesc.DepthEnable = false; depthDisabledStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; depthDisabledStencilDesc.DepthFunc = D3D11_COMPARISON_LESS; depthDisabledStencilDesc.StencilEnable = true; depthDisabledStencilDesc.StencilReadMask = 0xFF; depthDisabledStencilDesc.StencilWriteMask = 0xFF; depthDisabledStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; depthDisabledStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR; depthDisabledStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; depthDisabledStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; depthDisabledStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; depthDisabledStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR; depthDisabledStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; depthDisabledStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; // Create the state using the device. m_d3dDevice->CreateDepthStencilState(&depthDisabledStencilDesc, &depthDisabledStencilState); m_d3dContext->OMSetDepthStencilState(depthDisabledStencilState, 1); }

Direct3DBase.cpp

Direct3D App
Render 3 rectangles using Triangle Lists

CubeRenderer.cpp
VertexPositionColor cubeVertices[] = { {XMFLOAT3(0.0f, 0.0f, 0.0f), {XMFLOAT3(100.0f, 0.0f, 0.0f), {XMFLOAT3(100.0f, 100.0f, 0.0f), {XMFLOAT3(0.0f, 100.0f, 0.0f), {XMFLOAT3(50.0f, 50.0f, 0.0f), {XMFLOAT3(150.0f, 50.0f, 0.0f), {XMFLOAT3(150.0f, 150.0f, 0.0f), {XMFLOAT3(50.0f, 150.0f, 0.0f), {XMFLOAT3(100.0f, 100.0f, 0.0f), {XMFLOAT3(200.0f, 100.0f, 0.0f), {XMFLOAT3(200.0f, 200.0f, 0.0f), {XMFLOAT3(100.0f, 200.0f, 0.0f), }; unsigned short cubeIndices[] = { 0,1,2, 0,2,3, 4,5,6, 4,6,7, 8,9,10, 8,10,11, };

XMFLOAT3(0.0f, XMFLOAT3(0.0f, XMFLOAT3(0.0f, XMFLOAT3(0.0f, XMFLOAT3(0.0f, XMFLOAT3(0.0f, XMFLOAT3(0.0f, XMFLOAT3(0.0f, XMFLOAT3(1.0f, XMFLOAT3(1.0f, XMFLOAT3(1.0f, XMFLOAT3(1.0f,

0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,

1.0f)}, 1.0f)}, 1.0f)}, 1.0f)}, 0.0f)}, 0.0f)}, 0.0f)}, 0.0f)}, 0.0f)}, 0.0f)}, 0.0f)}, 0.0f)},

Direct3D App
0 (0,0) 1 (100,0)

3 (0,100)

2 (100,100)

Texture Mapping
0 (0,0) 1 (300,0)
Texel Coordinate System

0.0
V

1.0

3 (0,300)

2 (300,300)

1.0

Texturing allows adding photographs and other images onto polygon faces The format of the textures are Direct Draw Surface (.dds) files In the texel coordinate system, the width value is named "U" and the height value is named "V: The width goes from 0.0 on the left to 1.0 on the right The height goes from 0.0 on the top to 1.0 on the bottom

Update texture coordinates and render


Map texture to a square having width=300, height=300 and render it at (0, 0):
VertexPositionTexture cubeVertices[] = { {XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, {XMFLOAT3(300.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, {XMFLOAT3(300.0f, 300.0f, 0.0f), XMFLOAT3(1.0f, {XMFLOAT3(0.0f, 300.0f, 0.0f), XMFLOAT3(0.0f, };

0.0f, 0.0f, 1.0f, 1.0f,

0.0f)}, 0.0f)}, 0.0f)}, 0.0f)},

Choosing the right project template for your game


Features Direct3D UI (XAML) Exclusive Features Acts as a XAML control (can be placed anywhere on the screen, above or next to other XAML controls) No No Direct3D with XAML Yes Yes XAML with Direct3D Yes Yes

Exclusive Features:
Background Agents Browser Control Map Control Background Transfer Service Live Tiles Push Notifications The Windows Phone Ad Control Localized resources XAML controls

No

No

Yes

Choosing the right project template for your game for WP8
Performance Direct3D Startup time Rendering 2 3 Direct3D with XAML 1 2 XAML with Direct3D 1 1 Unofficial tests: Direct3D with XAML app is 18 20% slower than Direct3D app XAML with Direct3D app is 5 7% slower than Direct3D with XAML app

* Note: higher number means faster performance

Direct3D with XAML app


Choose project template

Direct3D with XAML app


Uses the DrawingSurfaceBackgroundGrid control Render graphics that are displayed across the entire background of your app, behind any XAML controls in your UI Must be the root element of the XAML tree and is always the full size of the screen Structure Made up of two components: a XAML-based Windows Phone app and a component thats based on the Windows Phone Runtime The XAML engine creates and maintains a Direct3D graphics device. Once per frame, the XAML engine passes the graphics device and an associated render target to the Windows Phone Runtime component Main classes MainPage: hosts your XAML-based UI and your managed code CubeRenderer: where the actual drawing to the shared texture is performed PhoneDirect3DXamlAppComponent: contains touch input handling

XAML with Direct3D app


Choose project template

XAML with Direct3D app


Uses the DrawingSurface control Render graphics that are displayed behind or inline with XAML controls and content The size and layout of your DrawingSurface are handled just as they are with other XAML controls Structure Made up of two components: a XAML-based Windows Phone app and a component thats based on the Windows Phone Runtime The Windows Phone Runtime component creates a Direct3D graphics device, which it uses to create a Texture that is shared with the XAML app. The Windows Phone Runtime component uses Direct3D to draw onto the Texture. The XAML engine maintains a swap chain that copies the texture to the screen within the bounds of the DrawingSurface control Main classes MainPage: hosts your XAML-based UI and your managed code CubeRenderer: where the actual drawing to the shared texture is performed Direct3DInterop: contains touch input handling

Porting 2D XNA Games to Asha Full Touch

3 5

Why porting to Asha Full Touch?


Minimal porting effort: 1 5 working days Leverage on Nokia Store payment system to maximize revenue: In-app purchasing with 145 operator billing integrations In-app advertising with Nokia Ad Exchange (NAX): 120 ad networks in over 200 countries

Screen Resolution

480x800

240x400

All images are scaled down by half All coordinates are divided by half

Images

68x74

34x37

Coordinates and Alignment

(x, y)

(x / 2, y / 2)

XNA & J2ME - C# and Java language


C#
namespace

Java
package

const bool override

final boolean N/A

XNA and Java ME Frameworks


XNA
Microsoft.Xna.Framework.Game GraphicsDeviceManager GraphicsDevice SpriteBatch RenderTarget2D protected override void Update(GameTime gameTime) protected override void Draw(GameTime gameTime) Color

Java ME
javax.microedition.lcdui.Canvas java.lang.Runnable

Graphics

public void run() public void paint(Graphics g)

int color Image

Texture2D

XNA and Java ME Frameworks

Rule #1 All coordinates divided by half


k_Factor: 1: Windows Phone 2: AshaFT

Rule #2 Do relative alignment, no hard code


DON'T's DOs

Rule #3 Use J2ME wrapper classes in XNA

Rule #3 Use J2ME wrapper classes in XNA

Porting Steps
1. Develop or modify XNA source code with J2ME wrapper classes: Graphics Image Touch input and media related classes

2. Resize all images to one half and copy to AshaFT project 3. Update all coordinates with scale factor = 4. Replace Microsoft.Xna.Framework.Game by Javax.microedition.lcdui.Canvas and java.lang.Runnable 5. Remove all wrapper classes, go with the ones in MIDP such as javax.microedition.lcdui.Graphics 6. Optimize memory and performance

mcpp preprocessor
http://mcpp.sourceforge.net/
Implements all of C90, C99 and C++98 specifications. Provides a validation suite to test C/C++ preprocessor's conformance and quality comprehensively. When this validation suite is applied, mcpp distinguishes itself among many existing preprocessors. Has plentiful and on-target diagnostics to check all the preprocessing problems such as latent bug or lack of portability in source code. Has #pragma directives to output debugging information. Is portable and has been ported to many compiler-systems, including GCC and Visual C++, on UNIX-like systems and Windows. Has various behavior modes. Can be built either as a compiler-specific preprocessor to replace the resident preprocessor of a particular compiler system, or as a compilerindependent command, or even as a subroutine called from some other main program. Provides comprehensive documents both in Japanese and in English. Is an open source software released under BSD-style-license.

Develop a game fully in XNA

Building jar and jad automatically

Launch the file with Nokia Java Emulator

Thank you!

Lets discuss more: https://www.facebook.com/groups/viet.nok.dev

You might also like