Tip:
Highlight text to annotate it
X
Hello.
My name is Bruno Oliveira, and I work in the Play Games team.
Today, we're here to talk about two of my favorite
things, which are the Play Games API and the NDK, and how
to use those two to make a game.
So when you're writing a game using the Play Games API, you
normally have to worry about connecting all of these
callbacks that the Android life cycle gives you.
So we have onCreate, we have onStart, we have onStop,
onActivityResult, and several other callbacks.
Normally if you're writing a game that's not native, you
can usually get away with just subclassing BaseGameActivity,
which is a class that we have in the samples.
When you subclass BaseGameActivity, all that
life cycle is connected for you.
Now of course, if you're writing a native game, as you
know, you can't subclass BaseGameActivity.
Why?
Because you have to use NativeActivity
for a native game.
So we're going to talk about how to set up NativeActivity
to do exactly that.
So first of all, you don't have to use
NativeActivity as it is.
You can actually subclass it.
So this is what we do here.
So before anything, we start with actually NativeActivity,
and then we derive our activity class from it.
So in this case, our game is called "Awesome Game." So we
are deriving AwesomeGameActivity from
NativeActivity.
Since we're going to use the GameHelper--
which is also in the samples--
we also implement GameHelper.GameHelperListener,
which is the listener class that GameHelper uses.
So next, we declare GameHelper,
inside of our activity.
And we're going to have to manage its life cycle.
Remember, this is actually done by BaseGameActivity, But
it's not actually very hard to do it yourself.
To do this, all you have to do-- first of all, you want to
load your game library, because it's an NDK game.
So we're loading the game library, using
System.loadLibrary.
Next we want to hook up the GameHelper.
To do this, for example, when you have onCreate, so first of
all, you create your GameHelper here.
And then what you have to do is call GameHelper, like
mHelper.setup.
And this is when you do the setup for the GameHelper.
Here, we're specifying that we want the GAMES client and we
also want the APPSTATE client.
And we're going to use those in our game.
After you do onCreate, all you have to do is
do the same on onStart.
So whenever you get the onStart callback, the
GameHelper needs to know that the onStart has happened, so
this is how you hook it up.
On onStop, it's been pretty much the same thing.
So on onStop, you just call mHelper.onStop, and that
connects it correctly.
Next, you'll also to onActivityResult.
You'll do just the same thing.
You're just calling helper to notify that, that the result
has come in.
Because that's necessary for the whole sign-in process with
the dialogues and so on.
So you need to get the results to the helper.
Next, you have to wait for the sign-in callback.
So you're going to be notified that sign-in succeeded or
failed through the sign-in callbacks, like
onSignInSucceeded and onSignInFailed.
So that's when you probably want to notify your native
code that the sign-in has succeeded or failed.
So let's talk about how to actually do sign-in.
So first of all, we're not going to talk into great
length about the JNI.
But you have to initialize the JNI.
So first of all, you can do that using
AttachCurrentThread, and then have a working attachment to
the thread that you can use to make JNI calls.
Of course, don't forget-- because
that I made that mistake--
don't forget to detach the current thread.
Otherwise, we're going to get strange crashes in the
background.
After you're done setting up the JNI, you're probably going
to want to have a sign-in button somewhere in your game.
So the sign-in button pretty much looks like that.
You have some liberty to customize it.
But when the player clicks on it, you should start the
sign-in flow.
So the sign-in flow is the whole set of dialogs that the
player has to click through to actually authorize your game
to access the Play Games API.
So when the user clicks that, what you want to call--
this is in Java, of course-- you want to call
mHelper.beginUserIntiatedSignIn.
So that's going to begin the whole sign-in flow.
However, since are going to be calling it from the game
thread- so remember, that the game is going to be running on
a separate thread.
It's not the UI thread.
So you need to wrap that with a runOnUIThread call so that
you can actually call that method from the game thread
and have it execute on the UI thread.
So this is why we have this method, which is called
postStartSignIn, which essentially can be called from
any thread and post to the UI thread.
And there, we call mHelper.beginUse
rInitiatedSignIn.
Now, let's show how to actually start
the flow from C++.
So nobody's afraid of JNI, right?
So this is how we invoke that method using JNI.
It's just standard JNI.
Just get the activity object, the activity class, and then
we get the method ID for our method and then invoke it.
Notice that when we do this, we actually sidestep one of
the major difficulties of using JNI in Android, which is
that if you just try to find a class by name, it's not going
to find it because it can only find the actual framework
classes using FindClass, unless you do funny stuff with
class loaders.
So notice that we are completely sidestepping this
whole difficulty by just using our own activity
as a starting point.
So we're using our own activity and calling method
that we wrote.
After we call this, then we get the sign-in flow.
All right, so after we do the sign-in flow, you have to know
when you're actually signed in so that your game can respond
to that appropriately.
You're going to know that when on the Java side, you get this
onSignInSucceeded callback.
So that's the callback that tells you that sign-in has
succeeded, or else that the sign-in has failed.
So how do you actually notify the code?
Well, you can--
to notify the native code that this has happened.
What you're usually going to have to do is to write the
native method that the Java side can call and then notify
your native code that this happened.
One of the ways to do this--
actually, I think it's a pretty useful pattern-- is not
to have just a Boolean saying yes or no.
It's actually to have a three-state variable, saying
either sign-in has failed, sign-in has succeeded, or
sign-in is in progress.
And then from native code, you can react appropriately to
those states.
So we're declaring these states as constants here.
And then we're also the declaring a native method from
Java, which is report sign-in results.
And we're going to call that method whenever we want to
report a sign-in result or progress to native code.
So this is how we do it.
So when we are on onStart, we say that
sign-in is in progress.
Why?
Because every time your application gets an onStart,
like comes back from the background or anything like
that, sign-in is not ready yet.
So sign-in is in progress, because Play
Games API has to reconnect.
It's only when you get onSignInSucceeded after
onStart that you can actually start to make calls.
So whenever you get onStart, this is when you report to
native code that the sign-in is currently in progress.
Then, of course, when you get onStop it's the same thing.
You also say that sign-in is in progress, even though it
had succeeded before.
Why?
Because when you get onStop, sign-in is no longer working,
and it's in progress because it's going to come back later.
Then when we onSignIn--
actually, when you start the sign-in process using
postStartSignIn, which is the method that we just showed,
you also say that it's in progress because, well, the UI
flow is happening right now.
And at the end of it, you're going to get on sign-in
succeeded or failed.
Next, of course, when you get onSignInSucceeded, that's when
you report that the sign-in state is success.
When you get onSignInFailed, you report that
sign-in was a failure.
And then your native code is going to have to know how to
handle those states.
So next, how do you actually handle this from native code?
It's just a JNI native method.
So all you have to do is write that method signature, that
you can generate with Java H.
And then when that method gets called, all you have to do is
react to that.
One caveat is that you're going to be running on the UI
thread on that method.
So be careful not to try to manipulate your game state and
so on in a way that may clash with your game thread.
So usually, one of the useful methods there is just to use
some sort of synchronization, or write to a write-once
variable, or something like that.
But it's important to note is that it's going to be on the
UI thread, so don't do anything funny there.
All right, so that's pretty much all there is for this
first episode.
Please watch the other ones, Because then we're going to go
more in depth into achievements.
Leaderboards, and to how we can actually do this on a
deeper level.
Thank you very much.