Would you care to see the menu?

I can still see two problems with the game. One obvious, one not so much. They both come from the same place though: What happens when you open the game up? It depends what else you have been up to. You might get a new game if it’s been a little while and the process manager has decided to evict the game process in favour of something more important, or you might get the results of the last game played. Depending on circumstances, we might want either of these situations but whichever one we want, we definitely don’t want to leave it to chance.

Today we are going to deal with getting to a new game. If the app hasn’t been run, or if it’s been terminated since the last game we have no problem because the user will be dropped into a brand new game, ready to go. If the the process was still runnning since the last game then we could just hold down the back button and rewind the game to the start but that’s really untidy. What we are going to do is grab the Menu button and make it work for us.

I want the menu button to bring up the standard Android menu with a “New Game” option. When I press that, I want a sub-menu that shows me my new game layout options. It has been pointed out that completely random starting positions could end up being wildly unfair so I want to be able to choose between fully random and random-but-reflected. The first thing we are going to need to do is add a function to clear the board to the Board view.

//Board.java
public void clearBoard() { 
	//create a new board state and pass it to the MoveHandler so they 
	//are both working on the same game state 
	mPieces = new int[8][8];
	if (mMoveHandler != null) mMoveHandler.setBoard(mPieces);
	invalidate();
}

Easy. We can already populate the board, and now we can clear the board we can fill it up in all manner of creative ways as soon as we have the menu available. We can either build the menu programatically, or we can use XML and a menu inflater. We’ll start with setting up the menu programatically before re-doing it in XML. The first task is to override the Activity function that gets called when the menu button is pressed.

//RPSChess.java
//game type flags. We'll use these as menu IDs so we can tell which option 
//the user clicked on and handle it. 
static final int RANDOM_GAME = 1;
static final int REFLECTED_GAME = 2;

//This is called the first time the menu button is pressed
@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
	//create a menu option that will open a submenu when clicked
	//parameters are "group", "menu id", "sort order", and "title" 
	//because this is only for opening other menus we only need the title.
	SubMenu sMenu = menu.addSubMenu(Menu.NONE,Menu.NONE,Menu.NONE, "New Game");
	
	//To that menu we add two items. These take the same parameters as addSubmenu
	//note the use of the game type flags as the second parameter.
	sMenu.add(Menu.NONE, RANDOM_GAME, Menu.NONE, "Random Layout");
	sMenu.add(Menu.NONE, REFLECTED_GAME, Menu.NONE, "Reflected Layout");
	
	//This line is not required and gets explained below. Be ready to delete it.
	Toast.makeText(getApplicationContext(), "Menu", Toast.LENGTH_SHORT).show();
	//We've handled the menu button press so return "true"
	return true; 
}

See something that doesn’t belong? Yep, the Toast is not helping us make a menu, but it shows something important. This function is only called the first time the menu button is pressed. If we want to change the menu at runtime we will also need to override the onPrepareOptionsMenu() which is called every time the menu button is pressed.

We have a menu which shows a submenu when you click on it, but nothing important happens. Now we have to override the Activity function that is called when we click a menu.

//RPSChess.java
//Called when the user clicks on a menu option
@Override
public boolean onOptionsItemSelected(MenuItem item) {
	
	//the MenuItem passed into this method will have the Item id we set using SubMenu.add()
	//further up. Use that to work out what the user clicked on.
	switch (item.getItemId()) {
	case RANDOM_GAME:
		//Set up a random game 
		b.clearBoard();
		randomSetup();
		//Menu item handled so return true
		return true;
	case REFLECTED_GAME:
		//Set up a reflected game
		b.clearBoard();
		reflectedSetup();
		//menu item handled so return true
		return true;
	} 
	//we should never get here, but if we do then a menu
	//option was used and we didn't know what to do with it
	//return false and let it be passed to anything else that
	//might be interested.
	return false;
}

The game type flags we used as ids in our menu setup turn up again as the item id of the menu object passed to onOptionsItemSelected() from where we can do whatever activity our menu is supposed to achieve. Pull out the useless Toast call and we could be done, but I’m going to yank all that code and rebuild using XML to create the menu.

If you need to, create a “menu” folder in the res folder in our project. In there create a new file called menu.xml containing the following XML.

    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/item1" android:title="New Game">
            <menu>
                <item android:id="@+id/random_game" android:title="Random Game"/>
                <item android:id="@+id/reflected_game" android:title="Reflected Setup"/>
            </menu>
        </item>
    </menu>

This layout will give us the same menu structure as we built previously and create resource ids to replace the game type flags, but we need to turn that into a menu with a MenuInflater. Scrap the game type flags and onCreateOptionsMenu code we set up above and replace it with the following.

>//RPSChess.java
//This is called the first time the menu button is pressed
@Override
public boolean onCreateOptionsMenu(Menu menu) {
	//Get a menu inflater from the activity object
	MenuInflater inflater = getMenuInflater();
	//inflate the menu.xml defined above
	inflater.inflate(R.menu.menu, menu);

	return true; 
} 

The MenuInflater will covert our XML above into a menu just like we used to have. The only diffence with our menu event handler is that the menu id will change.

//RPSChess.java
//Called when the user clicks on a menu option
@Override
public boolean onOptionsItemSelected(MenuItem item) {
	//MenuItem will have the ID picked up from the XML.
	//The XML also creates ID entries in the R object so use them
	//to work out which option the user pressed.
	switch (item.getItemId()) {
	case R.id.random_game:
		b.clearBoard();
		randomSetup();
		return true;
	case R.id.reflected_game:
		b.clearBoard();
		reflectedSetup();
		return true;
	}
	return false; 
}

As you can see, this bit is exactly the same as before except the case statement uses R.id items instead of integers. I’m leaving the reflectedSetup() function as an exercise to the reader. Every time we challenge a new person now we are two clicks away from a fresh game.

Submenu screen

Submenu screen

This entry was posted in android and tagged . Bookmark the permalink.

5 Responses to Would you care to see the menu?

  1. kumar says:

    Hi chris,
    I need your help to understand the code such that I need comments for each and every line so that how they link together and exact flow of the code, because I am new to the android . some times I am unable to understand the code properly and struck off. So ,kindly help me out to understand each and every line of the game code with comments.

    Thanks,
    Kumar.

    • Chris says:

      Hi Kumar,

      I’ve put a lot more comments into the code now. Take a look and let me know what you think. If you still have problems then let me know and I’ll see if I can make it clearer.

  2. NSD says:

    Hi chris,
    please update this tutorial.

  3. santhosh says:

    Hi Chris,

    I’ve a problem with back button. I want to change the functionality of the
    defalut back according to my requirement can you please tell me how to do that it would be a great help for me .

    • Chris says:

      Hi Santosh,

      You can see how I overrode the back button functionality in the Coming Undone post. You should be able to re-purpose that post to do whatever you need.

      Let me know how you get on.

Comments are closed.