Managed DirectX Tutorial 02: Creating a 2D Sprite

Note: The assumption is being made that previous tutorials have already been completed and that a project is available and in a state to make the changes to be laid out in the current tutorial. That way the same classes and references do not need to be made in each tutorial, but instead new classes can be added and existing classes and procedures can be expanded upon.

2D Game Development with Managed DirectX: Tutorial 02 - Creating a 2D Sprite

In this tutorial a you will again see the wonderfully rendered black form, but on top of that black will be a sprite object with a texture applied. To display a 2D Sprite, we will be making use of the Sprite object and so a new reference to another Microsoft DirectX dll will be required. So that's where we will start.

::Add the DirectX References::

A new DirectX dll is required for displaying a 2D sprite, so double-click on "My Project" and add a new reference to your project.



Referenced Dlls:
Microsoft.Direct3DX

I've provided the exact dll version of the dll, in this case I use the 1.0.1901.0 version of the Managed DirectX dlls. Again, no particular reason and you can probably use the latest versions from the SDK with some tweaks to the code where functions and parameters have changed.

::Creating the DXSimpleSprite class::

Start by adding a new class to your project called "DXSimpleSprite". This class will store and manage the information important to store about a sprite object. Yet, the class itself will not have a sprite object in it. The reason for this decision is to limit the number of objects tht must be created in a game project. As you play around with game development you will start to look for ways to limit expensive objects and really be forced to use good objected oriented development practices.

To begin to construct the DXSimpleSprite class, we'll add two class level objects, one for storing a texture and one for storing a rectangle.

Class level objects and properties in DXSimpleSprite

    'The rectangular area of a texture that will be displayed on a sprite 

object
    Private mSourceRectangle As Rectangle
    Public ReadOnly Property SourceRectangle() As Rectangle
        Get
            Return mSourceRectangle
        End Get
    End Property
 
    'The texture to be applied to a sprite object
    Private mTexture As Microsoft.DirectX.Direct3D.Texture
    Public ReadOnly Property Texture() As Microsoft.DirectX.Direct3D.Texture
        Get
            Return mTexture
        End Get
    End Property

A Texture is a DirectX object. In the most basic sense, a texture is kind of like a blanket with an image on it. You can then put that blanket over a cardboard box and each side of that box will display some of that image on that blanket. In 2D game development we only pay attention to one face of the box and we decide which portion of the blanket we want to display on that side of the box by setting a source rectangle. The source rectangle defines which part of the texture we want to display. Or in the real world example I used, what part of the blanket we want to move around to have that part of it's image display on the particular face of the box we are looking at.

Now, let's move on to making the class construction.

Class constructors for DXSimpleSprite

    'Description: The class constructor. Store the source rectangle and load an image 

into a texture.
    Public Sub New(ByVal theDevice As Microsoft.DirectX.Direct3D.Device, ByVal theTextureName As String, ByVal isLoadedFromFile As Boolean, ByVal theHeight As Integer, ByVal theWidth As Integer)
        'Store the rectangle for the sprite, this is the size of a rectangle on an 

image that makes up the 
        'texture for the sprite.
        mSourceRectangle = New Rectangle(0, 0, theWidth, theHeight)
 
        'Load the image, either from a file or from the project in a 

stream
        If isLoadedFromFile = True Then
            mTexture = Microsoft.DirectX.Direct3D.TextureLoader.FromFile(theDevice, theTextureName, 

theWidth, theHeight, 24, 0, Microsoft.DirectX.Direct3D.Format.Unknown, Microsoft.DirectX.Direct3D.Pool.Default, Microsoft.DirectX.Direct3D.Filter.None, Microsoft.DirectX.Direct3D.Filter.None, 0)
        Else
            mTexture = Microsoft.DirectX.Direct3D.TextureLoader.FromStream(theDevice, Me.GetType().Assembly.GetManifestResourceStream(theTextureName))
        End If
    End Sub

