Interactive Unity Cube

by SophieBaptists in Circuits > Arduino

1768 Views, 13 Favorites, 0 Comments

Interactive Unity Cube

IMG_3339.jpg

I made this project for a school assignment. I really liked the idea of making an interactive unity scene, since this would both improve my skills working with an game engine, but would also challenge me with the objective to combine arduino and multiple sensors to create an interesting scene. In the end of the process I was able to create 3 different interactable scenes, where the cube actually felt like it was turned into a controller. I hope that later on I will be able to implement the usage of sensors more subtle in my game designs, since I think it can really add something to immersive gameplay.

Supplies

Banner pic.png

For this design you'll need a couple of products, most of these were ordered online.

  • Arduino Uno
  • Photo cell (photo resistor)
  • MPU 6050 accelerometer gyroscope
  • 3 Leds (Green, Blue, Red)
  • Sound detection sensor Module
  • 3 200Ohm resistors
  • 2 10KOhm resistor
  • 1 Pushbutton
  • 10 15cm male to female jumpercables
  • 10 15cm male to male jumpercables
  • 2 printed circuit boards
  • Arduino uno case
  • 2 Elastic Bands
  • Breadboard

For the lasercutting part you'll need:

  • MDF plate 50cm, 60cm, 4mm
  • Laser cutting machine
  • Wood glue
  • 12 screws 10mm

For soldering:

  • Soldeer Station
  • Iron stand
  • Solder tin
  • Solder Sponge

Connection to unity:

  • Arduino one usb cable
  • Unity installed
  • Arduino installed

Connecting Sensors to Arduino

IMG_2829.jpg
image.png

The function of the sensors and buttons:

  • The button and lights will be connected in this circuit, everytime the button clicks it will rotate through the 3 lights, each light will determine which state the button is in. This will be important later on, since we want our Unity scene to be able to switch between Camera's/Scene's.


  • Photo cell will be used to read out the real time light values. We can use this to adjust the lighting in our unity scene based on how the player will use the interactable cube.


  • Sound sensor will also be used to read out the loudness of input, in the unity scene we have multiple ways to make use of these values. We can use sound to shoot lightbeams or create particle effects.


  • Gyroscope the gyroscope will give the player the function to move our cube and make it look around in our unity scene. It will impact the rotation of the camera.

To start off we want to make sure that all sensors that we will use in te circuit will be working well and can be individually called on in the arduino code. At this point in my project I hadn't connected the Gyroscope yet, but I will include a picture that has the right wiring circuit for all the sensors before putting it to use in code.

Make sure to follow the example of the schemetics pictures from above and connect everything to the breadboard and to the Arduino Uno.

Once everything is connected you can connect your arduino to your laptop by using the USB cable. If you build everything well some sensors will have some lights that will already light up as you can see in the picture where the arduino is connected to my laptop.

Once this step is finished you'll be able to move on to the next. We'll implement the code and see if everything will work smoothly together.

Uploading Code to Arduino

Screenshot 2023-05-02 184820.png

It's important for you to download multiple libraries you can see in the image above. Add those to your arduino project libraries. I've used the code you can see underneath this text. The code will read out multiple sensors by using the pins in arduino. By reading out the values and assigning them to an int, we will be able to write all the outputs in one string and send them through the serial port to Unity. You can copy paste this into your own arduino file/project.



// constants won't change. They're used here to set pin numbers:
#include
#include
#include

Adafruit_MPU6050 mpu;

const int buttonPin = 4; // the number of the pushbutton digital pin

const int ledPin = 13; // the number of the LED pin
const int ledPin1 = 12;
const int ledPin2 = 11;
const int LDRpin = 0;
const int soundPin=A1;

// variables will change:
int LDRValue = 0; // result of reading the analog pin
int initial = 1; //hold current initial
int oldstate = 0; //hold last initial
int buttonstate = 0; // variable for reading the pushbutton status

void setup() {
pinMode(ledPin, OUTPUT); // initialize the LED pin as an output:
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(buttonPin, INPUT); // initialize the pushbutton pin as an input:
Serial.begin(9600); // sets serial port for communication
// Try to initialize!
if (!mpu.begin()) {
Serial.println("Failed to find MPU6050 chip");
while (1) {
delay(10);
}
}

mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_5_HZ);

}
void loop(){
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);

