Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / game

XNA: How to Load Texture2D Sprites from HTTP

5.00/5 (1 vote)
14 Jul 2012CPOL4 min read 19.1K   341  
When you want your Texture2D resource to download from the Internet

Introduction

This example demonstrates downloading an image from the internet and then drawing it in an XNA Windows game. The image used in this example is none other than CodeProject's very own logo:

Image 1

Please note the following:

  • This applies to Windows Games. Probably works Windows Phone 7, but I have not tested it or looked into this. I have never had interest in compiling for Windows Phone.
  • Not for XBOX Games. We need to reference System.Net. From my understanding - it is a part of the .NET Framework not available on XNA for XBOX. I could be wrong. I don't develop for XBOX!
  • Project is a Visual Studio 2010 solution for XNA with the Windows Phone SDK 7.1 with Visual Basic. I suggest ensuring your XNA Game Studio is updated: XNA Game Studio 4.0 Refresh which includes support for Visual Basic unless you plan to port this to C#.
  • This project should compile in Visual Basic 2010 Express provided the required SDKs are installed, as well as Visual Studio Professional.
  • This generates temporary files. Never forget to clean them up. A method is supplied.

Background

While developing a 2D Game in XNA for Windows, I came up with the idea that for small 2D Games it could be possible to download image resources used as Texture2D sprites directly from a website via HTTP.

The purpose behind this idea is that Game Levels, and all resources, sprites and such through a dynamic instanced universe would be generated and stored entirely on the internet.

When a player moves through a gate to a new map instance - then we would download only the resources we need for that map - and the units.

This allows for a map's resources to change at any time on the webserver - the next time the player visits a particular map - changes in the resources would be noticeable.

This was intended for 2D MMO development where all content is stored on a server. While not particularly bandwidth efficient - this is just an example to demonstrate how you could load Texture2D resources from an HTTP URI. Which you can use as sprites and such.

What It Does

There is a simple NotInheritable class included. This contains the methods we need. It also keeps a temporary file list, as well as an array holding streams that need to be disposed when your game is unloading.

The included n_StreamHelper.vb has the following members:

VB.NET
' This uses System.Net.WebRequest to fetch a stream from the internet.
Private Shared Function n_RemoteStream(URL As String) As IO.Stream 

The following method does a bit more but also needs explanation:

VB.NET
Public Shared Function n_Remote_Texture2D(Graphics As GraphicsDevice, _
URL As String) As Texture2D

And finally:

VB.NET
Public Shared Sub n_CleanupTempData()

n_Remote_Texture2D() uses n_RemoteStream() to retrieve a stream via System.Net.WebRequest.

Initially, I had attempted to create a Texture2D directly from this stream but discovered Texture2D objects required a stream with <code>IO.Stream.<code>CanSeek=True.

The stream gained from Request.GetResponse().GetResponseStream() does not return stream with seek ability. This also proved to be a problem when writing it to other streams using Stream.Read or Stream.Write. Without seek, only exceptions.

The solution is a bit iffy:

  1. Get the data stream via HTTP(WebRequest)
  2. Iterate through the bytes of the stream - writing it to a temporary file.
  3. Load the texture2D into another stream from the temporary file which is used to create the Texture2D. Which has CanSeek=True.
  4. Keep a list of temporary files and loaded streams to cleanup when the game or level unloads.

It works, but because the web streams were not seek capable - we are forced to create a file stream and save the temporary resource there. Followed by a new stream using a filestream. It's a bit ugly.

Using the Code

Usage is pretty simple:

  1. Ask for a Texture2D from an HTTP source.
  2. Test the result.
  3. Display the result if successful.
  4. When game or level unloads - cleanup the temporary files.

1: So from the beginning, we request the resource. I am using a URI pointing directly to CodeProject's Logo Gif. Which we will display as a Texture2D. Texture2D Supports PNG, JPEG and GIF. We do this within LoadContent().

VB.NET
' Request a texture2D from a location on the internet.
MyRemoteTexture2D = n_StreamHelper.n_Remote_Texture2D _
        (
            GraphicsDevice,
            "http://s.codeproject.com/App_Themes/Std/Img/logo225x90.gif"
        )

2: Now we have to test the result. If it failed (or you are not connected to the internet), the result will be Nothing (Null). We do this within LoadContent().

VB.NET
' Test the result:
If MyRemoteTexture2D Is Nothing Then
    MsgBox("Failed to download resource from the internet")
    Me.Exit()
End If 

3: Display the result. Just like any other Texture2D we can draw it with our SpriteBatch. Within our game's Drawing routine: We do this within Draw().

VB.NET
With spriteBatch
    .Begin()
 
    ' Draw our texture2D at point 100, 100
    .Draw(MyRemoteTexture2D, New Vector2(100, 100), Color.White)
 
    ' draw it again:
    .Draw(MyRemoteTexture2D, New Vector2(100, 200), Color.White)
 
    ' and again:
    .Draw(MyRemoteTexture2D, New Vector2(100, 300), Color.White)
 
    .End()
End With

4: We want to remove all the temporary files that we have downloaded when we are done with them.
We do this within UnloadContent() or whenever you don't need them anymore.

VB.NET
''' <summary>
''' UnloadContent will be called once per game and is the place to unload
''' all content.
''' </summary>
Protected Overrides Sub UnloadContent()
    ' TODO: Unload any non ContentManager content here
    
    '  unload texture2D:
    MyRemoteTexture2D.Dispose()
 
    ' clean up temp data. ALL Texture2D created from URI should be Disposed first:
    ' --> otherwise some temp files won't be removed
    n_StreamHelper.n_CleanupTempData()
 
End Sub

If all goes well, you should see the following:

Image 2

How You Can Expand It

  1. Resources could be downloaded during a loading screen.
  2. Try to download grid sprites, and sprite fonts in the same manner.
  3. Come up with a more bandwidth-optimized approach.

History

  • July 14 2012: Original version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)