1508 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			1508 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using System.Text;
 | |
| using System.Threading.Tasks;
 | |
| using System.Threading;
 | |
| using System.ComponentModel;
 | |
| using System.Drawing;
 | |
| using System.Windows.Forms;
 | |
| using System.IO;
 | |
| using System.IO.Packaging;
 | |
| 
 | |
| namespace SpriteLibrary
 | |
| {
 | |
|     /// <summary>
 | |
|     /// SpriteLibrary is a .net graphical library for creating and controlling sprites on a PictureBox.
 | |
|     /// 
 | |
|     /// A sprite is an animated image that can be moved around on a
 | |
|     /// picturebox.  You can give the sprite an initial location, and either move it around manually or give it
 | |
|     /// specific movement controls.
 | |
|     /// 
 | |
|     /// To use this library, you will need to add a reference to it in your project.  You will also need a reference to
 | |
|     /// "Windows Base."
 | |
|     /// In the solution explorer, if you right-click your project and go to "add", and then "reference" and click 
 | |
|     /// "WindowsBase" towards the bottom.
 | |
|     /// On that same window, on the left, click "browse." Then, click the "Browse..." button and find the sprite-library dll.
 | |
|     /// The main places to find the SpriteLibrary and sample programs using this SpriteLibrary are here: 
 | |
|     /// <see href="http://www.codeproject.com/Articles/1085446/Using-Sprites-Inside-Windows-Forms"/>
 | |
|     /// and
 | |
|     /// <see href="http://tyounglightsys.ddns.info/SpriteLibrary"/>
 | |
|     /// </summary>
 | |
|     internal class NamespaceDoc
 | |
|     {
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// The various types of collisions a sprite can have.  Currently only rectangle works.  The other types were added when I
 | |
|     /// thought the different types of collision types were needed.  Someday we may add these if we find they are useful, or if
 | |
|     /// someone else decides they want to help program the SpriteLibrary.  These values are primarily used in Sprite Events
 | |
|     /// </summary>
 | |
|     public enum SpriteCollisionMethod {
 | |
|         /// <summary>
 | |
|         /// Checks if the two rectangles that contain the sprites overlap.  Each rectangle is the starting location of the sprite
 | |
|         /// (top left) with the sprite width, and height marking the other sides of the rectangle.
 | |
|         /// </summary>
 | |
|         rectangle,
 | |
|         /// <summary>
 | |
|         /// Draws a circle (ellipse) inside the sprite rectangles and see if those ellipses overlap
 | |
|         /// </summary>
 | |
|         circle,
 | |
|         /// <summary>
 | |
|         /// Check to see if nontransparent portions of a sprite collide.  Not working.
 | |
|         /// </summary>
 | |
|         transparency }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// A structure that contains the width and height adjustment ratio.  Use this if you need to manually calculate positions
 | |
|     /// between the PictureBox that the sprite is in, and the Background Image itself.
 | |
|     /// </summary>
 | |
|     public struct SpriteAdjustmentRatio {
 | |
|         /// <summary>
 | |
|         /// Divide a picturebox ratio by this to get the image location.  Multiply an image location by this to get the picturebox location.
 | |
|         /// </summary>
 | |
|         public double width_ratio;
 | |
|         /// <summary>
 | |
|         /// Divide a picturebox ratio by this to get the image location.  Multiply an image location by this to get the picturebox location.
 | |
|         /// </summary>
 | |
|         public double height_ratio; }
 | |
|     /// <summary>
 | |
|     /// The type of pause signals you can give a sprite or the sprite controller
 | |
|     /// </summary>
 | |
|     public enum SpritePauseType {
 | |
|         /// <summary>
 | |
|         /// Pause the animating.  Animation resumes from the current frame when we unpause.  A paused animation will continue
 | |
|         /// to display the same image frame until it is unpaused.
 | |
|         /// </summary>
 | |
|         PauseAnimation,
 | |
|         /// <summary>
 | |
|         /// Pause any automatic movement.  Movement resumes where it was left off if you unpause.  The sprite will 
 | |
|         /// just sit there until unpaused. 
 | |
|         /// </summary>
 | |
|         PauseMovement,
 | |
|         /// <summary>
 | |
|         /// Pause events. Sprite collisions, movement checks, etc are stopped until the unpause.
 | |
|         /// </summary>
 | |
|         PauseEvents,
 | |
|         /// <summary>
 | |
|         /// All pausable things are paused.  PauseAnimation, PauseMovement, and PauseEvents.
 | |
|         /// </summary>
 | |
|         PauseAll }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// A sprite controller is the main heart of the sprite class.  Each SpriteController manages one picturebox.
 | |
|     /// If at all possible, try to keep each game in one picturebox, and try to avoid making and destroying
 | |
|     /// new forms with SpriteController/pictureboxes in them.  It is hard to destroy them completely.
 | |
|     /// </summary>
 | |
|     /// <example>
 | |
|     /// A sprite controller controls animations and
 | |
|     /// can help you check for <see cref="SpriteController.IsKeyPressed(Keys)">key-presses.</see> To make a sprite controller,
 | |
|     /// you need to have one defined for your main form:
 | |
|     /// <code language="C#">
 | |
|     /// SpriteController MySpriteController;
 | |
|     /// </code>
 | |
|     /// And then, when the form is created, after the InitializeComponents() function, you
 | |
|     /// need to configure the drawing area and create the sprite controller:
 | |
|     /// <code language="C#">
 | |
|     /// MainDrawingArea.BackgroundImage = Properties.Resources.Background;
 | |
|     /// MainDrawingArea.BackgroundImageLayout = ImageLayout.Stretch;
 | |
|     /// MySpriteController = new SpriteController(MainDrawingArea);
 | |
|     /// </code>
 | |
|     /// In this case, MainDrawingArea is the picturebox where all the sprites will be displayed.
 | |
|     /// </example>
 | |
|     public class SpriteController
 | |
|     {
 | |
|         Image MyOriginalImage;  //The untainted background
 | |
|         PictureBox DrawingArea;   //The PictureBox we draw ourselves on
 | |
|         List<Sprite> Sprites = new List<Sprite>();
 | |
|         List<SpriteController> LinkedControllers = new List<SpriteController>(); //Other sprite controllers that we share sprites with
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Since everything needs a random number generator, we make one that should be accessible throughout your program.
 | |
|         /// </summary>
 | |
|         public Random RandomNumberGenerator = new Random();
 | |
| 
 | |
|         /// <summary>
 | |
|         /// This is only used by the SpriteController.  It allows us to queue up invalidation requests.
 | |
|         /// </summary>
 | |
|         private List<Rectangle> InvalidateList = new List<Rectangle>();
 | |
| 
 | |
|         private KeyMessageFilter MessageFilter = new KeyMessageFilter();
 | |
|         /// <summary>
 | |
|         /// The count of all the sprites the controller knows about.  This includes named 
 | |
|         /// sprites, which may not be visible.
 | |
|         /// </summary>
 | |
|         public int SpriteCount { get { return Sprites.Count; } }
 | |
|         System.Windows.Forms.Timer MyTimer = new System.Windows.Forms.Timer();
 | |
|         //private bool lockObject=false;
 | |
|         //System.Threading.Timer ThreadTimer; 
 | |
| 
 | |
| 
 | |
|         //These two are used for tracking mouse-leave, and mouse enter functions.
 | |
|         private Point MousePoint = Point.Empty;
 | |
|         private List<Sprite> SpritesUnderMouse = new List<Sprite>();
 | |
|         private List<Sprite> SpritesUnderMouseTransparent = new List<Sprite>();
 | |
| 
 | |
|         private SpriteAdjustmentRatio _AdjustmentRatio;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// If your sprite images need substantial growing or shrinking when displayed, you can try setting this to "true"
 | |
|         /// to see if it makes it run any faster.  What it does is to resize the image once, and keep a cached copy of that
 | |
|         /// image at that size.  If you use the same sprite, but with different sizes, setting this to "True" may actually slow
 | |
|         /// down the game instead of speeding it up.
 | |
|         /// </summary>
 | |
|         public bool OptimizeForLargeSpriteImages = false;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a sprite controller, specifying the picturebox on which the sprites
 | |
|         /// will be displayed.  You want to have the PictureBox already defined, and a background image
 | |
|         /// already set for the PictureBox.
 | |
|         /// </summary>
 | |
|         /// <example>
 | |
|         /// This is an example of a Form class that defines a SpriteController.  The MainDrawingArea is a 
 | |
|         /// <see cref="System.Windows.Forms.PictureBox">PictureBox.</see>
 | |
|         /// <code lang="C#">
 | |
|         /// public partial class ShootingFieldForm : Form
 | |
|         /// {
 | |
|         ///     public ShootingFieldForm()
 | |
|         ///     {
 | |
|         ///         InitializeComponent();
 | |
|         ///         MainDrawingArea.BackgroundImage = Properties.Resources.Background;
 | |
|         ///         MainDrawingArea.BackgroundImageLayout = ImageLayout.Stretch;
 | |
|         ///         MySpriteController = new SpriteController(MainDrawingArea);
 | |
|         ///     }
 | |
|         /// }
 | |
|         /// </code>
 | |
|         /// </example>
 | |
|         /// <param name="Area">The <see cref="System.Windows.Forms.PictureBox">PictureBox.</see> 
 | |
|         /// that the sprites will be drawn in</param>
 | |
|         public SpriteController(PictureBox Area)
 | |
|         {
 | |
|             DrawingArea = Area;
 | |
|             Local_Setup();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Create a sprite controller, specifying the picturebox on which the sprites
 | |
|         /// will be displayed.
 | |
|         /// </summary>
 | |
|         /// <example>
 | |
|         /// This is an example of a Form class that defines a SpriteController.  The MainDrawingArea is a 
 | |
|         /// <see cref="System.Windows.Forms.PictureBox">PictureBox.</see>  While defining the SpriteController, we
 | |
|         /// are also setting a function used for the <see cref="SpriteLibrary.SpriteController.DoTick">DoTick.</see> event.
 | |
|         /// <code lang="C#">
 | |
|         /// public partial class ShootingFieldForm : Form
 | |
|         /// {
 | |
|         ///     public ShootingFieldForm()
 | |
|         ///     {
 | |
|         ///         InitializeComponent();
 | |
|         ///         MainDrawingArea.BackgroundImage = Properties.Resources.Background;
 | |
|         ///         MainDrawingArea.BackgroundImageLayout = ImageLayout.Stretch;
 | |
|         ///         MySpriteController = new SpriteController(MainDrawingArea, CheckForKeyPress);
 | |
|         ///     }
 | |
|         ///     
 | |
|         ///     private void CheckForKeyPress(object sender, EventArgs e)
 | |
|         ///     {
 | |
|         ///         //Do stuff here
 | |
|         ///     }
 | |
|         /// }
 | |
|         /// 
 | |
|         /// </code>
 | |
|         /// </example>
 | |
|         /// <param name="Area">The picturebox that the sprites will be drawn in</param>
 | |
|         /// <param name="TimerTickMethod">A function on the form that you want to have run every tick</param>
 | |
|         public SpriteController(PictureBox Area, System.EventHandler TimerTickMethod)
 | |
|         {
 | |
|             DrawingArea = Area;
 | |
|             Local_Setup();
 | |
|             DoTick += new System.EventHandler(TimerTickMethod);
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Define some things and set up some things that need defining at instantiation
 | |
|         /// </summary>
 | |
|         private void Local_Setup()
 | |
|         {
 | |
|             //Make a clone of the background image.  We take images from the "original image"
 | |
|             //when we want to erase a sprite and re-draw it elsewhere.
 | |
|             if (DrawingArea.BackgroundImage == null)
 | |
|             {
 | |
|                 DrawingArea.BackgroundImage = new Bitmap(800, 600);
 | |
|                 Graphics.FromImage(DrawingArea.BackgroundImage).FillRectangle(new SolidBrush(Form.DefaultBackColor), 
 | |
|                     new Rectangle(0,0,800,600)); //Fill it with the default background color.
 | |
|             }
 | |
|             MyOriginalImage = (Image)DrawingArea.BackgroundImage.Clone(); //Duplicate it and store it
 | |
|                                                                           //The messagefilter allows us to check for keypresses.
 | |
|             Application.AddMessageFilter(MessageFilter);
 | |
| 
 | |
|             //Set up the timer.
 | |
|             MyTimer.Interval = 10;
 | |
|             MyTimer.Tick += TimerTick;
 | |
|             MyTimer.Start();
 | |
|             //ThreadTimer = new System.Threading.Timer(TryTimer, null, 0, 10);
 | |
| 
 | |
|             //Add a mouseclick event
 | |
|             DrawingArea.MouseClick += MouseClickOnBox;
 | |
|             DrawingArea.MouseHover += MouseHover;
 | |
|             DrawingArea.MouseMove += MouseMove;
 | |
| 
 | |
|             //Add a function to be called when the parent form is resized.  This keeps things from
 | |
|             //Misbehaving immediately after a resize.
 | |
|             Form tParent = (Form)DrawingArea.FindForm();
 | |
|             //tParent.ResizeEnd += ProcessImageResize;
 | |
|             tParent.SizeChanged += ProcessImageResize;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Change the Tick Interval.  By default, the spritecontroller does a tick every 10ms, which
 | |
|         /// is very fast.  Some people may prefer it to happen less regularly. Must be > 5, and less than 1001
 | |
|         /// </summary>
 | |
|         /// <param name="newTickMilliseconds">The new tick interval</param>
 | |
|         public void ChangeTickInterval(int newTickMilliseconds)
 | |
|         {
 | |
|             if (newTickMilliseconds < 5) return;
 | |
|             if (newTickMilliseconds > 1000) return;
 | |
|             MyTimer.Interval = newTickMilliseconds;
 | |
|         }
 | |
| 
 | |
|         //private void TryTimer(object state)
 | |
|         //{
 | |
|         //    if (System.Threading.Monitor.TryEnter(lockObject,10))
 | |
|         //    {
 | |
|         //        try
 | |
|         //        {
 | |
|         //            // Work here
 | |
|         //            DoTick(null,null);
 | |
|         //        }
 | |
|         //        finally
 | |
|         //        {
 | |
|         //            System.Threading.Monitor.Exit(lockObject);
 | |
|         //        }
 | |
|         //    }
 | |
|         //}
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Allow the sprite sort-method to be overridden.  
 | |
|         /// </summary>
 | |
|         /// <example>
 | |
|         /// The default sprite sort method is: 
 | |
|         /// <code lang="C#">
 | |
|         /// SpriteComparisonDelegate = delegate (Sprite first, Sprite second) { return first.Zvalue.CompareTo(second.Zvalue); };
 | |
|         /// </code>
 | |
|         /// Which compares just the Zvalues of the two sprites.  Often you will want to have a more refined sort.  The sort
 | |
|         /// order determines which sprites appear on top of other sprites.  In the default state, if two sprites have the
 | |
|         /// same Zvalue, it is very uncleaer which one will draw on top of the other one.  By overridding this sort function,
 | |
|         /// you can specify a very precise order of which sprite is on top and which is behind.
 | |
|         /// </example>
 | |
|         public Comparison<Sprite> SpriteComparisonDelegate = null;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// This is what happens when someone clicks on the PictureBox.  We want to pass any Click events to the Sprite
 | |
|         /// </summary>
 | |
|         /// <param name="sender"></param>
 | |
|         /// <param name="e"></param>
 | |
|         private void MouseClickOnBox(object sender, MouseEventArgs e)
 | |
|         {
 | |
|             List<Sprite> SpritesHere = SpritesAtPoint(e.Location);
 | |
|             foreach(Sprite one in SpritesHere.ToList())
 | |
|             {
 | |
|                 one.ClickedOn(SpriteCollisionMethod.rectangle);
 | |
|                 if (one.SpriteAtPictureBoxPoint(e.Location, SpriteCollisionMethod.transparency))
 | |
|                     one.ClickedOn(SpriteCollisionMethod.transparency);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Check to see if we are hovering over anything
 | |
|         /// </summary>
 | |
|         /// <param name="sender"></param>
 | |
|         /// <param name="e"></param>
 | |
|         private void MouseHover(object sender, EventArgs e)
 | |
|         {
 | |
|             if (MousePoint == Point.Empty) return;
 | |
|             List<Sprite> SpritesHere = SpritesAtPoint(MousePoint);
 | |
|             Point Place = DrawingArea.PointToClient(Cursor.Position);
 | |
|             foreach (Sprite one in SpritesHere.ToList())
 | |
|             {
 | |
|                 
 | |
|                 one.HoverOver();
 | |
|                 if (one.SpriteAtPictureBoxPoint(Place, SpriteCollisionMethod.transparency))
 | |
|                     one.HoverOverTransparent();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         //Track when we move over a new sprite, and when we leave a sprite.  Check to see if the sprite
 | |
|         //Is transparent at that spot to determine if we are moving over transparent or just in the rectangle
 | |
|         private void MouseMove(object sender, MouseEventArgs e)
 | |
|         {
 | |
|             try {
 | |
|                 MousePoint = e.Location;
 | |
|                 List<Sprite> SpritesHere = SpritesAtPoint(e.Location);
 | |
|                 List<Sprite> OldSprites = new List<Sprite>();
 | |
|                 List<Sprite> OldSpritesTransparent = new List<Sprite>();
 | |
|                 List<Sprite> NewSpritesTransparent = new List<Sprite>();
 | |
|                 OldSprites.AddRange(SpritesUnderMouse);
 | |
|                 OldSpritesTransparent.AddRange(SpritesUnderMouseTransparent);
 | |
|                 SpritesUnderMouse.Clear();
 | |
|                 SpritesUnderMouseTransparent.Clear();
 | |
|                 bool IsTransparent = false;
 | |
|                 Point Place = MousePoint;
 | |
|                 foreach (Sprite one in SpritesHere.ToList())
 | |
|                 {
 | |
|                     IsTransparent = false;
 | |
|                     //Console.WriteLine("Testing mouseover");
 | |
|                     if (one.SpriteAtPictureBoxPoint(Place, SpriteCollisionMethod.transparency))
 | |
|                     {
 | |
|                         // Console.WriteLine("Is Transparent!");
 | |
|                         IsTransparent = true;
 | |
|                         NewSpritesTransparent.Add(one);
 | |
|                     }
 | |
|                     if (!OldSprites.Contains(one))
 | |
|                     {
 | |
|                         //This is the first time we have run into it
 | |
|                         one.Enter();
 | |
|                     }
 | |
|                     if (IsTransparent && !OldSpritesTransparent.Contains(one))
 | |
|                     {
 | |
|                         //Console.WriteLine("Calling EnterTransparent");
 | |
|                         one.EnterTransparent();
 | |
|                     }
 | |
|                     if (IsTransparent)
 | |
|                     {
 | |
|                         OldSpritesTransparent.Remove(one);
 | |
|                     }
 | |
|                     OldSprites.Remove(one);
 | |
|                 }
 | |
|                 //Now, anything we have not "removed" is a sprite we are no longer over.
 | |
|                 foreach (Sprite donewith in OldSprites.ToList())
 | |
|                 {
 | |
|                     donewith.Leave();
 | |
|                 }
 | |
|                 foreach (Sprite donewith in OldSpritesTransparent.ToList())
 | |
|                 {
 | |
|                     //Console.WriteLine("Calling LeaveTransparent");
 | |
|                     donewith.LeaveTransparent();
 | |
|                 }
 | |
|                 SpritesUnderMouse.AddRange(SpritesHere);
 | |
|                 SpritesUnderMouseTransparent.AddRange(NewSpritesTransparent);
 | |
|             }
 | |
|             catch (AggregateException ee)
 | |
|             {
 | |
|                 Console.WriteLine(ee.ToString());
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Replace the image on which the sprites are drawn.  Use this when you move to a new playing field, 
 | |
|         /// or want to have a different background
 | |
|         /// <example>
 | |
|         /// Replacing the background image is actually a lot more complex than you might imagine.  Once you use the 
 | |
|         /// below code, it can be done without any problem.  But you need to do it this way, or it just goofs up in 
 | |
|         /// a number of small ways.
 | |
|         /// You need to tell the sprite controller that you are replacing the background image, 
 | |
|         /// and you need to change the image to that image as well.Because the Images are actually 
 | |
|         /// pointers to memory where the image sets, changes to one image will affect the other image.This goofs 
 | |
|         /// things up, so what we do is duplicate the image twice, and tell the sprite controller to use one of the 
 | |
|         /// copies and then set the background to be the other one of the two copies.Finally, we tell the picturebox 
 | |
|         /// to invalidate itself.That does everything that is needed.
 | |
|         /// <code lang="C#">
 | |
|         /// void ReplaceBackground(Image NewBackground)
 | |
|         ///{
 | |
|         ///    if (MyController == null) return;
 | |
|         ///    if (NewBackground == null) return;
 | |
|         ///
 | |
|         ///    Image OneImage = new Bitmap(NewBackground);
 | |
|         ///    MyController.ReplaceOriginalImage(OneImage);
 | |
|         ///
 | |
|         ///    Image TwoImage = new Bitmap(NewBackground);
 | |
|         ///    pb_map.BackgroundImage = TwoImage;
 | |
|         ///    pb_map.Invalidate();
 | |
|         ///}
 | |
|         /// </code>
 | |
|         /// </example>
 | |
|         /// </summary>
 | |
|         /// <param name="tImage">The new image that all sprites will be drawn on</param>
 | |
|         public void ReplaceOriginalImage(Image tImage)
 | |
|         {
 | |
|             if(MyOriginalImage == null)
 | |
|             {
 | |
|                 MyOriginalImage = (Image)DrawingArea.BackgroundImage.Clone();
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 Graphics.FromImage(MyOriginalImage).Clear(Color.Transparent); //erase the old image
 | |
|                 Graphics.FromImage(MyOriginalImage).DrawImage(tImage, new Rectangle(0, 0, MyOriginalImage.Width, MyOriginalImage.Height));
 | |
|                 Graphics.FromImage(DrawingArea.BackgroundImage).Clear(Color.Transparent); //erase the old image
 | |
|                 Graphics.FromImage(DrawingArea.BackgroundImage).DrawImage(tImage, new Rectangle(0, 0, MyOriginalImage.Width, MyOriginalImage.Height));
 | |
|             }
 | |
|             DrawingArea.Invalidate();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Notify the sprite controller that you have changed the background image on the
 | |
|         /// PictureBox.  Whatever background is on the picturebox is now used to draw all the sprites on.
 | |
|         /// </summary>
 | |
|         public void ReplaceOriginalImage()
 | |
|         {
 | |
|             if (MyOriginalImage == null)
 | |
|             {
 | |
|                 MyOriginalImage = (Image)DrawingArea.BackgroundImage.Clone();
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 Graphics.FromImage(MyOriginalImage).DrawImage(DrawingArea.BackgroundImage, new Rectangle(0, 0, MyOriginalImage.Width, MyOriginalImage.Height));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// The function called by the timer every 10 millisecods  We also call do_tick, which
 | |
|         /// is the function defined by the user.  This is usually where they will do the majority of the work.
 | |
|         /// </summary>        
 | |
|         /// <param name="sender"></param>
 | |
|         /// <param name="e"></param>
 | |
|         private void TimerTick(object sender, EventArgs e)
 | |
|         {
 | |
|             //If we have added a function to call on the timer, do it.
 | |
|             DoTick(sender, e);
 | |
|             Tick();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// The function called by the timer every 10 millisecods  This is usually where you will do the majority of the work.
 | |
|         /// You can define this manually, or when you <see cref="SpriteLibrary.SpriteController.SpriteController(PictureBox, EventHandler)">instantiate the SpriteController</see>
 | |
|         /// </summary>
 | |
|         /// <example>
 | |
|         /// The Sprite controller uses a <see cref="System.Windows.Forms.Timer">System.Windows.Forms.Timer.</see>  This timer is notoriously un-precise, but it is very 
 | |
|         /// easy to set up initially.  It tries to fire off every 10 milliseconds, but it can fire off incredibly 
 | |
|         /// slowly if you have long pieces of code; the DoTick function needs to finish before it can start again.  You want all your 
 | |
|         /// functions to run as quickly as possible to avoid things looking jerky.
 | |
|         /// Most programs you will make using the sprite library will begin by tapping into the DoTick Event. 
 | |
|         /// Every time the sprite controller is ready to pass control back to your program, it will call 
 | |
|         /// the DoTick event.  You want to see if you should be doing anything, and then exiting the do-tick function.
 | |
|         /// <code lang = "C#">
 | |
|         /// public partial class ShootingFieldForm : Form
 | |
|         /// {
 | |
|         ///     public ShootingFieldForm()
 | |
|         ///     {
 | |
|         ///         InitializeComponent();
 | |
|         ///         MainDrawingArea.BackgroundImage = Properties.Resources.Background;
 | |
|         ///         MainDrawingArea.BackgroundImageLayout = ImageLayout.Stretch;
 | |
|         ///         MySpriteController = new SpriteController(MainDrawingArea, CheckForKeyPress);
 | |
|         ///     }
 | |
|         ///     
 | |
|         ///     private void CheckForKeyPress(object sender, EventArgs e)
 | |
|         ///     {
 | |
|         ///        bool left = false;
 | |
|         ///        bool right = false;
 | |
|         ///        bool space = false;
 | |
|         ///        bool didsomething = false;
 | |
|         ///        TimeSpan duration = DateTime.Now - LastMovement;
 | |
|         ///        if (duration.TotalMilliseconds < 100)
 | |
|         ///            return;
 | |
|         ///        LastMovement = DateTime.Now;
 | |
|         ///        if (MySpriteController.IsKeyPressed(Keys.A) || MySpriteController.IsKeyPressed(Keys.Left))
 | |
|         ///        {
 | |
|         ///            left = true;
 | |
|         ///        }
 | |
|         ///        if (MySpriteController.IsKeyPressed(Keys.D)||MySpriteController.IsKeyPressed(Keys.Right))
 | |
|         ///        {
 | |
|         ///            right = true;
 | |
|         ///        }
 | |
|         ///        if (left && right) return; //do nothing if we conflict
 | |
|         ///        if (left)
 | |
|         ///        {               
 | |
|         ///            if (LastDirection != MyDir.left)
 | |
|         ///            {
 | |
|         ///                Spaceship.SetSpriteDirectionDegrees(180);
 | |
|         ///                //We want to only change animation once.  Every time we change
 | |
|         ///                //the animation, it starts at the first frame again.
 | |
|         ///                Spaceship.ChangeAnimation(0);
 | |
|         ///                LastDirection = MyDir.left;
 | |
|         ///            }
 | |
|         ///            didsomething = true;
 | |
|         ///            Spaceship.MovementSpeed = 15;
 | |
|         ///            Spaceship.AutomaticallyMoves = true;
 | |
|         ///        }
 | |
|         ///        if (right)
 | |
|         ///        {                
 | |
|         ///            if (LastDirection != MyDir.right)
 | |
|         ///            {
 | |
|         ///                Spaceship.SetSpriteDirectionDegrees(0);
 | |
|         ///                Spaceship.ChangeAnimation(0);
 | |
|         ///                LastDirection = MyDir.right;
 | |
|         ///            }
 | |
|         ///            didsomething = true;
 | |
|         ///            Spaceship.AutomaticallyMoves = true;
 | |
|         ///            Spaceship.MovementSpeed = 15;
 | |
|         ///        }
 | |
|         ///        if(!didsomething)
 | |
|         ///        {
 | |
|         ///            LastDirection = MyDir.stopped;
 | |
|         ///            //No keys pressed.  Stop moving
 | |
|         ///            Spaceship.MovementSpeed = 0;
 | |
|         ///        }
 | |
|         ///    }
 | |
|         /// </code>
 | |
|         /// </example>
 | |
|         public event EventHandler DoTick = delegate { };
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Process a form resize by recalculating all the picturebox locations for all sprites.
 | |
|         /// </summary>
 | |
|         /// <param name="sender">The form</param>
 | |
|         /// <param name="e">Form event args</param>
 | |
|         internal void ProcessImageResize(object sender, EventArgs e)
 | |
|         {
 | |
|             //Go through all sprites and recalculate the Ratio.
 | |
|             foreach (Sprite oneSprite in Sprites)
 | |
|             {
 | |
|                 oneSprite.RecalcPictureBoxLocation();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Count the number of sprites that were duplicated from the sprite with the specified name.  When you use a 
 | |
|         /// <see cref="SpriteLibrary.SpriteController.DuplicateSprite(string)">SpriteController.DuplicateSprite(string)</see>
 | |
|         /// command, it creates a new sprite that is based off the named sprite.  This function will count those duplicated sprites.
 | |
|         /// </summary>
 | |
|         /// <param name="Name">The name to look for</param>
 | |
|         /// <returns>The count of sprites that are duplicates of the specified name</returns>
 | |
|         public int CountSpritesBasedOff(string Name)
 | |
|         {
 | |
|             int count = 0;
 | |
|             foreach (Sprite OneSprite in Sprites)
 | |
|             {
 | |
|                 if (OneSprite.SpriteOriginName == Name)
 | |
|                     count++;
 | |
|             }
 | |
|             return count;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return a list of all sprites
 | |
|         /// </summary>
 | |
|         /// <returns>A list of all sprites</returns>
 | |
|         public List<Sprite> AllSprites()
 | |
|         {
 | |
|             return Sprites;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return all sprites that were based off a particular sprite name.
 | |
|         ///  When you use a 
 | |
|         /// <see cref="SpriteLibrary.SpriteController.DuplicateSprite(string)">SpriteController.DuplicateSprite(string)</see>
 | |
|         /// command, it creates a new sprite that is based off the named sprite.  This function returns a list of those
 | |
|         /// duplicated sprites.
 | |
|         /// </summary>
 | |
|         /// <param name="SpriteName">The sprite name to find</param>
 | |
|         /// <returns>A list of sprites that were based off the named sprite</returns>
 | |
|         public List<Sprite> SpritesBasedOff(string SpriteName)
 | |
|         {
 | |
|             List<Sprite> newList = new List<Sprite>();
 | |
|             foreach(Sprite one in Sprites)
 | |
|             {
 | |
|                 if (one.SpriteOriginName == SpriteName)
 | |
|                     newList.Add(one);
 | |
|             }
 | |
|             return newList;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return a list of all sprites which have been drawn on the image
 | |
|         /// </summary>
 | |
|         /// <returns>A list of sprites that have been drawn</returns>
 | |
|         public List<Sprite> SpritesThatHaveBeenDrawn()
 | |
|         {
 | |
|             List<Sprite> newList = new List<Sprite>();
 | |
|             foreach (Sprite one in Sprites)
 | |
|             {
 | |
|                 if (one.HasBeenDrawn)
 | |
|                     newList.Add(one);
 | |
|             }
 | |
|             return newList;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return a list of all sprites which are not master sprites (which are duplicates of something)
 | |
|         /// </summary>
 | |
|         /// <returns>A list of sprites</returns>
 | |
|         public List<Sprite> SpritesBasedOffAnything()
 | |
|         {
 | |
|             List<Sprite> newList = new List<Sprite>();
 | |
|             foreach (Sprite one in Sprites)
 | |
|             {
 | |
|                 if (one.SpriteOriginName != "" && one.SpriteOriginName != null)
 | |
|                     newList.Add(one);
 | |
|             }
 | |
|             return newList;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Get a list of all your named sprites.  These should just be your template sprites.
 | |
|         /// </summary>
 | |
|         /// <returns>A list containing all the named sprites</returns>
 | |
|         public List<Sprite> AllNamedSprites()
 | |
|         {
 | |
|             List<Sprite> tList = new List<Sprite>();
 | |
|             foreach(Sprite one in Sprites)
 | |
|             {
 | |
|                 if (one.SpriteName != "")
 | |
|                     tList.Add(one);
 | |
|             }
 | |
|             return tList;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return an adjustment ratio.  This is the image-size to picture-box ratio.
 | |
|         /// It is used for calculating precise pixels or picture-box locations.
 | |
|         /// </summary>
 | |
|         /// <returns>A SpriteAdjustmentRatio containing the current ratio of picture-box pixels to image-box pixels</returns>
 | |
|         public SpriteAdjustmentRatio ReturnAdjustmentRatio()
 | |
|         {
 | |
| 
 | |
|             //if (_AdjustmentRatio.height_ratio != 0 && _AdjustmentRatio.width_ratio != 0)
 | |
|             //    return _AdjustmentRatio;
 | |
|             //default to stretch
 | |
|             lock(DrawingArea) lock (MyOriginalImage)
 | |
|             {
 | |
| 
 | |
|                 SpriteAdjustmentRatio Ratio = new SpriteAdjustmentRatio();
 | |
|                 switch (DrawingArea.BackgroundImageLayout)
 | |
|                 {
 | |
|                     case ImageLayout.Center:
 | |
|                     case ImageLayout.None:
 | |
|                     case ImageLayout.Tile:
 | |
|                     case ImageLayout.Zoom:
 | |
|                     case ImageLayout.Stretch:
 | |
|                     default:
 | |
|                         //This is the code for Stretch.
 | |
|                         double CRW = DrawingArea.ClientRectangle.Width;
 | |
|                         double MOIW = MyOriginalImage.Width;
 | |
|                             Ratio.width_ratio =CRW / MOIW;
 | |
|                         double CRH = DrawingArea.ClientRectangle.Height;
 | |
|                         double MOIH = MyOriginalImage.Height;
 | |
|                             Ratio.height_ratio = CRH / MOIH;
 | |
|                         break;
 | |
|                 }
 | |
|                 _AdjustmentRatio = Ratio;
 | |
|                 return Ratio;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// This takes a point, the location on a picturebox, and returns the corresponding point on the BackgroundImage.
 | |
|         /// Picturebox locations are "sloppy"; the background image locations are very precise.  Since this takes a "sloppy"
 | |
|         /// number and returns a precise number, it does some rounding to figure out where the specified location is.  
 | |
|         /// </summary>
 | |
|         /// <param name="LocationOnPicturebox">A point on the picturebox that you want the corresponding image pixel location for.</param>
 | |
|         /// <returns>A point (x,y) on the background image which corresponds to the picture-box coordinates you sent into the function.</returns>
 | |
|         public Point ReturnPointAdjustedForImage(Point LocationOnPicturebox)
 | |
|         {
 | |
|             SpriteAdjustmentRatio Ratio = ReturnAdjustmentRatio();
 | |
|             Point returnedPoint = new Point((int)(LocationOnPicturebox.X / Ratio.width_ratio), (int)(LocationOnPicturebox.Y / Ratio.height_ratio));
 | |
|             return returnedPoint;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return the height of an object in picture-box terms.  It is basically the virtual height
 | |
|         /// of the sprite or other item.
 | |
|         /// </summary>
 | |
|         /// <param name="Height">The image-box heigh (or sprite height)</param>
 | |
|         /// <returns>An integer that corresponds to the hight as displayed in the picturebox</returns>
 | |
|         public int ReturnPictureBoxAdjustedHeight(int Height)
 | |
|         {
 | |
|             SpriteAdjustmentRatio Ratio = ReturnAdjustmentRatio();
 | |
|             int returnedAmount = (int)(Height * Ratio.height_ratio);
 | |
|             return returnedAmount;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return the width of an object in picture-box terms.  It takes the width of a sprite or other
 | |
|         /// item that is being displayed on the screen, and calculates the width as displayed in the
 | |
|         /// picture-box (taking into consideration stretching or shrinking)
 | |
|         /// </summary>
 | |
|         /// <param name="Width">An integer width of the drawn item</param>
 | |
|         /// <returns>An integer that contains the number of pixels wide it is on the picturebox</returns>
 | |
|         public int ReturnPictureBoxAdjustedWidth(int Width)
 | |
|         {
 | |
|             SpriteAdjustmentRatio Ratio = ReturnAdjustmentRatio();
 | |
|             int returnedAmount = (int)(Width * Ratio.width_ratio);
 | |
|             return returnedAmount;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// This does the reverse of an adjusted point.  It takes a point on the image and 
 | |
|         /// transforms it to one on the PictureBox
 | |
|         /// </summary>
 | |
|         /// <param name="LocationOnImage">A point on the image, using the x and y pixels on the image</param>
 | |
|         /// <returns>A location that can be used on the picture-box, taking into consideration the image being stretched.</returns>
 | |
|         public Point ReturnPictureBoxAdjustedPoint(Point LocationOnImage)
 | |
|         {
 | |
|             SpriteAdjustmentRatio Ratio = ReturnAdjustmentRatio();
 | |
|             Point returnedPoint = new Point((int)(LocationOnImage.X * Ratio.width_ratio), (int)(LocationOnImage.Y * Ratio.height_ratio));
 | |
|             return returnedPoint;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Adjust a rectangle that is based on the image, according to the stretch of the picturebox
 | |
|         /// </summary>
 | |
|         /// <param name="ImageRectangle">A rectangle using coordinates from the image</param>
 | |
|         /// <returns>a rectangle that is adjusted for the PictureBox</returns>
 | |
|         public Rectangle AdjustRectangle(Rectangle ImageRectangle)
 | |
|         {
 | |
|             if (DrawingArea.BackgroundImageLayout == ImageLayout.Stretch)
 | |
|             {
 | |
|                 SpriteAdjustmentRatio Ratio = ReturnAdjustmentRatio();
 | |
|                 double width_ratio = Ratio.width_ratio;
 | |
|                 double height_ratio = Ratio.height_ratio;
 | |
|                 int x, y, width, height;
 | |
|                 x = (int)(ImageRectangle.X * width_ratio);
 | |
|                 y = (int)(ImageRectangle.Y * height_ratio);
 | |
|                 width = (int)(ImageRectangle.Width * width_ratio);
 | |
|                 height = (int)(ImageRectangle.Height * height_ratio);
 | |
| 
 | |
|                 Rectangle newRec = new Rectangle(x, y, width, height);
 | |
|                 return newRec;
 | |
|             }
 | |
| 
 | |
|             return ImageRectangle; //If we do not know what it is, return the curent
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Adjust an image point so that it conforms to the picturebox.
 | |
|         /// </summary>
 | |
|         /// <param name="LocationOnImage">The image location</param>
 | |
|         /// <returns>the corresponding point on the PictuerBox</returns>
 | |
|         public Point AdjustPoint(Point LocationOnImage)
 | |
|         {
 | |
|             SpriteAdjustmentRatio Ratio = ReturnAdjustmentRatio();
 | |
|             double width_ratio = Ratio.width_ratio;
 | |
|             double height_ratio = Ratio.height_ratio;
 | |
|             int x, y;
 | |
|             x = (int)(LocationOnImage.X * width_ratio);
 | |
|             y = (int)(LocationOnImage.Y * height_ratio);
 | |
|             return new Point(x, y);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Invalidate a rectangle that is specified in image coordinates
 | |
|         /// </summary>
 | |
|         /// <param name="ImageRectangle">A rectangle based on the image coordinates</param>
 | |
|         /// <param name="QueueUpInvalidation">Whether to do it now, or to queue it up for another time.</param>
 | |
|         public void Invalidate(Rectangle ImageRectangle, bool QueueUpInvalidation = true)
 | |
|         {
 | |
|             if (QueueUpInvalidation)
 | |
|             {
 | |
|                 InvalidateList.Add(ImageRectangle);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 //Figure out the area we are looking at
 | |
|                 if (DrawingArea.BackgroundImageLayout == ImageLayout.Stretch)
 | |
|                 {
 | |
|                     Rectangle newRec = AdjustRectangle(ImageRectangle);
 | |
|                     newRec = new Rectangle(newRec.Location.X, newRec.Location.Y, newRec.Width + 2, newRec.Height + 2);
 | |
|                     //Now we invalidate the adjusted rectangle
 | |
|                     DrawingArea.Invalidate(newRec);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Invalidate the entire image on which the sprites are drawn
 | |
|         /// </summary>
 | |
|         /// <param name="QueueUpInvalidation">Whether to do it now, or to queue it up for another time.</param>
 | |
|         public void Invalidate(bool QueueUpInvalidation = true)
 | |
|         {
 | |
|             Invalidate(DrawingArea.ClientRectangle);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// The Background Image on which the sprites are drawn.  This image ends up having
 | |
|         /// sprite parts on it. The OriginalImage is the version that is clean.  Use
 | |
|         /// ReplaceOriginalImage to replace the background Image.
 | |
|         /// </summary>
 | |
|         public Image BackgroundImage { get { return DrawingArea.BackgroundImage; } }
 | |
|         /// <summary>
 | |
|         /// The Image from which the background is taken when we erase sprites.  The BackgroundImage
 | |
|         /// is the image that contains images of the sprites as well as the background image.  Use
 | |
|         /// ReplaceOriginalImage to replace this and the BackgroundImage.
 | |
|         /// </summary>
 | |
|         public Image OriginalImage { get { return MyOriginalImage; } }
 | |
| 
 | |
| 
 | |
|         //void Tick()
 | |
|         //{
 | |
|         //    BackgroundWorker bw = new BackgroundWorker();
 | |
| 
 | |
|         //    // this allows our worker to report progress during work
 | |
|         //    bw.WorkerReportsProgress = true;
 | |
| 
 | |
|         //    // what to do in the background thread
 | |
|         //    bw.DoWork += new DoWorkEventHandler(
 | |
|         //    delegate (object o, DoWorkEventArgs args)
 | |
|         //    {
 | |
| 
 | |
|         //        ThreadTick();
 | |
| 
 | |
|         //    });
 | |
|         //    bw.RunWorkerAsync();
 | |
| 
 | |
|         //}
 | |
| 
 | |
|         void Tick()
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 //We check for collisions.
 | |
|                 for (int looper = 0; looper < Sprites.Count; looper++)
 | |
|                 {
 | |
|                     if (Sprites[looper] != null && !Sprites[looper].Destroying && Sprites[looper].HasBeenDrawn)
 | |
|                     {
 | |
|                         for (int checkloop = 0; checkloop < Sprites.Count; checkloop++)
 | |
|                         {
 | |
|                             if (Sprites[checkloop] != null && !Sprites[checkloop].Destroying && Sprites[checkloop].HasBeenDrawn)
 | |
|                             {
 | |
|                                 //Check to see if they have hit
 | |
|                                 Sprites[looper].CheckSpriteHitsSprite(Sprites[checkloop], SpriteCollisionMethod.rectangle);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 //We do a tick for each sprite
 | |
|                 //Parallel.ForEach(Sprites.ToList(), tSprite =>
 | |
|                 //{
 | |
|                 //    if (!tSprite.Destroying)
 | |
|                 //    {
 | |
|                 //        tSprite.Tick();
 | |
|                 //    }
 | |
|                 //});
 | |
| 
 | |
|                 foreach (Sprite tSprite in Sprites.ToList())
 | |
|                 {
 | |
|                     if (!tSprite.Destroying)
 | |
|                     {
 | |
|                         tSprite.Tick();
 | |
|                     }
 | |
|                 };
 | |
| 
 | |
|                 foreach (Sprite tSprite in Sprites.ToList())
 | |
|                 {
 | |
|                     if (!tSprite.Destroying)
 | |
|                     {
 | |
|                         tSprite.ActuallyDraw();
 | |
|                     }
 | |
|                 }
 | |
|                 foreach(Rectangle rec in InvalidateList)
 | |
|                 {
 | |
|                     Invalidate(rec, false);
 | |
|                 }
 | |
|                 InvalidateList.Clear();
 | |
|             }
 | |
|             catch (AggregateException e)
 | |
|             {
 | |
|                 Console.WriteLine(e.ToString());
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Make a duplicate of the specified sprite.  The duplicate does not yet have a location.
 | |
|         /// </summary>
 | |
|         /// <param name="What">The sprite to duplicate</param>
 | |
|         /// <returns>A new sprite.  If What is null, returns null</returns>
 | |
|         public Sprite DuplicateSprite(Sprite What)
 | |
|         {
 | |
|             //Make a new sprite that is based off of the old one
 | |
|             if (What == null) return null;
 | |
|             return new Sprite(What);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Find a sprite that has been named with the specified name.  Then duplicate that sprite.  If you have
 | |
|         /// SpriteControllers which are linked (see 
 | |
|         /// <see cref="SpriteController.LinkControllersForSpriteTemplateSharing(SpriteController)">
 | |
|         /// SpriteController.LinkControllersForSpriteTemplateSharing</see> for how to do this), if the Sprite template is
 | |
|         /// not contained in this controller, it is looked up in any linked controllers.
 | |
|         /// </summary>
 | |
|         /// <example>
 | |
|         /// Below is a function that creates a sprite based off a name, and puts it at the designated coordinates.
 | |
|         /// <code lang="C#">
 | |
|         /// public void AddSprite(string name, int startx, int starty)
 | |
|         /// {
 | |
|         ///      Sprite NewSprite = MySpriteController.DuplicateSprite(What.ToString());
 | |
|         ///      if(NewSprite != null)
 | |
|         ///      {
 | |
|         ///          NewSprite.AutomaticallyMoves = true;
 | |
|         ///          NewSprite.CannotMoveOutsideBox = true;
 | |
|         ///          NewSprite.SetSpriteDirectionDegrees(180); //left
 | |
|         ///          NewSprite.PutBaseImageLocation(new Point(startx, starty));
 | |
|         ///          NewSprite.MovementSpeed = 5;
 | |
|         ///      }
 | |
|         /// }
 | |
|         /// </code>
 | |
|         /// </example>
 | |
|         /// <param name="Name">The name of a sprite</param>
 | |
|         /// <returns>A duplicate of the specified sprite.  It has no location, and does not retain the sprite name.</returns>
 | |
|         public Sprite DuplicateSprite(string Name)
 | |
|         {
 | |
|             Sprite tSprite = SpriteFromName(Name);
 | |
|             if (tSprite == null) return null;
 | |
|             return new Sprite(tSprite); //Make a new sprite that is based off the original
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Find a sprite that has a specified name.  This returns the actual sprite with that name.
 | |
|         /// You usually want to use DuplicateSprite(Name) to clone the sprite and get one you can
 | |
|         /// destroy.  If you destroy a named sprite without duplicating it, you may end up losing
 | |
|         /// it for the remainder of the program.
 | |
|         /// </summary>
 | |
|         /// <param name="Name">A string that matches something added to a sprite with Sprite.SetName</param>
 | |
|         /// <returns>A sprite that has the specified name, or null if no such sprite exists.</returns>
 | |
|         public Sprite SpriteFromName(string Name)
 | |
|         {
 | |
|             foreach (Sprite OneSprite in Sprites)
 | |
|             {
 | |
|                 if (OneSprite.SpriteName == Name)
 | |
|                 { return OneSprite; }
 | |
|             }
 | |
|             //If we have not found one on this controller, get it from another controller
 | |
|             foreach(SpriteController SC in LinkedControllers)
 | |
|             {
 | |
|                 Sprite Found = SC.SpriteFromNameInternal(Name);
 | |
|                 if (Found != null)
 | |
|                 {
 | |
|                     //If we get here, we do not have it in our list.  Add it to this controller and then return it
 | |
|                     AddSprite(Found);
 | |
|                     //Console.WriteLine("Found A Sprite in another controller:" + Found.SpriteName);
 | |
|                     return Found;
 | |
|                 }
 | |
|             }
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// The internal SpriteFromName does not check the linked controllers.  Keeps us from entering into an endless loop
 | |
|         /// </summary>
 | |
|         /// <param name="Name"></param>
 | |
|         /// <returns></returns>
 | |
|         internal Sprite SpriteFromNameInternal(string Name)
 | |
|         {
 | |
|             foreach (Sprite OneSprite in Sprites)
 | |
|             {
 | |
|                 if (OneSprite.SpriteName == Name)
 | |
|                 { return OneSprite; }
 | |
|             }
 | |
|             return null;
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Add the specified sprite to the list of sprites we know about.  You usually do not need to do this.
 | |
|         /// Sprites add themselves to the controller when you create a new sprite.
 | |
|         /// </summary>
 | |
|         /// <param name="SpriteToAdd">The sprite to add to the sprite-controller</param>
 | |
|         public void AddSprite(Sprite SpriteToAdd)
 | |
|         {
 | |
|             SpriteToAdd.MySpriteController = this;
 | |
|             Sprites.Add(SpriteToAdd);
 | |
|             AddSpriteToLinkedControllers(SpriteToAdd);
 | |
|             SortSprites();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// This internal function is for adding named sprites from other controllers to keep them in sync
 | |
|         /// </summary>
 | |
|         /// <param name="SpriteToAdd">The sprite to add if it does not exist yet on this controller</param>
 | |
|         internal void AddSpriteIfNotExists(Sprite SpriteToAdd)
 | |
|         {
 | |
|             if (SpriteToAdd.SpriteName == "") return; //We only add named sprites
 | |
|             Sprite found = SpriteFromName(SpriteToAdd.SpriteName);
 | |
|             if (found == null)
 | |
|             {
 | |
|                 Sprite Clone = new Sprite(SpriteToAdd,true);
 | |
|                 Clone.MySpriteController = this;
 | |
|                 Sprites.Add(Clone);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// If we are linked to other controllers, add this sprite template to the other controllers also
 | |
|         /// </summary>
 | |
|         /// <param name="SpriteToAdd">The sprite we are trying to add</param>
 | |
|         internal void AddSpriteToLinkedControllers(Sprite SpriteToAdd)
 | |
|         {
 | |
|             if (SpriteToAdd.SpriteName == "") return; //We only add named sprites
 | |
|             foreach (SpriteController one in LinkedControllers)
 | |
|             {
 | |
|                 one.AddSpriteIfNotExists(SpriteToAdd);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Tell a sprite to destroy itself.  The sprite will have Destroying property set to true from
 | |
|         /// the time you destroy it until it vanishes.  Whe you destroy a sprite, it will erase itself 
 | |
|         /// and remove itself from the controller.  After it is destroyed, it is completely gone.
 | |
|         /// </summary>
 | |
|         /// <param name="what">The Sprite to destroy</param>
 | |
|         public void DestroySprite(Sprite what)
 | |
|         {
 | |
|             if (what == null) return;
 | |
|             Sprites.Remove(what);
 | |
|             if (!what.Destroying)
 | |
|             {
 | |
|                 what.Destroy();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Remove all sprites (even named sprites that have not yet been displayed)
 | |
|         /// </summary>
 | |
|         public void DestroyAllSprites()
 | |
|         {
 | |
|             for(int i= Sprites.Count -1; i>=0; i--)
 | |
|             {
 | |
|                 Sprites[i].Destroy();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Find the specified Sprite in the controller and change its name to the specified string.
 | |
|         /// You can do the same thing with <see cref="SpriteLibrary.Sprite.SetName(string)">Sprite.SetName(Name)</see>
 | |
|         /// </summary>
 | |
|         /// <param name="What">The Sprite to find</param>
 | |
|         /// <param name="Name">The string to change the name to</param>
 | |
|         public void NameSprite(Sprite What, string Name)
 | |
|         {
 | |
|             What.SetName(Name);
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Link up a sprite controller so that it shares sprites with this other sprite controller.  If one sprite controller
 | |
|         /// does not have the named sprite, it will query any linked controllers for that named sprite and copy it to the
 | |
|         /// controller that did not have it.  This means you only need to create a sprite once, and you can use it on multiple
 | |
|         /// sprite controllers.  In many games, you will want to have a sprite appear on different PictureBoxes, and this is
 | |
|         /// a way to do that.  For example, you may want to have a bad-guy running around on the screen, but also have his sprite
 | |
|         /// appear in a bad-guy summary, along with his stats, on the side.  Loading sprites can be slow, so this makes things a bit
 | |
|         /// faster by only needing to load them once.
 | |
|         /// </summary>
 | |
|         /// <param name="ControllerToLinkToThis">The sprite-controller to link.  You only need to link it one direction,
 | |
|         /// the sprite controller will automatically create a bi-directional link</param>
 | |
|         public void LinkControllersForSpriteTemplateSharing(SpriteController ControllerToLinkToThis)
 | |
|         {
 | |
|             if (ControllerToLinkToThis == null) return;
 | |
|             if(!LinkedControllers.Contains(ControllerToLinkToThis))
 | |
|             {
 | |
|                 LinkedControllers.Add(ControllerToLinkToThis);
 | |
|             }
 | |
|             ControllerToLinkToThis.LinkControllersForSpriteTemplateSharingInternal(this); //link the other direction also
 | |
|         }
 | |
|         internal void LinkControllersForSpriteTemplateSharingInternal(SpriteController ControllerToLinkToThis)
 | |
|         {
 | |
|             if (ControllerToLinkToThis == null) return;
 | |
|             if (!LinkedControllers.Contains(ControllerToLinkToThis))
 | |
|             {
 | |
|                 LinkedControllers.Add(ControllerToLinkToThis);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Unlink a previously linked controller.  If you have linked a controller from a different window and are trying to
 | |
|         /// kill off the controller in a window you are closing, you want to unlink them as the window closes.  We take a brief
 | |
|         /// moment to copy over any templates that have not yet been copied over.
 | |
|         /// </summary>
 | |
|         /// <param name="ControllerToUnlink">The </param>
 | |
|         public void UnlinkControllersForSpriteTemplateSharing(SpriteController ControllerToUnlink)
 | |
|         {
 | |
|             if (ControllerToUnlink == null) return; //nothing to do.
 | |
|             if (LinkedControllers.Contains(ControllerToUnlink))
 | |
|             {
 | |
|                 LinkedControllers.Remove(ControllerToUnlink);
 | |
|             }
 | |
|                 ControllerToUnlink.UnlinkControllersForSpriteTemplateSharingInternal(this);
 | |
|                 List<Sprite> MySpriteTemplates = AllNamedSprites();
 | |
|                 List<Sprite> TheirSpriteTemplates = ControllerToUnlink.AllNamedSprites();
 | |
|                 foreach (Sprite one in MySpriteTemplates)
 | |
|                     ControllerToUnlink.AddSpriteIfNotExists(one);
 | |
|                 foreach (Sprite one in TheirSpriteTemplates)
 | |
|                     AddSpriteIfNotExists(one);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// This unlinks the second half.  This is an internal function so people using SpriteController cannot accidentally
 | |
|         /// unlink half a controller.
 | |
|         /// </summary>
 | |
|         /// <param name="ControllerToUnlink"></param>
 | |
|         internal void UnlinkControllersForSpriteTemplateSharingInternal(SpriteController ControllerToUnlink)
 | |
|         {
 | |
|             if (ControllerToUnlink == null) return; //nothing to do.
 | |
|             if (LinkedControllers.Contains(ControllerToUnlink))
 | |
|             {
 | |
|                 LinkedControllers.Remove(ControllerToUnlink);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// This takes a point, as given by the mouse-click args, and returns the sprites at that point. Different
 | |
|         /// functions use different coordinates, whether based off the background image, or based off the picturebox.
 | |
|         /// This one uses the picturebox coordinates.  So you can use this directly from a MouseDown or MouseUp function.
 | |
|         /// </summary>
 | |
|         /// <param name="Location">The picture-box point being clicked on</param>
 | |
|         /// <returns>A list of sprites that are all at the specified point.</returns>
 | |
|         public List<Sprite> SpritesAtPoint(Point Location)
 | |
|         {
 | |
|             List<Sprite> tList = new List<Sprite>();
 | |
|             foreach (Sprite OneSprite in Sprites)
 | |
|             {
 | |
|                 if (OneSprite.HasBeenDrawn && OneSprite.SpriteAtPictureBoxPoint(Location))
 | |
|                 {
 | |
|                     tList.Add(OneSprite);
 | |
|                 }
 | |
|             }
 | |
|             return tList;
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// This takes a point, as as specified on the image, and returns the sprites at that point. Different
 | |
|         /// functions use different coordinates, whether based off the background image, or based off the picturebox.
 | |
|         /// This one uses the background image coordinates.  Use SpritesAdPoint() if you are doing something based off
 | |
|         /// a MouseUp or MouseDown function.  This is used for functions based on sprite location or based off the absoloute
 | |
|         /// location (using the background image location is much more precise than the visible location in the picturebox)
 | |
|         /// </summary>
 | |
|         /// <param name="Location">The point being looked at</param>
 | |
|         /// <returns>A list of sprites that are all at the specified image point</returns>
 | |
|         public List<Sprite> SpritesAtImagePoint(Point Location)
 | |
|         {
 | |
|             List<Sprite> tList = new List<Sprite>();
 | |
|             foreach (Sprite OneSprite in Sprites)
 | |
|             {
 | |
|                 if (OneSprite.HasBeenDrawn && OneSprite.SpriteAtImagePoint(Location))
 | |
|                 {
 | |
|                     tList.Add(OneSprite);
 | |
|                 }
 | |
|             }
 | |
|             return tList;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return a list of all the sprites that intersect with the given background-image-based rectangle
 | |
|         /// </summary>
 | |
|         /// <param name="Location">The rectangle on the image we are trying to find</param>
 | |
|         /// <returns>A list of the sprites that have any portion of it inside the rectangle</returns>
 | |
|         public List<Sprite> SpritesInImageRectangle(Rectangle Location)
 | |
|         {
 | |
|             List<Sprite> tList = new List<Sprite>();
 | |
|             foreach (Sprite OneSprite in Sprites)
 | |
|             {
 | |
|                 if (OneSprite.HasBeenDrawn && OneSprite.SpriteIntersectsRectangle(Location))
 | |
|                 {
 | |
|                     tList.Add(OneSprite);
 | |
|                 }
 | |
|             }
 | |
|             return tList;
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Check to see if any keys are pressed. There is a small glitch with the
 | |
|         /// key-pressed system.  If the form loses focus, and someone releases a key, the key-up is never
 | |
|         /// triggered.  It is a good thing to ResetKeypressState() occasionally if you think your form may have
 | |
|         /// lost focus.
 | |
|         /// </summary>
 | |
|         /// <returns>True if a key is pressed, false if no keys are pressed.</returns>
 | |
|         public bool IsKeyPressed()
 | |
|         {
 | |
|             return MessageFilter.IsKeyPressed();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return a list of all the keys that are currently pressed.  There is a small glitch with the
 | |
|         /// key-pressed system.  If the form loses focus, and someone releases a key, the key-up is never
 | |
|         /// triggered.  It is a good thing to ResetKeypressState() occasionally if you think your form may have
 | |
|         /// lost focus.
 | |
|         /// </summary>
 | |
|         /// <returns>A List of Keys which are currently considered to be pressed.</returns>
 | |
|         public List<Keys> KeysPressed()
 | |
|         {
 | |
|             return MessageFilter.KeysPressed();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Check to see if the given key is pressed. There is a small glitch with the
 | |
|         /// key-pressed system.  If the form loses focus, and someone releases a key, the key-up is never
 | |
|         /// triggered.  It is a good thing to ResetKeypressState() occasionally if you think your form may have
 | |
|         /// lost focus.
 | |
|         /// </summary>
 | |
|         /// <param name="k">The key to check to see if it is pressed</param>
 | |
|         /// <returns>True if the key is pressed, false if that key is not pressed</returns>
 | |
|         public bool IsKeyPressed(Keys k)
 | |
|         {
 | |
|             return MessageFilter.IsKeyPressed(k);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// If you want to have a KeyDown function that is triggered by a keypress function, add the event here.
 | |
|         /// The event should have the parameters (object sender, KeyEventArgs e)
 | |
|         /// </summary>
 | |
|         /// <param name="Func">The function to set</param>
 | |
|         public void RegisterKeyDownFunction(SpriteKeyEventHandler Func)
 | |
|         {
 | |
|             MessageFilter.KeyDown += Func;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// If you want to have a KeyUp function that is triggered by a keypress function, add the event here.
 | |
|         /// The event should have the parameters (object sender, KeyEventArgs e)
 | |
|         /// </summary>
 | |
|         /// <param name="Func">The function to set</param>
 | |
|         public void RegisterKeyUpFunction(SpriteKeyEventHandler Func)
 | |
|         {
 | |
|             MessageFilter.KeyUp += Func;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Reset the keypress status.  Sometimes the sprite controller misses a key being released (usually
 | |
|         /// because a window has taken priority, or something has changed).  Calling this function will reset
 | |
|         /// the stored memory of whether a key has been pressed.
 | |
|         /// </summary>
 | |
|         public void ResetKeypressState()
 | |
|         {
 | |
|             MessageFilter.ResetState();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Change the display order of the specified sprite so it goes in front of all other sprites.
 | |
|         /// </summary>
 | |
|         /// <param name="What">The sprite we want to show up in front</param>
 | |
|         public void SpriteToFront(Sprite What)
 | |
|         {
 | |
|             What.Zvalue = 100;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Change the display order of the specified sprite so it goes behind all other sprites.
 | |
|         /// </summary>
 | |
|         /// <param name="What">The sprite to send behind all other sprites</param>
 | |
|         public void SpriteToBack(Sprite What)
 | |
|         {
 | |
|             What.Zvalue = 0;
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Change the display order of the specified sprite so it is more likely to go behind all other sprites.
 | |
|         /// </summary>
 | |
|         /// <param name="What">The sprite to send behind all other sprites</param>
 | |
|         public void SpriteBackwards(Sprite What)
 | |
|         {
 | |
|             What.Zvalue--;
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Change the display order of the specified sprite so it is more likely to go in front of other sprites
 | |
|         /// </summary>
 | |
|         /// <param name="What">The sprite to send behind all other sprites</param>
 | |
|         public void SpriteForwards(Sprite What)
 | |
|         {
 | |
|             What.Zvalue++;
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Change the display order of the sprites such that the specified sprite appears behind the other sprite.
 | |
|         /// </summary>
 | |
|         /// <param name="WhatToSend">The sprite we are changing the display order of</param>
 | |
|         /// <param name="ToGoBehind">The sprite we want to go behind</param>
 | |
|         public void PlaceSpriteBehind(Sprite WhatToSend, Sprite ToGoBehind)
 | |
|         {
 | |
|             if (WhatToSend == ToGoBehind) return;
 | |
|             if (WhatToSend == null) return;
 | |
|             if (ToGoBehind == null) return;
 | |
|             WhatToSend.Zvalue = ToGoBehind.Zvalue - 1;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Make the sprite go in front of the specified sprite.
 | |
|         /// </summary>
 | |
|         /// <param name="WhatToSend">The sprite to change the display order of</param>
 | |
|         /// <param name="ToGoInFrontOf">The sprite we want to make sure we display in front of</param>
 | |
|         public void PlaceSpriteInFrontOf(Sprite WhatToSend, Sprite ToGoInFrontOf)
 | |
|         {
 | |
|             if (WhatToSend == ToGoInFrontOf) return;
 | |
|             if (WhatToSend == null) return;
 | |
|             if (ToGoInFrontOf == null) return;
 | |
|             WhatToSend.Zvalue = ToGoInFrontOf.Zvalue + 1;
 | |
|         }
 | |
| 
 | |
|         //****************************//
 | |
|         //*******  SOUND Stuff *******//
 | |
|         private struct SoundEntry
 | |
|         {
 | |
|             public string SoundName;
 | |
|             public bool HasBeenPlayed;
 | |
|         }
 | |
| 
 | |
|         List<SoundEntry> MySounds = new List<SoundEntry>();
 | |
|         /// <summary>
 | |
|         /// Play a sound that we can check to see if it has completed.
 | |
|         /// </summary>
 | |
|         /// <param name="ToPlay">The sound to play</param>
 | |
|         /// <param name="Name">The name, which we can use to determine if it has finished.</param>
 | |
|         public void SoundPlay(System.IO.Stream ToPlay, string Name)
 | |
|         {
 | |
|             if (SoundIsFinished(Name))
 | |
|             {
 | |
|                 PlayAsync(ToPlay, Name, SoundIsDone);
 | |
|                 RegisterSound(Name);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Play a sound bit in a separate thread.  When the thread is done, set a bool saying that
 | |
|         /// </summary>
 | |
|         /// <param name="ToPlay">The sound to play</param>
 | |
|         /// <param name="RegisterName">The string that we can use to track the status of the sound</param>
 | |
|         /// <param name="WhenDone">A function that gets called when the sound is complete</param>
 | |
|         private void PlayAsync(System.IO.Stream ToPlay, string RegisterName, EventHandler WhenDone)
 | |
|         {
 | |
|             ToPlay.Position = 0;
 | |
|             System.Threading.ThreadPool.QueueUserWorkItem(delegate
 | |
|             {
 | |
|                 using (System.Media.SoundPlayer player = new System.Media.SoundPlayer(ToPlay))
 | |
|                 {
 | |
|                     player.PlaySync();
 | |
|                 }
 | |
| 
 | |
|                 if (WhenDone != null) WhenDone(RegisterName, EventArgs.Empty);
 | |
|             });
 | |
|             //new System.Threading.Thread(() => {
 | |
|             //    var c = new System.Windows.Media.MediaPlayer();
 | |
|             //    byte[] buffer = new byte[ToPlay.Length];
 | |
|             //    int totalBytesCopied;
 | |
|             //    for (totalBytesCopied = 0; totalBytesCopied < ToPlay.Length;)
 | |
|             //        totalBytesCopied += ToPlay.Read(buffer, totalBytesCopied, Convert.ToInt32(ToPlay.Length) - totalBytesCopied);
 | |
|             //    Uri tURI = Create_Memory_Resource_Uri(buffer, totalBytesCopied);
 | |
|             //    c.Open(tURI);
 | |
|             //    c.Play();
 | |
|             //    if (WhenDone != null) WhenDone(RegisterName, EventArgs.Empty);
 | |
|             //}).Start();
 | |
|         }
 | |
| 
 | |
|         //Uri Create_Memory_Resource_Uri(byte[] in_memory_resource, int Size)
 | |
|         //{
 | |
|         //    MemoryStream packStream = new MemoryStream();
 | |
|         //    using (
 | |
|         //    Package pack =
 | |
|         //        Package.Open(packStream, FileMode.Create, FileAccess.ReadWrite))
 | |
|         //    {
 | |
|         //        Uri packUri = new Uri("AnyBeforeColon:");
 | |
|         //        PackageStore.AddPackage(packUri, pack);
 | |
|         //        Uri packPartUri = new Uri("/AnyAfterSlash", UriKind.Relative);
 | |
|         //        //PackagePart packPart = 
 | |
|         //        //   pack.CreatePart(packPartUri, "application/vnd.ms-opentype");
 | |
|         //        PackagePart packPart =
 | |
|         //          pack.CreatePart(packPartUri, "AnyBeforeSlash/AnyAfterSlash");
 | |
|         //        //MemoryStream resourceStream = new MemoryStream(in_memory_resource);
 | |
|         //        //CopyStream(resourceStream, packPart.GetStream());
 | |
|         //        packPart.GetStream().Write(in_memory_resource, 0, Size);
 | |
|         //        Uri memory_resource_uri =
 | |
|         //            PackUriHelper.Create(packUri, packPart.Uri);
 | |
|         //        return memory_resource_uri;
 | |
|         //    }
 | |
|         //}
 | |
| 
 | |
|         private void SoundIsDone(object sender, EventArgs e)
 | |
|         {
 | |
|             string Name = (string)sender;
 | |
|             RemoveEntry(Name);
 | |
|             SoundEntry newsound = new SoundEntry();
 | |
|             newsound.SoundName = Name;
 | |
|             newsound.HasBeenPlayed = true; //Mark it as done
 | |
|             MySounds.Add(newsound);
 | |
|         }
 | |
| 
 | |
|         private void RemoveEntry(string Name)
 | |
|         {
 | |
|             if (Name == null || Name == "") return;
 | |
|             for (int count = MySounds.Count - 1; count >= 0; count--)
 | |
|             {
 | |
|                 if (MySounds[count].SoundName == Name)
 | |
|                 {
 | |
|                     MySounds.RemoveAt(count);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         private void RegisterSound(string Name)
 | |
|         {
 | |
|             if (Name == null || Name == "") return;
 | |
|             RemoveEntry(Name);
 | |
|             SoundEntry newsound = new SoundEntry();
 | |
|             newsound.SoundName = Name;
 | |
|             newsound.HasBeenPlayed = false;
 | |
|             MySounds.Add(newsound);
 | |
|         }
 | |
| 
 | |
|         private void RegisterSoundDone(string Name)
 | |
|         {
 | |
|             if (Name == null || Name == "") return;
 | |
|             RemoveEntry(Name);
 | |
|             SoundEntry newsound = new SoundEntry();
 | |
|             newsound.SoundName = Name;
 | |
|             newsound.HasBeenPlayed = true;
 | |
|             MySounds.Add(newsound);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Check to see if the specified sound has finished playing
 | |
|         /// </summary>
 | |
|         /// <param name="Name">The name of the sound</param>
 | |
|         /// <returns>True if the sound is not currently playing.  False if it is currently playing.</returns>
 | |
|         public bool SoundIsFinished(string Name)
 | |
|         {
 | |
|             foreach(SoundEntry one in MySounds.ToList())
 | |
|             {
 | |
|                 if (one.SoundName == Name)
 | |
|                     return one.HasBeenPlayed;
 | |
|             }
 | |
|             return true; //It does not exist, therefore it is not playing
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Pause everything.  It loops through all the sprites in the SpriteController and sends the specified
 | |
|         /// SpritePauseType to each one.  Look at the documentation for SpritePauseType to determine which pause
 | |
|         /// type to use.
 | |
|         /// </summary>
 | |
|         /// <param name="What">The SpritePauseType to send all sprites</param>
 | |
|         public void Pause(SpritePauseType What = SpritePauseType.PauseAll)
 | |
|         {
 | |
|             for(int i=0; i< Sprites.Count; i++)
 | |
|             {
 | |
|                 Sprites[i].Pause(What);
 | |
|             }
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// un-Pause everything.  This will send the specified SpritePauseType unpause command
 | |
|         /// to all sprites.
 | |
|         /// </summary>
 | |
|         /// <param name="What">The SpritePauseType to unpause for all sprites</param>
 | |
|         public void UnPause(SpritePauseType What = SpritePauseType.PauseAll)
 | |
|         {
 | |
|             for (int i = 0; i < Sprites.Count; i++)
 | |
|             {
 | |
|                 Sprites[i].UnPause(What);
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         internal void SortSprites()
 | |
|         {
 | |
|             //Define the sort we use if we do not have another one specified
 | |
|             Comparison<Sprite> G = null;
 | |
|             //G = delegate (Sprite first, Sprite second) {
 | |
|             //    if(first.Zvalue != second.Zvalue) return first.Zvalue.CompareTo(second.Zvalue);
 | |
|             //    if (first.BaseImageLocation.Y != second.BaseImageLocation.Y) return first.BaseImageLocation.Y.CompareTo(second.BaseImageLocation.Y);
 | |
|             //    return first.BaseImageLocation.X.CompareTo(second.BaseImageLocation.X);
 | |
|             //};
 | |
|             G = delegate (Sprite first, Sprite second) { return first.Zvalue.CompareTo(second.Zvalue); }; 
 | |
|             if (SpriteComparisonDelegate != null)
 | |
|                 G = SpriteComparisonDelegate;            
 | |
|             //Sprites.Sort((x, y) => x.Zvalue.CompareTo(y.Zvalue));
 | |
|             Sprites.Sort(G);
 | |
|         }
 | |
|     }
 | |
| 
 | |
| }
 |