long sum = 0;
for(int i=0; i<100; i++)
{
sum += analogRead(soundPin);
}

sum = sum/100;

//Serial.println(sum);
//Serial.println((String)"Sound = "+sum);


LDRValue = analogRead(LDRpin); // read the value from the LDR
//Serial.println(LDRValue); // print the value to the serial port
//Serial.println((String)"Light = "+LDRValue);

//debouncing routline to read button
buttonstate = digitalRead(buttonPin); //state the initial of button
if(buttonstate == HIGH){ //check if it has been pressed
delay(50);
buttonstate = digitalRead(buttonPin);//state button again
if(buttonstate == LOW){
if(initial == 3) {
initial = 1;
}
else{ //if it is 0 considered one press
initial = oldstate + 1;
} //increase initial by 1
}
}else{ //check if it has been NOT pressed
delay(100);
}
switch (initial){ //react to button press a initial
case 1: //if initial is 1
digitalWrite(ledPin, HIGH);//on
digitalWrite(ledPin1, LOW);//off
digitalWrite(ledPin2, LOW);//off
oldstate = initial; //set oldstate initial as current initial
break;
case 2:
digitalWrite(ledPin, LOW);
digitalWrite(ledPin1, HIGH);
digitalWrite(ledPin2, LOW);
oldstate = initial;
break;
case 3:
digitalWrite(ledPin, LOW);
digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, HIGH);
oldstate = initial;
break;
default: //if initial is not 1 2 3
digitalWrite(ledPin, LOW); //off
digitalWrite(ledPin1, LOW);
digitalWrite(ledPin2, LOW);
oldstate = 0; //reset to all off/initial 0
break;
}
//string to send serial port data to unity using recognition tags so we can read them out in UNITY
Serial.println((String) "S:" + sum + ":S" + " L:" + LDRValue + ":L" + " B:" + initial + ":B" + " RX:" + g.gyro.x + ":RX" + " RY:" + g.gyro.y + ":RY" + " RZ:" + g.gyro.z + ":RZ" + " AX:" + a.acceleration.x + ":AX" + " AY:" + a.acceleration.y + ":AY");
}

Soldering

IMG_3142.jpg
IMG_2839.jpg
image.png

Follow the schematics above for the soldering. It's important that you make your wires long enough to reach the arduino. You only have to solder the wires that are connected to the breadboard, only now you will replace the breadboard by 2 printed circuit boards you can see in the image above.

Tips when soldering:

-Make sure after you stripped your wires that you tin it well, for me it broke apart multiple times when I didn't do this.

You can use this link in case you have no experience with soldering:

https://www.youtube.com/watch?v=Qps9woUGkvI

Lasercutting Case

Screenshot 2023-05-12 123623.png
IMG_3145.jpg

To make sure the casing of the project will look nice we will use a lasercutting machine. For my design I wanted to have a cube that is easy to hold so not too big for one hand. To make a vector drawing I used the program Inkscape, which can be downloaded from the internet online. In the picture above you can see the template I made I will also attach the Inkscape file itself. For laser cutting make sure you safe it as a the right file (in my case this was .dxf).

Use the right size MDF plate, 50cm, 60cm, 4mm. This has been noted in the material list.

!Only the text and camera in the picture should be engraved, the rest should be fully cut out!

Lasercut the materials. In the second photo u can see my first design. Only this one was slightly to small. Make sure you use the file attached, and the WxLxH of the box should be 11cm x 11cm x 11 cm in total.

Make sure to safe the waste materials as we will use this later on when building our arduino into the casing.

Downloads

Put the Casing Together

IMG_3339.jpg
IMG_3326.jpg
IMG_3340.jpg
IMG_3341.jpg
IMG_3342.jpg
IMG_3343.jpg
IMG_3344.jpg

For this step we will glue the box partly together and install the printed plates to the box plates by using screws.