The constructor for DXSimpleSprite takes a couple of parameters. First the device object. This is necessary so that a texture object can be created, but it is not necessary for the DXSimpleSprite class to know how to create a device, it just needs to make use of one already created.

The name of the texture will either be a path to an image file on disk or the name of a texture embedded as a stream in the project. The final parameter 'isLoadedFromFile' helps the constructor to determine which type of texture name has been passed into the constructor.

The height and the width passed in are used to construct the source rectangle. They help define what part of the texture we want to display on the sprite object.

So in the constructor, a source rectangle has been defined and stored and a texture object has been created either from file or from a stream. Typically in a project you would probably only use file or stream exclusively, but I wanted to demonstrate both methods of loading a texture.

Well, there really isn't much more to the DXSimpleSprite class, we've constructed it and now all that's left is destroying it and disposing of any objects it created.

Class Destructor and Dispose procedure DXSimpleSprite

    'Description: Class destructor, destroy the objects
    Protected Overrides Sub 

Finalize()
        Call Dispose()
 
        MyBase.Finalize()
    End Sub
 
    'Description: Dispose of the objects created in the class
    Private Sub Dispose()
        mSourceRectangle = Nothing
 
        If Not (mTexture Is Nothing) Then
            mTexture.Dispose()
        End If
        mTexture = Nothing
    End Sub

That's all we need for the new DXSimpleSprite class, now we need to begin enhancing other parts of the project to work with this newly created class.

::Enhancing the DX3DEngine class to support Sprites::

Now that we have a DXSimpleSprite class, the DX3DEngine needs to be enhanced to work with sprites. This will be accomplished by adding new sprite object and a procedure to draw a sprite. Again, by placing the sprite object in the Engine, only one sprite object will be needed for the entire project.

Sprite object and DrawSprite procedure for DX3DEngine

    'A Direct3D sprite object
    Private mSprite As Microsoft.DirectX.Direct3D.Sprite
    Public Sub DrawSprite(ByVal theSprite As DXSimpleSprite)
        If DeviceAvailable() = False Then
            Exit Sub
        End If
 
        If mSprite Is Nothing Then
            mSprite = New Microsoft.DirectX.Direct3D.Sprite(myD3DDevice)
        End If
 
        If mSprite.Disposed = True Then
            Exit Sub
        End If
 
        mSprite.Transform = Microsoft.DirectX.Matrix.Identity
        mSprite.Begin(Microsoft.DirectX.Direct3D.SpriteFlags.AlphaBlend)
        mSprite.Draw(theSprite.Texture, theSprite.SourceRectangle, New 

Microsoft.DirectX.Vector3(0.0F, 0.0F, 0.0F), New Microsoft.DirectX.Vector3(0.0F, 0.0F, 0.0F), 

Color.White)
        mSprite.End()
    End Sub

The procedure begins similar to the "BeginRender" procedures that were created previously. It first checks to make sure that a device is available for rending the sprite and if it isn't, the sub is exited so that errorr will not occur rendering to a device that has been disposed or is currently unavailable.

A check is then made to see if the class level sprite object has been created and if it hasn't one (and only one) is made. Next, a quick check to see if the sprite has been disposed. If this is the case then the application is most likely shutting down so we again don't want to cause errors by trying to render a sprite that's been disposed.

Next comes some more DirectX mumbo jumbo code. These are important concept to learn when you begin advancing further in 3D game development, but are not really necessary to be understood on any deep level for 2D development.

Tranform basically has to do with how the "cardboard box" needs to be changed or rotated. The DirectX help for "Transform"is awesome because it says (and I quote) "A Matrix object used to transform a Sprite object.". Boy, if that doesn't make it crystal clear what transform does....

Anyway, just know that we don't really want to "transform" our sprite at this moment and that's why we define the Identitymatrix...so moving on. We want to actually draw a sprite now and we see a familar pattern beginning to take place. Before you can draw something you have to "Begin" to draw, then draw and then "End" your drawing. This is a concept that DirectX uses over and over.

