Step by Step: Managed Casual Game Development
4/7/2010
Microsoft Corporation
February 2007
Learn how to use the game libraries in the Microsoft® .NET Compact Framework running on a Microsoft Windows Mobile® 5.0 device to render both two dimensions and three dimensions using the Managed DirectX® Mobile libraries. This includes creating a device, rendering sprites, vertices, matrix, and meshes. This HOL will take 1 hour and 30 minutes to complete.
Microsoft .NET Compact Framework version 2.0Windows Mobile 5.0Microsoft Visual Studio® 2005Microsoft DirectX 9.0 SDKMicrosoft Direct3D®
The following applications are required to run this HOL:
Microsoft Windows® XP Professional
DirectX 9.0 SDK
Download and install DirectX 9.0.Visual Studio 2005
This HOL requires Visual Studio 2005 Standard, Professional, or Team System Editions. It will not work with any of the Express Editions. If you do not have the correct edition of Visual Studio 2005, find out how you can acquire it from the Visual Studio 2005 Developer Center.Microsoft ActiveSync® 4.0
ActiveSync 4.0 allows for connectivity between a Windows Mobile powered device and your computer.
Download and install ActiveSync 4.0.Windows Mobile 5.0 SDKs.
The Windows Mobile 5.0 SDKs for Pocket PC and Smartphone enable development for Windows Mobile powered devices in Visual Studio 2005.
Download and install Windows Mobile 5.0 SDK for Pocket PC.
Download and install Windows Mobile 5.0 SDK for Smartphone.Note
If you used an emulator in a previous HOL, you should do a hard reset of the emulator before starting this HOL. (On the emulator, click File, point to Reset, and then click Hard.)
Note
During development, if you receive an error that indicates that the process or file is in use, the program is still running on the emulator, and you must close the program before you can deploy and run a new copy. This error may appear anytime in the HOL that you deploy the emulator.
Introduction
Lab 1: Create a Managed D3DM Device
Lab 2: Create a Spinning Triangle with Managed D3DM
Lab 3: Create a Spinning Mesh
Lab 4: Create a Simple Two-Dimensional Sprite Casual Game
Conclusion
This HOL shows you how to use transforms to modify the rendered images to run all resolutions devices offer, including VGA Pocket PCs and Smartphones. By the end of this HOL, you will have a basic understanding about how to use these features when you create device-based casual games.
Managed Direct3D Mobile (Managed D3DM) will reduce the volume of code and increase your productivity. The interfaces are more intuitive--inheriting from the powerful and easy-to-use .NET Compact Framework common types. Managed code also frees you from having to deal with most memory management tasks, such as releasing objects. Managed D3DM is provided as a part of the .NET Compact Framework version 2.0. Managed D3DM runs on top of the native Direct3D Mobile, which is being delivered in all Windows Mobile 5.0 powered devices. At a minimum, each new Windows Mobile 5.0 device ships with software drivers, and some are planned to ship with hardware acceleration.
If you're interested in writing a three-dimensional game, you should work through all of the labs in this HOL. If you're interested in writing a two-dimensional game, you can skip Labs 2 and 3.
In this HOL, you will work with the Treo 700 device, which runs a software D3D driver. You can also experiment with the device emulator, which includes the reference software driver. This platform is too slow to do much, but it is available for investigation.
The objective of this lab is to create a new managed D3DM device as your first Hello World application. The managed D3DM device is the parent of all graphical objects that are painted in your solution. This lab shows you how to create the new device and run it on a Pocket PC.
In this lab, you will perform the following exercise:
- Creating a new managed D3DM device
In this exercise, you will use Visual Studio 2005 to create a blank C# project, write the code to create a device, and then compile and deploy the managed D3DM device to a Pocket PC.
To create new project in Visual Studio 2005
In Visual Studio 2005, click File | New | Project.
On the New Project dialog box, open a blank C# project and select Smart Device | Windows Mobile 5.0 Pocket PC.
On the Project menu, click Add Reference.
Add the following references to the project:
- Microsoft.WindowsMobile.DirectX
- System.Drawing
- System.Windows.Forms
- System
To create a managed D3DM device
Click Project | Add New Item.
In the Add New Item dialog box, delete all the code in the new class.
Add all of the needed references and class definitions by adding the following code.
using System; using System.Drawing; using System.Windows.Forms; using Microsoft.WindowsMobile.DirectX; using Microsoft.WindowsMobile.DirectX.Direct3D; namespace Microsoft.Samples.MD3DM { // The main class for this sample public class CreateDevice : Form { // The global variables for this project Device device = null; // CreateDevice here //InitializeGraphics here //Render here //OnPaint here // OnPaintBackground here // OnKeyPress here // Main here } }
Replace
// CreateDevice
here by adding the following code to the CreateDevice class. This code sets the Text and MinimizeBox properties so the form can be closed.public CreateDevice() { // Set the caption this.Text = "Hello World"; this.MinimizeBox = false; }
Initialize the managed D3DM subsystem by adding InitializeGraphics. Replace
//InitializeGraphics
here with the following code.public bool InitializeGraphics() { try { // Set up the D3D parameters PresentParameters presentParams = new PresentParameters(); // Causes the display to appear in a window rather than // full screen presentParams.Windowed = true; // When a new frame is swapped to the front buffer, // the old frame will be discarded presentParams.SwapEffect = SwapEffect.Discard; // The first parameter of 0 indicates that the Device object // should use the system's physical adapter. The second parameter // identifies the device type. When working with D3DM, the only // supported device type is the default. The third parameter is a // reference to the current form which will be doing the // rendering.The forth parameter, CreateFlags, allows you to set // various options for the device. The final parameter, // presentParams, contains the details about how the image will // be displayed in the render area, what buffers it will use, and // the formats it will have. device = new Device(0, DeviceType.Default, this, CreateFlags.None, presentParams); } catch (DirectXException) { return false; } return true; }
Set up the render logic to draw each frame with the color of blue. Replace
// Render
here with the following code.private void Render() { if (device != null) { //Clear the back buffer to a blue color device.Clear(ClearFlags.Target, Color.Blue, 1.0f, 0); //Begin the scene device.BeginScene(); // Rendering of the scene objects can happen here //End the scene device.EndScene(); device.Present(); } }
Create a game loop by overriding OnPaint. Replace
//OnPaint
here with the following code.protected override void OnPaint(PaintEventArgs e) { // Render on painting this.Render(); // Render again this.Invalidate(); }
Do not include any logic here because you are filling the entire back buffer with blue in the Render function. Add the following code to your class.
protected override void OnPaintBackground(PaintEventArgs e) { // Do nothing to ensure that the rendering area is not overdrawn }
Add OnKeyPress to detect when the user presses the ESC to exit the application. Replace
//OnKeyPress
here with the following code.protected override void OnKeyPress(KeyPressEventArgs e) { // Esc was pressed if ((int)(byte)e.KeyChar == (int)Keys.Escape) this.Close(); }
Create Main to launch the application. Replace
//Main
here with the following code.static void Main() { CreateDevice frm = new CreateDevice(); // Initialize Direct3D if (!frm.InitializeGraphics()) { MessageBox.Show("Could not initialize Direct3D. " + "This tutorial will exit."); return; } Application.Run(frm); }
To compile and deploy the managed D3DM project
Press F5 to compile and run the application. If any compilation issues occur, you need to fix them.
On the Deploy dialog box, select Windows Mobile 5.0 PocketPC Device.
Click Deploy. Visual Studio deploys the project.
Click Yes when the device prompts you to accept the project from an unknown publisher. You should see the blue managed D3DM device with the title Hello World.
On the managed D3DM device, click OK to close it.
In this lab, you performed the following exercise:
- Creating a new managed D3DM device
The objective of this lab is to create a simple object, a triangle, from a vertex buffer, render the object, and then make it rotate by using the Hello World application as a starting point.
In this lab, you will perform the following exercises:
- Creating a triangle
- Changing the triangle's perspective
This exercise uses the skeleton managed D3DM device that you created in the first lab to draw a triangle with three vertices. Triangles are the building blocks of all D3D drawings; given enough triangles, you can draw anything.
To modify the Hello World code to draw a triangle
Modify the global variables in the CreateDevice class to include a VertexBuffer variable. Replace
// The global variables for this project
with the following code.VertexBuffer vertexBuffer = null; PresentParameters presentParams = new PresentParameters();
Change the form text in the CreateDevice function. Replace
this.Text = "Hello World";
with the following code.this.Text = "Spinning Tringle";
Modify the code in InitializeGraphics by replacing all of the code in the try block with the following code.
presentParams.Windowed = true; presentParams.SwapEffect = SwapEffect.Discard; device = new Device(0, DeviceType.Default, this, CreateFlags.None, presentParams); device.DeviceReset += new EventHandler(this.OnResetDevice); this.OnCreateDevice(device, null); this.OnResetDevice(device, null);
Add OnCreateDevice to the CreateDevice class to configure the device on creation, as shown in the following code.
void OnCreateDevice(object sender, EventArgs e) { Pool vertexBufferPool; Caps caps; Device dev = (Device)sender; // Get the device capabilities caps = dev.DeviceCaps; if (caps.SurfaceCaps.SupportsVidVertexBuffer) vertexBufferPool = Pool.VideoMemory; else vertexBufferPool = Pool.SystemMemory; // Now create the VertexBuffer vertexBuffer = new VertexBuffer( typeof(CustomVertex.PositionColored), 3, dev, 0, CustomVertex.PositionColored.Format, vertexBufferPool); vertexBuffer.Created += new EventHandler( this.OnCreateVertexBuffer); this.OnCreateVertexBuffer(vertexBuffer, null); }
Add OnResetDevice to configure the device on reset, as shown in the following code.
void OnResetDevice(object sender, EventArgs e) { Device dev = (Device)sender; // Turn off culling, so you see the front and back of the triangle dev.RenderState.CullMode = Cull.None; // Turn off D3D lighting because you are providing your own vertex // colors dev.RenderState.Lighting = false; }
Add OnCreateVertexBuffer to configure the triangle when the buffer is created or recreated, as shown in the following code.
void OnCreateVertexBuffer(object sender, EventArgs e) { VertexBuffer vb = (VertexBuffer)sender; CustomVertex.PositionColored[] verts = (CustomVertex.PositionColored[])vb.Lock(0, 0); verts[0].X = -1.0f; verts[0].Y = -1.0f; verts[0].Z = 0.0f; verts[0].Color = System.Drawing.Color.DarkGoldenrod.ToArgb(); verts[1].X = 1.0f; verts[1].Y = -1.0f; verts[1].Z = 0.0f; verts[1].Color = System.Drawing.Color.MediumOrchid.ToArgb(); verts[2].X = 0.0f; verts[2].Y = 1.0f; verts[2].Z = 0.0f; verts[2].Color = System.Drawing.Color.Cornsilk.ToArgb(); vb.Unlock(); }
Modify Render to draw the TriangleList. Replace
// Rendering of the scene objects can happen here
with the following code.device.SetStreamSource(0, vertexBuffer, 0); device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
To compile and deploy the managed D3DM project
Press F5 to compile and run the application. If any compilation issues occur, you need to fix them.
On the Deploy dialog box, select Windows Mobile 5.0 PocketPC Device.
Click Deploy. Visual Studio deploys the project.
Click Yes when the device prompts you to accept the project from an unknown publisher. You should see the blue managed D3DM device with a triangle drawn in the center of it.
On the managed D3DM device, click OK to close it.
In this exercise, you will add a view matrix to change the triangle's perspective, so the triangle appears to rotate.
To change perspective in code by using matrices
Create SetupMatrices by setting up the world view, and then by changing that view each frame, as shown in the following code.
private void SetupMatrices() { // For the world matrix, you will rotate the object about // the y-axis. Set up the rotation matrix to generate 1 full // rotation (2*PI radians) every 1000 ms. To avoid the loss of // precision inherent in very high floating point numbers, the // system time is modulated by the rotation period before // conversion to a radian angle. int iTime = Environment.TickCount % 1000; float fAngle = iTime * (2.0f * (float)Math.PI) / 1000.0f; device.Transform.World = Matrix.RotationY(fAngle); // Set up the view matrix. A view matrix can be defined given // an eye point, a point to look at, and a direction for which // way is up. In this code, you set the eye five units back along the // z-axis and up three units, look at the origin, and define // "up" to be in the y-direction. device.Transform.View = Matrix.LookAtLH( new Vector3(0.0f, 3.0f, -5.0f), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f)); // For the projection matrix, you set up a perspective transform // (which transforms geometry from three-dimensional view space to // two-dimensional viewport // space, with a perspective divide that makes objects smaller in // the distance). To build a perpsective transform, you need the // field of view (1/4 pi is common), // the aspect ratio, and the near and far clipping planes // (which define at what distances geometry should be no longer // be rendered). device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, 1.0f, 1.0f, 100.0f); }
Call SetupMatrices, as shown in the following code, from the Render function by adding a call to it just after the BeingScene.
SetupMatrices();
To compile and deploy the managed D3DM project
Press F5 to compile and run the application. If any compilation issues occur, you need to fix them.
On the Deploy dialog box, select Windows Mobile 5.0 PocketPC Device.
Click Deploy. Visual Studio deploys the project.
Click Yes when the device prompts you to accept the project from an unknown publisher. You should see the blue managed D3DM device with a triangle drawn in the center of it.
On the managed D3DM device, click OK to close it.
In this lab, you performed the following exercises:
- Creating a triangle
- Changing the triangle's perspective
Three-dimensional modeling software can represent an object by using complicated geometry. Data representing this geometry is called a mesh and is commonly stored in a Direct3D .x file. Direct3D uses meshes to load the objects from these files. This lab introduces the topic of meshes and shows how to load, render, and unload a mesh. Managed D3DM uses meshes in a file format that is a subset of the .x format with the extension .md3dm. A mesh contains the data for a complex model. It is an abstract data container that contains resources, such as textures and materials, and attributes, such as position data and adjacency data.
The objective of this lab is to show you how to convert an .x file, load that mesh on a device, and change the perspective to make it appear to spin.
In this lab, you will perform the following exercises:
- Converting an .x file to an .md3dm file
- Loading a mesh onto a device
- Creating a Spinning Tiger Project
Note
This lab has a weakness in the OnResetDevice method, where resources are loaded from the assembly. If the assembly name and the default namespace is not Lab3; it will fail. If you fail to run the tiger, check the default namespace by opening the project's properties (click Project | Properties). The Application tab includes the default namespace. If the value is not Lab3, change it.
Visual Studio 2005 includes a sample that converts .x files to .md3dm files. You will use the application that you build from that sample to create an .md3dm file.
To convert an .x file to an .md3dm file
Open a Command Prompt window (click Start | Run, and then type cmd).
Type cd c:.
Type cd C:\HOL320\Tools\.
Type MeshConvertercs.exe Tiger.x Tiger.md3dm to convert the Tiger.x file to Tiger.md3dm.
To set up a new Pocket PC project
In Visual Studio 2005, click File | New | Project.
In the New Project dialog box, open a new C# project, and then select SmartDevices | Windows Mobile 5.0 Pocket PC.
Add an empty project, and name it Lab3. (The project name is referenced in the code.)
On the Project menu, click Add Reference.
Add the following references:
- Microsoft.WindowsMobile.DirectX
- System.Drawing
- System.Windows.Forms
- System
To embed the Tiger.md3dm file and Tiger.bmp file as resources in your project
Click Project | Add Existing Item.
Click Add Resource | Add Existing File.
Change Files of Type to All Files.
Change the Look In value to C:\HOL320\Tools\.
Add Tiger.md3dm and Tiger.bmp (holding down SHIFT and clicking the left mouse button selects multiple files).
Get the properties of each resource by looking in Solution Explorer, right-clicking the resource, and then choosing Properties.
Change the Build Action value to Embedded Resource to compile these resources into the assembly.
Click Project | Add Existing Item.
Browse to C:\HOL320\Tools\Create Project, and add MeshLoader.cs. MeshLoader.cs is a part of the Mesh sample and includes the code to load an .md3dm mesh.
This exercise leads you through loading the mesh.
To add a new class
Click Project | Add New Item.
On the Add New Item dialog box, add a new code file.
To add a class definition
Add all of the needed references and class definitions by adding the following code:
using System; using System.Drawing; using System.Windows.Forms; using Microsoft.WindowsMobile.DirectX; using Microsoft.WindowsMobile.DirectX.Direct3D; using System.Reflection;
Add a namespace and the class definitions by adding the following code:
namespace Microsoft.Samples.MD3DM { public class Meshes : Form { // The D3D rendering device Device device = null; // The mesh object in the system Mesh mesh = null; // Materials for the mesh Material[] meshMaterials; // Textures for the mesh Texture[] meshTextures; // The display parameters for drawing a D3D window PresentParameters presentParams = new PresentParameters(); //InitializeGraphics here //Add OnDeviceReset //SetupMatrices here //Render here //OnPaint here //OnPaintBackGround here //OnKeyPress here //OnResize here //Main here } }
This exercise shows you how to change the perspective of the Tiger project to make it appear to spin.
To add code to the project and render it
Replace
//InitializeGraphics here
by adding the following code to the InitializeGraphics method in the Meshes class.bool InitializeGraphics() { try { // Draw the graphics inside a standard window presentParams.Windowed = true; // Discard the current frame when drawing a new one presentParams.SwapEffect = SwapEffect.Discard; // Create a 16-bit depth buffer presentParams.EnableAutoDepthStencil = true; presentParams.AutoDepthStencilFormat = DepthFormat.D16; // Create the D3D device device = new Device(0, DeviceType.Default, this, CreateFlags.None, presentParams); device.DeviceReset += new System.EventHandler( this.OnResetDevice); this.OnResetDevice(device, null); } catch (Exception) { return false; } return true; }
Replace
//Add OnDeviceReset
by adding the following code.Note
GetManifestResourceStream
starts with the path to the default namespace. Project1 is referenced as the default. Check the default namespace property before completing this step.void OnResetDevice(object sender, EventArgs e) { string[] textureFilenames = null; Device dev = (Device)sender; // Turn on the zbuffer dev.RenderState.ZBufferEnable = true; // Turn on ambient lighting dev.RenderState.Ambient = System.Drawing.Color.White; // Turn on perspective correction for textures. // This provides a more accurate visual at the cost // of a small performance overhead dev.RenderState.TexturePerspective = true; // Load the mesh from the specified file. //Note Project1 refers to the defalut namespace mesh = MeshLoader.LoadMesh(device, Assembly.GetExecutingAssembly().GetManifestResourceStream( "Lab3.Tiger.md3dm"), MeshFlags.SystemMemory, out meshMaterials, out textureFilenames); // Extract the material properties and texture names meshTextures = new Texture[meshMaterials.Length]; for (int i = 0; i < meshMaterials.Length; i++) { // Set the ambient color for the material // (D3DX does not do this) meshMaterials[i].Ambient = meshMaterials[i].Diffuse; // Create the texture meshTextures[i] = TextureLoader.FromStream(dev, Assembly.GetExecutingAssembly().GetManifestResourceStream( "Lab3." + textureFilenames[i])); } }
Replace
//SetupMatrices here
by adding the following code.void SetupMatrices() { // For the world matrix, you will just leave it as the identity device.Transform.World = Matrix.RotationY(Environment.TickCount / 1000.0f); // Set up the view matrix. A view matrix can be defined given // an eye point, a point to look at, and a direction for which // way is up. In this code, you set the eye five units back along the // z-axis and up three units, look at the origin, and define // "up" to be in the y-direction. device.Transform.View = Matrix.LookAtLH( new Vector3(0.0f, 2.0f, -3.0f), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f)); // For the projection matrix, you set up a perspective // transform (which transforms geometry from three-dimensional view // space to two-dimensional // viewport space, with a perspective divide that makes objects // smaller in the distance). To build a perpsective transform, // you need the field of view (1/4 pi is common), the aspect // ratio, and the near and far clipping planes (which define at // what distances geometry should be no longer be rendered). device.Transform.Projection = Matrix.PerspectiveFovLH((float)(Math.PI / 4), 1.0f, 1.0f, 100.0f); }
Replace
//Render here
with the following code.private void Render() { if (device == null) return; //Clear the back buffer to a blue color device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, System.Drawing.Color.Blue, 1.0f, 0); //Begin the scene device.BeginScene(); // Set up the world, view, and projection matrices SetupMatrices(); // Meshes are divided into subsets; one for each material. // Render them in a loop for (int i = 0; i < meshMaterials.Length; i++) { // Set the material and texture for this subset device.Material = meshMaterials[i]; device.SetTexture(0, meshTextures[i]); // Draw the mesh subset mesh.DrawSubset(i); } //End the scene device.EndScene(); device.Present(); }
Replace
//OnPaint here
with the following code.protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) { // Render the mesh to the screen Render(); // Invalidating the window will cause it to be redrawn in // the future Invalidate(); }
Replace
//OnPaintBackGround here
with the following code.protected override void OnPaintBackground( System.Windows.Forms.PaintEventArgs e) { // Doing nothing ensures the background will never overdraw // the previous rendering }
Replace
//OnKeyPress here
with the following code.protected override void OnKeyPress(KeyPressEventArgs e) { // If ESC was pressed, then shut down if ((int)e.KeyChar == (int) Keys.Escape) this.Close(); }
Replace
//OnResize here
with the following code.protected override void OnResize(EventArgs e) { base.OnResize(e); }
Replace
//Main here
with the following code.static void Main() { Meshes meshForm = new Meshes(); // Initialize Direct3D if (!meshForm.InitializeGraphics()) { MessageBox.Show("Could not initialize Direct3D. " + "This tutorial will exit."); return; } // Run the form try { Application.Run(meshForm); } catch (Exception e) { MessageBox.Show("An error occured and this sample needs " + " to close:" + e.Message); } }
To compile and deploy the managed D3DM project
Press F5 to compile and run the application. If any compilation issues occur, you need to fix them.
On the Deploy dialog box, select Windows Mobile 5.0 PocketPC Device.
Click Deploy. Visual Studio deploys the project.
Click Yes when the device prompts you to accept the project from an unknown publisher.
On the managed D3DM device, click OK to close it.
In this lab, you performed the following exercises:
- Converting an .x file to an .md3dm file
- Loading a mesh onto a device
- Creating a Spinning Tiger Project
Traditional two-dimensional casual games are based on animated sprites. Managed D3DM offers a Sprite class that allows you render and rotate sprites.
Managed D3DM handles sprites as textures. These textures get loaded then displayed on the managed D3DM device through the Sprite class. The Sprite class takes parameters to allow different areas of the texture to be rendered. This lab refers to these areas as tiles. Moving from area to area renders the animations of the sprite, causing it to appear to rotate, as shown in Figure 1. The Sprite class also places the sprite on the managed D3DM device, thus allowing it to move from frame to frame. Finally sprites can be transformed to allow the texture to be modified, in this example, scaled to fit the screen.
Figure 1. Donut.bmp appears to be rotating
The objective of this lab is to render a static sprite, animate a sprite, move the sprite on the screen and detect collisions, and scale the sprite according to the device's screen.
In this lab, you will perform the following exercises:
- Rendering a static sprite
- Animating a sprite
- Moving a sprite
- Detecting collisions
- Scaling a sprite according to screen size
This exercise will lead you through rendering a static sprite, including creating the project, constructing the data class, and rendering one of tiles of the sprite.
To create a new project
In Visual Studio 2005, click File | New | Project.
In the New Project dialog box, open a new C# project, and then select SmartDevices | Windows Mobile 5.0 Pocket PC.
Name the project Lab4.
On the Project menu, click Add Reference.
Add the following references:
- Microsoft.WindowsMobile.DirectX
- System.Drawing
- System.Windows.Forms
- System
Click Project | Add Existing Item.
Add donuts.bmp to the project. (Select Files of Type Image Files, and then locate file at C:\HOL320\Image.)
Get the properties of each resource by looking in Solution Explorer, right-clicking the resource, and then choosing Properties.
Change the Build Action value to Embedded Resource to compile donuts.bmp into the assembly.
The sprite data is stored in the TileSet class.
To add the data class TileSet
Click Project | Add New Item.
In the Add New Item dialog box, add a new class.
Name the new class TileSet.cs.
Delete all of the code in the new class.
Add the following code to the new class.
using System; using Microsoft.WindowsMobile.DirectX; using Microsoft.WindowsMobile.DirectX.Direct3D; namespace SpriteLab { public class TileSet { private Texture texture; //Returns the sprite texture public Texture Texture { get { return texture; } } private int xOrigin; //Returns the x starting location public int XOrigin { get { return xOrigin; } } private int yOrigin; //Returns the y starting location public int YOrigin { get { return yOrigin; } } private int numberFrameRows; //Returns the number of frames in a row public int NumberFrameRows { get { return numberFrameRows; } } private int numberFrameColumns; //Returns the number of frames in a column public int NumberFrameColumns { get { return numberFrameColumns; } } private int xExtent; //Returns the x coordinate for the center of the sprite public int ExtentX { get { return xExtent; } } private int yExtent; //Returns the y coordinate for the center of the sprite public int ExtentY { get { return yExtent; } } //Class constructor public TileSet(Texture tex, int StartX, int StartY, int RowCount, int ColumnCount, int xWidth, int yHeight) { xOrigin = StartX; yOrigin = StartY; xExtent = xWidth; yExtent = yHeight; numberFrameRows = RowCount; numberFrameColumns = ColumnCount; texture = tex; } } }
To create the SpriteLab class code that will render one sprite
Click Project | Add New Item.
On the Add New Item dialog box, add a new code file.
Name the new class SpriteLab.cs.
Add the following code to the new class.
using System; using System.Drawing; using System.Windows.Forms; using Microsoft.WindowsMobile.DirectX; using Microsoft.WindowsMobile.DirectX.Direct3D; using System.Reflection; namespace SpriteLab { // The main class for this sample public class CreateDevice : Form { // Global variables for this project Device device = null; //MD3DM Device Texture texture = null; //Sprite bmp Rectangle tilePosition; //Location of tile TileSet tileSet = null; //Local TileSet Sprite sprite; //Sprite Varible Int16 countX = 0; //Count to Track Columes of Tiles Int16 countY = 0; //Count to Track Rows of Tiles Vector3 spritePosition = new Vector3(50, 50, 0); //Start Location of Sprite Vector3 spriteCenter = new Vector3(0, 0, 0); //Sprite Center, 0,0,0 Vector2 spriteVelocity = new Vector2(1, 1); // x,y velocity float scale = 1; //Configure Scale for screen size //Implementation here } }
Under
//Implementation here
, add the following code.public CreateDevice() { // Set the caption this.Text = "Sprite Sample"; this.MinimizeBox = false; // Add Key Event Handler here }
Under the CreateDevice class, add the following code.
public bool InitializeGraphics() { try { // Set up the D3D parameters PresentParameters presentParams = new PresentParameters(); // Causes the display to appear in a window rather than // full screen presentParams.Windowed = true; // When a new frame is swapped to the front buffer, // the old frame will be discarded presentParams.SwapEffect = SwapEffect.Discard; // The first parameter of 0 indicates that the Device object // should use the system's physical adapter. The second parameter // identifies the device type. When working with D3DM, the only // supported device type is the default. The third parameter is a // reference to the current form which will be doing the // rendering.The forth parameter, CreateFlags, allows you to set // various options for the device. The final parameter, // presentParams, contains the details about how the image will // be displayed in the render area, what buffers it will use, and // the formats it will have. device = new Device(0, DeviceType.Default, this, CreateFlags.None, presentParams); device.DeviceReset += new EventHandler( this.OnResetDevice); this.OnResetDevice(device, null); } catch (DirectXException) { return false; } return true; }
Under InitializeGraphics, add the following code.
void OnResetDevice(object sender, EventArgs e) { Device dev = (Device)sender; //Create sprite object on device sprite = new Sprite(dev); //Get the donuts resource out of the assembly and assign to //texture //Default parameters for TextureLoader.FromStream //(device, stream,D3DX.Default, D3DX.Default, D3DX.Default, // D3DX.Default, Usage.None, Format.Unknown, // Pool.VideoMemory,(Filter)D3DX.Default, (Filter)D3DX.Default, 0) //Load texture from the resource, and set the color black as the //alpha blended color texture = TextureLoader.FromStream(dev, Assembly.GetExecutingAssembly() .GetManifestResourceStream("Lab4.donuts.bmp"), D3DX.Default, D3DX.Default, D3DX.Default, D3DX.Default, Usage.None, Format.Unknown, Pool.VideoMemory, (Filter)D3DX.Default, (Filter)D3DX.Default, Color.Black.ToArgb()); //Configure TileSet to the size of tile in bmp tileSet = new TileSet(texture, 0, 0, 6, 5, 32, 32); //Set tilePosition including the offset to the center of the //sprite tilePosition = new Rectangle(tileSet.XOrigin, tileSet.YOrigin, tileSet.ExtentX * 2, tileSet.ExtentY * 2); //Add a call to Calcualte Scale here }
Add the following code to render the sprite.
private void Render() { //Clear the back buffer to a blue color device.Clear(ClearFlags.Target, System.Drawing.Color.BlueViolet, 1.0f, 0); //Begin the scene device.BeginScene(); sprite.Begin(SpriteFlags.AlphaBlend); //Add transform here //Draw a sprite at the current position sprite.Draw(tileSet.Texture, tilePosition, spriteCenter, spritePosition, Color.White.ToArgb()); sprite.End(); //End the scene device.EndScene(); device.Present(); //rotateSprite code here //moveSprite code here }
Add the following code for OnPaint, OnPointBackground and Main, which finishes the sample.
// Called to repaint the window protected override void OnPaint(PaintEventArgs e) { // Render on painting this.Render(); // Render again this.Invalidate(); } // Called to repaint the window's background protected override void OnPaintBackground(PaintEventArgs e) { // Do nothing to ensure that the rendering area is not overdrawn } static void Main() { CreateDevice frm = new CreateDevice(); // Initialize Direct3D if (!frm.InitializeGraphics()) { MessageBox.Show("Could not initialize Direct3D. " + "This tutorial will exit."); return; } Application.Run(frm); }
To compile and deploy the managed D3DM project
Press F5 to compile and run the application. If any compilation issues occur, you need to fix them.
On the Deploy dialog box, select Windows Mobile 5.0 PocketPC Device.
Click Deploy. Visual Studio deploys the project.
Click Yes when the device prompts you to accept the project from an unknown publisher.
On the managed D3DM device, click OK to close it.
In this exercise, you will move from tile to tile with each render loop, which makes the donut appear to spin.
To rotate the sprite
Add the following rotateSprite function above the Main function.
private void rotateSprite() { //Change the count to move to the next sprite tile if (++countX > 4) { countX = 0; if (++countY > 5) { countY = 0; } } //Set the coordinates for the current tile tilePosition.X = tileSet.XOrigin + (countX * tileSet.ExtentX * 2); tilePosition.Y = tileSet.YOrigin + (countY * tileSet.ExtentY * 2); }
Replace
//rotateSprite
code here with the following code to call rotateSprite from the Render function.rotateSprite();
To compile and deploy the managed D3DM project
Press F5 to compile and run the application. If any compilation issues occur, you need to fix them.
On the Deploy dialog box, select Windows Mobile 5.0 PocketPC Device.
Click Deploy. Visual Studio deploys the project.
Click Yes when the device prompts you to accept the project from an unknown publisher.
On the managed D3DM device, click OK to close it.
In this exercise, you will move the sprite around the screen. You will move the sprite location based on an x and y velocity set by using the direction keys.
To move the sprite
Above the Main function, add the following function to move the sprite.
private void moveSprite() { //Add collision logic here //Advance sprite by adding to its position the velocity spritePosition.X += spriteVelocity.X; spritePosition.Y += spriteVelocity.Y; //Add calculate sprite center here }
Replace
//moveSprite
code here with the following code to add the moveSprite function to the Render function.moveSprite();
Above the Main function, add the following code to change the spriteVelocity by using the navigation pad.
private void CreateDevice_KeyDown(object sender, KeyEventArgs e) { //Use rocker to modify the velocity if ((e.KeyCode == System.Windows.Forms.Keys.Up)) { // Rocker Up // Up spriteVelocity.Y -= 1; } if ((e.KeyCode == System.Windows.Forms.Keys.Down)) { // Rocker Down // Down spriteVelocity.Y += 1; } if ((e.KeyCode == System.Windows.Forms.Keys.Left)) { // Left spriteVelocity.X -= 1; } if ((e.KeyCode == System.Windows.Forms.Keys.Right)) { // Right spriteVelocity.X += 1 + 1; } }
Replace
// Add Key Event Handler here
with the following code to add the navigation pad event handler to the CreateDevice function.this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.CreateDevice_KeyDown);
To compile and deploy the managed D3DM project
Press F5 to compile and run the application. If any compilation issues occur, you need to fix them.
On the Deploy dialog box, select Windows Mobile 5.0 PocketPC Device.
Click Deploy. Visual Studio deploys the project.
Click Yes when the device prompts you to accept the project from an unknown publisher. You should see the blue managed D3DM device with the rotating donut. You can use the navigation pad to move it around.
On the managed D3DM device, click OK to close it.
You will notice from the last procedure that the donut moves off the screen and keeps going. In this exercise, you add will code to detect collisions with walls and change the velocity of the donut.
To detect walls and change the velocity by 90 degrees
Replace
//Add collision logic here
with the following collision code to add it to the moveSprite function.//Simple collision detection with end of screen. if ((spritePosition.X * scale) > (this.Width - (tileSet.ExtentX * 2 * scale)) || (spritePosition.X * scale) < 0) { //If the sprite hits either the left or right side of screen, //provide the reciprocal velocity spriteVelocity.X *= -1; } if ((spritePosition.Y * scale) > (this.Height - (tileSet.ExtentY * 2 * scale)) || (spritePosition.Y * scale) < 0) { //If the sprite hits either the top or bottom of the screen, //provide the reciprocal velocity spriteVelocity.Y *= -1; }
To compile and deploy the managed D3DM project
Press F5 to compile and run the application. If any compilation issues occur, you need to fix them.
On the Deploy dialog box, select Windows Mobile 5.0 PocketPC Device.
Click Deploy. Visual Studio deploys the project.
Click Yes when the device prompts you to accept the project from an unknown publisher. You should see the blue managed D3DM device with the rotating donut. You can use the navigation pad to move the donut around.
On the managed D3DM device, click OK to close it.
The donut image is created for a VGA screen with a screen resolution of 640 x 480. But not all devices have a VGA resolution. In this exercise, you will use a transform to modify the size of the donut according to the screen size.
To scale the donut to the current screen
Above the Main function, add the calculateScale function.
private float calculateScale() { //Donunts.bmp is drawn for a VGA resolution. If the device is not //VGA resolution, provide a scale to modify the image. float vgaWidth = 480; return this.Width / vgaWidth; }
Replace
//Add call to calculate scale here
with the following code.scale = calculateScale();
Replace
//Add calculate sprite center here
with the following code. Transforms need the sprite center calculated.spriteCenter.X = spritePosition.X + tileSet.ExtentX; spriteCenter.Y = spritePosition.Y + tileSet.ExtentY;
Replace
//Add transform here
with the following code to add the transform to the Render function.sprite.Transform = Matrix.Translation(spriteCenter) * Matrix.Scaling(scale, scale, 1.0f);
To compile and deploy the managed D3DM project
Press F5 to compile and run the application. If any compilation issues occur, you need to fix them.
On the Deploy dialog box, select Windows Mobile 5.0 PocketPC Device.
Click Deploy. Visual Studio deploys the project.
Click Yes when the device prompts you to accept the project from an unknown publisher. You should see the blue managed D3DM device with the rotating donut. You can use the navigation pad to move it around.
On the managed D3DM device, click OK to close it.
In this lab, you performed the following exercises:
- Rendering a static sprite
- Animating a sprite
- Moving a sprite
- Detecting collisions
- Scaling a sprite according to screen size