First its important you screw the printed plates to the right box side. Make sure the lightsensor is visible from the other side of the box plate, so you're sure it will catch light. Also screw the gyroscope to the back box part since this is the right placement for how the box is held. Then glue all the parts of the box together, EXCEPT the top part and the behind part. (So the one with the camera drawing and the one with the leds on top should not be glued!)

Then with the reserve waste parts we will glue 2 small plates on top of each other ( 7cm x 5cm). Once the glue is dried screw the arduino casing onto the small plate that has now a thickness of 2x4mm (8mm total). Then install the arduino in the casing. Make sure when gluing the bottom wood part with the arduino you make sure that the part where the cable needs to put in can be reached through the hole underneath the camera engraving.

Then with the 4 tiny blocks we printed we will make a system with elastics that can hold the box together while we are not trying to access the inside. Glue two of the tiny blocks on the top plate of the box (view the reference photo's) and the other 2 blocks on the bottom plate of the box (again view reference photo's).

Then glue the top part of the top plate of the box in the right place, so the gap is around the button and the leds are still visible.

After this dries you can put the top part and back part on the box and use 2 elastics to hold it together.

Now you can put all the wires in the right arduino pins, also make sure you put the sound sensor in the round hole in the middle of the other holes. If it's not a perfect fit then make sure to use wood file and vile till it fits.

Eventually it should look like the reference pictures.


Connecting Arduino to Unity

yaw-pitch-roll-1024x579.jpg
IMG_3345.jpg

In this step we will send the information that arduino reads out in the serial port and have Unity read this information out. We will have to create a new Unity project, once loaded add a new script. For this we will need the following base code:

Make sure after you safe your script. To put the script on an empty object and assign a camera and rotation speed.

If you play the scene you should be able to read the values in the UI and your camera should also be able to rotate over the Y-Axis. You're able to make the camera rotate because of using the Gyroscope, the gyroscope has the function to use the Roll, Pitch Yaw. As you will be able to see in the picture above. We will only make use of the Yaw function so the player can look around and rotate in the Y axis.

Make sure you have uploaded the arduino code to your arduino, Also make sure that once you play the unity scene you have the serial port in the arduino program closed!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;
using System.IO;
using System;
using System.Threading;
using System.Net.Http.Headers;
using Unity.VisualScripting;
using System.Diagnostics.Eventing.Reader;
using UnityEngine.VFX;
using UnityEngine.UIElements;


public class ManageArduino : MonoBehaviour
{
    private Thread thread1;
    public static SerialPort serialPort = new SerialPort("COM5", 9600);
    public static int buttonState = 0;
    int lastButtonState = 0;
    public static int soundValue = 0;
    public static int lightValue = 0;
    public static Vector3 rotation;
    public static Vector2 acceleration;
    public Transform cameraVision;
    public float rotateSpeed;
    float intensityLight;


    private void Start()
    {
        //Opent de waarden Serial Port
        //ThreadWork.m_SerialPort = new SerialPort("COM5", 9600);


        thread1 = new Thread(ReadSerialData);
        thread1.Start();
        
    }


    private void Update()
    {


        float gyroX = rotation.x * Mathf.Rad2Deg * Time.deltaTime;
        float gyroY = rotation.y * Mathf.Rad2Deg * Time.deltaTime;
        float gyroZ = rotation.z * Mathf.Rad2Deg * Time.deltaTime;


        // cameraVision.Rotate(0, gyroY * rotateSpeed * -1, 0);
        Debug.Log(gyroY);

        cameraVision.Rotate(0, gyroY*-1, 0);     
        
    }


