"High Stakes" is a game of Seven-Card Stud Poker that will be a fun and interactive experience for players.

What will make this stand out from all the other Poker videogames out there is the emphasis on a physical interaction as well as competition against smart, reactive opponents. The plan is to use both Nintendo's Wiimote and NaturaPoint's TrackIR head tracker for control to play against responsive, motion captured avatars for a truly immersive poker playing experience.

Friday, October 26, 2007

GUI Design

I used Crazy Eddie's GUI (http://www.cegui.org.uk/wiki/index.php/Main_Page) to build the GUI ad Menu systems. CEGUI is a very nice system using a combination of XML based files and its C++ library. The great thing using the XML is that you can make code independent changes to a lot of the aesthetic components of the GUI and test without having to recompile the program. For the XML part , I had to write the following types of XML files:

IMAGESET files: Used to load images from an image file(tga, jpeg, etc) into the system, based on their leftmost and topmost positions, in pixels, on the screen. Their width and height in pixels must also be specified as well as if they could be scaled or not. For each imageset file, you may load any piece of an image file in, so it is advantageous to have many images in one image file if possible.

LOOKNFEEL files: Used to define skins/frames/text colors for windows or buttons

SCHEME files: A simple and less time consuming way to tell the system which imagsets, looknfeel types and fonts you will be using.

LAYOUT files: Indicates the layout of a particular GUI sheet. Here, you name and specify window types (button, static image) to be on a particular sheet. Each window may have nested windows inside of them.

However, the while the XML files can be changed independently from the code, C++ code must be written to load them into the system initially and give them advanced features.

There are 4 main GUI component types in High Stakes Poker: menu screens, images, buttons, information containers and invisible “look areas” :

Images: just a static image which can be a background or a nested image like the how to play menu images.

Buttons: an interactive window, that changes the image on mouse/TrackIR hovering over the area and trigger calls to change menu screens or other game functions when pressed. The buttons in High Stakes Poker are flippable cards, to fit the theme.

Information containers: hold real time information to be echoed to the user in game such as betting/turn information or images of your opponents visible cards.

Look areas/hot spots: these areas, invisible to the user, can indicate whether they are looking at a particular area of the screen that may show an information container,or cause an event to be triggered. For example, if you are looking at the area around the opponent avatar Alex's face, a call can be sent to trigger a timer that will cause him to say something if you've been looking in that area too long. Or, looking at the users chips will pop up the info container that shows the user's chip value.

For each of these GUI component types, in the layout files I had to specify their placement. I also had to choose whether this positioning would be relative (screen percentages) or absolute(exact pixel placement) Knowing that our game runs in different resolutions and after fixing a pixel placement problem with our debug overlay being cut off, I decided to use relative placement if only for the reason so that components wouldn't get cut off the screen when resolution is decreased.

The percentages where determined by taking a screen shot of our game at a certain resolution, i.e. 1650x1080, drawing boxes around the area of the screen where I wanted the component to be seen, and finding the left, right, bottom and topmost pixel boundaries. Then I was able to calculate percentages based on those values. In example, if the top of a component was 650 pixels from the top of a 1650 x 1080 screen shot, I would get it's starting y position percentage by calculating 650/1080 = .6019 and putting that into the appropriate part of its layout file.

On the C++ side of things, I used CEGUI's window management library functions to load the scheme into the system and layout files into variables so that I could manipulate when to show them them. I also made variables for each one of the buttons and look areas so that I could subscribe event handler functions for them to call other functions.

For example, for the player chips looking area :
Declaration:
CEGUI::Window* playerChipsArea; //Hotspot window for player's chips area
Initialization:
playerChipsArea = (CEGUI::Window*)wmgr.getWindow("InGame/PchipsArea"); //get the window specified in the layout file by the name “InGame/PchipsArea”
Subscribing an event handler:
playerChipsArea->subscribeEvent(CEGUI::Window::EventMouseEnters, CEGUI::Event::Subscriber(&HSPokerApp::HandleEyeOnPlayerChipsArea, this)); //triggers HandleEyeOnPlayerChipsArea() funtion when mouse cursor enters window area

