//-----------------------------------------------------------------------------
// MainMenu.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using RacingGame.GameLogic;
using RacingGame.Graphics;
using RacingGame.Helpers;
using RacingGame.Sounds;
namespace RacingGame.GameScreens
{
///
/// Main menu
///
class MainMenu : IGameScreen
{
static readonly Rectangle[] ButtonRects = new Rectangle[]
{
UIRenderer.MenuButtonPlayGfxRect,
UIRenderer.MenuButtonHighscoresGfxRect,
UIRenderer.MenuButtonOptionsGfxRect,
UIRenderer.MenuButtonHelpGfxRect,
UIRenderer.MenuButtonQuitGfxRect,
};
static readonly Rectangle[] TextRects = new Rectangle[]
{
UIRenderer.MenuTextPlayGfxRect,
UIRenderer.MenuTextHighscoresGfxRect,
UIRenderer.MenuTextOptionsGfxRect,
UIRenderer.MenuTextHelpGfxRect,
UIRenderer.MenuTextQuitGfxRect,
};
const int NumberOfButtons = 5,
ActiveButtonWidth = 132,
InactiveButtonWidth = 108,
DistanceBetweenButtons = 14;
///
/// The amount of time idle at the menu before returning to the splash screen
///
const float TimeOutMenu = 60000.0f;
///
/// Start with button 0 being selected (play game)
///
int selectedButton = 0;
private int SelectedButton
{
get
{
return selectedButton;
}
set
{
selectedButton = value;
idleTime = 0.0f;
}
}
///
/// Current button sizes for scaling up/down smooth effect.
///
float[] currentButtonSizes =
new float[NumberOfButtons] { 1, 0, 0, 0, 0 };
///
/// Ignore the mouse unless it moves;
/// this is so the mouse does not disrupt game pads and keyboard
///
bool ignoreMouse = true;
float idleTime = 0.0f;
bool musicHasStarted = false;
public MainMenu()
{
}
///
/// Handle starting the menu music.
///
///
public void Update(GameTime gameTime)
{
// Start playing the menu music
if (!musicHasStarted)
{
Sound.Play(Sound.Sounds.MenuMusic);
musicHasStarted = true;
}
}
///
/// Interpolate rectangle
///
/// Rectangle 1
/// Rectangle 2
/// Interpolation
/// Rectangle
internal static Rectangle InterpolateRect(
Rectangle rect1, Rectangle rect2,
float interpolation)
{
return new Rectangle(
(int)Math.Round(
rect1.X * interpolation + rect2.X * (1 - interpolation)),
(int)Math.Round(
rect1.Y * interpolation + rect2.Y * (1 - interpolation)),
(int)Math.Round(
rect1.Width * interpolation + rect2.Width * (1 - interpolation)),
(int)Math.Round(
rect1.Height * interpolation + rect2.Height * (1 - interpolation)));
}
float pressedLeftMs = 0;
float pressedRightMs = 0;
///
/// Render
///
/// Bool
public bool Render()
{
// This starts both menu and in game post screen shader!
if(BaseGame.UsePostScreenShaders)
BaseGame.UI.PostScreenMenuShader.Start();
// Render background and black bar
BaseGame.UI.RenderMenuBackground();
BaseGame.UI.RenderBlackBar(280, 192);
// Show logos
// Little helper to keep track if mouse is actually over a button.
// Required because buttons are selected even when not hovering over
// them for GamePad support, but we still want the mouse only to
// be apply when we are actually over the button.
int mouseIsOverButton = -1;
// If the user manipulated the mouse, stop ignoring the mouse
// This allows the mouse to override the game pad or keyboard selection
if (Input.HasMouseMoved || Input.MouseLeftButtonJustPressed)
ignoreMouse = false;
// Show buttons
// Part 1: Calculate global variables for our buttons
Rectangle activeRect = BaseGame.CalcRectangleCenteredWithGivenHeight(
0, 0, ActiveButtonWidth, ButtonRects[0]);
Rectangle inactiveRect = BaseGame.CalcRectangleCenteredWithGivenHeight(
0, 0, InactiveButtonWidth, ButtonRects[0]);
int totalWidth = activeRect.Width +
(NumberOfButtons - 1) * inactiveRect.Width +
(NumberOfButtons - 1) * BaseGame.XToRes(DistanceBetweenButtons);
int xPos = BaseGame.XToRes(512) - totalWidth / 2;
int yPos = BaseGame.YToRes(316);
for (int num = 0; num < NumberOfButtons; num++)
{
// Is this button currently selected?
bool selected = num == SelectedButton;
// Increase size if selected, decrease otherwise
currentButtonSizes[num] +=
(selected ? 1 : -1) * BaseGame.MoveFactorPerSecond * 2;
if (currentButtonSizes[num] < 0)
currentButtonSizes[num] = 0;
if (currentButtonSizes[num] > 1)
currentButtonSizes[num] = 1;
// Use this size to build rect
Rectangle thisRect =
InterpolateRect(activeRect, inactiveRect, currentButtonSizes[num]);
Rectangle renderRect = new Rectangle(
xPos, yPos - (thisRect.Height - inactiveRect.Height) / 2,
thisRect.Width, thisRect.Height);
BaseGame.UI.Buttons.RenderOnScreen(renderRect, ButtonRects[num],
selected ? Color.White : new Color(192, 192, 192, 192));
// Add border effect if selected
if (selected)
BaseGame.UI.Buttons.RenderOnScreen(renderRect,
UIRenderer.MenuButtonSelectionGfxRect);
// Also add text below button
Rectangle textRenderRect = new Rectangle(
xPos, renderRect.Bottom + BaseGame.YToRes(5),
renderRect.Width,
renderRect.Height * TextRects[0].Height / ButtonRects[0].Height);
if (selected)
BaseGame.UI.Buttons.RenderOnScreen(textRenderRect, TextRects[num],
selected ? Color.White : new Color(192, 192, 192, 192));
// Also check if the user hovers with the mouse over this button
if (Input.MouseInBox(renderRect))
mouseIsOverButton = num;
xPos += thisRect.Width + BaseGame.XToRes(DistanceBetweenButtons);
}
if (!ignoreMouse && mouseIsOverButton >= 0)
SelectedButton = mouseIsOverButton;
// Handle input, we have 2 modes: Immediate response if one of the
// keys is pressed to move our selected menu entry and after a timeout we
// move even more. Controlling feels more natural this way.
if (Input.KeyboardLeftPressed ||
Input.GamePadLeftPressed)
pressedLeftMs += BaseGame.ElapsedTimeThisFrameInMilliseconds;
else
pressedLeftMs = 0;
if (Input.KeyboardRightPressed ||
Input.GamePadRightPressed)
pressedRightMs += BaseGame.ElapsedTimeThisFrameInMilliseconds;
else
pressedRightMs = 0;
// Handle GamePad input, and also allow keyboard input
if (Input.GamePadLeftJustPressed ||
Input.KeyboardLeftJustPressed ||
(pressedLeftMs > 250 &&
(Input.KeyboardLeftPressed ||
Input.GamePadLeftPressed)))
{
pressedLeftMs -= 250;
Sound.Play(Sound.Sounds.Highlight);
SelectedButton =
(SelectedButton + NumberOfButtons - 1) % NumberOfButtons;
ignoreMouse = true;
}
else if (Input.GamePadRightJustPressed ||
Input.KeyboardRightJustPressed ||
(pressedRightMs > 250 &&
(Input.KeyboardRightPressed ||
Input.GamePadRightPressed)))
{
pressedRightMs -= 250;
Sound.Play(Sound.Sounds.Highlight);
SelectedButton = (SelectedButton + 1) % NumberOfButtons;
ignoreMouse = true;
}
// If user presses the mouse button or the game pad A or Space,
// start the game screen for the currently selected game part.
if ((mouseIsOverButton >= 0 && Input.MouseLeftButtonJustPressed) ||
Input.GamePadAJustPressed ||
Input.KeyboardSpaceJustPressed)
{
idleTime = 0.0f;
// Start game screen
switch (SelectedButton)
{
case 0:
RacingGameManager.AddGameScreen(new CarSelection());
break;
case 1:
RacingGameManager.AddGameScreen(new Highscores());
break;
case 2:
RacingGameManager.AddGameScreen(new Options());
break;
case 3:
RacingGameManager.AddGameScreen(new Help());
break;
case 4:
// Exit
return true;
}
}
if (Input.KeyboardEscapeJustPressed ||
Input.GamePadBackJustPressed)
return true;
// If the game sits idle at the menu for too long,
// return to the splash screen
idleTime += BaseGame.ElapsedTimeThisFrameInMilliseconds;
if (idleTime > TimeOutMenu)
{
idleTime = 0.0f;
RacingGameManager.AddGameScreen(new SplashScreen());
}
return false;
}
}
}