using System; using System.Collections.Generic; using System.Linq; #if ANDROID using Android.App; #endif using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; namespace RenderTarget2DSample { /// /// This is the main type for your game /// public class Game1 : Microsoft.Xna.Framework.Game { /// /// The GraphicsDeviceManager is what creates and automagically manages the game's GraphicsDevice. /// GraphicsDeviceManager graphics; /// /// We use SpriteBatch to draw all of our 2D graphics. /// SpriteBatch spriteBatch; /// /// This is the rendertarget we'll be drawing to. /// RenderTarget2D renderTarget; /// /// This is a texture we'll be using to load a picture of Seamus the dog. /// Texture2D mooTheMerciless; /// /// This is a texture we'll be using to load a picture of a tileable wood surface. /// Texture2D wood; bool oneTimeOnly = true; /// /// The constructor for our Game1 class. /// public Game1 () { // Create the GraphicsDeviceManager for our game. graphics = new GraphicsDeviceManager (this); #if ANDROID || IOS graphics.IsFullScreen = true; #else graphics.PreferredBackBufferWidth = 800; graphics.PreferredBackBufferHeight = 600; graphics.IsFullScreen = false; #endif // Set the root directory of the game's ContentManager to the "Content" folder. Content.RootDirectory = "Content"; } /// /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// protected override void Initialize () { // We don't have anything to initialize. base.Initialize (); } /// /// LoadContent will be called once per game and is the place to load /// all of your content. /// protected override void LoadContent () { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch (GraphicsDevice); // Create a rendertarget that matches the back buffer's dimensions, does not generate mipmaps automatically // (the Reach profile requires power of 2 sizing in order to do that), uses an RGBA color format, and // has no depth buffer or stencil buffer. renderTarget = new RenderTarget2D (GraphicsDevice, GraphicsDevice.PresentationParameters.BackBufferWidth, GraphicsDevice.PresentationParameters.BackBufferHeight, false, SurfaceFormat.Color, DepthFormat.None); // Load in the picture of Seamus. mooTheMerciless = Content.Load ("MooTheMerciless"); // Load in our wood tile. wood = Content.Load ("wood"); } /// /// UnloadContent will be called once per game and is the place to unload /// all content. /// protected override void UnloadContent () { // While not strictly necessary, you should always dispose of assets you create // (excluding those you load the the ContentManager) when those assets implement // IDisposable. RenderTarget2D is one such asset type, so we dispose of it properly. if (renderTarget != null) { // We put this in a try-catch block. The reason is that if for some odd reason this failed // (e.g. we were using threading and nulled out renderTarget on some other thread), // then none of the rest of the UnloadContent method would run. Here it doesn't make a // difference, but it's good practice nonethless. try { renderTarget.Dispose (); renderTarget = null; } catch { } } } /// /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// /// Provides a snapshot of timing values. protected override void Update (GameTime gameTime) { // Allows the game to exit. If this is a Windows version, I also like to check for an Esc key press. I put // it within an #if WINDOWS .. #endif block since that way it won't run on other platforms. if (GamePad.GetState (PlayerIndex.One).Buttons.Back == ButtonState.Pressed //#if WINDOWS || Keyboard.GetState ().IsKeyDown (Keys.Escape) //#endif ) { this.Exit (); } // We don't have any update logic since this is just an example usage of RenderTarget2D base.Update (gameTime); } /// /// This is called when the game should draw itself. /// /// Provides a snapshot of timing values. protected override void Draw (GameTime gameTime) { // A one time only flag to help test for memory leaks if (oneTimeOnly) { oneTimeOnly = false; // Set renderTarget as the surface to draw to instead of the back buffer GraphicsDevice.SetRenderTarget (renderTarget); // Clear the renderTarget. By default it's all a bright purple color. I like to use Color.Transparent to // enable easy alpha blending. GraphicsDevice.Clear (Color.Transparent); Vector2 woodPosition = Vector2.Zero; // Begin drawing spriteBatch.Begin (); int xBlank = 0; int yBlank = 0; // Use nested do-whiles to fill the rendertarget with tiles. We use some trickery to draw every other tile do { do { // We use the modulus operator to get the remainder of dividing xBlank by 2. If xBlank is odd, it'll // return 1 and the spriteBatch.Draw call gets skipped. If it's even, it'll return 0 so // spriteBatch.Draw will get called and it'll draw a tile there. if (xBlank % 2 == 0) { spriteBatch.Draw (wood, woodPosition, Color.White); } // Increment xBlank by one so that every other tile will get drawn. xBlank++; // Increase the X coordinate of where we'll draw the wood tile in order to progressively draw // each column of tiles. woodPosition.X += wood.Width; // We draw so long as woodPosition.X is less than our renderTarget's width } while (woodPosition.X < renderTarget.Width); // We increment yBlank by one. Why is explained below. yBlank++; // We use the modulus operater to get the remainder of dividing yBlank by 2. If yBlank is odd, we reset // xBlank to 1. If it's even, we reset xBlank to 0. This way each row shifts by one so that the tiles // are drawn in a checkered pattern rather than in columns. if (yBlank % 2 == 0) { xBlank = 0; } else { xBlank = 1; } // Reset woodPosition.X to zero so that we start drawing from the beginning of the next row. woodPosition.X = 0; // Increase the Y coord of where we'll draw the wood tile in order to progressively draw each // row of tiles. woodPosition.Y += wood.Height; // We draw so long as woodPosition.Y is less than our renderTarget's width } while (woodPosition.Y < renderTarget.Height); // Now that we've drawn the wood tiles, we draw Moo the Merciless. We draw him centered in the rendertarget. spriteBatch.Draw (mooTheMerciless, new Vector2 ((renderTarget.Width / 2f) - (mooTheMerciless.Width / 2f), (renderTarget.Height / 2f) - (mooTheMerciless.Height / 2f)), Color.White); // End the spriteBatch draw. spriteBatch.End (); // Switch back to drawing onto the back buffer GraphicsDevice.SetRenderTarget (null); } // Now that we're back to drawing onto the back buffer, we want to clear it. If we had done so earlier // then when we switched to drawing to the render target, the old back buffer would've just be filled with // that bright purple color when we came back to it. GraphicsDevice.Clear (Color.CornflowerBlue); // Ok. At this point we have everything we drew in renderTarget, which we can use just like a regular Texture2D. // To make it look more interesting, we're going to scale up and down based on total elapsed time. float scale = 1.0f; if (gameTime.TotalGameTime.TotalSeconds % 10 < 5.0) { // We're running on a ten second scale timer. For the first five second we scale down from 1f to // no less than 0.01f. scale = MathHelper.Clamp (1f - (((float)gameTime.TotalGameTime.TotalSeconds % 5) / 5f), 0.01f, 1f); } else { // For the second five seconds, we scale up from no less than 0.01f up to 1f. scale = MathHelper.Clamp (((float)gameTime.TotalGameTime.TotalSeconds % 5) / 5f, 0.01f, 1f); } // Start spriteBatch again (this time drawing to the back buffer) spriteBatch.Begin (); // Now we draw our render target to the back buffer so that it will get displayed on the screen. We // position it in the center of the screen, but we make the origin be the center of the render target // such that it actually gets drawn centered (as opposed to shrinking and exanding with the left corner // in the center). We use our scale computation, and specify no SpriteEffects and an unused 0f for layer // depth spriteBatch.Draw (renderTarget, new Vector2 (GraphicsDevice.PresentationParameters.BackBufferWidth / 2, GraphicsDevice.PresentationParameters.BackBufferHeight / 2), null, Color.White, 0f, new Vector2 (renderTarget.Width / 2, renderTarget.Height / 2), scale, SpriteEffects.None, 0f); // End our spriteBatch call. spriteBatch.End (); base.Draw (gameTime); } } }