    public static void ReadSerialData()
    {
        serialPort.Open();
        serialPort.DiscardInBuffer();
        while (true)
        {
            string value = serialPort.ReadLine(); //lees informatie uit


            if (value.Contains("B:"))
            {
                int length = value.IndexOf(":B") - value.IndexOf("B:");
                String temp = value.Substring(value.IndexOf("B:"), length);
                String result = temp.Trim('B', ':');
                buttonState = int.Parse(result);
                //buttonState = int.Parse(temp);
            }


            if (value.Contains("S:"))
            {
                int length = value.IndexOf(":S") - value.IndexOf("S:");
                String temp = value.Substring(value.IndexOf("S:"), length);
                String result = temp.Trim('S', ':');
                soundValue = int.Parse(result);
                //buttonState = int.Parse(temp);
            }


            if (value.Contains("L:"))
            {
                int length = value.IndexOf(":L") - value.IndexOf("L:");
                String temp = value.Substring(value.IndexOf("L:"), length);
                String result = temp.Trim('L', ':');
                lightValue = int.Parse(result);
                //buttonState = int.Parse(temp);
            }
            if (value.Contains("RX:"))
            {
                int length = value.IndexOf(":RX") - value.IndexOf("RX:");
                String temp = value.Substring(value.IndexOf("RX:"), length);
                String result = temp.Trim('R','X', ':');
                rotation.x = float.Parse(result);
                //buttonState = int.Parse(temp);
            }
            if (value.Contains("RY:"))
            {
                int length = value.IndexOf(":RY") - value.IndexOf("RY:");
                String temp = value.Substring(value.IndexOf("RY:"), length);
                String result = temp.Trim('R', 'Y', ':');
                rotation.y = float.Parse(result);
                //buttonState = int.Parse(temp);
            }
            if (value.Contains("RZ:"))
            {
                int length = value.IndexOf(":RZ") - value.IndexOf("RZ:");
                String temp = value.Substring(value.IndexOf("RZ:"), length);
                String result = temp.Trim('R', 'Z', ':');
                rotation.z = float.Parse(result);
                //buttonState = int.Parse(temp);
            }
            if (value.Contains("AX:"))
            {
                int length = value.IndexOf(":AX") - value.IndexOf("AX:");
                String temp = value.Substring(value.IndexOf("AX:"), length);
                String result = temp.Trim('A','X', ':');
                acceleration.x = float.Parse(result);
                //buttonState = int.Parse(temp);
            }
            if (value.Contains("AY:"))
            {
                int length = value.IndexOf(":AY") - value.IndexOf("AY:");
                String temp = value.Substring(value.IndexOf("AY:"), length);
                String result = temp.Trim('A', 'Y', ':');
                acceleration.y = float.Parse(result);
                //buttonState = int.Parse(temp);
            }


        }
    }
        private void OnDestroy()
    {
        serialPort.Close();
        thread1.Abort();
    }


    private void OnGUI()
    {
        string newString = "Connected: " + buttonState + " Sound:" + soundValue + " Light:" + lightValue + " Rotation:" + rotation + " Acceleration:" + acceleration;
        GUI.Label(new Rect(10, 10, 300, 100), newString); // Display waarden
    }
}


Making Scene Interactable

You'll now be able to use the values to your liking. You can play with the buttonstate, soundvalue and lightvalues. By using tresholds you can determine when you'd like an effect to happen or not. I will give you the example on how I implemented it in my own scene and give you the code. The process will be shown in the next steps.

Adding Multiple Views (with Camera)

Screenshot 2023-05-12 115336.png
Screenshot 2023-05-12 115416.png
Screenshot 2023-05-12 115504.png
Screenshot 2023-05-12 115535.png
Screenshot 2023-05-12 120536.png

I started off by building 3 different area's that each had a different camera. I used assets from the Unity assets store to distinguish them and give them each an individual feel.

I wanted each scene to have a different interactable function based on the input we give in the arduino box.

Nature scene:

  • Blow bubbles by using the sound input, which value is in Decibels. (If soundinput > soundTreshold)
  • When the light detector detects less light I want the scene to turn dark.
  • If the light detector has low values and makes the scene dark, I want instead of blowing bubbles with the sound input to make it show lightning.

Church scene:

  • I want the candles to go out when the light sensor detects less light.
  • When the scene keeps detecting low light, I want by using sound input for the statues eyes to glow up.

Training dummy scene:

  • I want the training dummy scene to have the ability to fire bolts by using sound loudness input.

(if soundinput > soundTreshold, there will fire a bolt from te center of the camera)

  • When you adjust the light value to low with your hand and use sound input again, I want the attack to turn into a big range attack that blows all 3 training dummies to the ground.