HandleEyeOnChipsArea() after being declared could now be given code to do whatever it needed to do whenever the cursor is in that area by myself or my teammates. For the buttons, handler functions were created to switch GUI sheets, or call functions to quit or restart.

Variables for each info container had to be created as well so that the information contained could be dynamically change in updateStats(), which updated in game variables as they changed. Most of the info containers were just text, so I just had to update each one with CEGUI's setText call. The cards info container, which needed to echo the opponents visible cards as images when the user was looking at the area was a little more sophisticated. Luckily for me, a very good naming system for each card in the computer's hand had been implemented by my awesome teammates, so that made things easier. Inside the imageset file that loaded a ,tga containing images of all 52 cards, I just named each card by the same name as it would have in the opponent's hand array:

Then, in our HSPSceneManager class I was able set the visible cards names to variables while it updated like so:
oppCardSize = (int)m_vPlayer2Cards.size();
if(oppCardSize <= 2){ visCard3 = "empty"; visCard4 = "empty"; visCard5 = "empty"; visCard6 = "empty"; } else if(oppCardSize <= 3){ visCard3 = m_vPlayer2Cards[2]->getNode()->getName();
visCard4 = "empty";
visCard5 = "empty";
visCard6 = "empty";
} else if(oppCardSize <= 4){ visCard4 = m_vPlayer2Cards[3]->getNode()->getName();
visCard5 = "empty"; visCard6 = "empty";
} else if(oppCardSize <= 5){ visCard5 = m_vPlayer2Cards[4]->getNode()->getName();
visCard6 = "empty";
} else if(oppCardSize <= 6){ visCard6 = m_vPlayer2Cards[5]->getNode()->getName();
}

Then I could use those variable names to grab the correct image at the correct time in update() using:
//update visible cards
if(m_pHSPManager->visCard3 != "empty")
VisCard3->setProperty("Image", "set:AllCards image:" + m_pHSPManager->visCard3); //if not empty, show appropriate card
else VisCard3->setProperty("Image", "set:Transparent image:EmptyWin"); //if empty, show a transparent window

if(m_pHSPManager->visCard4 != "empty")
VisCard4->setProperty("Image", "set:AllCards image:" + m_pHSPManager->visCard4);
else
VisCard4->setProperty("Image", "set:Transparent image:EmptyWin");

if(m_pHSPManager->visCard5 != "empty")
VisCard5->setProperty("Image", "set:AllCards image:" + m_pHSPManager->visCard5);
else
VisCard5->setProperty("Image", "set:Transparent image:EmptyWin");

if(m_pHSPManager->visCard6 != "empty")
VisCard6->setProperty("Image", "set:AllCards image:" + m_pHSPManager->visCard6);
else
VisCard6->setProperty("Image", "set:Transparent image:EmptyWin");
}
This way, only visible cards on the table will pop up when looked at.

For the menu system, what was shown on screen is triggered by show functions which essentially just show a GUI sheet defined by the loaded layout file. Since I am not an artist by trade, I tried to make use of as many pre-made graphics as I could, but I also had to do much image editing in the free image editing program, GIMP. The info containers are made from GIMP's button generator, the background for the main menu, how to play and credits menu are from the table texture that James had already made with a clothify bump mapped effect on it. The images for the controls page are from the storyboard images that he had created for our original presentation with a neon effect put on them. I also used GIMP to put together some image files with multiple images in them for imagesets.

I had to make sure that each menu shown on screen was the correct one, especially in the case of the How To Play and quit confirmation menus, which could be accessed from both the main and pause menus and had a back button. For instance, on the How To Play controls screen, the back button had to know if it was going back to the main or pause menu, so I simply set a boolean gameInProgress set to false until he play button on he main menu was pressed, making the main menu no longer the primary menu since it is only supposed to show before the game play is started. Then it was a simple task:
bool HSPokerApp::HandleHTPControlsBackButton(const CEGUI::EventArgs& e){
//If previous screen was the pause menu, go back to that. Otherwise, go back to main menu
if(gameInProgress)
showPauseMenu();
else showMainMenu();
return true;
}

No comments: