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:
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:
Private Shared Function n_RemoteStream(URL As String) As IO.Stream
The following method does a bit more but also needs explanation:
Public Shared Function n_Remote_Texture2D(Graphics As GraphicsDevice, _
URL As String) As Texture2D
And finally:
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 stream
s using Stream.Read
or Stream.Write
. Without seek, only exceptions.
The solution is a bit iffy:
- Get the data stream via HTTP(
WebRequest
) - Iterate through the bytes of the
stream
- writing it to a temporary file. - Load the
texture2D
into another stream
from the temporary file which is used to create the Texture2D
. Which has CanSeek=True
. - Keep a list of temporary files and loaded
stream
s to cleanup when the game or level unloads.
It works, but because the web stream
s 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:
- Ask for a
Texture2D
from an HTTP source. - Test the result.
- Display the result if successful.
- 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()
.
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()
.
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()
.
With spriteBatch
.Begin()
.Draw(MyRemoteTexture2D, New Vector2(100, 100), Color.White)
.Draw(MyRemoteTexture2D, New Vector2(100, 200), Color.White)
.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.
Protected Overrides Sub UnloadContent()
MyRemoteTexture2D.Dispose()
n_StreamHelper.n_CleanupTempData()
End Sub
If all goes well, you should see the following:
How You Can Expand It
- Resources could be downloaded during a loading screen.
- Try to download grid sprites, and sprite fonts in the same manner.
- Come up with a more bandwidth-optimized approach.
History
- July 14 2012: Original version