If you are an SAP Employee, please follow us on Jam.
Since a long time...I had the idea of making Unity3D and Alexa work together...however...other project kept me away for actually doing it...so...a couple of days ago...a conversation with a friend made me remember that I actually really wanted to do this...so I did 🙂
At first...I wasn't exactly sure how to do it...but then slowly the main idea came into my mind...what if Unity read a webservice that gets updated by Alexa? When the right command is parsed, then Unity will create the object and problems is solved...seems easy? Well...it actually is...
First things first...we need to create a small NodeJS webserver on Heroku...then...we need to install the Heroku Toolbelt...
Now...create a folder called node_alexa and inside create the following files...
{
"dependencies": {
"express": "4.13.3"
},
"engines": {
"node": "0.12.7"
}
}
web: node index.js
var express = require('express')
,app = express()
,last_value;
app.set('port', (process.env.PORT || 5000));
app.get('/', function (req, res) {
if(req.query.command == ""){
res.send("{ \"command\":\"" + last_value + "\"}");
}else{
if(req.query.command == "empty"){
last_value = "";
res.send("{}");
}else{
res.send("{ \"command\":\"" + req.query.command + "\"}");
last_value = req.query.command;
}
}
})
app.listen(app.get('port'), function () {
console.log("Node app is running on port', app.get('port')");
})
Once you have that...log into your Heroku Toolbelt and write the following...
cd node_alexa
git init .
git add .
git commit -m "Init"
heroku apps:create "yourappname"
git push heroku master
heroku ps:scale = web 0
heroku ps:scale = web 1
Your webservice is ready to rock 🙂 You should be able to find by going to "http://yourappname.herokuapp.com/"
Now...this simple NodeJS powered webservice will serve as a simple Echo server...meaning...whatever you type will be returned as a json response...of course...if you type "empty" then the response will be a empty json...so the main idea here is that we can keep the last entered value...if you pass a command it will be called again when you don't pass any commands at all...so by calling it once...we can cal it multiple times without disrupting its value...
Next in line...will be to create our Unity app...
Create a new app and call it "WebService" or something like that...project name doesn't matter too much...
If the Hierarchy window select "Main Camera" and change the "Tranform" details like this...
Now, create a new "3D Object" -> "Cube" and name it "Platform" with the following "Transform" details...
Now...create another folder called "Script" and inside create a new C# file called "MetaCoding"...or whatever you like...
MetaCoding.cs
using UnityEngine;
using System.Collections;
using System.Net;
using System.IO;
using SimpleJSON;
public class MetaCoding : MonoBehaviour {
int counter = 1;
IEnumerator DownloadWebService()
{
while (true) {
WWW w = new WWW("http://yourapp.herokuapp.com/?command");
yield return w;
print("Waiting for webservice\n");
yield return new WaitForSeconds(1f);
print("Received webservice\n");
ExtractCommand(w.text);
print("Extracted information");
WWW y = new WWW("http://yourapp.herokuapp.com/?command=empty");
yield return y;
print("Cleaned webservice");
yield return new WaitForSeconds(5);
}
}
void ExtractCommand(string json)
{
var jsonstring = JSON.Parse(json);
string command = jsonstring["command"];
print(command);
if (command == null) { return; }
string[] commands_array = command.Split(" "[0]);
if(commands_array.Length < 3)
{
return;
}
if (commands_array[0] == "create")
{
CreateObject(commands_array[1], commands_array[2]);
}
}
void CreateObject(string color, string shape)
{
string name = "NewObject_" + counter;
counter += 1;
GameObject NewObject = new GameObject(name);
switch (shape)
{
case "cube":
NewObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
break;
case "sphere":
NewObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
break;
case "cylinder":
NewObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
break;
case "capsule":
NewObject = GameObject.CreatePrimitive(PrimitiveType.Capsule);
break;
}
NewObject.transform.position = new Vector3(0, 5, 0);
NewObject.AddComponent<Rigidbody>();
switch (color)
{
case "red":
NewObject.GetComponent<Renderer>().material.color = Color.red;
break;
case "yellow":
NewObject.GetComponent<Renderer>().material.color = Color.yellow;
break;
case "green":
NewObject.GetComponent<Renderer>().material.color = Color.green;
break;
case "blue":
NewObject.GetComponent<Renderer>().material.color = Color.blue;
break;
case "black":
NewObject.GetComponent<Renderer>().material.color = Color.black;
break;
case "white":
NewObject.GetComponent<Renderer>().material.color = Color.white;
break;
}
}
// Use this for initialization
void Start () {
print("Started webservice import...\n");
StartCoroutine(DownloadWebService());
}
// Update is called once per frame
void Update () {
}
}
There's a bunch of course...so type in "Color" in the filter box...
Choose a name and a description...
You will be presented with a screen where you can upload your source code (which will be doing later on) and an ARN number...which we need for the next step...
The following part deals with create the Alexa skill...so please follow along...and log in here...
{
"intents": [
{
"intent": "GetUnityIntent",
"slots": [
{
"name": "color",
"type": "LITERAL"
},
{
"name": "shape",
"type": "LITERAL"
}
]
},
{
"intent": "HelpIntent",
"slots": []
}
]
}
GetUnityIntent create {red|color} {sphere|shape}
GetUnityIntent create {yellow|color} {sphere|shape}
GetUnityIntent create {green|color} {sphere|shape}
GetUnityIntent create {blue|color} {sphere|shape}
GetUnityIntent create {black|color} {sphere|shape}
GetUnityIntent create {white|color} {sphere|shape}
GetUnityIntent create {red|color} {cube|shape}
GetUnityIntent create {yellow|color} {cube|shape}
GetUnityIntent create {green|color} {cube|shape}
GetUnityIntent create {blue|color} {cube|shape}
GetUnityIntent create {black|color} {cube|shape}
GetUnityIntent create {white|color} {cube|shape}
GetUnityIntent create {red|color} {cylinder|shape}
GetUnityIntent create {yellow|color} {cylinder|shape}
GetUnityIntent create {green|color} {cylinder|shape}
GetUnityIntent create {blue|color} {cylinder|shape}
GetUnityIntent create {black|color} {cylinder|shape}
GetUnityIntent create {white|color} {cylinder|shape}
GetUnityIntent create {red|color} {capsule|shape}
GetUnityIntent create {yellow|color} {capsule|shape}
GetUnityIntent create {green|color} {capsule|shape}
GetUnityIntent create {blue|color} {capsule|shape}
GetUnityIntent create {black|color} {capsule|shape}
GetUnityIntent create {white|color} {capsule|shape}
GetUnityIntent {thank you|color}
sudo npm install --prefix=~/Unity/src request
Then, create a new file called "index.js"
index.js
var request = require("request")
, AlexaSkill = require('./AlexaSkill')
, APP_ID = 'yourappid';
var error = function (err, response, body) {
console.log('ERROR [%s]', err);
};
var getJsonFromUnity = function(color, shape, callback){
var command = "create " + color + " " + shape;
if(color == "thank you"){
callback("thank you");
}
else{
var options = { method: 'GET',
url: 'http://yourapp.herokuapp.com/',
qs: { command: command },
headers:
{ 'postman-token': '230914f7-c478-4f13-32fd-e6593d8db4d1',
'cache-control': 'no-cache' } };
var error_log = "";
request(options, function (error, response, body) {
if (!error) {
error_log = color + " " + shape;
}else{
error_log = "There was a mistake";
}
callback(error_log);
});
}
}
var handleUnityRequest = function(intent, session, response){
getJsonFromUnity(intent.slots.color.value,intent.slots.shape.value, function(data){
if(data != "thank you"){
var text = 'The ' + data + ' has been created';
var reprompt = 'Which shape would you like?';
response.ask(text, reprompt);
}else{
response.tell("You're welcome");
}
});
};
var Unity = function(){
AlexaSkill.call(this, APP_ID);
};
Unity.prototype = Object.create(AlexaSkill.prototype);
Unity.prototype.constructor = Unity;
Unity.prototype.eventHandlers.onSessionStarted = function(sessionStartedRequest, session){
console.log("onSessionStarted requestId: " + sessionStartedRequest.requestId
+ ", sessionId: " + session.sessionId);
};
Unity.prototype.eventHandlers.onLaunch = function(launchRequest, session, response){
// This is when they launch the skill but don't specify what they want.
var output = 'Welcome to Unity. Create any color shape by saying create and providing a color and a shape';
var reprompt = 'Which shape would you like?';
response.ask(output, reprompt);
console.log("onLaunch requestId: " + launchRequest.requestId
+ ", sessionId: " + session.sessionId);
};
Unity.prototype.intentHandlers = {
GetUnityIntent: function(intent, session, response){
handleUnityRequest(intent, session, response);
},
HelpIntent: function(intent, session, response){
var speechOutput = 'Create a new colored shape. Which shape would you like?';
response.ask(speechOutput);
}
};
exports.handler = function(event, context) {
var skill = new Unity();
skill.execute(event, context);
};
And here the action video...
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.