Creating Particle System

It's important that after you build the scene, you create the particle effects, shaders and lightobjects you want to trigger to your liking. Make sure to give them all adjustable or public variables so those can be adjusted in code, using the values of the sensor.

Making Scene's Interactable

Screenshot 2023-05-12 132749.png
Screenshot 2023-05-12 132835.png
Screenshot 2023-05-12 132920.png
Screenshot 2023-05-12 132953.png
Screenshot 2023-05-12 133020.png
Screenshot 2023-05-12 134543.png

To change the scene's we will make use of the button states, which we assign to the led states. By switching through the button states we will switch through the 3 camera's. So each led will represent a different camera. You will be able to find the code underneath this explanation.

To make use of the sound loudness input we will create a variable that is the soundTreshold. This will determine how loud someone needs to scream or talk into the box in order to trigger an event.

We will do a similar thing with the light values. We create a light treshold, when the light value goes below a certain value it will also trigger an event in the scene.

I only want all of the different effects to only work with the assigned camera's so we will make sure to work with our if statements within the buttonstate, since those represent the different cameras. You can see this in the code below.

I used a lot of public objects, make sure that if you want to use the same, you assign all the objects and visual effects you made to the right public objects in the scene. You can see this in the example picture, shown above.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;
using System.IO;
using System;
using System.Threading;
using System.Net.Http.Headers;
using Unity.VisualScripting;
using System.Diagnostics.Eventing.Reader;
using UnityEngine.VFX;
using UnityEngine.UIElements;


public class ManageArduino : MonoBehaviour
{
    private Thread thread1;


    public Material SkyBox1;
    public Material SkyBox2;


    public Material boevenLicht;
    public Material boevenDonker;


    public Transform bulletPrefab;
    public ParticleSystem bubbles;
    public Transform cameraNature;
    public Transform cameraChurch;
    public Transform cameraTurrets;


    public GameObject directionalLight;
    public GameObject daySounds;
    public GameObject nightSounds;
    public GameObject lightTurrets;
    public VisualEffect lightning;
    public GameObject churchLights;
    public GameObject demonEyes;
    public GameObject areaLightin;
    public GameObject bigAttack;


    public int lightTreshold;
    public float soundTreshold;
    public static SerialPort serialPort = new SerialPort("COM5", 9600);
    public static int buttonState = 0;
    int lastButtonState = 0;
    public static int soundValue = 0;
    public static int lightValue = 0;
    public static Vector3 rotation;
    public static Vector2 acceleration;
    public Transform cameraVision;
    public float rotateSpeed;
    public float fireRate;
    float intensityLight;
    float fireRateTimer;
    float attackTimer = 0;
    float dissapearTimer = 1;
    public List<GameObject> listBoeven;


    bool canFire = false;
    bool hasFired = false;
    private void Start()
    {
        //Opent de waarden Serial Port
        //ThreadWork.m_SerialPort = new SerialPort("COM5", 9600);


        thread1 = new Thread(ReadSerialData);
        thread1.Start();
        bigAttack.SetActive(false);
        
    }


