//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {Contact : darkwynter.com for licensing information //--------------------------------------------------------------------------------------------------------------------------------------------------- namespace DarkWynter.Engine.UserInterface { #region Using Statements using System; using System.Collections.Generic; using System.Collections; using System.Diagnostics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; using DarkWynter.Stream; using DarkWynter.Engine.Globals; using System.ComponentModel; using System.Xml; #endregion /// /// Creates, updates, and draws a heads up display on the user's viewport. /// public class HeadsUpDisplay { #region Init and Update // XML Loading variables for HUD private string nameID; private string texturePath; private Vector2 displayLocation = new Vector2(); private bool toDraw; // The nameID of the image that the second needs to get the location from private string imageReference; // The imageAttributes that we need to figure out the location from private string imageAttribute; private Texture2D textureImage; private Color newColor; // Which of the nine quadrants to draw in private string quadrant; // An addition modifier to the image location, must be 0 if null private int modifier; // Text Display specific private string operation; private string textToScreen; private Vector2 offset; private const int MARGIN_GUTTER = 15; private const int SCROLL = 20; private int dialogueBoxIndex; private int playerIndex = 0; private int speakerTextIndex; private int dialogueTextIndex; private int displayLength = 0; public List textDisplays { get { return _textDisplays; } set { _textDisplays = value; } } private List _textDisplays = new List(); public List imageDisplays { get { return _imageDisplays; } set { _imageDisplays = value; } } public List _imageDisplays = new List(); public List imageSpinners { get { return _imageSpinners; } set { _imageSpinners = value; } } private List _imageSpinners = new List(); // Dimensions of the Viewport updated when Level Loads private Vector2 ViewportSize = new Vector2(1280, 1024); /// /// Heads Up Display constructor. /// public HeadsUpDisplay() { playerIndex = 0; CreateHUD(); InitializeDialogControl(); } /// /// Heads Up Display constructor with player index and predefined viewport. /// /// Player this HUD belongs to. public HeadsUpDisplay(int index) { playerIndex = index; CreateHUD(); InitializeDialogControl(); } /// /// Update Hud events. /// public void Update() { UpdateDialogue(); } #endregion #region HUDCreation /// /// Generate the HUD from XML file /// public void CreateHUD() { try { string fileName = System.IO.Directory.GetCurrentDirectory(); fileName += "\\_xml\\HUD.xml"; // Load the HUD Images, Text, and Values XmlDocument reader = new XmlDocument(); reader.Load(fileName); XmlNodeList allNodes = reader.ChildNodes; foreach (XmlNode eventNode in allNodes) { if (eventNode.Name == "HUDSettings") { XmlNodeList eventNodes = eventNode.ChildNodes; foreach (XmlNode node in eventNodes) { if (node.Name == "ImageDisplay") { LoadImageDisplays(node); } if (node.Name == "TextDisplay") { LoadTextDisplays(node); } } } } } catch (Exception e) { System.Diagnostics.Debug.WriteLine("Error reading xml"); throw e; } // Once everything is added to the HUD, call resize for correct image locations ViewportSize = new Vector2( Statics_Stream.RenderSettings.cameraList[0].viewport.Width, Statics_Stream.RenderSettings.cameraList[0].viewport.Height ); } /// /// Loads the imageDisplay into the imageDisplays list /// /// XML Node ImageDisplay private void LoadImageDisplays(XmlNode node) { this.nameID = node.Attributes["nameID"].Value; this.texturePath = node.Attributes["texturePath"].Value; this.textureImage = Statics_Engine.SystemSettings.content.Load(texturePath); this.displayLocation = new Vector2(int.Parse(node.Attributes["posX"].Value), int.Parse(node.Attributes["posY"].Value)); this.newColor = new Color( byte.Parse(node.Attributes["colorR"].Value), byte.Parse(node.Attributes["colorG"].Value), byte.Parse(node.Attributes["colorB"].Value), byte.Parse(node.Attributes["colorA"].Value) ); this.toDraw = bool.Parse(node.Attributes["toDraw"].Value); this.quadrant = node.Attributes["quadrant"].Value; if (quadrant != "null") { QuadrantLocationsTranslationImage(); } this.imageReference = node.Attributes["imageReference"].Value; this.imageAttribute = node.Attributes["imageAttribute"].Value; this.modifier = int.Parse(node.Attributes["modifier"].Value); if (imageReference != "null") { AdjustLocationBasedOnReferenceImage(); } AddImageDisplay(this.textureImage, this.nameID, this.displayLocation, this.textureImage.Width, this.textureImage.Height, newColor, this.toDraw); } /// /// Loads the textDisplay into the textDisplays list /// /// XML Node TextDisplay private void LoadTextDisplays(XmlNode node) { this.nameID = node.Attributes["nameID"].Value; this.textToScreen = node.Attributes["text"].Value; this.displayLocation = new Vector2(int.Parse(node.Attributes["posX"].Value), int.Parse(node.Attributes["posY"].Value)); this.newColor = new Color( byte.Parse(node.Attributes["colorR"].Value), byte.Parse(node.Attributes["colorG"].Value), byte.Parse(node.Attributes["colorB"].Value), byte.Parse(node.Attributes["colorA"].Value) ); this.toDraw = bool.Parse(node.Attributes["toDraw"].Value); this.imageReference = node.Attributes["imageReference"].Value; this.operation = node.Attributes["operation"].Value; this.offset = new Vector2(int.Parse(node.Attributes["offsetX"].Value), int.Parse(node.Attributes["offsetY"].Value)); this.quadrant = node.Attributes["quadrant"].Value; if (this.quadrant != "null") { QuadrantLocationsTranslationText(); } if (imageReference != "null") { for (int x = 0; x < imageDisplays.Count; x++) { if (imageDisplays[x].name == imageReference) { LocationBasedOnReference(x); AddTextDisplay(this.nameID, this.textToScreen, this.displayLocation, this.newColor, this.toDraw); } } } else { AddTextDisplay(this.nameID, this.textToScreen, this.displayLocation, this.newColor, this.toDraw); } } #region Loading HUD helper methods /// /// Translate from XML quadrant to viewport location /// private void QuadrantLocationsTranslationImage() { if (quadrant == "UL") { // (0,0) + offset (offset can be another image or a hard coded number(gutter)) this.displayLocation = new Vector2(MARGIN_GUTTER, MARGIN_GUTTER); } else if (quadrant == "ML") { // viewport.h-self.h/2, w = gutter this.displayLocation.X = MARGIN_GUTTER; this.displayLocation.Y = (Statics_Stream.RenderSettings.cameraList[0].viewport.Height - this.textureImage.Height) / 2; } else if (quadrant == "BL") { // w = offset, viewport.h-image.h + gutter this.displayLocation.X = MARGIN_GUTTER; this.displayLocation.Y = Statics_Stream.RenderSettings.cameraList[0].viewport.Height - this.textureImage.Height - MARGIN_GUTTER; } else if (quadrant == "UC") { // h= gutter, view.w-image.w/2 this.displayLocation.Y = MARGIN_GUTTER; this.displayLocation.X = (Statics_Stream.RenderSettings.cameraList[0].viewport.Width - this.textureImage.Width) / 2; } else if (quadrant == "MC") { // viewport-self/2 this.displayLocation.X = (Statics_Stream.RenderSettings.cameraList[0].viewport.Width - this.textureImage.Width) / 2; this.displayLocation.Y = (Statics_Stream.RenderSettings.cameraList[0].viewport.Height - this.textureImage.Height) / 2; } else if (quadrant == "BC") { //view.w-image.w/2, viewport.h-image.h + gutter this.displayLocation.X = (Statics_Stream.RenderSettings.cameraList[0].viewport.Width - this.textureImage.Width) / 2; this.displayLocation.Y = Statics_Stream.RenderSettings.cameraList[0].viewport.Height - this.textureImage.Height - MARGIN_GUTTER; } else if (quadrant == "UR") { //viewport.w-texture.w - gutter, h = gutter this.displayLocation.Y = MARGIN_GUTTER; this.displayLocation.X = Statics_Stream.RenderSettings.cameraList[0].viewport.Width - this.textureImage.Width - MARGIN_GUTTER; } else if (quadrant == "MR") { //viewport.w-texture.w - gutter, h =1/2(view-text) this.displayLocation.X = Statics_Stream.RenderSettings.cameraList[0].viewport.Width - this.textureImage.Width - MARGIN_GUTTER; this.displayLocation.Y = (Statics_Stream.RenderSettings.cameraList[0].viewport.Height - this.textureImage.Height) / 2; } else if (quadrant == "BR") { // viewport.w-text.w - gutter, viewport.h-image.h + gutter this.displayLocation.X = Statics_Stream.RenderSettings.cameraList[0].viewport.Width - this.textureImage.Width - MARGIN_GUTTER; this.displayLocation.Y = Statics_Stream.RenderSettings.cameraList[0].viewport.Height - this.textureImage.Height - MARGIN_GUTTER; } } /// /// If the image has a reference variable, loads the image based on the imageAttribute. /// Called by LoadImageDisplays /// private void AdjustLocationBasedOnReferenceImage() { if (imageReference == "self") { if (imageAttribute == "height") { displayLocation.Y = displayLocation.Y - (textureImage.Height + 10); } else if (imageAttribute == "width") { displayLocation.X = displayLocation.X - (textureImage.Width / 2); } else if (imageAttribute == "both") { displayLocation.Y = displayLocation.Y - (textureImage.Height / 2); displayLocation.X = displayLocation.X - (textureImage.Width / 2); } } else { for (int x = 0; x < imageDisplays.Count; x++) { if (imageDisplays[x].name == imageReference) { if (imageAttribute != null) { if (imageAttribute == "width") { displayLocation.X = MARGIN_GUTTER + modifier + imageDisplays[x].width; } else if (imageAttribute == "height") { displayLocation.Y = imageDisplays[x].height + modifier; } else if (imageAttribute == "both") { displayLocation.X = MARGIN_GUTTER + modifier + imageDisplays[x].width; displayLocation.Y = imageDisplays[x].height + modifier; } } } } } } /// /// Translate from XML quadrant to viewport location /// private void QuadrantLocationsTranslationText() { if (quadrant == "UL") { // (0,0) + offset (offset can be another image or a hard coded number(gutter)) this.displayLocation = new Vector2(MARGIN_GUTTER, MARGIN_GUTTER); } else if (quadrant == "ML") { // viewport.h-self.h/2, w = gutter this.displayLocation.X = MARGIN_GUTTER; this.displayLocation.Y = (Statics_Stream.RenderSettings.cameraList[0].viewport.Height - this.textureImage.Height) / 2; } else if (quadrant == "BL") { // w = offset, viewport.h-image.h + gutter this.displayLocation.X = MARGIN_GUTTER; this.displayLocation.Y = Statics_Stream.RenderSettings.cameraList[0].viewport.Height - Statics_Stream.Fonts.Arial.MeasureString(this.textToScreen).Y - MARGIN_GUTTER; } else if (quadrant == "UC") { // h= gutter, view.w-image.w/2 this.displayLocation.Y = MARGIN_GUTTER; this.displayLocation.X = (Statics_Stream.RenderSettings.cameraList[0].viewport.Width - Statics_Stream.Fonts.Arial.MeasureString(this.textToScreen).X) / 2; } else if (quadrant == "MC") { // viewport-self/2 this.displayLocation.X = (Statics_Stream.RenderSettings.cameraList[0].viewport.Width - Statics_Stream.Fonts.Arial.MeasureString(this.textToScreen).X) / 2; this.displayLocation.Y = (Statics_Stream.RenderSettings.cameraList[0].viewport.Height - Statics_Stream.Fonts.Arial.MeasureString(this.textToScreen).Y) / 2; } else if (quadrant == "BC") { //view.w-image.w/2, viewport.h-image.h + gutter this.displayLocation.X = (Statics_Stream.RenderSettings.cameraList[0].viewport.Width - Statics_Stream.Fonts.Arial.MeasureString(this.textToScreen).X) / 2; this.displayLocation.Y = Statics_Stream.RenderSettings.cameraList[0].viewport.Height - Statics_Stream.Fonts.Arial.MeasureString(this.textToScreen).Y - MARGIN_GUTTER; } else if (quadrant == "UR") { //viewport.w-texture.w - gutter, h = gutter this.displayLocation.Y = MARGIN_GUTTER; this.displayLocation.X = Statics_Stream.RenderSettings.cameraList[0].viewport.Width - Statics_Stream.Fonts.Arial.MeasureString(this.textToScreen).X - MARGIN_GUTTER; } else if (quadrant == "MR") { //viewport.w-texture.w - gutter, h =1/2(view-text) this.displayLocation.X = Statics_Stream.RenderSettings.cameraList[0].viewport.Width - Statics_Stream.Fonts.Arial.MeasureString(this.textToScreen).X - MARGIN_GUTTER; this.displayLocation.Y = (Statics_Stream.RenderSettings.cameraList[0].viewport.Height - Statics_Stream.Fonts.Arial.MeasureString(this.textToScreen).Y) / 2; } else if (quadrant == "BR") { // viewport.w-text.w - gutter, viewport.h-image.h + gutter this.displayLocation.X = Statics_Stream.RenderSettings.cameraList[0].viewport.Width - Statics_Stream.Fonts.Arial.MeasureString(this.textToScreen).X - MARGIN_GUTTER; this.displayLocation.Y = Statics_Stream.RenderSettings.cameraList[0].viewport.Height - Statics_Stream.Fonts.Arial.MeasureString(this.textToScreen).Y - MARGIN_GUTTER; } } /// /// If the text has a reference, load based on the offset /// Called by LoadTextDisplays /// /// private void LocationBasedOnReference(int x) { if (operation != "null") { if (operation == "add") { displayLocation = imageDisplays[x].position + offset; } else if (operation == "subtract") { displayLocation = imageDisplays[x].position - offset; } else if (operation == "multiply") { displayLocation = imageDisplays[x].position * offset; } else if (operation == "divide") { displayLocation = imageDisplays[x].position / offset; } } } #endregion #endregion #region Dialogue Controls /// /// Inits the dialogue control system /// public void InitializeDialogControl() { for (int x = 0; x < imageDisplays.Count; x++) { if (imageDisplays[x].name == "dialogueBox") { dialogueBoxIndex = x; } } for (int x = 0; x < textDisplays.Count; x++) { if (textDisplays[x].name == "speakerText") { speakerTextIndex = x; } if (textDisplays[x].name == "dialogueText") { dialogueTextIndex = x; } } imageDisplays[dialogueBoxIndex].stopWatch.Reset(); } /// /// Shows the dialogue /// /// Which image to post in the background /// Who is talking /// What the message is public void ShowDialog(Texture2D backgroundImage, string speaker, string message) { imageDisplays[dialogueBoxIndex].visible = true; textDisplays[speakerTextIndex].text = speaker; textDisplays[speakerTextIndex].visible = true; textDisplays[dialogueTextIndex].text = message; textDisplays[dialogueTextIndex].visible = true; } /// /// Removes the dialogue from the HUD /// public void RemoveDialog() { imageDisplays[dialogueBoxIndex].visible = false; textDisplays[speakerTextIndex].text = "ERROR"; textDisplays[speakerTextIndex].visible = false; textDisplays[speakerTextIndex].color = Color.White; textDisplays[dialogueTextIndex].text = "YOU SHOULDN'T EVER SEE THIS"; textDisplays[dialogueTextIndex].visible = false; textDisplays[dialogueTextIndex].color = Color.White; } /// /// Displays the dialogue on the HUD /// /// Which image to post in the background /// Who is talking /// What the message is /// Time limit to display message public void DisplayDialog(Texture2D backgroundImage, string speaker, string message, int limitMilli) { displayLength = limitMilli; if (!imageDisplays[dialogueBoxIndex].stopWatch.IsRunning) { displayLength = limitMilli; imageDisplays[dialogueBoxIndex].stopWatch.Start(); } else { displayLength = limitMilli; imageDisplays[dialogueBoxIndex].stopWatch.Reset(); } ShowDialog(backgroundImage, speaker, message); } /// /// Removes dialogue once time limit expires /// public void UpdateDialogue() { //Remove dialogue once the limit has passed if (imageDisplays[dialogueBoxIndex].stopWatch.ElapsedMilliseconds >= displayLength) { RemoveDialog(); imageDisplays[dialogueBoxIndex].stopWatch.Reset(); displayLength = 0; } } #endregion #region Add images/text to HUD and helper methods /// /// Add a Text display to the TextDisplay list. /// /// ID of the text to be displayed /// Text to add /// Position on the HUD /// Color to display the text in /// Toggle to turn draw on/off /// public int AddTextDisplay(string nameID, string text, Vector2 position, Color color, bool draw) { TextDisplay temp = new TextDisplay(); temp.name = nameID; temp.text = text; Vector2 size = Statics_Stream.Fonts.Arial.MeasureString(text); temp.width = (int)(size.X); temp.height = (int)(size.Y); temp.position = position; temp.color = color; temp.visible = draw; textDisplays.Add(temp); return textDisplays.Count - 1; } /// /// Add an Image display to our ImageDisplay list. /// /// Image to display /// Name of the image /// Position to display image /// Width of the image's texture /// Height of the image's texture /// Color of the image /// Toggle to turn draw on/off public void AddImageDisplay(Texture2D image, string name, Vector2 position, int width, int height, Color color, bool draw) { ImageDisplay temp = new ImageDisplay(); temp.image = image; temp.name = name; temp.width = width; temp.height = height; temp.position = position; temp.color = color; temp.visible = draw; temp.rotation = 0.0f; _imageDisplays.Add(temp); } /// /// Resizes the HUD based on viewport change /// /// The ratio between old viewport and resized viewport public void Resize(Vector2 currentViewportSize) { if (currentViewportSize != ViewportSize) { // Determine multiplier Vector2 HUDScaleMultiplier = currentViewportSize / ViewportSize; for (int i = 0; i < textDisplays.Count; i++) { textDisplays[i].position = textDisplays[i].position * HUDScaleMultiplier; } for (int i = 0; i < _imageDisplays.Count; i++) { _imageDisplays[i].position = _imageDisplays[i].position * HUDScaleMultiplier; } for (int i = 0; i < imageSpinners.Count; i++) { imageSpinners[i].position = imageSpinners[i].position * HUDScaleMultiplier; } ViewportSize = currentViewportSize; } } #endregion #region Draw functions /// /// Default Draw function. /// /// SpriteBatch used to draw used to draw. public void Draw(SpriteBatch spriteBatch) { Draw(spriteBatch, 0, 0); } /// /// Draw function for drawing our displays at a certain offset position. /// NOTE: SpriteBatch Begin and End are handled outside this scope. /// /// SpriteBatch used to draw used to draw. /// X-Offset to draw location. /// Y-Offset to draw location. public void Draw(SpriteBatch spriteBatch, int xoffset, int yoffset) { foreach (ImageDisplay element in _imageDisplays) { if (element.visible == true) { if (element.name == "boop") { spriteBatch.Draw(element.image, new Rectangle((int)element.position.X + xoffset, (int)element.position.Y + yoffset, element.Size.Width, element.Size.Height), element.Source, element.color, element.rotation, new Vector2(element.Size.Height / 2, element.Size.Width /2), SpriteEffects.None, 1.0f); } else { spriteBatch.Draw(element.image, new Rectangle((int)element.position.X + xoffset, (int)element.position.Y + yoffset, element.Size.Width, element.Size.Height), element.Source, element.color); } } } foreach (ImageSpinner_old elementBig in imageSpinners) { if (elementBig.visible == true) { //ImageDisplay element = elementBig.images[elementBig.activeIndex]; //spriteBatch.Draw(element.image, // new Rectangle((int)element.position.X + xoffset, // (int)element.position.Y + yoffset, // element.width, // element.height), // new Rectangle(0, 0, (int)(element.image.Width * element.xScale), (int)(element.image.Height * element.yScale)), // element.color); } } foreach (TextDisplay element in textDisplays) { if (element.visible) { spriteBatch.DrawString(Statics_Stream.Fonts.Arial, element.text, element.position, element.color); } } } #endregion } } # region Spinner ///// ///// Add an Image spinner to our ImageDisplay list ///// ///// Image spinner to add ///// Count of image spinners //public int AddImageSpinner(ImageSpinner_old val) //{ // this.imageSpinners.Add(val); // return imageSpinners.Count - 1; //} ///// ///// Set the image spinner at index location to the next in-line ///// ///// location //public void SpinnerNext(int index) //{ // if (index < 0 || index >= this.imageSpinners.Count) // { // // Invalid index // return; // } // else // { // ImageSpinner_old temp = this.imageSpinners[index]; // temp.next(); // this.imageSpinners[index] = temp; // } //} ///// ///// Set the image spinner at index location to the previous inline ///// ///// location //public void SpinnerBack(int index) //{ // if (index < 0 || index >= this.imageSpinners.Count) // { // // Invalid index // return; // } // else // { // ImageSpinner_old temp = this.imageSpinners[index]; // temp.prev(); // this.imageSpinners[index] = temp; // } //} ///// ///// Set the active index to val in our image spinner at index ///// ///// location ///// Active value //public void SpinnerSet(int index, int val) //{ // if (index < 0 || index >= this.imageSpinners.Count) // { // // Invalid index // return; // } // ImageSpinner_old temp = this.imageSpinners[index]; // if (val < 0 || temp.images.Length <= val) // { // return; // } // else // { // temp.activeIndex = val; // this.imageSpinners[index] = temp; // } //} #endregion