To get started with this conversation, add the OnTouchEvent
method to the LiveDrawingView
class:
@Override public boolean onTouchEvent(MotionEvent motionEvent) { return true; }
This is an overridden method and it is called by Android every time the user interacts with the screen. Look at the one and only parameter of onTouchEvent
.
It turns out that motionEvent
has a whole bunch of data tucked away inside of it, and this data contains the details of the touch that just occurred. The operating system sent it to us because it knows we will probably need some of it.
Notice that I said some of it. The MotionEvent
class is quite extensive. It contains within it dozens of methods and variables.
Over the course of this book, we will uncover quite a lot of them, but nowhere near all of them. You can explore the MotionEvent
class here:
https://stuff.mit.edu/afs/sipb/project/android/docs/reference/android/vie w/MotionEvent.html.
Note that it is not necessary to do further research to complete this book.
For now, all we need to know is the screen coordinates at the precise moment when the player's finger was moved, touched the screen, or removed.
Some of the variables and methods contained within motionEvent
that we will use include the following:
getAction
method, which, unsurprisingly, "gets" the action that was performed. Unfortunately, it supplies this information in a slightly encoded format, which explains the need for some of these other variables.ACTION_MASK
variable, which provides a value known as a mask, which, with the help of a little bit more Java trickery, can be used to filter the data from getAction
.ACTION_UP
variable, which we can use to compare to see whether the action performed is the one (removing a finger) we want to respond to.ACTION_DOWN
variable, which we can use to compare to see whether the action performed is the one we want to respond to.ACTION_MOVE
variable, which we can use to compare to see whether the action performed is a move/drag.getX
method notifies us of a horizontal floating point coordinate where the event happened.getY
method notifies us of a vertical floating-point coordinate where the event happened.As a specific example, say we need to filter the data returned by getAction
using ACTION_MASK
and see whether the result is the same as ACTION_UP
. If it is, then we know that the user has just removed their finger from the screen; perhaps because they just tapped a button. Once we are sure that the event is of the correct type, we will need to find out where it happened using getX
and getY
.
There is one final complication. The Java trickery I referred to is the &
bitwise operator, which is not to be confused with the logical &&
operator we have been using in conjunction with the if
keyword.
The &
bitwise operator checks to see whether each corresponding part in two values is true. This is the filter that is required when using ACTION_MASK
with getAction
.
Sanity check. I was hesitant to go into detail about MotionEvent
and bitwise operators. It is possible to complete this entire book and even a professional quality interactive app without ever needing to fully understand them. If you know that the line of code we write in the next section determines the event type the player has just triggered, that is all you need to know. I just guessed that a discerning reader such as yourself would like to know the ins and outs. In summary, if you understand bitwise operators, great, you are good to go. If you don't, it doesn't matter; you are still good to go. If you are curious about bitwise operators (there are quite a few), you can read more about them here: https://en.wikipedia.org/wiki/Bitwise_operation.
Now, we can code the onTouchEvent
method and see all the MotionEvent
stuff in action.
You can handle the user moving their finger on the screen by adding the following highlighted code inside the onTouchEvent
method to the code we already have:
// User moved a finger while touching screen if ((motionEvent.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_MOVE) { mParticleSystems.get(mNextSystem).emitParticles( new PointF(motionEvent.getX(), motionEvent.getY())); mNextSystem++; if (mNextSystem == MAX_SYSTEMS) { mNextSystem = 0; } } return true;
The if
condition checks to see whether the type of event was the user moving their finger. If it was, then the next particle system in mParticleSystems
has its emitParticles
method called. Afterward, the mNextSystem
variable is incremented and a test is performed to see whether it was the last particle system. If it was, then mNextSystem
is set to zero ready to start reusing existing particle systems the next time one is required.
You can handle the user pressing one of the buttons by adding the following highlighted code right after the previous code we have just discussed, and before the return
statement we have already coded:
// Did the user touch the screen if ((motionEvent.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) { // User pressed the screen see if it was in a button if (mResetButton.contains(motionEvent.getX(), motionEvent.getY())) { // Clear the screen of all particles mNextSystem = 0; } // User pressed the screen see if it was in a button if (mTogglePauseButton.contains(motionEvent.getX(), motionEvent.getY())) { mPaused = !mPaused; } } return true;
The condition of the if
statement checks to see whether the user has tapped the screen. If they have, then the contains
method of the RectF
class is used in conjunction with getX
and getY
to see whether that press was inside one of our custom buttons. If the reset button was pressed, all the particles will disappear when mNextSystem
is set to zero. If the paused button is pressed, then the value of mPaused
is toggled, causing the update
method to stop/start being called in the thread.
Add the following highlighted code to the printDebuggingText
method:
// We will add more code here in the next chapter mCanvas.drawText("Systems: " + mNextSystem, 10, mFontMargin + debugStart + debugSize * 2, mPaint); mCanvas.drawText("Particles: " + mNextSystem * mParticlesPerSystem, 10, mFontMargin + debugStart + debugSize * 3, mPaint);
This code will just print some interesting statistics to the screen to tell us how many particles and systems are currently being drawn.
18.216.124.145