//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// Copyright (C)2007 DarkWynter Studios. All rights reserved.
//
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------
namespace DarkWynterEngine.UserInterface
{
#region Using Statements
using System;
using System.Collections.Generic;
using System.Collections;
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 Globals;
#endregion
///
/// Creates, updates, and draws a heads up display on the user's viewport.
///
public class HeadsUpDisplay
{
// Attributes:
// Screen dead zone percentage
private const float SIDES_DEAD_ZONE_PERCENT = 0.05f;
private const float TOP_BOTTOM_DEAD_ZONE_PERCENT = 0.03f;
private int playerIndex = 0;
///
/// View-port on which our HUD will draw itself
///
public Viewport parentViewport;
// List of Text Displays
private List textDisplays = new List();
// List of Value Displays
private List valueDisplays = new List();
// List of Image Displays
private List imageDisplays = new List();
private List imageSpinners = new List();
///
/// Indicates what type of Heads Up Display element this is.
///
public enum DisplayType
{
///
/// A string of text.
///
TEXT,
///
/// A numerical value.
///
VALUE,
///
/// An image.
///
IMAGE,
///
/// Default.
///
BASE
};
///
/// Base class for all types.
///
public class HUDDisplay
{
///
/// Text string drawn to HUD.
///
public string text;
///
/// Position of HUD element.
///
public Vector2 position = new Vector2();
///
/// Width of HUD element.
///
public int width;
///
/// Height of HUD element.
///
public int height;
///
/// Color of text element.
///
public Color color;
///
/// Type of HUD element.
///
public DisplayType type = DisplayType.BASE;
///
/// Visibility of HUD element.
///
public bool visible = true;
};
///
/// Used to display Text.
///
private class TextDisplay : HUDDisplay
{
///
/// Text display constructor.
///
public TextDisplay()
{
type = DisplayType.TEXT;
}
}
///
/// Used to display Values.
///
private class ValueDisplay : HUDDisplay
{
///
/// Numerical value drawn to HUD.
///
public float value;
///
/// Value display constructor.
///
public ValueDisplay()
{
type = DisplayType.VALUE;
}
}
///
/// Used to display Images.
///
public class ImageDisplay : HUDDisplay
{
///
/// Image drawn to HUD.
///
public Texture2D image;
///
/// X scale of image.
///
public float xScale;
///
/// Y scale of image.
///
public float yScale;
///
/// Image display constructor.
/// Scale defaults to 1.
///
public ImageDisplay()
{
xScale = 1.0f;
yScale = 1.0f;
type = DisplayType.IMAGE;
}
}
///
/// Used to display image sequences
///
public class ImageSpinner : HUDDisplay
{
///
/// Array of images
///
public ImageDisplay[] images;
///
/// Index of active image
///
public int activeIndex;
///
/// Constructor
///
/// Size of Image Display
public ImageSpinner(int size)
{
this.activeIndex = 0;
this.images = new ImageDisplay[size];
}
///
/// Add an image to our array
///
/// Image
/// Location
public void addImage(ImageDisplay val, int slot)
{
images[slot] = val;
}
///
/// Iterate to next image
///
public void next()
{
if (this.images.Length <= this.activeIndex + 1)
{
this.activeIndex = 0;
}
else
{
this.activeIndex++;
}
}
///
/// Iterate to previous image
///
public void prev()
{
if (this.activeIndex == 0)
{
this.activeIndex = this.images.Length - 1;
}
else
{
this.activeIndex--;
}
}
}
///
/// Heads Up Display constructor.
///
public HeadsUpDisplay()
{
playerIndex = 0;
}
///
/// Heads Up Display constructor with player index and predefined viewport.
///
/// Player this HUD belongs to.
/// Player's viewport.
public HeadsUpDisplay(int index, Viewport viewport)
{
playerIndex = index;
parentViewport = viewport;
}
// Methods:
//*******************************************************************************************
// Still buggy.. I need to come back to it later
// Check for edges of the screen if playing on Xbox360
private void AdjustForDeadZone(HUDDisplay element)
{
#if false//XBOX360
float deadZoneX = Statics.GAME_WINDOW_WIDTH * SIDES_DEAD_ZONE_PERCENT;
float deadZoneY = Statics.GAME_WINDOW_HEIGHT * TOP_BOTTOM_DEAD_ZONE_PERCENT;
Vector2 absolutePosition = Vector2.Zero + element.position;
// Player 1 always in absolute coordinates
// Check Player 2:
if (playerIndex == 1)
{
if (Statics.TOTAL_PLAYERS_PLAYING == 2)
{
absolutePosition += new Vector2(0, parentViewport.Height);
}
else
{
absolutePosition += new Vector2(parentViewport.Width, 0);
}
}
else if (playerIndex == 2)
{
absolutePosition += new Vector2(0, parentViewport.Height);
}
else if (playerIndex == 3)
{
absolutePosition += new Vector2(parentViewport.Width, parentViewport.Height);
}
// First check for the left side dead zone
// If its on the left side
if (absolutePosition.X < Statics.GAME_WINDOW_WIDTH * 0.5f)
{
if (playerIndex == 0 || (playerIndex == 1 && Statics.TOTAL_PLAYERS_PLAYING == 2) ||
(playerIndex == 2 && Statics.TOTAL_PLAYERS_PLAYING > 2))
{
element.position.X += deadZoneX;
}
}
// else.. check for right side
else if (absolutePosition.X > Statics.GAME_WINDOW_WIDTH * 0.5f)
{
if (playerIndex == 1 || (playerIndex == 0 && Statics.TOTAL_PLAYERS_PLAYING <= 2) ||
playerIndex == 3)
{
element.position.X -= deadZoneX;
}
}
// Then check upper side
if (absolutePosition.Y < Statics.GAME_WINDOW_HEIGHT * 0.5f)
{
if (playerIndex == 0 || (playerIndex == 1 && Statics.TOTAL_PLAYERS_PLAYING > 2))
{
element.position.Y += deadZoneY;
}
}
else if (absolutePosition.Y > Statics.GAME_WINDOW_HEIGHT * 0.5f)
{
if (playerIndex == 2 || playerIndex == 3 || (playerIndex == 0 && Statics.TOTAL_PLAYERS_PLAYING == 1) ||
(playerIndex == 1 && Statics.TOTAL_PLAYERS_PLAYING == 2))
{
element.position.Y -= deadZoneY;
}
}
#endif
}
///
/// Add a Text display to the TextDisplay list.
///
/// Text to add.
/// Position to locate text.
/// Color to display text with.
/// Count of text displays
public int AddTextDisplay(string text, Vector2 position, Color color)
{
TextDisplay temp = new TextDisplay();
temp.text = text;
Vector2 size = FontWriter.Arial.MeasureString(text);
temp.width = (int)(size.X);
temp.height = (int)(size.Y);
temp.position = position;
AdjustForDeadZone(temp);
temp.color = color;
textDisplays.Add(temp);
return textDisplays.Count - 1;
}
///
/// Add a Value display to the ValueDisplay list.
///
/// Text to display.
/// Value to display.
/// Position to display value.
/// Width of value display.
/// Height of value display.
/// Color of value and text.
/// Count of value displays
public int AddValueDisplay(string text, float value, Vector2 position, int width, int height, Color color)
{
ValueDisplay temp = new ValueDisplay();
temp.text = text;
temp.value = value;
temp.width = width;
temp.height = height;
temp.position = position;
AdjustForDeadZone(temp);
temp.color = color;
valueDisplays.Add(temp);
return valueDisplays.Count - 1;
}
///
/// Add an Image display to our ImageDisplay list.
///
/// Image to display.
/// Position to display value.
/// Width of value display.
/// Height of value display.
/// Color of value and text.
/// Toggle to turn drawing on/off.
/// Count of image displays
public int AddImageDisplay(Texture2D image, Vector2 position, int width, int height, Color color, bool draw)
{
ImageDisplay temp = new ImageDisplay();
temp.image = image;
temp.width = width;
temp.height = height;
temp.position = position;
AdjustForDeadZone(temp);
temp.color = color;
temp.visible = draw;
imageDisplays.Add(temp);
return imageDisplays.Count - 1;
}
///
/// Add an Image spinner to our ImageDisplay list
///
/// Image spinner to add
/// Count of image spinners
public int AddImageSpinner(ImageSpinner 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 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 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 temp = this.imageSpinners[index];
if (val < 0 || temp.images.Length <= val)
{
return;
}
else
{
temp.activeIndex = val;
this.imageSpinners[index] = temp;
}
}
///
/// Method which allows us to change the text in a TextDisplay
///
/// location
/// New text
public void UpdateText(int index, string newText)
{
if (index < 0 || index >= textDisplays.Count)
{
// Invalid index
return;
}
else
{
// Change the text
textDisplays[index].text = newText;
}
}
///
/// Updates the visibility of a text display
///
/// location
/// New text
/// Visibility
/// Display color
public void UpdateTextVis(int index, string newText, bool vis, Color color)
{
if (index < 0 || index >= textDisplays.Count)
{
// Invalid index
return;
}
else
{
// Change the text
textDisplays[index].color = color;
textDisplays[index].text = newText;
textDisplays[index].visible = vis;
}
}
///
/// Method which allows us to change the Value in a ValueDisplay.
///
/// Location of ValueDisplay in list.
/// New value of value display.
public void UpdateValue(int index, float newValue)
{
if (index < 0 || index >= valueDisplays.Count)
{
// Invalid index
return;
}
else
{
// Change the value
valueDisplays[index].value = newValue;
}
}
///
/// Updates the x and y scale of an image display
///
/// Location of ValueDisplay in list.
/// X-scale value.
/// Y-scale value.
public void UpdateImageScale(int index, float xScale, float yScale)
{
if (index < 0 || index >= this.imageDisplays.Count)
{
// Invalid index
return;
}
else
{
this.imageDisplays[index].xScale = xScale;
this.imageDisplays[index].yScale = yScale;
}
}
///
/// Change height of an image.
///
/// Location of ValueDisplay in list.
/// New height of Image..
public void UpdateImageHeight(int index, int amount)
{
if (index < 0 || index >= this.imageDisplays.Count)
{
// Invalid index
return;
}
else
{
this.imageDisplays[index].height = amount;
}
}
///
/// Chage position of image.
///
/// Location of ValueDisplay in list.
/// New position of image.
public void UpdateImagePosition(int index, Vector2 newPosition)
{
if (index < 0 || index >= this.imageDisplays.Count)
{
// Invalid index
return;
}
else
{
this.imageDisplays[index].position = newPosition;
}
}
///
/// Change whether image is drawn of not.
///
/// Location of ValueDisplay in list.
/// True to draw image, false to hide.
public void UpdateImageDraw(int index, bool value)
{
if (index < 0 || index >= this.imageDisplays.Count)
{
// Invalid index
return;
}
else
{
this.imageDisplays[index].visible = value;
}
}
///
/// Method that sets a text display as visible or invisible.
///
/// Location of ValueDisplay in list.
/// True to draw image, false to hide.
public void UpdateTextVisible(int index, bool visible)
{
if (index < 0 || index >= textDisplays.Count)
{
// Invalid index
return;
}
else
{
// Change the value
textDisplays[index].visible = visible;
}
}
///
/// Method which allows us to change the color of a TextDisplay.
///
/// Location of ValueDisplay in list.
/// New color of text.
public void UpdateTextColor(int index, Color color)
{
if (index < 0 || index >= textDisplays.Count)
{
// Invalid index
return;
}
else
{
// Change the value
textDisplays[index].color = color;
}
}
///
/// 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 (TextDisplay element in textDisplays)
{
if (element.visible)
{
spriteBatch.DrawString(FontWriter.Arial, element.text, element.position, element.color);
}
}
foreach (ImageDisplay element in imageDisplays)
{
if (element.visible == true)
{
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 (ImageSpinner 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);
}
}
}
}
}