    private void Update()
    {


        float gyroX = rotation.x * Mathf.Rad2Deg * Time.deltaTime;
        float gyroY = rotation.y * Mathf.Rad2Deg * Time.deltaTime;
        float gyroZ = rotation.z * Mathf.Rad2Deg * Time.deltaTime;


        // cameraVision.Rotate(0, gyroY * rotateSpeed * -1, 0);
        Debug.Log(gyroY);


        intensityLight -= Time.deltaTime;
        if(intensityLight<=0)
        {
            intensityLight = 0;
        }


        //makes sure the gyro does not get any off set when held still
        if (Mathf.Abs(gyroY)<0.09f)
        {
            gyroY = 0;
        }
        cameraVision.Rotate(0, gyroY*-1, 0);


        if (buttonState != lastButtonState)
        {
            lastButtonState = buttonState;
            Debug.Log(lastButtonState);
            buttonEvents();
        }

//camera 1 active
        if (buttonState == 1)
        {
            daySounds.SetActive(true);
            lightTurrets.SetActive(false);


            if (lightValue < lightTreshold)
            {
                RenderSettings.skybox = SkyBox2; //activates different lightbox
                directionalLight.SetActive(false); //turn off directional light
                daySounds.SetActive(false); //changes sound
                nightSounds.SetActive(true);
                DynamicGI.UpdateEnvironment(); //updates environmental light


                if(soundValue > soundTreshold)
                {
                    lightning.SetFloat("SpawnRate", 40); //spawn lightning with sound input
                }
                else
                {
                    lightning.SetFloat("SpawnRate", 0);
                }
                var emission = bubbles.emission;
                emission.rateOverTime = 0;


            }
            else
            {
                RenderSettings.skybox = SkyBox1;
                directionalLight.SetActive(true);
                daySounds.SetActive(true);
                nightSounds.SetActive(false);
                lightning.SetFloat("SpawnRate", 0);
                DynamicGI.UpdateEnvironment();


                if (soundValue > soundTreshold)
                {
                    var emission = bubbles.emission;
                    emission.rateOverTime = 10f;
                }
                else
                {
                    var emission = bubbles.emission; //spawn bubbles with sound input
                    emission.rateOverTime = 0;


                }


            }
        }

//camera 2 active
        if (buttonState == 2)
        {
            if (lightValue < lightTreshold)
            {
                RenderSettings.skybox = SkyBox2;
                churchLights.SetActive(false);
                demonEyes.SetActive(true); //light up demon eyes with sound input
                DynamicGI.UpdateEnvironment();


                demonEyes.GetComponent<Light>().intensity = intensityLight;
                areaLightin.GetComponent<Light>().intensity = intensityLight;
                demonEyes.transform.GetChild(0).GetComponent<Light>().intensity = intensityLight;


                if (soundValue>soundTreshold)
                {
                    intensityLight += 2 * Time.deltaTime;
                }


            }


            else
            {
                RenderSettings.skybox = SkyBox1;
                churchLights.SetActive(true);
                demonEyes.SetActive(false);
                DynamicGI.UpdateEnvironment();
            }
        }

//camera 3 active
        if (buttonState == 3)
        {
            attackTimer -= Time.deltaTime;
            lightTurrets.SetActive(true);


            if (lightValue < lightTreshold)
            {
                if (soundValue > soundTreshold && attackTimer < 0)
                {
                    bigAttack.SetActive(true); //spawn erea of attack vfx
                    attackTimer = 5;
                    hasFired = true;
                }
                foreach (var boef in listBoeven)
                {
                    boef.GetComponent<Renderer>().material = boevenDonker;
                }
                lightTurrets.SetActive(false);


            }
            else
            {
                if (soundValue > soundTreshold)
                {
                    Shoot();
                }


                foreach (var boef in listBoeven)
                {
                    boef.GetComponent<Renderer>().material = boevenLicht;
                }
                lightTurrets.SetActive(true);
            }
        }


        if (hasFired)
        {
//timer to see if you can fire again (cooldown)
            dissapearTimer -= Time.deltaTime;
            if (dissapearTimer < 0)
            {
                bigAttack.SetActive(false);
                hasFired = false;
                dissapearTimer = 1;
            }
        }
        
    }

//shoot bolts
    public void Shoot()
    {
        if (Time.time >= fireRateTimer + fireRate)
        {
            Transform bullet = Instantiate(bulletPrefab, cameraVision.position, cameraVision.rotation);
            Rigidbody rigidbody = bullet.GetComponent<Rigidbody>();
            rigidbody.velocity = cameraVision.forward * 12;
            fireRateTimer = Time.time;
        }
    }

//assign button state to the right camera
    public void buttonEvents()
    {
        switch (buttonState)
        {
            case 1:
                cameraVision.gameObject.SetActive(false);
                cameraVision = cameraNature;
                cameraVision.gameObject.SetActive(true);
                break;


            case 2:
                cameraVision.gameObject.SetActive(false);
                cameraVision = cameraChurch;
                cameraVision.gameObject.SetActive(true);
                break;


            case 3:
                cameraVision.gameObject.SetActive(false);
                cameraVision = cameraTurrets;
                cameraVision.gameObject.SetActive(true);
                break;


        }
    }


