Chapter     4

The Menu Screen

You might have already built a game, or are in the process of building one, but still need a proper menu screen from which to launch it. Fear not. If you are having problems creating a working menu screen for your game, this chapter should be able to help you out.

In this chapter, you will find solutions for creating a two-button menu screen, wiring the buttons on said menu screen to start and exit the game, and many more problems that could arise while you create a menu.

The first solution will give you a proper, two-button menu screen for your game.

4.1 Create a Two-Button Menu Screen

Problem

Your game needs a menu screen for presenting options to the player.

Solution

Create a menu using an Android layout that has two buttons: one to start the game, and one to exit the game.

How It Works

While you don’t have to use the full example, this solution works well with the splash screen created as a solution to the Chapter 3 problems. If you do want to use the solutions together, replace the creditscreen.xmlfrom Chapter 3 (this is the layout that is faded into from the first splash screen) with the main_menu.xml that will be created in this solution.

The first step is to add some images to your project. The first image, shown in Figure 4-1, is the background for the menu screen. In this case, we are going to use the same image we used for the game splash screen, but feel free to use whatever image you want.

9781430257646_Fig04-01.jpg

Figure 4-1. The menu screen background

Now you need two more images, one for each button. For this solution you are creating one button that will launch the game, and one button that will exit the game. Figures 4-2 and 4-3 represent the start button image and the exit button image, respectively.

9781430257646_Fig04-02.jpg

Figure 4-2. The start button image

9781430257646_Fig04-03.jpg

Figure 4-3. The exit button image

Note   The images that I used in the finished solution consist of white text on a transparent background. However, for these images to be displayed properly in this book, the backgrounds were filled with grey.

Create a new xml layout named main_menu.xml. This layout will hold the new background image (in an ImageView) and the two buttons, using ImageButton nodes, as shown in Listing 4-1.

Listing 4-1.  main_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SBGMenuScreen" >

<ImageView
android:id="@+id/imageView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:contentDescription="@string/splash_screen_description"
android:scaleType="fitXY"
android:src="@drawable/titlescreen" />

<RelativeLayout
android:id="@+id/buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:orientation="horizontal" >
</RelativeLayout>

<ImageButton
android:id="@+id/btnExit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/buttons"
android:layout_alignParentRight="true"
android:layout_marginBottom="50dp"
android:layout_marginRight="55dp"
android:clickable="true"
android:contentDescription="@string/start_description"
android:src="@drawable/exit" />

<ImageButton
android:id="@+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignTop="@+id/btnExit"
android:layout_marginLeft="48dp"
android:clickable="true"
android:contentDescription="@string/exit_description"
android:src="@drawable/start" />

</RelativeLayout>

Now that you have a layout for your menu, you need an Activity to display it. Create a new Activity in your game project; in this example, it will be named SBGMenuScreen. The SBGMenuScreen Activity should use setContentView()to display the new main_menu layout (see Listing 4-2).

Listing 4-2.  SBGMenuScreen Layout

public class SBGMenuScreen extends Activity{

@Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main_menu);
   }}

You now have a main menu that is displayed by an Activity, but where does it fit in with your game project?

You have two choices here. The first choice is to set SBGMenuScreen as the entry point for your game. The second is to use a splash screen to fade into the menu.

If you go with the first option, and set SBGMenuScreen as the main entry point for your game, then this will be the first screen seen by your player. In many cases, this could be a very valid solution and the example stops here for you. However, if you followed the solution in Chapter 3, and want to continue to use a splash screen, the rest of this solution will explain how to fit the menu in your splash screen.

Open the MainActivity from Chapter 3. This is where the splash screen is launched from. Change the references that have been bolded in Listing 4-3 to point to the new SBGMenuScreenActivity that you created.

Listing 4-3.  Launching the Menu

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int GAME_THREAD_DELAY = 4000;
setContentView(R.layout.activity_main);
new Handler().postDelayed(new Thread() {
@Override
public void run() {
Intent mainMenu = new Intent(MainActivity.this, SBGMenuScreen.class);
MainActivity.this.startActivity(mainMenu);
   MainActivity.this.finish();
overridePendingTransition(R.layout.fadein,R.layout.fadeout);
}
}, GAME_THREAD_DELAY);
}

}

No matter how you finished off your solution, the finished menu screen should appear as in Figure 4-4.

9781430257646_Fig04-04.jpg

Figure 4-4. The menu screen

4.2 Wire Menu Buttons

Problem

The buttons do not respond when clicked.

Solution

Use OnClickListener() to react to button clicks.

How It Works

You have a menu for your game, like that in Solution 4.1. However, your buttons do not react when the player touches them. The solution for this is easier than you might think. All you have to do to fix this is create a couple of OnClickListener()s that will be used to listen for, and respond to, user interaction with your buttons.

