Advertisement
Spectrewiz

Star Field Depth Test (2d depth perception)

Oct 6th, 2012
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.98 KB | None | 0 0
  1. using System;
  2. using Microsoft.Xna.Framework;
  3. using Microsoft.Xna.Framework.Graphics;
  4. using Microsoft.Xna.Framework.Content;
  5.  
  6. namespace Starfield
  7. {
  8.     /// <summary>
  9.     /// The starfield that renders behind the game, including a parallax effect.
  10.     /// </summary>
  11.     public class Starfield : IDisposable
  12.     {
  13.         #region Constants
  14.  
  15.  
  16.         /// <summary>
  17.         /// The number of stars in the starfield.
  18.         /// </summary>
  19.         const int numberOfStars = 256;
  20.  
  21.         /// <summary>
  22.         /// The number of layers in the starfield.
  23.         /// </summary>
  24.         const int numberOfLayers = 8;
  25.  
  26.         /// <summary>
  27.         /// The colors for each layer of stars.
  28.         /// </summary>
  29.         static readonly Color[] layerColors = new Color[numberOfLayers]
  30.             {
  31.                 new Color(255, 255, 255, 255),
  32.                 new Color(255, 255, 255, 216),
  33.                 new Color(255, 255, 255, 192),
  34.                 new Color(255, 255, 255, 160),
  35.                 new Color(255, 255, 255, 128),
  36.                 new Color(255, 255, 255, 96),
  37.                 new Color(255, 255, 255, 64),
  38.                 new Color(255, 255, 255, 32)
  39.             };
  40.  
  41.         /// <summary>
  42.         /// The movement factor for each layer of stars, used in the parallax effect.
  43.         /// </summary>
  44.         static readonly float[] movementFactors = new float[numberOfLayers]
  45.             {
  46.                 0.9f, 0.8f, 0.7f, 0.6f, 0.5f, 0.4f, 0.3f, 0.2f
  47.             };
  48.  
  49.         /// <summary>
  50.         /// The maximum amount of movement allowed per update.
  51.         /// </summary>
  52.         /// <remarks>
  53.         /// Any per-update movement values that exceed this will trigger a
  54.         /// starfield reset.
  55.         /// </remarks>
  56.         const float maximumMovementPerUpdate = 128f;
  57.  
  58.         /// <summary>
  59.         /// The background color of the starfield.
  60.         /// </summary>
  61.         static readonly Color backgroundColor = new Color(0, 0, 32);
  62.  
  63.         /// <summary>
  64.         /// The size of each star, in pixels.
  65.         /// </summary>
  66.         const int starSize = 2;
  67.  
  68.  
  69.         #endregion
  70.  
  71.  
  72.         #region Gameplay Data
  73.  
  74.  
  75.         /// <summary>
  76.         /// The last position, used for the parallax effect.
  77.         /// </summary>
  78.         private Vector2 lastPosition;
  79.  
  80.         /// <summary>
  81.         /// The current position, used for the parallax effect.
  82.         /// </summary>
  83.         private Vector2 position;
  84.  
  85.         /// <summary>
  86.         /// The stars in the starfield.
  87.         /// </summary>
  88.         private Vector2[] stars;
  89.  
  90.  
  91.         #endregion
  92.  
  93.  
  94.         #region Graphics Data
  95.  
  96.  
  97.         /// <summary>
  98.         /// The graphics device used to render the starfield.
  99.         /// </summary>
  100.         private GraphicsDevice graphicsDevice;
  101.  
  102.         /// <summary>
  103.         /// The content manager used to manage the textures in the starfield.
  104.         /// </summary>
  105.         private ContentManager contentManager;
  106.  
  107.         /// <summary>
  108.         /// The SpriteBatch used to render the starfield.
  109.         /// </summary>
  110.         private SpriteBatch spriteBatch;
  111.  
  112.         /// <summary>
  113.         /// The texture used for each star, typically one white pixel.
  114.         /// </summary>
  115.         private Texture2D starTexture;
  116.  
  117.         /// <summary>
  118.         /// The cloud texture that appears behind the stars.
  119.         /// </summary>
  120.         private Texture2D cloudTexture;
  121.  
  122.         /// <summary>
  123.         /// The effect used to draw the clouds.
  124.         /// </summary>
  125.         private Effect cloudEffect;
  126.  
  127.         /// <summary>
  128.         /// The parameter on the cloud effect that receives the current position
  129.         /// </summary>
  130.         private EffectParameter cloudEffectPosition;
  131.  
  132.  
  133.         #endregion
  134.  
  135.  
  136.         #region Initialization Methods
  137.  
  138.  
  139.         /// <summary>
  140.         /// Create a new Starfield object.
  141.         /// </summary>
  142.         /// <param name="position"></param>
  143.         /// <param name="graphicsDevice">The graphics device used to render.</param>
  144.         /// <param name="contentManager">The content manager for this object.</param>
  145.         public Starfield(Vector2 position, GraphicsDevice graphicsDevice,
  146.             ContentManager contentManager)
  147.         {
  148.             // safety-check the parameters, as they must be valid
  149.             if (graphicsDevice == null)
  150.             {
  151.                 throw new ArgumentNullException("graphicsDevice");
  152.             }
  153.             if (contentManager == null)
  154.             {
  155.                 throw new ArgumentNullException("contentManager");
  156.             }
  157.  
  158.             // assign the parameters
  159.             this.graphicsDevice = graphicsDevice;
  160.             this.contentManager = contentManager;
  161.  
  162.             // initialize the stars
  163.             stars = new Vector2[numberOfStars];
  164.             Reset(position);
  165.         }
  166.  
  167.  
  168.         /// <summary>
  169.         /// Load graphics data from the system.
  170.         /// </summary>
  171.         public void LoadContent()
  172.         {
  173.             // load the cloud texture
  174.             cloudTexture = contentManager.Load<Texture2D>("Textures/Clouds");
  175.  
  176.             // load the cloud effect
  177.             cloudEffect = contentManager.Load<Effect>("Effects/Clouds");
  178.             cloudEffectPosition = cloudEffect.Parameters["Position"];
  179.      
  180.             // create the star texture
  181.             starTexture = new Texture2D(graphicsDevice, 1, 1, false, SurfaceFormat.Color);
  182.             starTexture.SetData<Color>(new Color[] { Color.White });
  183.  
  184.             // create the SpriteBatch object
  185.             spriteBatch = new SpriteBatch(graphicsDevice);
  186.         }
  187.  
  188.  
  189.         /// <summary>
  190.         /// Release graphics data.
  191.         /// </summary>
  192.         public void UnloadContent()
  193.         {
  194.             cloudTexture = null;
  195.             cloudEffect = null;
  196.             cloudEffectPosition = null;
  197.  
  198.             if (starTexture != null)
  199.             {
  200.                 starTexture.Dispose();
  201.                 starTexture = null;
  202.             }
  203.  
  204.             if (spriteBatch != null)
  205.             {
  206.                 spriteBatch.Dispose();
  207.                 spriteBatch = null;
  208.             }
  209.         }
  210.  
  211.  
  212.         /// <summary>
  213.         /// Reset the stars and the parallax effect.
  214.         /// </summary>
  215.         /// <param name="position">The new origin point for the parallax effect.</param>
  216.         public void Reset(Vector2 position)
  217.         {
  218.             // recreate the stars
  219.             int viewportWidth = graphicsDevice.Viewport.Width;
  220.             int viewportHeight = graphicsDevice.Viewport.Height;
  221.             for (int i = 0; i < stars.Length; ++i)
  222.             {
  223.                 stars[i] = new Vector2(RandomMath.Random.Next(0, viewportWidth),
  224.                     RandomMath.Random.Next(0, viewportHeight));
  225.             }
  226.  
  227.             // reset the position
  228.             this.lastPosition = this.position = position;
  229.         }
  230.  
  231.  
  232.         #endregion
  233.  
  234.  
  235.         #region Draw Methods
  236.  
  237.  
  238.         /// <summary>
  239.         /// Update and draw the starfield.
  240.         /// </summary>
  241.         /// <remarks>
  242.         /// This function updates and draws the starfield,
  243.         /// so that the per-star loop is only run once per frame.
  244.         /// </remarks>
  245.         /// <param name="position">The new position for the parallax effect.</param>
  246.         public void Draw(Vector2 position)
  247.         {
  248.             // update the current position
  249.             this.lastPosition = this.position;
  250.             this.position = position;
  251.  
  252.             // determine the movement vector of the stars
  253.             // -- for the purposes of the parallax effect,
  254.             //    this is the opposite direction as the position movement.
  255.             Vector2 movement = -1.0f * (position - lastPosition);
  256.  
  257.             // create a rectangle representing the screen dimensions of the starfield
  258.             Rectangle starfieldRectangle = new Rectangle(0, 0,
  259.                 graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height);
  260.  
  261.             // draw a background color for the starfield
  262.             spriteBatch.Begin();
  263.             spriteBatch.Draw(starTexture, starfieldRectangle, backgroundColor);
  264.             spriteBatch.End();
  265.  
  266.             // draw the cloud texture
  267.             cloudEffectPosition.SetValue(this.position);
  268.             spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied,
  269.                 null, null, null, cloudEffect);
  270.             spriteBatch.Draw(cloudTexture, starfieldRectangle, null, Color.White, 0.0f,
  271.                 Vector2.Zero, SpriteEffects.None, 1.0f);
  272.             spriteBatch.End();
  273.  
  274.             // if we've moved too far, then reset, as the stars will be moving too fast
  275.             if (movement.Length() > maximumMovementPerUpdate)
  276.             {
  277.                 Reset(position);
  278.                 return;
  279.             }
  280.  
  281.             // draw all of the stars
  282.             spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
  283.             for (int i = 0; i < stars.Length; i++)
  284.             {
  285.                 // move the star based on the depth
  286.                 int depth = i % movementFactors.Length;
  287.                 stars[i] += movement * movementFactors[depth];
  288.  
  289.                 // wrap the stars around
  290.                 if (stars[i].X < starfieldRectangle.X)
  291.                 {
  292.                     stars[i].X = starfieldRectangle.X + starfieldRectangle.Width;
  293.                     stars[i].Y = starfieldRectangle.Y +
  294.                         RandomMath.Random.Next(starfieldRectangle.Height);
  295.                 }
  296.                 if (stars[i].X > (starfieldRectangle.X + starfieldRectangle.Width))
  297.                 {
  298.                     stars[i].X = starfieldRectangle.X;
  299.                     stars[i].Y = starfieldRectangle.Y +
  300.                         RandomMath.Random.Next(starfieldRectangle.Height);
  301.                 }
  302.                 if (stars[i].Y < starfieldRectangle.Y)
  303.                 {
  304.                     stars[i].X = starfieldRectangle.X +
  305.                         RandomMath.Random.Next(starfieldRectangle.Width);
  306.                     stars[i].Y = starfieldRectangle.Y + starfieldRectangle.Height;
  307.                 }
  308.                 if (stars[i].Y >
  309.                     (starfieldRectangle.Y + graphicsDevice.Viewport.Height))
  310.                 {
  311.                     stars[i].X = starfieldRectangle.X +
  312.                         RandomMath.Random.Next(starfieldRectangle.Width);
  313.                     stars[i].Y = starfieldRectangle.Y;
  314.                 }
  315.  
  316.                 // draw the star
  317.                 spriteBatch.Draw(starTexture,
  318.                     new Rectangle((int)stars[i].X, (int)stars[i].Y, starSize, starSize),
  319.                     null, layerColors[depth]);
  320.             }
  321.             spriteBatch.End();
  322.         }
  323.  
  324.  
  325.         #endregion
  326.  
  327.    
  328.         #region IDisposable Implementation
  329.  
  330.  
  331.         /// <summary>
  332.         /// Finalizes the Starfield object, calls Dispose(false)
  333.         /// </summary>
  334.         ~Starfield()
  335.         {
  336.             Dispose(false);
  337.         }
  338.  
  339.  
  340.         /// <summary>
  341.         /// Disposes the Starfield object.
  342.         /// </summary>
  343.         public void Dispose()
  344.         {
  345.             Dispose(true);
  346.             GC.SuppressFinalize(this);
  347.         }
  348.  
  349.        
  350.         /// <summary>
  351.         /// Disposes this object.
  352.         /// </summary>
  353.         /// <param name="disposing">
  354.         /// True if this method was called as part of the Dispose method.
  355.         /// </param>
  356.         protected virtual void Dispose(bool disposing)
  357.         {
  358.             if (disposing)
  359.             {
  360.                 lock (this)
  361.                 {
  362.                     if (starTexture != null)
  363.                     {
  364.                         starTexture.Dispose();
  365.                         starTexture = null;
  366.                     }
  367.                     if (spriteBatch != null)
  368.                     {
  369.                         spriteBatch.Dispose();
  370.                         spriteBatch = null;
  371.                     }
  372.                 }
  373.             }
  374.         }
  375.  
  376.  
  377.         #endregion
  378.     }
  379. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement