XNA Popup Dialog Box
Hey guys, I'm working on a game and I want to add a screen that will open when the user clicks on certain objects. The screen will be laid out to have an image on the left, a heading in the upper right corner, and text below the heading.
I have several problems with this, 1) How do I create a popup? (preferably with rounded edges) 2) How would I wrap the text (in front of the image, but not outside the popup, I might even need vertical scrollbars) 3) How would I account for different screen resolutions (could they even make a difference?)
Thanks for any help, Max.
a source to share
rounded edges, etc. can be handled best by creating an image of what you want the popup to look like and styling it however you want.
lets say you made a box, 300px by 300px
then from there you will want to wrap your text inside and maybe scroll through it or still want to process it by specifying the height and width of the text to find where to wrap the text ...
for example, you could make a function that would take your full text and wrap it based on some measurements.
private string WrapText(string text)
{
string[] words = text.Split(' ');
StringBuilder sb = new StringBuilder();
float linewidth = 0f;
float maxLine = 250f; //a bit smaller than the box so you can have some padding...etc
float spaceWidth = spriteFont.MeasureString(" ").X;
foreach (string word in words)
{
Vector2 size = spriteFont.MeasureString(word);
if (linewidth + size.X < 250)
{
sb.Append(word + " ");
linewidth += size.X + spaceWidth;
}
else
{
sb.Append("\n" + word + " ");
linewidth = size.X + spaceWidth;
}
}
return sb.ToString();
}
if your text is very suitable for top-down presentation - you will have to come up with some kind of scrollable text or a "continue" button to load the next page of text, for example.
finally as far as resolution goes, it depends on the platform you want to build your game and art towards the platform, for example a 300x300 image for a dialog probably won't work that well if that's what you are building in XNA 4 for a phone but it will be fine for xbox build and build build is most logical. Although with viewports, you could probably use the same art (it just would be worth using smaller images for a much smaller screen.
to resolve issues you probably want to look at some things, such as the tile safe area , and read a little about viewports . It was also suggested to set the game to 1280 x 720, which is a native 720p resolution that should work on all TVs and gives you a link to your art.
public Game1()
{
graphics = new GraphicsDeviceManager(this);
this.graphics.PreferredBackBufferWidth = 1280;
this.graphics.PreferredBackBufferHeight = 720;
Content.RootDirectory = "Content";
}
which will hopefully at least nudge you in the right direction.
a source to share
I haven't touched XNA in years, but I would suggest you take a look at a sample game state. This is probably a little dated now, but will give you a good starting point for managing your game state and Popups, menus, etc.
http://creators.xna.com/en-US/samples/gamestatemanagement
a source to share
For any kind, here is the complete code that I worked on it, the code is a curious chicken, but it does the job.
Note that I put the FillText loader in the main function, you have to move this outside (so it won't be called multiple times) if you use this code
public void DisplayPopup (string Title, string Text, string AssetPicturePath, SpriteBatch batch)
{
FillText = new Texture2D(game.GraphicsDevice, 1, 1);
FillText.SetData(new Color[] { Color.White });
//Draw rectangle, center screen,
Rectangle MainBox;
MainBox.Width = 700;
MainBox.Height = 400;
MainBox.X = game.Window.ClientBounds.Width / 2 - MainBox.Width / 2;
MainBox.Y = game.Window.ClientBounds.Height / 2 - MainBox.Height / 2;
//Draw Title
Rectangle TitleBox;
TitleBox.Width = 650;
TitleBox.Height = (int)ArialFont.MeasureString(Title).Y;
Padding = MainBox.Width / 2 - TitleBox.Width / 2;
TitleBox.X = (int)Padding + MainBox.X;
TitleBox.Y = (int)Padding + MainBox.Y;
//Draw Line Between Title and TextBox
Rectangle TextSeperator;
TextSeperator.Width = MainBox.Width - (int)Padding * 2;
TextSeperator.Height = 1;
TextSeperator.X = MainBox.X + (int)Padding;
TextSeperator.Y = TitleBox.Y + (int)(Padding * 1.2);
//Draw PictureBox
Rectangle PictureBox;
if (AssetPicturePath != string.Empty)
PictureBox.Width = 200;
else
PictureBox.Width = 0;
PictureBox.Height = 250;
PictureBox.X = MainBox.X + (int)Padding;
PictureBox.Y = MainBox.Y + TitleBox.Height + (int)Padding * 2;
MainBox.Height = PictureBox.Y - MainBox.Y + PictureBox.Height + (int)Padding;
//Draw TextBody
Rectangle TextBody;
if (AssetPicturePath == string.Empty)
TextBody.Width = MainBox.Width - ((int)Padding * 2);
else
TextBody.Width = MainBox.Width - ((int)Padding * 3) - PictureBox.Width;
TextBody.Height = MainBox.Height - ((int)Padding * 3) - TitleBox.Height;
if (AssetPicturePath == string.Empty)
TextBody.X = PictureBox.X;
else
TextBody.X = PictureBox.X + PictureBox.Width + (int)Padding;
TextBody.Y = TitleBox.Y + TitleBox.Height + (int)Padding;
//Draw MainBox
batch.Draw(FillText, MainBox, Color.Wheat);
//Draw PictureBox
//batch.Draw(FillText, PictureBox, Color.Green);
if (AssetPicturePath != string.Empty)
batch.Draw(game.Content.Load<Texture2D>(AssetPath + AssetPicturePath.TrimStart(new char[] { '/' })), PictureBox, Color.White);
//Draw TitleBox
//batch.Draw(FillText, TitleBox, Color.BlueViolet);
batch.DrawString(ArialFont, Title, new Vector2(TitleBox.X, TitleBox.Y),Color.Blue);
//Draw Line Between Title And TextBody
batch.Draw(FillText, TextSeperator, Color.Gray);
//Draw TextBody
//batch.Draw(FillText, TextBody, Color.Indigo);
int LineNumber = 0;
foreach (string Line in WrapText(Text, TextBody.Width))
{
batch.DrawString(ArialFont, Line, new Vector2(TextBody.X, TextBody.Y + (LineNumber * ArialFont.MeasureString(Line).Y)), Color.Black);
LineNumber++;
}
}
private object[] WrapText(string text, float Length)
{
string[] words = text.Split(' ');
ArrayList Lines = new ArrayList();
float linewidth = 0f;
float spaceWidth = ArialFont.MeasureString(" ").X;
int CurLine = 0;
Lines.Add(string.Empty);
foreach (string word in words)
{
Vector2 size = ArialFont.MeasureString(word);
if (linewidth + size.X < Length)
{
Lines[CurLine] += word + " ";
linewidth += size.X + spaceWidth;
}
else
{
Lines.Add(word + " ");
linewidth = size.X + spaceWidth;
CurLine++;
}
}
return Lines.ToArray();
}
a source to share