How to Create Your First Windows 8 Metro-style Game Chas. Boyd Principal Program Manager Microsoft Corporation.

Download Report

Transcript How to Create Your First Windows 8 Metro-style Game Chas. Boyd Principal Program Manager Microsoft Corporation.

How to Create Your First
Windows 8 Metro-style Game
Chas. Boyd
Principal Program Manager
Microsoft Corporation
Three Presentations Today
Step by Step through Game Development
1) How to set up the game
2) How to code it
<- You are here
3) How to optimize it
Agenda
Quick summary of the platform
Step through the process of development
from a programmer’s perspective:
App Initialization
Opening a Window
Rendering Graphics
Loading and Saving
Adding Input Controls
Adding Sound Effects
Adding an Art Pipeline
This talk’s sample code is in C++
Platform Overview
Model
Controller
View
Metro style apps
DX
C
C++
XAML
C#
VB
Desktop apps
HTML / CSS
JavaScript
HTML
JavaScript
Kernel
System Services
WinRT APIs
Communication
& Data
Graphics
& Media
Application Model
C
C++
C#
VB
Win32
.NET
SL
Devices
& Printing
Internet
Explorer
Windows Kernel Services
Your Killer Game
Graphics
Movies & Cut
Scenes
Game Input
Audio
Local Services
Connected
Services
Tools
Direct3D
DirectX
Video
Pointer
Point
WASAPI
PLM
Windows
Live
Visual
Studio
Direct2D
Media
Foundation
Sensor API
XAudio2
AppData
Windows
Store
Asset
Viewers
Contracts
Xbox LIVE
Asset
Processors
HTML
XAML
XInput
Windows Runtime
All WinRT APIs are native
WinRT APIs feel natural in C++, C#/VB, and JavaScript
Reuse of portable C++ code just works
WinRT APIs provide rich access to devices, OS, and services
HTML5/CSS/JavaScript and XAML are great for Metro style apps
Providing a rich set of controls
Native DirectX is great for Metro style apps
Updated C++ language support
File->New Project templates for native DirectX C++ apps
DirectX HLSL shader compilation and syntax highlighting
Packaging compiled HLSL shaders into the .appx package
Support for other asset types in MSBuild and previewer
Visualization, processing and packaging of Textures,
meshes, shaders, and audio
Debugging DirectX API calls
Win32
CoCreateInstance
QueryInterface
WRL
ComPtr<IObject>
foo.As(&bar)
WinRT
Foo^ foo = ref new Foo()
N/A
AddRef / Release
N/A
N/A
std::vector
N/A
Platform::Array<>^
Chapter 1/6
App Initialization
ref class MyApp : public IFrameworkView
{
public:
MyApp();
// IFrameworkView Methods
virtual void Initialize(CoreApplicationView^ applicationView);
virtual void SetWindow(CoreWindow^ window);
virtual void Load(String^ entryPoint);
virtual void Run();
virtual void Uninitialize();
void MyApp::Run()
{
auto dispatcher = CoreWindow::GetForCurrentThread()->Dispatcher;
while (!m_windowClosed)
{
dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
m_renderer->Update();
m_renderer->Render();
m_renderer->Present();
}
}
Chapter 2/6
Handling Window Events
void MyApp::SetWindow(CoreWindow^ window)
{
window->SizeChanged +=
ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(
this, &MyApp::OnWindowSizeChanged);
ApplicationView::GetForCurrentView()->ViewStateChanged +=
ref new TypedEventHandler
<ApplicationView^, ApplicationViewStateChangedEventArgs^>(
this, &MyApp::OnViewStateChanged);
}
Resize Handler
void DirectXApp::OnWindowSizeChanged(
_In_ CoreWindow^ sender,
_In_ WindowSizeChangedEventArgs^ args
)
{
if (m_window->Bounds.Width != m_windowBounds.Width ||
m_window->Bounds.Height != m_windowBounds.Height)
{
m_d2dContext->SetTarget(nullptr);
m_d2dTargetBitmap = nullptr;
m_renderTargetView = nullptr;
m_depthStencilView = nullptr;
CreateWindowSizeDependentResources();
}
}
void MyApp::OnWindowActivationChanged(
CoreWindow^ sender,
WindowActivatedEventArgs^ args)
{
auto state = args->WindowActivationState;
if(state == CoreWindowActivationState::Deactivated)
OutputDebugString("Focus Lost");
if(state == CoreWindowActivationState::CodeActivated ||
state == CoreWindowActivationState::PointerActivated)
OutputDebugString("Focus Regained");
}
{
DisplayOrientations::None;
DisplayOrientations::Landscape;
DisplayOrientations::LandscapeFlipped;
DisplayOrientations::Portrait;
DisplayOrientations::PortraitFlipped;
// Enable rotation by OS/Accelerometer
// Lock rotation by OS/Accelerometer
//
and enable this orientation
}
using namespace Windows::Graphics::Display;
DisplayProperties::AutoRotationPreferences = DisplayOrientations::Landscape
| DisplayOrientations::LandscapeFlipped;
Chapter 3/6
Rendering Graphics
3D Graphics via Direct3D 11
3D Graphics uses the same API as on Desktop/Classic
WinRT API set includes only the latest DirectX 11 syntax
DirectX 11 API supports multiple hardware generations
via FeatureLevels: Feature_Level_9, Feature_Level_10, Feature_Level_11
Direct3D 11 updated for Windows 8
Creating a swap chain
CoreWindow
ComPtr ID3D11Device1
ComPtr IDXGISwapChain1
// app’s core window
// renderer
// front/back buffers of
RT
// Obtain the final swap chain for this window from the DXGI factory.
nullptr
//
//
//
//
//
the Direct3D device that will render to it
IUnknown interface on our core window
double or triple buffered, stereo, etc.
allow on all displays
the resulting swap chain object
void myApp::Render()
{
m_d3dContext->OMSetRenderTargets(
// rebind every frame!
1,
m_renderTargetView.GetAddressOf(),
m_depthStencilView.Get() );
if (!m_loadingComplete)
return;
// only draw the cube once it's loaded
// (this is async)
m_d3dContext->IASetVertexBuffers(
0, 1,
m_vertexBuffer.GetAddressOf(),
&stride,
&offset );
m_d3dContext->IASetIndexBuffer(
m_indexBuffer.Get(),
DXGI_FORMAT_R16_UINT, 0 );
m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_d3dContext->IASetInputLayout(m_inputLayout.Get());
m_d3dContext->VSSetConstantBuffers(
0, 1,
m_constantBuffer.GetAddressOf() );
m_d3dContext->VSSetShader( m_vertexShader.Get(),
nullptr, 0 );
m_d3dContext->PSSetShader( m_pixelShader.Get(),
nullptr, 0 );
m_d3dContext->DrawIndexed( m_indexCount, 0, 0 );
}
Chapter 4/7
Loading and Saving
Process Lifetime Management
Suspend/Resume
User
Launches
App
Running
App
suspending
resuming
Suspended
App
Low Memory
Terminated
App
using namespace Concurrency;
float f = 1.0f;
// task defined with capturing lambda
task<int>([=]()
{
return foo(f);
}).then([](int x) // continuation lambda argument is return value of previous
{
bar(x);
// continuation using existing function baz()
}).then(baz);
void MyApp::OnSuspending(Object^ sender, SuspendingEventArgs^ args)
{
SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
task<void>([=]()
{
auto localState = ApplicationData::Current->LocalSettings->Values;
auto roamingState = ApplicationData::Current->RoamingSettings->Values;
localState->Insert(
"GameTime", PropertyValue::CreateSingle(m_gameTime));
roamingState->Insert(
"MaxLevel", PropertyValue::CreateUInt32(m_maxLevelUnlocked));
}).then([=]()
{
deferral->Complete();
});
}
void MyApp::Load(String^ entryPoint)
{
LoadMyGameStateAsync().then([=]()
{
auto localState = ApplicationData::Current->LocalSettings->Values;
auto roamingState = ApplicationData::Current->RoamingSettings->Values;
m_gameTime = safe_cast<IPropertyValue^>
(localState->Lookup("GameTime"))->GetSingle();
m_maxLevelUnlocked = safe_cast<IPropertyValue^>
(roamingState->Lookup("MaxLevel"))->GetUInt32();
}).then([=]()
{
m_loadingComplete = true;
});
}
task<byte*> LoadSkyAsync()
{
auto folder = Package::Current->InstalledLocation;
return task<StorageFile^>(
folder->GetFileAsync("sky.dds")).then([](StorageFile^ file){
return FileIO::ReadBufferAsync(file);
}).then([](IBuffer^ buffer){
auto fileData = ref new Array<byte>(buffer->Length);
DataReader::FromBuffer(buffer)->ReadBytes(fileData);
return fileData->Data;
});
}
...
LoadSkyAsync().then([=](byte* skyTextureData)
{
CreateTexture(skyTextureData);
m_loadingComplete = true;
});
Chapter 5/7
Adding Input
Mouse and Touch Input
win->PointerPressed += ref new TypedEventHandler<CoreWindow^,PointerEventArgs^>
(this, &LonLatController::OnPointerPressed);
void LonLatController::OnPointerPressed(
_In_ CoreWindow^ sender,
_In_ PointerEventArgs^ args
)
{
float2 position = float2(
args->CurrentPoint->Position.X,
args->CurrentPoint->Position.Y
);
// position of contact
m_lonLatLastPoint = position;
// save for use in controller
m_lonLatPointerID = args->CurrentPoint->PointerId;
}
// Arrow keys or WASD example
auto upKeyState = window->GetKeyAsyncState(VirtualKey::Up);
auto wKeyState = window->GetAsyncKeyState(VirtualKey::W);
if (upKeyState & CoreVirtualKeyStates::Down ||
wKeyState & CoreVirtualKeyStates::Down)
{
m_playerPosition.y += 1.0f;
}
using Windows::Devices::Sensors;
// Get current reading from sensor
OrientationSensorReading^ orientationReading = m_orientationsensor->GetCurrentReading();
SensorQuaternion^ quat = orientationReading->Quaternion;
// Transform quaternion from device orientation space to world space
// Orientation space is Z-up, right-handed coordinate system
// World space is Y-up, left-handed coordinate system
XMVECTOR orientationQuat = XMVectorSet(-quat->X, quat->Z, quat->Y, -quat->W);
// Create a rotation matrix from the quaternion
// This matrix can be used to rotate an object inside the scene to match
// the rotation of the device
XMMATRIX rotXMMatrix = XMMatrixRotationQuaternion(orientationQuat);
Windows 8 supports Xbox360 -compatible controllers
Check out new ControllerSketch sample
Demonstrates game controller usage from JavaScript app
if ( m_xinputState.Gamepad.wButtons & XINPUT_GAMEPAD_A )
{
m_aButtonWasPressed = true;
}
else if ( m_aButtonWasPressed )
{
m_aButtonWasPressed = false;
// Trigger once, only on button release
TriggerSoundEffect();
}
if (abs(thumbLeftX) < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
thumbLeftX = 0;
SHORT thumbLeftY = inputState.Gamepad.sThumbLY;
if (abs(thumbLeftY) < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
thumbLeftY = 0;
combinedTiltX += (float)thumbLeftX / 32768.0f;
combinedTiltY += (float)thumbLeftY / 32768.0f;
Chapter 6/7
Adding Sound Effects
// Create the XAudio2 engine and mastering voice on the default audio device
// Load all audio data for the sound effect into a single in-memory buffer
new
// Create a single source voice for a sound effect
// Trigger sound effect: queue in-memory buffer for playback and start the voice
Chapter 7/7
Creating an Asset Pipeline
Author-time
Asset
shader.hlsl
Build Step
Run-time Asset
Packager
shader.cso
Package
texture.bmp
texture.dds
mesh.obj
mesh.vbo
music.wav
music.wma
myApp
.appx
Installer
Run-time
Asset
Loader
Component
Bindable
API object
shader.cso
Shader
texture.dds
Texture
mesh.vbo
VertexBuffer
music.wma
Stream
Package
myApp
.appx
Pro Dev Hints
Find commands in the IDE via the search textport
Set up a multi-monitor dev PC with a touch monitor
as the primary
To work with the samples, set a breakpoint inside the
DX::
macro in DirectSample.h line 18
Time to Act
Biggest opportunity. Ever.
Windows 8 Consumer Preview is now available.
Check out the store.
Go build great games.
http://dev.windows.com
Q&A