This solution uses the Activity that is displaying your menu. If you created a menu using the solution in Recipe 4.1, then the file you need to open is the SBGMenuScreen. Listing 4-4 provides the current code for the menu Activity.

Listing 4-4.  SBGMenuScreen

public class SBGMenuScreen extends Activity{

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_menu);
}

The main_menu layout that is referred to in the SBGMenuScreen contains the following code. I am giving you the code to the main_menu layout because the solution is going to need to call elements from the layout. Therefore, you will have a reference to work from, just in case your menu layout does not match exactly.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SBGMenuScreen" >

<ImageView
android:id="@+id/imageView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:contentDescription="@string/splash_screen_description"
android:scaleType="fitXY"
android:src="@drawable/titlescreen" />

<RelativeLayout
android:id="@+id/buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:orientation="horizontal" >
</RelativeLayout>

<ImageButton
android:id="@+id/btnExit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/buttons"
android:layout_alignParentRight="true"
android:layout_marginBottom="50dp"
android:layout_marginRight="55dp"
android:clickable="true"
android:contentDescription="@string/start_description"
android:src="@drawable/exit" />

<ImageButton
android:id="@+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignTop="@+id/btnExit"
android:layout_marginLeft="48dp"
android:clickable="true"
android:contentDescription="@string/exit_description"
android:src="@drawable/start" />

</RelativeLayout>

The first step in the solution is to create a pair of ImageButtonvariables and set them to the image buttons used in your menu layout. The method that you will use to set your variables to your image buttons is findViewById().

Tip   Because findViewById() does not inherently know the type of the view you are finding, be sure to case the result as the proper type before assigning it.

Listing 4-5.  findViewByIf

public class SBGMenuScreen extends Activity{

@Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main_menu);
ImageButton start = (ImageButton)findViewById(R.id.btnStart);
        ImageButton exit = (ImageButton)findViewById(R.id.btnExit);

   }
}

All views have the method setOnClickListener(). You will use this method to assign a new OnClickListener() to the specific button.That is all you need to complete the solution.

Listing 4-6.  setOnClickListener

public class SBGMenuScreen extends Activity{

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_menu);

ImageButton start = (ImageButton)findViewById(R.id.btnStart);
ImageButton exit = (ImageButton)findViewById(R.id.btnExit);

start.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {

//TODO all of your startup code

}

});

exit.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {

//TODO all of your exit code

}
});

   }
}

Each OnClickListener() has an OnClick() method. The code within the OnClick() method will be executed each time the OnClickListener() for that button is tripped. Replace

the TODO comments with the code that you wish to execute when the player presses the start or exit buttons, respectively.

4.3 Launch a Game Thread

Problem

The game thread needs to start when the player presses the Start Game button on the menu.

Solution

Launch the game Activity from within the OnClick() method of the start button.

How It Works

This is a relatively simple solution that will have you adding a couple of lines of code to your OnClick() method for the start button. If you already have an Activity that is used to start your game, use that here. If you do not yet have an Activity for your game, create a basic Activity, as shown in Listing 4-7.

Listing 4-7.  A Basic Activity

public class SBGGameMain extends Activity {

private SBGGameView gameView;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//The content view here represents the GLSurfaceView
//for your game
gameView = new SBGGameView(this);
setContentView(gameView);
}
@Override
protected void onResume() {
super.onResume();
gameView.onResume();
}

@Override
protected void onPause() {
super.onPause();
gameView.onPause();
}

}

Again, if you already have an Activity created for your game, use that in place of this in your solution.

The only step you need to take to launch your game is to modify the OnClick() method of the OnClickListener() attached to your start button. Simply create a new Intent for the game Activty and start it from inside the OnClick(), as shown in Listing 4-8.

Listing 4-8.  Launching an Activity from onClick()

start.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
//Start the game
Intent game = new Intent(getApplicationContext(),SBGGameMain.class);
SBGMenuScreen.this.startActivity(game);

}

});

Now when the player presses the start button, your menu will launch cleanly into the game.

4.4 Exit a Game Thread Cleanly

Problem

The game needs to clean up any threads and running processes when it is exited.

Solution

Create a method that closes open items before the game is exited. Then, kill the game thread.

How It Works

This is a two-part solution that involves creating a single method that can be called to complete any housekeeping before the game exits, and then kills the game thread.

Before your player closes your game, you might want to take care of tasks such as saving player data, updating statistics to a central server, or even killing any background music that is playing. To do this, you will need to create a method somewhere in your game that can be called from the main menu.

