Although its not often the first thing written, the first thing you see when
you start a game is the menu. In this chapter we will create a menu class for
our breakout game. It will be fairly simple, only having 2 options - new game
and quit.
Topics Covered in this Chapter:
Setting up a New Project
Creating The Menu
Getting the quit message
The Menu class is the first class in starting the actual programming of breakout.
In the Part 2 Chapter 2 code I have started a new project, and I have a new
layout for the classes. All of the classes we created in part one have been
place in a common folder outside the chapter folders. The files are included
with ../common/ . This way all of the DirectX classes we wrote in part one,
which will not be changing will not be duplicated for each of part 2's chapters.
The Menu:
The menu itself is fairly simple, and just consists of a background image,
and images of each menu item. There are two images for each menu item, one highlighted
to indicate the item is selected and one normal. The currently selected menu
item is kept track of as a number. When the up or down arrow is pressed the
selected menu item is adjusted accordingly. When the enter key is pressed the
menu message is set based on the item selected. Like previous examples the menu
has an update and render function that are called from the main game update
and render loop. At each update call the main game loop also checks the menu
for messages so it can take action accordingly.
Take a look at the BreakoutMenu class from the part 2, chapter 2 code. You
will notice in the header I make use of a function called ENUM. ENUM is used
to define constants, I have defined NEW_GAME, and EXIT. They will be used to
check and set the menu message which is just an integer. The code is a lot more
readable if the message is being set to NEW_GAME instead of 1. The constants
are accessible from outside the BreakoutMenu class and can be accessed as BreakoutMenu::NEW_GAME
etc.
The Deconstructor is worth noting, as we start writing the game we are going
to be creating many objects that use memory. If we don't explicitly free the
memory when we are finished with an object the memory remains allocated to our
program. If you don't unallocated memory you are not using anymore your program
will grow over time and will eventually fill all the system ram. So always remember
to free up any memory you are finished using.
The first main function in BreakoutMenu is init.
Init loads all of our images and sets the starting
menu state.
bool BreakoutMenu::init(InputManager* input, LPDIRECT3DDEVICE9 device){
myInput = input;
//0 is new game, 1 is exit;
menuItemSelected = 0;
message = 0;
//load menu Images
//load background menubackground.jpg
background = new Surface();
background->loadSurface(device, "menubackground.jpg");
//load new game image
newGame = new Surface();
newGame->loadSurface(device, "newgame.jpg");
newGame->setPosition(200,300);
newGameHighlighted = new Surface();
newGameHighlighted->loadSurface(device, "newgameh.jpg");
newGameHighlighted->setPosition(200,300);
//load exit image
exit = new Surface();
exit->loadSurface(device, "exit.jpg");
exit->setPosition(200,400);
exitHighlighted = new Surface();
exitHighlighted->loadSurface(device, "exith.jpg");
exitHighlighted->setPosition(200,400);
return true;
}
The update function is next, it gets the input
from the keyboad and sets the active menu item, and menu message.
void BreakoutMenu::update(){
myInput->getInput();
//get menu movement input
if (myInput->keyPress(DIK_UP) || myInput->keyPress(DIK_DOWN)){
if (menuItemSelected == 0){
menuItemSelected = 1;
} else {
menuItemSelected = 0;
}
}
//get menu pressed input
if (myInput->keyPress(DIK_RETURN)){
switch (menuItemSelected){
case 0: {message = NEW_GAME; break;}
case 1: {message = EXIT; break;}
}
}
}
Render, renders the background and menu items
base on which is selected.
void BreakoutMenu::render(LPDIRECT3DDEVICE9 device){
//render menu
//render background
background->render(device);
//render menu items based on which is highlighted
if (menuItemSelected == 0){
newGameHighlighted->render(device);
exit->render(device);
} else {
newGame->render(device);
exitHighlighted->render(device);
}
}
The last funciton getMessage returns the current
message.
int BreakoutMenu::getMessage(){
return message;
}
The BreakoutMenu needs to be added to the GameMain in order to use it. I have
removed all of the testing objects from the GameMain so we are starting with
a clean one.
Changes to GameMain init:
bool GameMain::init(HWND wndHandle, HINSTANCE hInst)
{
dxManager = new dxMgr(); //create our direct Manager
dxManager->init(wndHandle, 800, 600, true); //Initialize our DirectX Manager
if (!dxManager){
return false;
}
//Create a new InputManager
input = new InputManager();
input->init(hInst, wndHandle);
//create a new Menu
menu = new BreakoutMenu();
menu->init(input, dxManager->getD3DDevice());
active = MENU;
//create a new frame timer
timer = new FrameTimer();
timer->init(60);
return true;
}
Changes to GameMain update:
void GameMain::update(void)
{
int framesToUpdate;
//call our update function
framesToUpdate = timer->framesToUpdate();
//update the menu
if (active == MENU){
menu->update();
if (menu->getMessage() == BreakoutMenu::EXIT){
PostQuitMessage(0);
}
if (menu->getMessage() == BreakoutMenu::NEW_GAME){
active=GAME;
}
}
//game update calls go here
if (active == GAME){
}
// begin rendering
dxManager->beginRender(); //menu render calls go here
if (active == MENU){
menu->render(dxManager->getD3DDevice());
}
//game render calls go here
if (active == GAME){
}
//end render
dxManager->endRender();
}
I have added an active variable to the GameMain, to keep track of which objects
it should be rendering. In this case it is just the game or the menu. In the
case of a large number of items, adding an active state to the classes themselves
is a better idea.
Compile and run the project. You now have a simple menu.
Summing Up - Chapter 2
The menu is just a couple of images and states. Enumeration is used so the
menu states are readable in the code. The getMessage
needs to be called by the main loop to take action based on the menu selection.