You can see that the "Begin" takes a parameter. This is actually an important parameter and learning to play with the different rendering flags you can pass in to the "Begin" procedure will help you achieve some different effects when rendering sprites. For now we will just use one flag, "AlphaBlend" which is useful and necessary when rendering text. (which we aren't but might want to at some point). I'm still learning a lot about the various flags and what they do whenset in the Begin myself so as I discover new techniques and tricks I will try and share.

Now we actually draw or "render" the sprite object on the DirectX device object. You can see that the Draw function usesquite a few of the properties of our DXSimpleSprite object and then a few defaults. First is uses the texture object so that the appropriate "blanket" can be draped over our sprite "box". Then it looks at the Source Rectangle so it knows which part of the texture "blanket" should be draped over the face of the box that is looking up at the screen. Next, it wants the "center" and "position" and alpha "color". For now those properties are just defaulted because we are only concerned with actually getting a sprite to render so we'll be revisiting some of those again in the future.

Then finally we "End" the rendering of the sprite.

Well, that's it for the DrawSprite procedure. Now we just need to be good little developers and add our new Sprite object to the Dispose procedure so we can be sure we are keeping things neat and tidy in memory.

Add the new Sprite Object to the Dispose procedure for DX3DEngine

    'Description: Dispose of the objects created in the class
    Private Sub Dispose()
        'Destroy the Present Parameters object
        mPresentParams = Nothing
 
        'Destroy the Direct3D Device object
        If Not (mDirect3DDevice Is Nothing) Then
            mDirect3DDevice.Dispose()
        End If
        mDirect3DDevice = Nothing
 
        'Destroy the Sprite object
        If Not (mSprite Is 

Nothing) Then
            mSprite.Dispose()
        End If
        mSprite = Nothing
    End Sub

Now that good coding practices have been maintained, we can move on to the next step in this tutorial. We have a DXSimpleSprite class, the DX3DEngine has been enhanced to draw a sprite so now the next thing we need to do is actually create a DXSimpleSprite somewhere and get it drawn. This will be done in the "GameEngine" class.

::Enhancing the Game Engine class::

To start out, a new class level DXSimpleSprite object needs to be added.

DXSimpleSprite Class level object for GameEngine

Public Class GameEngine
 
    Private mGraphics As DX3DEngine
    Private mFirstSprite As DXSimpleSprite

Now, the object needs to be created in the Class constructor.

DXSimpleSprite object creation in Class constructor for GameEngine

    'Description: The class constructor. Create the objects for the class
    Public Sub New(ByVal theRenderTarget As Control)
        mGraphics = New DX3DEngine(theRenderTarget, True)
 
        'Create a new spirte object from a file
        mFirstSprite = New DXSimpleSprite(mGraphics.myD3DDevice, "Textures/MyFirstSprite.PNG", True, 64, 64)
 
        'Create a new sprite object from a resource stream
        'mFirstSprite = New DXSimpleSprite(mGraphics.myD3DDevice, 

"CreatingA2DSprite.MyFirstSprite.PNG", False, 64, 64)
    End Sub

You can see that I've added to different creations of the sprite object, but one is commented out. I wanted to give both methods of creating the texture from file and from a stream. Just play around with using both so you can get familiar with the option available to you.

Well, now that we have the DXSimpleSprite object available, it can be rendered and we'll do that in the Render sub of theGameEngine class.

Render the Sprite in GameEngine

    'Description: Setup the device for rendering
    Public Sub Render()
        mGraphics.BeginRender()
        mGraphics.DrawSprite(mFirstSprite)
        mGraphics.EndRender()
    End Sub

The actually rendering of the sprits really is as simple as using the new "DrawSprite" procedure we crated in the DX3DEngine. The simple sprite object we've create in the GameEngine is passed in to the DrawSprite procedure and so it's that information that will be used when the sprite is drawn on the device.

