Posts

  • Making a better Pokémon Go

    I’ve been working on this project for a few months now, which is honestly a bit ridiculous. This short project making the core systems of a Pokémon Go clone took me about 3 days for the actual Android plugin and about two and a half months on and off to get the map rendering and documentation sorted. But now it’s “done”. There’s still a lot of polish and documentation missing but I feel like I need to show this to the world eventually, and now is as good a time as any. And who knows, maybe it’ll help a few people out who were as lost as I was when I started.

    Contents

    Prologue: Why did I do this?

    pokemon_go_logo.png

    As the title says, this is a Pokémon Go clone, but not in the case of gameplay (yet). This is more focused on the technical side of things. It’s a plugin for Unity, the same engine Pokémon Go uses, that only performs the geolocation side of things. This is the bit that people would normally use Unity’s LocationService for. However, that has certain limitations which make it unsuitable for the job, so the best way to go about this is creating your own plugin. But before I get into that, first I’d like to explain some background.

    I really loved the idea of Pokémon Go when I first heard of it. the idea of real world Pokémon was something that 10-year-old me could have only dreamed of. And here it was, happening during my lifetime! I was going to go out, catch my own starter, train it up, get into battles, catch more Pokémon, form a team and win real world gym badges. Even more exciting, I regularly run 10+ kilometers several times a week out in the countryside. I was going to catch some rare Pokémon out in the great unknown and trade them with my real world friends, who would also all be playing Pokémon Go, because it was that awesome.

    Of course, it didn’t actually turn out anything like this. Of the half dozen features I just described we only got about half of them; and even then they were gimped. This irked me, not just as a player, but as a game designer and developer. I thought to myself, “why couldn’t they have added battles? Why couldn’t they place Pokémon outside of cities instead of just in the middle of them? And why couldn’t the damn game work without having the screen on all the time!?”

    Most people with complaints about games can only write really whiny posts online (like I am now). But I decided that I could do more than that. I was going to make a Pokémon Go Clone.

    Step Zero: Planning everything

    Pokemon-Gold.png

    After I wrote down the list of things that I wanted to have in the game I quickly realized that this wouldn’t be practical. It wasn’t a long list, I just didn’t have the time to create all the assets and gameplay functions (even though I knew that I had the programming capability). So I decided to put that on the backburner and tackle just one feature, the distance tracking.

    I knew distance trackers and loggers could run with the screen off on Android and iOS, I used a fitness tracker while running on my Nexus 5. However, I wasn’t sure if I could that in Unity, the engine that Pokémon Go used. And I needed to prove a point, so I also had to achieve my goal using the same engine they used. It didn’t take me long to find out that an Android service would do what I needed and that it was entirely possible to connect the two together according to the documentation for Android plugins in Unity.

    The entire location tracking service had to work when the main Unity app was off. I’d use Google Location Services to get the location data and distance travelled in a service, then I’d attach a listener that is attached to the Unity app to get the data. Simple and easy.

    Unfortunately I don’t have a spare iPhone or a Mac to compile with. I just assumed that if it worked on Android then it would work on iOS. Partway through I realized that the reason that Pokémon Go might have missed so many functions wasn’t poor development but Apple’s overly restrictive APIs. They may not have wanted to release the game with different features on each platform.

    After checking up on the state on location tracking on iOS I wasn’t so sure of giving them benefit of the doubt. You can build Unity plugins for iOS same as Android (more info [here][se-unity-ios]) and it is possible to get the user’s location in the background on iOS as well. I’d love to try and make the plugin for iOS as well but for now I consider having it work on Android as proof enough.

    Step One: learning how to make Unity Plugins

    First I had to get the Android Native code and Unity working together. This tutorial was a huge help getting started. I created a simple Java class that would return a number when a method was called (source). I opened a plain Android Studio project and made a few changes to how it built so it would create libraries.

    1
    2
    3
    4
    5
    6
    7
    public class GeocachingGamePlugin {
    
        public static float GetMeaningOfLife()
        {
            return 42.0f;
        }
    }
    

    A Hitchhikers Guide to the Galaxy reference in a programming blog, original I know. However, it was either this or another “Hello World”. I built this script into a jar and dropped it in Plugins/Android.

    Then I called the script from Unity. The version of the script I’m showing here is a much nicer version than the one I originally wrote but if you want to see the original source you can find it here.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class ShowMeaningOfLife : MonoBehaviour
    {
    	Text testText;
    	float meaningOfLife;
    
    	void Start ()
    	{
    		testText = GetComponent<Text>();
    
    		if (Application.platform == RuntimePlatform.Android)
    		{
    			using (var androidPlugin = new AndroidJavaClass("com.deovolentegames.geocachingunityplugin.GeocachingGamePlugin"))
    			using (var javaUnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
    			using (var currentActivity = javaUnityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
    			{
    				meaningOfLife = androidPlugin.CallStatic<float>("GetMeaningOfLife");
    			}
    
    			testText.text = "The Meaning of life is " + meaningOfLife + ".";
    		}
    	}
    }
    

    This looks complicated but it’s really very simple. First, AndroidJavaClass is not an instance of a class, it is the Unity representation of the java.lang.Class. So what I’m doing is getting the class of both the Unity Activity and my custom plugin class, then getting the instance of the current activity before running my method to get the number 42.

    ShowMeaningOfLife

    The image might not be very exciting but this is half the job done.

    Step Two: Learning how to use Android Services

    Now for the service. What I used was an AndroidJavaProxy, an object that can basically be shared between the Java service and the C# Unity app. The dollar symbol in the constructor is used to specify an internal class. TODO: Link source?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class LocationPluginListener : AndroidJavaProxy
    {
    	GeocachingPlugin geoPlugin;
    
    	public LocationPluginListener(GeocachingPlugin geocachingPlugin) :
    		base("com.deovolentegames.geocachingunityplugin.GeocachingGamePlugin$LocationPluginListener")
    	{
    		geoPlugin = geocachingPlugin;
    	}
    
    	public void OnReceiveLocation(double lat, double lon, int distanceInCentimeters)
    	{
    		Debug.LogFormat("[LocationPluginListener] {0}, {1}", lat, lon);
    
    		geoPlugin.UpdateLocation(lat, lon, distanceInCentimeters);
    	}
    }
    

    In the main static class of the plugin is this code that starts the service, saves a reference to it as geocachingGameService and registers a listener of type LocationPluginListener. TODO: Link source?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // Called by Unity to start the service
    public void StartLocationCacheService(Activity unityActivity, LocationPluginListener callback) {
      // Set the callback
      this.callback = callback;
    
      Intent intent = new Intent(unityActivity, GeocachingGameService.class);
      unityActivity.bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }
    
    private ServiceConnection connection = new ServiceConnection() {
      @Override
      public void onServiceConnected(ComponentName className,
                                     IBinder service) {
        GeocachingGameService.LocalBinder binder = (GeocachingGameService.LocalBinder) service;
        geocachingGameService = binder.getService();
        // Registering the listener with the service
        geocachingGameService.registerListener(callback);
        isBound = true;
      }
    
      // DeregisterListener ...
    };
    
    public interface LocationPluginListener {
        void OnReceiveLocation(double lat, double lon, int distInCM);
    }
    

    Finally I call StartLocationCacheService from my Unity code. This is a bit different to my ShowMeaningOfLife test due to the fact that StartLocationCacheService is neither a TODO: Link source?

    1
    2
    3
    // After all the usings are set up as shown in the ShowMeaningOfLife example...
    pluginClass = new AndroidJavaObject("com.deovolentegames.geocachingunityplugin.GeocachingGamePlugin");
    pluginClass.Call("StartLocationCacheService", currentActivity, new LocationPluginListener(this));
    

    The way this works is that the Unity app holds a reference to the GeocachingGamePlugin which itself holds a reference to the GeocachingGameService. Then Unity creates a C# class LocationPluginListener that implements the Java interface LocationPluginListener using the whole AndroidJavaProxy thing. In the end we end up with an object which is present in both C# and Java with a method that the native Android service can call to update data in the Unity app.

    adblogcat.png

    Step Three: Learning how to get location data

    Next I had to get the location. This was pretty simple; There were many tutorials on getting location on Android. Most pointed to Google Play Location services as being the way to go so I followed the official Android tutorial for using them. There’s not much point in me listing all of that here; if you’re interested in that part read the tutorials and compare them to the GeocachingGameService source.

    Here’s a summary: I created a class that extends Service and implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, and LocationListener. In onCreate I initialise instances of googleApiClient and locationRequest, making sure that I disconnect the API in onDestroy. I implemented all the required methods for the interfaces and I created a method to handleNewLocations, calling it in onLocationChanged.

    That wasn’t very clear at all I think. Just check out the documentation or read the source, I link all my references at the start of the class.

    I also had to get the right libraries for Google play services. I’m pretty sure that there is a better way to do this but the simplest way is to just drop the AARs in.

    GGP - location data working.png

    Step Four: Visualisation

    Finally I had to add the map renderer. Or not. Because that wasn’t what I was trying to prove; adding nice 3D graphics is not necessary for the plugin to work. I was going to leave it there until I found MapzenGo, an open source project that was trying to recreate that Pokémon Go style using data from the Mapzen Vector Tile Service. It was perfect for the job, even though development of it had stopped once the developer was picked up by Mapzen to create their official Unity SDK.

    The problem was integrating it, I just didn’t understand the code very well. I ended up making a load of unnecessary changes but in the end I got it working. If you’re curious most of what I changed was in the DynamicTileRenderer. Taking so long to get graphics not important to the overall function of the plugin was probably worth it in the end; it visually proves that the plugin works in a way that you can immediately see and feel is right.

    Conclusion

    In future I’d love to add more features, like better recording of distance and reporting of statistics. Or maybe even making a real Pokémon Go clone, with art assets and gameplay. But for now it works and that’s good enough for me. If you want to try out an actual build you can download the .apk here.

    This is all proof-of-concept, learning opportunity, dirty hack sort of stuff. Please don’t ever use it in a production plugin!

    Caveats

    You may have noticed a glaring omission. A big thing I left out is the lack of controls in this plugin to save battery life; once it starts running it’s going to run until the whole app stops. This makes it a huge battery hog, even when you aren’t moving. I really need to fix this but it isn’t really “relevant” to my proof of concept. If you want to use any of this code please be aware of this!

    There’s also a bug with my integration of MapzenGo that causes an unsightly flicker when crossing a tile border, it doesn’t effect the function of the plugin in any way and I’ll get around to fixing it later.

  • Welcome to DeoVolenteGames!

    It's time to write a blog. A development blog.

    It’s time to write a blog. A development blog.

    I’ve written about by programming before, in documentation and resumes. I’ve written many notes and reminders to myself. I wrote a semi-regular email newsletter. But now it’s time to graduate to the next level and start a public blog.

    Hi, in case you don’t know me my name is Rory and I like to write code and play games. I also like to mix the two together. I’ve mostly been working with Unity and C# for a few years though I’ve dabbled in Game Maker, Construct 2, Java, Javascript, C++ and more. My first foray into game making was using Game Maker around the age of twelve. I never really considered becoming a full time game developer as a real option until recently.

    The next few posts will document the process of starting a new blog using Gitlab, Jekyll and Bootstrap. At the time of writing this the website still has it’s base theme which is clashing horribly with Bootstrap (though at least it’s functional). I should warn you that while I know my way around a little html and css I am only barely a competent web developer, most of my programming knowledge is wrapped up in game development. Take everything in the next few posts with a grain of salt; what works for me may not be the best way of doing things. After that I intend to get back to Unity development and I’ll try to post at least once a week.

    Be sure to check out some of my newer posts (once they exist) and try a few of my games and experiments as well. See you next time!

subscribe via RSS

My collection of experiments and games. Maybe I'll write about them too. This website is still under constuction and is likely to change a lot.