    public static void ReadSerialData()
    {
        serialPort.Open();
        serialPort.DiscardInBuffer();
        while (true)
        {
            string value = serialPort.ReadLine(); //lees informatie uit


            if (value.Contains("B:"))
            {
                int length = value.IndexOf(":B") - value.IndexOf("B:");
                String temp = value.Substring(value.IndexOf("B:"), length);
                String result = temp.Trim('B', ':');
                buttonState = int.Parse(result);
                //buttonState = int.Parse(temp);
            }


            if (value.Contains("S:"))
            {
                int length = value.IndexOf(":S") - value.IndexOf("S:");
                String temp = value.Substring(value.IndexOf("S:"), length);
                String result = temp.Trim('S', ':');
                soundValue = int.Parse(result);
                //buttonState = int.Parse(temp);
            }


            if (value.Contains("L:"))
            {
                int length = value.IndexOf(":L") - value.IndexOf("L:");
                String temp = value.Substring(value.IndexOf("L:"), length);
                String result = temp.Trim('L', ':');
                lightValue = int.Parse(result);
                //buttonState = int.Parse(temp);
            }
            if (value.Contains("RX:"))
            {
                int length = value.IndexOf(":RX") - value.IndexOf("RX:");
                String temp = value.Substring(value.IndexOf("RX:"), length);
                String result = temp.Trim('R','X', ':');
                rotation.x = float.Parse(result);
                //buttonState = int.Parse(temp);
            }
            if (value.Contains("RY:"))
            {
                int length = value.IndexOf(":RY") - value.IndexOf("RY:");
                String temp = value.Substring(value.IndexOf("RY:"), length);
                String result = temp.Trim('R', 'Y', ':');
                rotation.y = float.Parse(result);
                //buttonState = int.Parse(temp);
            }
            if (value.Contains("RZ:"))
            {
                int length = value.IndexOf(":RZ") - value.IndexOf("RZ:");
                String temp = value.Substring(value.IndexOf("RZ:"), length);
                String result = temp.Trim('R', 'Z', ':');
                rotation.z = float.Parse(result);
                //buttonState = int.Parse(temp);
            }
            if (value.Contains("AX:"))
            {
                int length = value.IndexOf(":AX") - value.IndexOf("AX:");
                String temp = value.Substring(value.IndexOf("AX:"), length);
                String result = temp.Trim('A','X', ':');
                acceleration.x = float.Parse(result);
                //buttonState = int.Parse(temp);
            }
            if (value.Contains("AY:"))
            {
                int length = value.IndexOf(":AY") - value.IndexOf("AY:");
                String temp = value.Substring(value.IndexOf("AY:"), length);
                String result = temp.Trim('A', 'Y', ':');
                acceleration.y = float.Parse(result);
                //buttonState = int.Parse(temp);
            }


        }
    }
        private void OnDestroy()
    {
        serialPort.Close();
        thread1.Abort();
    }


    private void OnGUI()
    {
        string newString = "Connected: " + buttonState + " Sound:" + soundValue + " Light:" + lightValue + " Rotation:" + rotation + " Acceleration:" + acceleration;
        GUI.Label(new Rect(10, 10, 300, 100), newString); // Display waarden
    }
}

Have Fun and Play

IMG_3346.jpg

:D

Future Adjustments & Improvements

There are multiple things I noticed throughout the process of making this interactable unity cube that can be improved on. 


Firstly it would be nice in a newer design to let unity communicate back to the arduino as well. This way the player can receive more visual feedback in the cube that it’s holding. 


Secondly I think the design of the cube and the placement of the sensors can also be better. Sometimes you accidentally trigger an effect when you try to grab or turn the cube in your hand that is not wished for. The same counts for the offset the Gyroscoop gives, but this is almost impossible to prevent since the sensor is simply not optimal. 


Overall I am really happy I got this module in school. I think I gained an interesting set of skills that can really improve my designs in future prototypes or design for player’s immersion and usability in games. I learned that a physical element outside our laptop’s can enhance your experience and also can be very fun to do.