We've created the simple sprite object, we've drawn it to the device so what's left? I hope you screamed it out loud because you're getting so used to it. WE DISPOSE OF THE OBJECTS WE CREATED IN OUR CLASS. Yep, that's correct. Let's make sure we clean up our mess.

Dispose of the new DXSimpleSprite object for GameEngine

    'Description: Dispose of any object created in the class
    Private Sub Dispose()
        mFirstSprite = Nothing
        mGraphics = Nothing
    End Sub

Well, that's it for the GameEngine, but don't compile and run just yet. There is still one more final thing we need to take care of. An actual image is needed to be used fo the texture. We referenced an image called "MyFirstSprite.PNG" in the constructor of the GameEngine class, but currently no such image exists.

::Adding the Images::

I've provided an image here, that can be used. And I'll walk through the process of adding an image as an embedded resource to your project.

To start, in the Solution Explorer add a new folder to your project called "Textures". Next, drag an image from a folder on your computer into that folder in your Solution Explorer. This will add that image to your project. Now select that image, and change the "Build Action" property to "Embedded Resource".



By changing the build action to "Embedded Resource" for that image, you will be able to reference it's stream in code by using a path like this "NameOfProject.ImageName.ImageExtension". In my case my project is called "CreatingA2Dsprite", my image name is "MyFirstSprite" and it's extension is "PNG" so I can reference the image stream using "CreatingA2DSprite.MyFirstSprite.PNG".

Well, that's it. Now that you have created the textures folder and moved the image into it, you can load it from the file from that location OR you can load it as a stream since you've also set it's build action to "Embedded Resource".

::The Rendered Sprite::

Now you can run it and you should see the lovely image of stick man raising his hand in joy at being rendered in such wonderful manner.



If only you could make him move....

The source code for the tutorial is available here.

While I begin work on the next tutorial, I would recommend playing with loading the images in both manners, making a few DXSimpleSprite objects to be rendered and making a few of your own images to be used as textures.

Again, I'm still very new tutorials and any feedback is welcome. If you found the tutorial useful, have a suggestion or just think they are a waste of time, please just take a few moments to leave me a comment. I appreciate the feedback!

Print | posted @ Saturday, July 08, 2006 8:10 AM

Comments on this entry:

Gravatar # re: Managed DirectX Tutorial 02: Creating a 2D Sprite
by HopeDagger at 7/8/2006 3:56 PM

Fantastic. Your code was very clear and concise, and even without really knowing VB.NET I fully (more or less ;P) understood what was going on and what was being shown.

I'm particularly glad that you decided to focus on the 2D side of Managed DirectX. There's a million tutorials on getting started with 3D, but a nice intro to 2D game development with a nifty API like MDX marks yours out as unique.

Great work, George! :)
Gravatar # re: Managed DirectX Tutorial 02: Creating a 2D Sprite
by DXNovice at 9/1/2006 2:34 AM

Finally a tutorial that explains the basics of 2D in D3D in a manner that is easy to understand for someone who has no idea what a matrix is... Just what I needed to get started. Rewriting the code to C# was good practice too! Thanks!
Gravatar # re: Managed DirectX Tutorial 02: Creating a 2D Sprite
by MarshalzLaw at 9/18/2006 8:55 PM

Why did sprite increases the size of image against its actual size being rendered. This streches the pixels and quality loose.
Gravatar # re: Managed DirectX Tutorial 02: Creating a 2D Sprite
by Quentin Carravagio at 2/19/2007 5:47 AM

Is there any one that knows how to Render the Textures dynamicly with the ratio of 30 frams per second
Gravatar # re: Managed DirectX Tutorial 02: Creating a 2D Sprite
by Wayne at 7/4/2008 11:27 PM

Excellent~0

Your comment:

Title:
Name:
Email:
Website:
 
Italic Underline Blockquote Hyperlink
 
 
Please add 2 and 1 and type the answer here:
 
Twitter