This Samsung GearVR hack covers connecting Unity C# to WebAPIs and utilizing the response to create a Weather App that responds to temperature.
Section 1: Dev Environment Set Up- 1) Install the latest version of Unity, accepting all the default configurations and package options during instillation. You'll have to create a Unity account using a valid email address. The free version of Unity is all you'll need! Unity Download Link.
- 2) Head on over to Oculus and download Oculus Mobile SDK 0.6.0.1
- 3) Download the Java Development Kit 8 (JDK) from Oracle, accepting all the License Agreements. If you are a Mac, reference the screenshot below to see the correct version to download highlighted.
- 4) Lastly you'll need the Android SDK 5.0 installed, along with the SDK Tools.
Our goal in this first section is to get an application built in Unity that can be sent to your Samsung phone and demoed in the GearVR. This application is going to be simple, and do nothing other than display a cube in front of the camera. However, in doing so you'll learn everything you need to begin developing for the GearVR, giving you a great foundation to make useful applications that utilize real world API data (which we will begin covering in section two)!
- 1) Opening Unity, lets create a New Project called AtlasVR (or whatever you'd like to call your app). You may have to log into your Unity account first. However, once signed in you will be brought to a menu that allows you to create a new project. Make sure that "3D" is selected before clicking the "Create Project" button. Also feel free to specify the directory where you'd like the project to be saved on your hard-drive. The project will begin build itself once you click the create button, and Unity will open up a new environment in the editor for you to start working in.
- 2) It's first important that you create a Unity scene. Do this by going to the File tab and selecting "Save Scene". Name the scene Main, and place it in a new Scenes directory within the Assets directory (Assets/Scenes/Main). For the purposes of this application we will only ever have one scene. However it's important to stay organized!
- 3) At the top level of the Hierarchy pane (screen left by default), right click and create a new Cube within the 3D Object tab. Given the orientation of your camera, drag the cube using the colored X, Y, Z arrows so that it is in view of the camera. Click on the Main Camera in the Hierarchy to preview whether your cube is in view. Changing the cube's material is not necessary - but go to town if you feel like it!
- 1) Now under the File tab, select Build Settings. This is where we are going to start setting up our project to properly export the build for Samsung GearVR. Firstly, select Android as the Platform you will be building for, and then change the Texture Compression drop down menu to ETC2 (GLES 3.0) and check the box Development Build.
- 2) Pressing the button "Player Settings" at the bottom left of the menu will bring up a settings menu on screen right. Under the Other Settings tab, check "Virtual Reality Supported". The Bundle Identifier is a reverse URL you can make up following the convention of "
com.somthing.something
". Reference the screenshot below to make sure that you have the proper settings selected! However, make sure that the Minimum API Level is set to Android 4.4 'Kit Kat' or greater! In my build of this project, I've selected Android 5.0 'Lollipop'.
Samsung GearVR is powered by Oculus. In order to build apps that will be recognized by the Samsung Gear, you must create an Oculus Signature file and include it in your project. Oculus provides a tool and set of instructions for successfully doing this. However, there is an easier way!
- 3) On your Samsung phone, download the SideloadVR DeviceID on the Google Play store. Once installed, open up the app to find out what your Device ID is.
- 4) Go to this link on Oculus's developer website and enter your device ID into the prompted input. Once this is done, click Download File to generate your signature file. Store this signature file in a safe place for future use, and do not edit the file name!
- 5) Now back in your Unity editor we need to nest the signature file in the required path structure that is expected by the GearVR. So within the Assets directory, create the following path Assets/Plugins/Android/assets/ and place a copy of your signature file in there. That's it!
At this point, if all has gone smoothly you should be ready to build the app in Unity. Awesome! Let's do it. Go back to the File tab and select Build Settings. Once the menu pops up, make sure that all the configurations are as we last had them and press Build. Personally, we like creating an App/ folder within the project to store all my .apk
builds. However, feel free to save the new appName.apk
to wherever feels right.
There are many ways to get the .apk file to your phone. The easiest may be using Google Drive and then just downloading it from the cloud. We recommend doing it this way, as Android File Transfer can be VERY annoying and deserves a tutorial within itself.
- 1. Go onto the Google Play store and download an APK Installer - if you don't already have one. We uses APK Installer and it works great. However you must do this in order to actually install your GearVR app on your phone for use. After it is installed, open the app and your appName.apk should be present. Select it and press Install.
- 2. Fingers crossed. Does everything work? Try opening your app to find out! Hopefully you are prompted to slide the phone into you GearVR, and then are able to bask in the glory of your magnificent cube!
Now that we've successfully created, configured, exported and demoed our GearVR app, we are in a great position to go back into Unity and really focus on building out our application! It's easy to build something awesome and then be dragged through hell and back trying to get it deployed. It's worthwhile to practice first ensuring that your projects are properly configured for its intended hardware/platform before investing too much time in creating the environment.
Scripting on GameObjects and Calling an API
Game Object's in Unity get instantiated at the beginning of every scene. We have the ability to attach scripts to any game object that ends up being run on instantiation. Within a Unity c# script developers are given two default functions, Start and Update. The start script is run once on instantiation, while the Update function continues to be run once per frame throughout the duration of the Scene. Meaning that if your environment is set to render at 30fps, the Update function on every game object will be run 30 times per second.
- 1. At the top level of your Hierarchy create an Empty Game Object and rename it WeatherAPI. We will never add a material to this object, so its location within the Scene is somewhat irrelevant.
- 2. Within the Assets directory (Project/Assets/), create a new folder called Scripts (Project/Assets/Scripts/). Within that Scripts/ folder, right click to create a new C# script and name it WeatherAPIScript. Then, using your mouse or trackpad, click and drag the WeatherAPIScript into the Hierarchy pane and drop it directly on top of the WeatherAPI. The script will not become visible in the Hierarchy. However, if you click on the WebAPI object, you should see that the script you just created is now a component of it.
- 3. Open up the WeatherAPIScript in your preferred text editor (usually Visual Studio or MonoDevelop when using Unity). Once it opens you will see the Start and Update functions we talked about! The first step will be to declare the endpoint URL of our API, which from OpenWeatherMap can be structured as "
http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139&APPID=<YOUR API KEY>
". Next, instead of leaving our Start function as Void Start we are going to change it to IEnumerator Start.
- 4. The way we will be calling our API is by using Unity's WWW object. By creating a new instance of WWW with an endpoint URL passed in as the argument, it will return a promise that we assign to a variable. That promise can then be yielded to a block that will wait until its response is received before it returns and continues executing the function.
- 5. The response we are given will have an error if the call was unsuccessful. So you may test for that error before trying to access the response data. However, if there is no error, the response will be stored on the return object ("
object.text
") as single string of data.
Here is the code!
// WeatherAPIScript.cs script
using UnityEngine;
using System.Collections;
public class WeatherAPI : MonoBehaviour {
public string url = "http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139&APPID=<YOUR API KEY>";
// Use this for initialization
IEnumerator Start () {
WWW request = new WWW(url);
yield return request;
if (request.error == null || request.error == "")
{
Debug.Log("Response: " + request.text);
}
else
{
Debug.Log("Error: " + request.error);
}
}
// Update is called once per frame
void Update () {
}
}
Section 4: Setting up your Scene in UnityUnity is great because drag and drop is the primary interaction. You can easy add almost any element to your scene.
If you haven't already, download landscape_final.obj below. We modeled this quickly in blender.
Section 5: Reading JSON in Unity to Manipulate Objects and EnvironmentWe hope everything so far has been extremely helpful for you! If you think about it, what you just learned is HUGE. Instead of being limited to your own environment within Unity, you're now accessing any web API data. ANY WEB API! Whether you want to put us to shame by building an even better weather app, virtually visualize your favorite Reddit threads, or do something related to food with Yelp's data, you now have that power.
For those of you working with a web-stack, manipulating and reading JSON is likely a no brainer. Doing so with c# in Unity is not exactly as much fun, however completely possible. So here we go on showing you how to do just that, and then make use of the data within your project.
Using SimpleJSON to Parse out WWW Text Response
At this point all the JSON data that was returned from our Weather API is actually one long string. In order to parse that string into JSON We use SimpleJSON. There are other ways of doing this, however this method worked for me without much fuss.
- 1. Go to the SimpleJSON wiki page and download the file. Once downloaded, you will need to import the SimpleJSON.unitypackage file. First unzip this SimpleJSON package and then go to the Assets tab in Unity and select Import Package > Custom Package. Navigate to the unzipped directory and import the SimpleJSON.unitypackage file.
- 2. Once the SimpleJSON package has been installed you will be able to use it in your scripts by specifying it at the top (as seen in the provided code below). Given that you've received a valid API response, we suggest creating a separate function within your script that will parse out the JSON. In my code, we create that new function as setWeatherAttributes(string jsonString). And then when we evoke the method we pass in the text that is stored on our response object as so setWeatherAttributes(request.text).
- 3) Now, very simply within this method we are able to create a new variable that will store the JSON we parse from our string. And doing so using SimpleJSON looks like this, var weatherJson = JSON.Parse(jsonString).
- 4) Tada! You now have JSON and are able to access its keys and values using standard syntax. Take a look at the code below for examples on how we've drawn out the different values into their own variables. Also note that we've declared each variable as a public variable at the top of the script! This is important, as by doing so we will have the ability to access these variables from other scripts throughout our application.
// WeatherAPIScript.cs script
using UnityEngine;
using System.Collections;
using SimpleJSON;
public class WeatherAPI : MonoBehaviour {
public string url = "http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139&APPID=<YOUR API KEY>";
public string city;
public string weatherDescription;
public float temp;
public float temp_min;
public float temp_max;
public float rain;
public float wind;
public float clouds;
// Use this for initialization
IEnumerator Start () {
WWW request = new WWW(url);
yield return request;
if (request.error == null || request.error == "")
{
setWeatherAttributes(request.text);
}
else
{
Debug.Log("Error: " + request.error);
}
}
// Update is called once per frame
void Update () {
}
void setWeatherAttributes(string jsonString) {
var weatherJson = JSON.Parse(jsonString);
city = weatherJson["name"].Value;
weatherDescription = weatherJson["weather"][0]["description"].Value;
temp = weatherJson["main"]["temp"].AsFloat;
temp_min = weatherJson["main"]["temp_min"].AsFloat;
temp_max = weatherJson["main"]["temp_max"].AsFloat;
rain = weatherJson["rain"]["3h"].AsFloat;
clouds = weatherJson["clouds"]["all"].AsInt;
wind = weatherJson["wind"]["speed"].AsFloat;
}
}
Transforming Objects in Unity using Scripts
Good news, this lengthy tutorial is pretty much finished. You've created a project and deployed it to your phone, successfully made an call to a web API, and converted that response into JSON that can be utilized throughout your application. Congrats! The last nugget of wisdom we're going to give you is an example on how to use that information in another Script to manipulate the property of an element or object.
You will see from the screenshots that our version of the application is pretty built out at this point. Know though that there is nothing special about what we did versus what is explained here! It is all built repeating the same steps we've discussed.
Displaying the City Name from your Response
- 1) Within the Hierarchy I created an Empty Game Object called ViewCollectionCanvas that will be the parent to all our canvases. In Unity, text is a UI element that must be displayed on a Canvas. However, all the elements are created in the Hierarchy by right clicking and selecting whats needed. In the screen shot below, know that Canvas2 is a Canvas UI element and that City is a Text UI element.
- 2) In addition, we've also created a new script called CityScript. The sole function of this script will be to display the name of the city where we looked up the weather. So to make sure it gets run, add it as a component to the City UI element you just created. Go ahead and open it up in your editor.
- 3) Now, given that the API call to
OpenWeatherMap
takes time, we don't want our script to run and throw an error when there is no response data captured yet! The way we worked our this was creating a boolean variable called knowsWeather and setting it to false. In the Start function, we grab the instance of the WeatherAPI that is created and then begin checking it once per frame in the Update method to see whether or not it knows the temperature. Once it does, the we set the text value of the City UI element to the city name, and then set the knowsWeather boolean to true.
- 4) Once again looking at the Start function though, you can see in the code that we are able to access objects in the scene by name, and then from that instance access it's various components. Given that we want the Text component of the City UI element, we use GameObject.Find("City").GetComponent<Text>().
- 5) Now, easy as pie, we access of WeatherAPI and from it pull the city name (which you remember us making public). On the Text component that we defined as a variable, we simply need to set it's text equal to the city. In the code, you'll see that we also concatenated the country code to the string. However, feel free to edit it as you wish!
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class CityScript : MonoBehaviour {
public bool knowsWeather;
private WeatherAPI weather;
Text cityText;
// Use this for initialization
// Use this for initialization
void Start () {
knowsWeather = false;
cityText = GameObject.Find("City").GetComponent<Text>();
weather = WeatherAPI.FindObjectOfType<WeatherAPI>();
}
// Update is called once per frame
void Update () {
if (!knowsWeather && weather.temp != 0)
{
cityText.text = weather.city + ", " + weather.country;
knowsWeather = true;
}
}
}
Fin!
As question pop up we will continue to add on to and supplement this tutorial. Thank you for your time and attention. We hope you learned something awesome!
Comments