Linking up our methods
So far, we know that we can define methods with code like this:
void draw(){ // Handle all the drawing here }
And we can call/execute methods with code like this:
draw();
We have also referred to, as well as mentioned in our comments, that the onCreate
method (provided automatically by Android) will handle the One-off Setup part of the flowchart.
The reason for this is that all Android games (and the vast majority of other Android apps) must have an Activity
class as the starting point. Activity
is what interacts with the operating system. Without one, the operating system cannot run our code. The way that the operating system interacts with and executes our code is through the methods of the Activity
class. There are many methods in the Activity
class, but the one we care about right now is the onCreate
method.
The onCreate
method is called by Android itself when the player taps our game's icon on their screen.
Important note
In fact, there are a number of methods that are called, but onCreate
is enough to complete the Sub' Hunter game. As we write more complicated games, we will learn about and use more methods that the operating system can call.
All we need to know, for now, is how to put the One-off Setup code in onCreate
, and we can be sure it will be executed before any of our other methods.
If you look at the flowchart, you will notice that we want to call newGame
from the end of onCreate
, and after that, we want to initially draw the screen, so we also call draw
. Add this highlighted code, as follows:
/* Android runs this code just before the app is seen by the player. This makes it a good place to add the code that is needed for the one-time setup. */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); Log.d("Debugging", "In onCreate"); newGame(); draw(); }
So that we can track the flow of the code and perhaps, if necessary, debug our game, the previous code not only calls the newGame
method followed by the draw
method, but it also contains the following line of code:
Log.d("Debugging", "In onCreate");
This code will print out a message in Android Studio to let us know that we are "Debugging
" and that we are "In onCreate
". Once we have connected the rest of the methods, we will view this output to see whether our methods work as we intended.
Now, let's print some text in the newGame
method, so we can see it being called as well. Add the following highlighted code:
/* This code will execute when a new game needs to be started. It will happen when the app is first started and after the player wins a game. */ public void newGame(){ Log.d("Debugging", "In newGame"); }
Following this, to implement the course of our flowchart, we need to call the takeShot
method from the onTouchEvent
method. Additionally, note that we are printing some text for tracking purposes here. Remember that the onTouchEvent
method is called by Android when the player touches the screen. Add the highlighted code to the onTouchEvent
method:
/* This part of the code will handle detecting that the player has tapped the screen */ @Override public boolean onTouchEvent(MotionEvent motionEvent) { Log.d("Debugging", "In onTouchEvent"); takeShot(); return true; }
Let's complete all the connections. Add a call to the draw
method along with some debugging text into the takeShot
method, as per the flowchart:
/* The code here will execute when the player taps the screen It will calculate the distance from the sub' and determine a hit or miss */ void takeShot(){ Log.d("Debugging", "In takeShot"); draw(); }
In the draw
method, we will just print to Android Studio to show that it is being called. Remember that on the flowchart, after we complete the drawing, we wait for touches. As the onTouchEvent
method handles this and receives a call directly from Android, there is no need to connect the draw
method to the onTouchEvent
method.
Important note
The connection between Android and the onTouchEvent
method is permanent and never broken. We will explore how this is possible when we discuss threads in Chapter 9, The Game Engine, Threads, and the Game Loop.
Add the following highlighted code to the draw
method:
/* Here we will do all the drawing. The grid lines, the HUD, the touch indicator and the "BOOM" when a sub' is hit */ void draw() { Log.d("Debugging", "In draw"); }
Note that we haven't added any code to the printDebuggingText
or boom
methods. Neither have we called these methods from any of the other methods. This is because we need to learn some more Java, and then do more coding before we can add any code to these methods.
When we run our game and the screen is clicked/tapped on, the onTouchEvent
method, which is analogous to the Wait for Input phase, will call the takeShot
method. This, in turn, will call the draw
method. Later in this project, the takeShot
method will make a decision to call either draw
or boom
depending upon whether the player taps on the grid square with the sub' in it or not.
We will also add a call to the printDebuggingText
method once we have some data to debug.
Start the emulator if it isn't already running by following these same steps from Chapter 1, Java, Android, and Game Development:
- In the Android Studio menu bar, select Tools | AVD Manager.
- Click on the green play icon for the emulator.
- Now you can click on the play icon in the Android Studio quick launch bar, and, when prompted, choose whatever your emulator is called and the game will launch on the emulator.
Now open the Logcat window by clicking on the Logcat tab at the bottom of the screen, as shown in the following screenshot.
In the Logcat window, when we start the game, lots of text has been output to Logcat. The following screenshot shows a snapshot of the entire Logcat window to make sure you know exactly where to look:
The following screenshot zooms in on the three relevant lines, so you can clearly see the output even in a black and white printed book:
Moving forward, I will only show the most relevant part of the Logcat output, as text in a different font, like this:
Debugging: In onCreate Debugging: In newGame Debugging: In draw
Hopefully, the font and the context of the discussion will make it clear when we are discussing the Logcat output and when we are discussing Java code.
Here is what we can gather from all of this:
- When the game was started, the
onCreate
method was called (by Android). - This was followed by the
newGame
method, which was executed and then returned to theonCreate
method. - This then executed the next line of code and called the
draw
method.
The game is now currently at the Wait for Input phase, just as it should be according to our flowchart:
Now, go ahead and click on the screen of the emulator. We should see that the onTouchEvent
, takeShot
, and draw
methods are called, in that order. The Logcat output might not be exactly what you expect, however. Here is the Logcat output I received after clicking on the screen of the emulator just once:
Debugging: In onTouchEvent Debugging: In takeShot Debugging: In draw Debugging: In onTouchEvent Debugging: In takeShot Debugging: In draw
As you can see from the output, exactly the correct methods were called. However, they were called twice.
What is happening is that the onTouchEvent
method is very versatile, and it is detecting a touch when you click on the mouse button (or tap a finger), and it is also called when the mouse button (or a finger) is released. To simulate a tap, we only want to respond to releases (that is, a finger up).
To code this functionality, we need to learn some more Java. Specifically, we need to learn how to read and compare variables, then make decisions based on the result.
Variables are our game's data. We will cover everything we need to know about variables in the next chapter, and we will make decisions based on the value of those variables in Chapter 7, Making Decisions with Java If, Else, and Switch, when we put the finishing touches (pun intended) on the Sub' Hunter game.