In Listing 4-9, I have created a method called onExit(). Within onExit(), I am killing some background music that is playing in my game. Again, you add whatever code you need to perform your housekeeping to onExit(). The important part of the method is that is returns a Boolean. A result of true means that everything has been taken care of and the game is good to exit, while a result of false will need to be handled further before the game can exit.

Listing 4-9.  onExit()

public boolean onExit(View v) {
try
{
//Sample code to stop some background music
Intent bgmusic = new Intent(context, SFMusic.class);
context.stopService(bgmusic);
musicThread.stop();

return true;
}catch(Exception e){
return false;

}

}

Tip   The onExit() method can be anywhere in your project as long as it has visibility to everything that you want do within it.

Now, modify your OnClick() method for you exit button’s OnClickListener() to call onExit() (see Listing 4-10).

Listing 4-10.  Calling onExit()

exit.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
boolean clean = false;
clean = onExit(v);
if (clean)
{
}
}
});

Finally, assuming that your onExit() returned a true result, kill the current process and exit (see Listing 4-11).

Listing 4-11.  Killing the Game Process

exit.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
boolean clean = false;
clean = engine.onExit(v);
if (clean)
{
int pid= android.os.Process.myPid();
android.os.Process.killProcess(pid);
}
}
});

4.5 Swap Menu Button Images

Problem

Menu buttons should change color or image when clicked.

Solution

Point the source of the button’s image to an xml selector that controls the swapping on images.

How It Works

You might want your game’s menu to have an added punch to it by changing the menu’s button images when the player selects them. You can easily achieve this by creating an xml selector that holds pointers to the images you want, and the states under which to display them. Then, in your layout file, replace the source pointer to the button’s original image file with that of your xml selector.

For this solution, you will be swapping between the images in Figures 4-2 and 4-3 with those in Figures 4-5 and 4-6 when the player selects the appropriate button.

9781430257646_Fig04-05.jpg

Figure 4-5. The new start button image

9781430257646_Fig04-06.jpg

Figure 4-6. The new exit button image

The original button images are referred to as @drawable/start and @drawable/exit, respectively. The new files, once added to the drawable folder, will be @drawable/newstart and @drawable/newexit. You can accomplish this in three steps.

The first step is to create a new xml file named startselector.xml and be sure to place it in the drawable folder with the images. This is not the usual place for xml files. Normally, you would think of putting an xml file into the layout

folder. However, because this file is going to be substituted for an image source, it needs to be placed in the drawable folder.

Open the startselector.xmlfile and create the xml selector shown in Listing 4-12.

Listing 4-12.  startselector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/start" />
<item android:state_pressed="true" android:drawable="@drawable/newstart"  />
</selector>

The two items in the selector indicate the different states for which you want to swap out the image. The first item is the default state. This is the image that will be displayed under idle conditions. The second item is only displayed when the state_pressed is true. Therefore, when the button is pressed, the selector will send it the newstart image to be displayed.

Create a second selector xml file named exitselector.xml, as shown in Listing 4-13. The file should be formatted the same as the startselector.xml file, though it will be used to change the exit button images.

Listing 4-13.  exitselector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/exit" />
<item android:state_pressed="true" android:drawable="@drawable/newexit"  />
</selector>

The last step to this solution is to change the layout file for your menu. Change the image source for each button to point to the appropriate selector rather than the image file (see Listing 4-14).

Listing 4-14.  main_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SBGMenuScreen" >

<ImageView
android:id="@+id/imageView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:contentDescription="@string/splash_screen_description"
android:scaleType="fitXY"
android:src="@drawable/titlescreen" />

<RelativeLayout
android:id="@+id/buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:orientation="horizontal" >
</RelativeLayout>

<ImageButton
android:id="@+id/btnExit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/buttons"
android:layout_alignParentRight="true"
android:layout_marginBottom="50dp"
android:layout_marginRight="55dp"
android:clickable="true"
android:contentDescription="@string/start_description"
android:src="@drawable/exitselector" />

<ImageButton
android:id="@+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignTop="@+id/btnExit"
android:layout_marginLeft="48dp"
android:clickable="true"
android:contentDescription="@string/exit_description"
android:src="@drawable/startselector" />

</RelativeLayout>

4.6 Lock the Screen Orientation

Problem

The menu screen should not change orientation when the device is moved between landscape and portrait mode.

Solution

Lock the screen orientation so that it cannot change.

How It Works

This is a rather easy solution to a common problem. The quickest way to achieve this is to manually edit the project’s AndroidManifest.xml file. The manifest file contains the project’s main settings for its activities. It is a good idea to lock all of the screens for your game on specific orientation.

Locate the activity tag for your main menu’s Activity and lock it to landscape mode, as shown here:

<activity android:name="SBGMenuScreen" android:screenOrientation="landscape"></activity>
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.65.61