Phoenix, Adding to the Background

Monday, May 23 2005

Over the last few weeks I have looked over the code, and talked to others and have decided to make some changes to the code that we already have. These changes will assist in increasing the codes performance and generally tidy it up.

Changing the MainDisplay Class.

First off what I will get you to do is add the following line of code just under the section where you set up the const and main device objects.

private DrawText DebugText; // Drawtext Object for Debug Text

This will allow us to use the DrawText code that we added earlier, (I know I went over it a little bit in an earlier post but I just want to make sure it is in). Next I will get you to comment out this line of code "this.FormBorderStyle = FormBorderStyle.None;" from the MainDisplay_Load Procedure, this will allow the project to draw inside a true windows form giving it a title bar that you can grab to move the project form around. Now just under the section where we set the RenderState.ZBufferEnable in the InitializeGraphics Procedure add the following section of code, This will enable us to start handling the Device Reset Events.

// Added an OnDeviceReset Event 200504291100
device.DeviceReset += new System.EventHandler(this.OnResetDevice);
OnResetDevice(device, null);

Next add the following procedure to the MainDisplay Class.

private void OnResetDevice(object sender, EventArgs e)
{
     // Added an OnDeviceReset Event 200504291100
     Device device = (Device)sender;
}

Ok Thats Done, Last change to the MainDisplay.cs File for the moment is to add the following line just below where we set up the background object in the InitializeGraphics procedure.

// Set up the Debug Text Object
DebugText = new DrawText(device);

Thats it for MainDisplay.cs, Lets move onto the Background.cs file.

Making Changes and Animating the Background Object.

With this class and the changes I am making I will more then likely brease over the code and not explain a lot of it, but I will try and explain the changes that I do make and why. If you go back to the first article on the background object it will give you some more information on the basic functions.

Some of the major changes that I did make to this class where in the clean up of the objects, in this case I implemented the IDisposable Interface so that we can clean it up nice and neat. To get information on this I just did a simple look up on the MSDN Help files that where installed with the VSE C# Install. From there the example that is given gives you all the information to use it in your own classes. The next change was to do with the loading of the textures and the way I used the TextureLoader.

Now on to animating the back ground objects. For the project I wanted to have just a simple animated background that would be there to simulate the movement of the space craft while it was flying. To do this I thought that I would go back to an old way of animating it (Like we used to with Movie Animations and Cells). With this method I would have the main background that would stay still and then have another layer that would sit on top and just cycle through in an endless loop. So as you know we already have the first static layer drawn, so I had to draw another image that just has stars on it and and the rest of the image had a transparent alpha channel.
To animate this I copied the code that drew the first layer and replicated it three times so that I had, one section that loaded the background star layer, and the 3 background layer sprites. These three sprites would then be configured or positioned on the screen so that they could rotate.... I would have the first 1 drawn at 0.-600, the second at 0.0, and the last at 0.600. Then each time I processed a frame I would move the layers down, when each layer had a y position greater then 600 I would move it to -600 so it would then be at the top... and so the animation (in The ZMans words) works but looks very 70's.

So Here is the New Background.cs File.....

using System;
using System.Collections.Generic;
using System.Text;

