This article is dedicated to utilizing Mapbox to create an AR fitness application prototype. This is because here we’ll be focusing on utilizing GPS, geolocation, and the Android/Apple device hardware to communicate with satellites and receive data. In brief, this article will cover:
- Mapbox basics
- Integrating Mapbox into Unity
- Implementing Mapbox data into an AR application
Mapbox
Mapbox is a provider of custom online maps for websites and applications. It allows you to create Location-based, City simulators, TabletopAR and WorldScaleAR applications and games. It is free for web and mobile SDKs for up to 50000 map views, geocode requests, direction requests, and matrix elements per month. After reaching 50,000 map views, there exists a charge of 0.5 cents per 1000 web map views, geocode requests and matrix elements per month for mobile SDKs and web page.
There is a commercial option that includes private or paid apps for up to 250 seats, asset tracking for up to 1000 different assets, and turn-by-turn navigation apps for up to 50 seats.
Project Overview
We will be creating a small application that allows the user to select the location they want to walk to and it will set the destination. The build time will be around 20 minutes.
The technical requirements for this project are as follows:
- Android device with kernel version 24 or above
- Unity 2018
- Mapbox (https://www.mapbox.com/)
Setting up Mapbox
- The very first thing required to set up Mapbox is to sign up for it. This requires a username, email address, and password:
- After you have signed up and verified your email address, it will take you to a page to find out which version of Mapbox you need. You have the option of iOS, Android, Web, and Unity:
- The version we want will obviously be the Maps SDK for Unity, so be sure to download the Unity package before proceeding:
- As per the following screenshot, you will be given an access token, which will be required to utilize the Mapbox software. Be sure to copy this key and paste it into Notepad for later use:
- Create a new Unity project and call it ‘Chapter 6 or Fitness for Fun’
- Import the Mapbox Unity asset file into the project:
- This will probably take some time to install:
- Immediately after the installation, you should notice a new menu item called Mapbox. This opens up quite a few new features that are exposed for us to play with:
- Mapbox gives us Atlas Template Generator, Clear File Cache, Setup, and Map Editor options:
- The Mapbox Atlas Template Generator is a tool that allows you to create and test custom map atlases:
- The Map Editor allows you to visualize the underlying data structure of the maps you create and use:
- In addition to that, the Map Editor’s data is tied directly to the Map object’s Abstract Map Script. Any changes you make to the Abstract Map Script data is reflected in the Map Editor, and any changes you make in the Map Editor are reflected in the Abstract Map Script’s data:
- The Mapbox Setup option allows you to select Example scenes or Map Prefabs, however, this can only be accessed after you copy and paste your Access Token and submit the information. This will require you to be connected to the internet for verification:
Important Items to Note
With different project types, you will have prefabs that will automatically be added to the active scene. Here, we will go over the main object that is added to any template type, which is the Map object.
The Map is the most important object that is added to with any of our templates and has many extremely important items within the script that we should go over:
The first item within the Map object is the Abstract Map script. The most important items within are MAP LAYERS, GENERAL, Location, and Others:
Within the GENERAL tab, we have:
Latitude Longitude: If you click on Search, you can set this by typing in an address, or country and city, or even city and state, depending on the location you want to utilize. It will automatically convert it to be latitude and longitude values.
Zoom: This is specifically set for how close and far away the map can be drawn; be advised that the zoom function will only work appropriately if you have the proper tilesets generated for it.
Extent Options: These are how far you want the map to be drawn. By default, it is set to the bounds of the camera.
Camera: This is the camera you want to use, whether it is an AR camera with Vuforia, ARCore, ARKit, or even the regular Unity camera.
Update Interval: This is how long the program should wait before updating positions and drawing.
Initialize On Start: This is a Boolean value for whether or not you want the map to immediately be drawn upon the start of the scene:
In the Others tab, we have a few options as well:
Placement Options allows you to choose between At Location Center and At Tile Center. This controls the centre or root placement of the tiles. Location centre is able to be defined by you, whereas the tile centre is the centre of the tile.
Snap Map To Zero is a Boolean value that specifies whether or not the map’s root should be snapped to 0,0,0.
Scaling Options allows you to choose whether you want a custom or world scale. Custom is defined by Unity using a Mercator conversion factor. World scale means that the actual scale is rendered and the Mercator conversion is ignored.
Unity Tile Size is the size of the tiles used in Unity units.
Loading Texture is the texture used when the textures are loading.
The next tab is the IMAGE tab:
- Data Source: This is the source of our maps. We can use Mapbox Streets, Mapbox Outdoors, Mapbox Dark, Mapbox Light, Mapbox Satellite, Mapbox Satellite Street, Custom, or None. These are essentially theme options for the map you want to use.
- Use Retina: This is a Boolean that allows you to choose whether you want to enable the usage of larger texture maps and better visual quality for retina displays.
- Use Compression: This is a Boolean that allows you to choose to use Unity compression for the tile texture.
- Use Mip Map: This is a Boolean that lets you choose whether to use Unity-generated mipmapping.
The next tab is TERRAIN, which gives us the ability to modify the terrain of our Mapbox maps:
- Data Source: This is the first option available, and it lets us choose between using Mapbox Terrain, Custom, or None. Mapbox Terrain provides us with digital elevation with worldwide coverage. Custom allows us to use a custom elevation model. None is a flat terrain.
- Map Id: This is the Id of the corresponding tileset that we want to use.
- Elevation Layer Type: This gives us the choice between Flat Terrain, Terrain with Elevation, Low Polygon Terrain, and Globe Terrain. This allows us to render our terrain with the specified elevation type. Flat Terrain renders a flat terrain with no elevation. Terrain with Elevation renders terrain with elevation from the source specified. Low Polygon Terrain renders a low polygon terrain with elevation from the source specified. Globe Terrain renders a terrain with no elevation for a globe.
- Base Material: This is the material used to render the terrain tiles.
- Exaggeration Factor: This multiplies the factor to vertically exaggerate elevation on the terrain; however, it does not work with the Flat Terrain Elevation Layer Type.
- Add Collider: This is a Boolean that lets us add Unity physics colliders to terrain tiles for detecting collisions.
The Others tab within the TERRAIN tab has a few options available to us as well:
- Sample Count: This gives us the resolution for our terrain, with the result being an n x n grid.
- Use Relative Height: This is a Boolean that lets us use a world-relative scale for scaling the terrain height.
- Earth Radius: This is the radius of the Earth we want to use in Unity units of measurements, which is a meter.
- Show Sidewalls: This is a Boolean that adds side walls to terrain meshes, which reduces visual artefacts.
- Add to Unity layer: This adds the terrain tiles to the Unity layer. Upon checking the checkbox, you will get the choice of which layer you want to add them to—Default, TransparentFX, Ignore Raycast, Water, UI, Postprocessing, and Add Layer.
Next is the MAP LAYERS tab:
- Data Source: This is the source dataset for the vector data.
- Map Id: This is the Id of the map we are using.
- Use Optimized Style: This is a Boolean that allows us to use Mapbox-style-optimized tile sets that remove any layers or features in the tile that is not represented by a Mapbox style. Style-optimized vector tiles are smaller, serve over the wire, and are a great way to reduce the size of offline caches.
- Enable Co routines: This is a Boolean that allows us to use co routines.
- Entity Per Co routine: This specifies how many entities can be grouped together in a single coroutine call.
POINTS OF INTEREST is the next tab. Here you can create special markers for important locations in your application or game:
- Required Map Id: This is the map Id of the tileset we are using and cannot be empty.
- Add Layer: This allows us to add points of interest layers.
- Remove Selected: This allows us to delete a layer.
The last tab is FEATURES, which gives us Vector Layer Visualizers with the options to add or remove visualizers. FEATURES allow us to modify how certain features look in relation to the point of interest we create:
- Add Visualizer: This allows us to change how we visualize a point of interest layer
- Remove Selected: This allows us to delete the selected visualizer
Finally, we have another script, called Initialize Map With Location Provider, which only has the option to add an Abstract Map object to it. This script does what the name states—it registers if you are on an iOS, Windows, or Android device, and selects the Location Provider that is most relevant for it.
Setting Up the Project
It’s now time to set up our project:
- Let’s create a new scene and call it FitnessFun:
- Click on Mapbox and then Setup. This will open a setup menu where you need to paste your Access Token in order to gain access to the Map Prefabs template:
- The Map Prefabs template we want to use is Location Based Game:
- It will add a prefab onto our scene, which will have what looks like a pawn in the scene edit tab:
- If you look over in the Hierarchy pane, you will notice a LocationBasedGame prefab added there, and if you drill down to look at the objects inside, you will see a Map, Player, and LocationProvider inside. You will also notice a Canvas and EventSystem automatically added to the Hierarchy:
- Inside the Scenes folder, create a Scripts folder:
- Inside that Scripts folder, create a C# script called TargetLocationController:
- Create another script called DestroyTargetLocation:
- Go back to the Hierarchy pane and make a copy of the Player component:
- Remove the Immediate Position and Rotation with Location scripts along with renaming it to targetLocation:
- Inside the Scenes folder, create a folder called Prefabs:
- Drag and drop the TargetLocation object into the Prefabs folder:
- Navigate to our Scripts folder and open the TargetLocationController script.
We need to write our script to create a new instance of the TargetLocation object and to destroy the object when something happens.
Scripting the Project
- We will first make sure to utilize Unity Engine, as we need access to MonoBehaviour:
Using UnityEngine;
- Our public class will be called TargetLocationController, which is the same name as the script file we named in the Unity Editor. We will also inherit from MonoBehaviour:
public class TargetLocationController : MonoBehaviour
{
1)We will create a public GameObject called targetObject; this is so that we can drag and drop our prefab onto this object to set a reference to it:
private GameObject targetObject;
2)We will create a Start() method at this point. We want to find the object in the project with the tag of targetLocation, as we will be creating it upon a touch event instantiating it:
private void Start()
{
targetObject = GameObject.FindGameObjectWithTag(“targetLocation”);
}
3)We will need to create a SetLocation method and instantiate a new raycast to utilize the touch event the way we want for reading finger presses on the screen:
private void SetLocation()
{
RaycastHit hit = new RaycastHit();
4)We need to loop through to check on our input via touch events:
for (int i = 0; i < Input.touchCount; ++i)
5)We check to see if the touch count is greater than 0, and if our touch phase is moved:
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
6)Now, we will construct a ray from the current touch coordinates on the screen:
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(i).position);
7)We need to do a check to see if the raycast hits anything:
if (Physics.Raycast(ray, out hit))
8)If the raycast hits anything, then we will create a new instance of our prefab with the position based on our touch event:
Instantiate(targetObject, new Vector3(Input.GetTouch(i).position.x, 4.23f, Input.GetTouch(i).position.y), Quaternion.identity);
}
}
9)In our Update() method, we call our SetLocation script:
private void Update()
{
SetLocation();
}
}
- Now, we just need a simple collision check script to check if the player object collides with the targetlocation object. We want to destroy our targetLocation object if the player object collides with it.
- Open the Destroy Target Location script.
- We will need the UnityEngine namespace as usual, since we want to inherit from MonoBehaviour:
using UnityEngine;
using System.Collections;
- The name of the class is the same as the name we gave the C# script file and inherits from MonoBehaviour, so we can attach it to a game object in the Unity Editor:
public class DestroyTargetLocation: MonoBehaviour
{
- We create an OnCollisionEnter method with the parameters of Collision col:
void OnCollisionEnter (Collision col)
{
- We will do a simple if check to see if what we are colliding with is the targetLocation object via the object’s tag name:
if(col.gameObject.tag == “targetLocation”)
{
- If the simple if check returns true, then we will destroy the targetLocation object:
Destroy(col.gameObject);
}
}
}
Finalizing the Project
- Navigate back to the Unity Editor, attach the targetLocation script to the player object, and set the object to be the targetLocation object:
- Attach the DestroyTargetLocationscript to our object called LocationBasedGame:
- Now we can click on File | Build:
- Set the project type for Android:
- Make sure the only scene added for the building is the Chapter6 scene. If the scenes list is empty, click on Add Current Scene:
- Now, build the project and install it on your Android device to run the program.
In this article, we conceptualized and created a fitness application prototype that encourages walking to different locations for the user’s enjoyment. We learned about Mapbox, what it does and how to integrate it into Unity. We then leveraged Mapbox to create a viewable AR map that is able to use geolocation technology to track the user’s position and destination.