using System.Drawing;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace Phoenix
{
    /// <summary>
    /// This is a basic Class that will be used to display a
    /// background image on a directX Device.
    /// Used for 2D Drawing on a D3D Device.
    /// </summary>
    public class Background : IDisposable
    {
        // Track whether Dispose has been called.
        private bool disposed = false;

        private float updateMovement = 2.0f;

        // Full path and file name to be used as the background
        private string backgroundImagePath = "";
        private string backgroundLayerImagePath = "";

        private Texture backgroundSpriteTexture;
        private Microsoft.DirectX.Direct3D.Sprite backgroundSprite;
        private Rectangle backgroundTextureSize;

        // to create a moveable image background layer we need three sprite locations
        // these will then be rotated around. But these will use the same sprite.
        private Texture backgroundLayerTexture;
        private Microsoft.DirectX.Direct3D.Sprite backgroundLayerSprite;
        private Rectangle backgroundLayerTextureSize;

        private Vector3 backgroundPosition = new Vector3(0,0,1);

        private Vector3 backgroundLayer1 = new Vector3(0,-600,1);
        private Vector3 backgroundLayer2 = new Vector3(0,0,1);
        private Vector3 backgroundLayer3 = new Vector3(0,600,1);

        /// <summary>
        /// Sets up the background Object
        /// </summary>
        /// <param name="device">The DirectX Device that the Background will
        /// be assigned to.</param>
        /// <param name="BackgroundImagePath">The Full path and filename
        /// to the Image file to be used as the background</param>
        public Background(Device device, string BackgroundImagePath, string BackgroundLayerPath)
        {

            backgroundImagePath = BackgroundImagePath;
            this.backgroundLayerImagePath = BackgroundLayerPath;
            // Load in the background texture from the file and assign it to
            // the sprite
            // backgroundSpriteTexture = TextureLoader.FromFile(device, backgroundImagePath);
            // Changed - 200504281200
            backgroundSpriteTexture = TextureLoader.FromFile(device, backgroundImagePath,
                0, 0, 1, Usage.None, Format.Unknown, Pool.Managed, Filter.None, Filter.None,0);

            using (Surface s = backgroundSpriteTexture.GetSurfaceLevel(0))
            {
                SurfaceDescription desc = s.Description;
                backgroundTextureSize = new Rectangle(0, 0, desc.Width, desc.Height);

            }
            backgroundSprite = new Sprite(device);

            backgroundLayerTexture = TextureLoader.FromFile(device, backgroundLayerImagePath,
    0, 0, 1, Usage.None, Format.Unknown, Pool.Managed, Filter.None, Filter.None, 0);

            using (Surface s = backgroundLayerTexture.GetSurfaceLevel(0))
            {
                SurfaceDescription desc = s.Description;
                backgroundLayerTextureSize = new Rectangle(0, 0, desc.Width, desc.Height);

            }
            backgroundLayerSprite = new Sprite(device);


        }
        /// <summary>
        /// Full file name and Path to the Image
        /// to be used as the background image.
        /// </summary>
        public string BackgroundImagePath
        {
            get { return backgroundImagePath; }
            set { backgroundImagePath = value; }
        }

        /// <summary>
        /// Draw the Background to the Device
        /// </summary>
        public void Draw()
        {
            backgroundSprite.Begin(SpriteFlags.AlphaBlend | SpriteFlags.SortTexture);
            backgroundSprite.Draw(backgroundSpriteTexture, backgroundTextureSize, new Vector3(0, 0, 0), this.backgroundPosition, Color.White);
            backgroundSprite.End();

            // Draw Background Layer
            backgroundLayerSprite.Begin(SpriteFlags.AlphaBlend | SpriteFlags.SortTexture);
            backgroundLayerSprite.Draw(backgroundLayerTexture, backgroundLayerTextureSize, new Vector3(0, 0, 0), this.backgroundLayer1, Color.White);
            backgroundLayerSprite.Draw(backgroundLayerTexture, backgroundLayerTextureSize, new Vector3(0, 0, 0), this.backgroundLayer2, Color.White);
            backgroundLayerSprite.Draw(backgroundLayerTexture, backgroundLayerTextureSize, new Vector3(0, 0, 0), this.backgroundLayer3, Color.White);
            backgroundLayerSprite.End();

            // 200505030722 - Added the SpriteFlags.SortTexture
            /* Sorts sprites by texture prior to drawing. This option is recommended
             * when drawing non-overlapping sprites of uniform depth; for example,
             * drawing screen-aligned text with Font.
             */

        }

        private void moveLayerDown()
        {
            if (this.backgroundLayer1.Y < 600)
                this.backgroundLayer1.Y += this.updateMovement;
            else
                this.backgroundLayer1.Y = -600;
            if (this.backgroundLayer2.Y < 600)
                this.backgroundLayer2.Y += this.updateMovement;
            else
                this.backgroundLayer2.Y = -600;
            if (this.backgroundLayer3.Y < 600)
                this.backgroundLayer3.Y += this.updateMovement;
            else
                this.backgroundLayer3.Y = -600;
        }

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if (disposing)
                {
                    backgroundSpriteTexture.Dispose();
                    backgroundLayerTexture.Dispose();
                    backgroundSprite.Dispose();
                    backgroundLayerSprite.Dispose();
                }

                // Call the appropriate methods to clean up
                // unmanaged resources here.
                // If disposing is false,
                // only the following code is executed.
               
            }
            disposed = true;        

        }

        ~Background()     
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(false) is optimal in terms of
            // readability and maintainability.
            Dispose(false);
        }

    }
}

Finally to intergrate this into the MainDisplay code replace the Setup Background code in the InitializeGraphics Procedure with the Following.

// Setup our Background
background = new Background(device,
      Properties.Settings.Default.MediaPathGraphics + "background.png",
      Properties.Settings.Default.MediaPathGraphics + "l2.png");

Now if you run the Application you should see the animated Background that I have been talking about. As always I will post the source code for this article in the forums for you to download.

Similar Posts

  1. Phoenix, Drawing Text on the Screen
  2. Phoenix, Drawing the Main Background for the Project
  3. Phoenix, Setting up the DirectX Device