Code Samples

GyroMoveObject
(Unity script for using the gyroscope on mobile devices to move an object around a constrained space)

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(Rigidbody))]
public class GyroMoveObject : MonoBehaviour {

bool isGyroEnabled;
bool canUseGyro = false;

Gyroscope gyro;

// Common gyro properties
[FloatSliderInInspector(0.1f, 2.0f)]
[InspectorTooltip("How much the gyro affects object's position.\nHigh sensitivity requires less tilting, low sensitivity requires more tilting.")]
public float sensitivity = 0.5f; // By how much the gyro affects the object's movement

[FloatSliderInInspector(0.1f, 10.0f)]
[InspectorTooltip("Max speed the object can move.")]
public float maxSpeed = 4f; // By how much the object moves

Vector2 velocity;
Vector3 initialGyroAccel;

[FloatSliderInInspector(0.05f, 1.0f)]
[InspectorTooltip("Highest value that can be read directly from gyro. All greater values clamp to this so as to reduce by how much the device can be tilted.")]
public float maxGyroThreshold = 0.3f; // Max amount gyro can affect position

[InspectorTooltip("Editor Only: Fakes gyroscope input data when in the Editor.")]
public Vector2 editorDirection; // Debug input to fake gyro input in the Editor

// Set true to rotate around a pivot; false to float within a set area
[InspectorTooltip("Set true to rotate around pivot using gyro.\nSet false to move freely within volume.")]
public bool rotateAroundAnchor = false;

Vector3 initRotation;
[ShowInInspectorIfBool("rotateAroundAnchor", true)]
public float minRotateAngle = -20f;
[ShowInInspectorIfBool("rotateAroundAnchor", true)]
public float maxRotateAngle = 20f;

[ShowInInspectorIfBool("rotateAroundAnchor", false)]
[InspectorTooltip("Let object bounce when it approaches edges of Floating Range.")]
public bool canBounce = true;
bool isBouncing = false;

[ShowInInspectorIfBool("rotateAroundAnchor", false)]
[InspectorTooltip("Area that object can float freely within.")]
public Vector2 floatingRange = new Vector2(2f,1.1f);

[ShowInInspectorIfBool("rotateAroundAnchor", false)]
[InspectorTooltip("If object shouldn't start in the Floating Range's center, then use this property.\nMake sure to stay within 'floating range'.")]
public Vector2 startPos; // Where the object actually starts at on the page

[ShowInInspectorIfBool("rotateAroundAnchor", false)]
[FloatSliderInInspector(0.1f, 2.0f)]
[InspectorTooltip("How many seconds bounce lasts.")]
public float bounceDuration = 1f; // How long bounces last
float curBounceTime = 0f;
//Vector3 bounceDirection;

[HideInInspector]
public Vector3 origPos; // Where the bounding box is centered on
[HideInInspector]
public Vector3 origLocalPos;


// Use this for initialization
void Start () {
isGyroEnabled = SystemInfo.supportsGyroscope;

if (isGyroEnabled)
{
gyro = Input.gyro;
gyro.enabled = true;
StartCoroutine(CalibrateGyro());
}

if (origPos == Vector3.zero)
SetupGyro();
/*origPos = transform.position;
origLocalPos = transform.localPosition;

if (rotateAroundAnchor)
{
initRotation = transform.localRotation.eulerAngles;
}*/
}

IEnumerator CalibrateGyro() {
yield return new WaitForSeconds(0.3f);
initialGyroAccel = Vector3.zero;
initialGyroAccel.y = -0.7f;
//Debug.Log("\nInitial Gyro Setting: " + initialGyroAccel);
}


void SetupGyro() {
origPos = transform.position;
origLocalPos = transform.localPosition;

if (rotateAroundAnchor)
{
initRotation = transform.localRotation.eulerAngles;
}
}

// Called from PageNode
void SetupAnimation() {
//if (isGyroEnabled)
//{

if (origPos == Vector3.zero)
SetupGyro();

canUseGyro = true;
transform.position = new Vector3(origPos.x + startPos.x, origPos.y + startPos.y, transform.position.z);
transform.rotation = Quaternion.Euler(initRotation);
//}
}

// Called from PageNode
void StopAllAnimations() {
//if (/*isGyroEnabled &&*/ canUseGyro)
//{
canUseGyro = false;
GetComponent<Rigidbody>().velocity = Vector3.zero;
GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
//}
}


// Called from BookController
void PauseAnimation() {
canUseGyro = false;
GetComponent<Rigidbody>().velocity = Vector3.zero;
GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
}

void FixedUpdate () {
#if UNITY_EDITOR
if (canUseGyro)
#else
if (isGyroEnabled && canUseGyro)
#endif
{
Vector3 direction = GetGyroInput();

#if UNITY_EDITOR
direction = editorDirection;
#endif

if (canBounce && isBouncing)
{
/*if (rotateAroundAnchor)
{
Vector3 torqueDir = new Vector3(0f, 0f, bounceDirection.x * (maxSpeed / 2f));
rigidbody.AddTorque(torqueDir);
}
else
{*/
Vector3 bounceDirection = origLocalPos - transform.localPosition;
bounceDirection.Normalize();
bounceDirection /= 20f;
GetComponent<Rigidbody>().AddForce(bounceDirection * maxSpeed);
//}

curBounceTime += Time.fixedDeltaTime;
if (curBounceTime > bounceDuration)
isBouncing = false;
}
else
{
if (rotateAroundAnchor)
{
direction.x *= -1f;
direction = RotateObject(direction);

Vector3 torqueDir = new Vector3(0f, 0f, direction.x * maxSpeed);
GetComponent<Rigidbody>().AddTorque(torqueDir);
}
else
{
direction = FloatObject(direction);
GetComponent<Rigidbody>().AddForce(direction * maxSpeed);
}
}
}
}

Vector3 GetGyroInput() {
// Get value from gyro
Vector3 dir = Vector3.zero;

dir.x = Mathf.Clamp(Input.acceleration.x * sensitivity, -maxGyroThreshold, maxGyroThreshold);
dir.y = Mathf.Clamp((Input.acceleration.y - initialGyroAccel.y) * sensitivity, -maxGyroThreshold, maxGyroThreshold);
dir.y *= -1f;

return dir;
}

Vector3 FloatObject(Vector3 dir)
{
Vector3 temp = transform.localPosition;
temp += dir;

Vector2 tempRangeX = new Vector2(origLocalPos.x - floatingRange.x, origLocalPos.x + floatingRange.x);
Vector2 tempRangeY = new Vector2(origLocalPos.y - floatingRange.y, origLocalPos.y + floatingRange.y);

// Constrain movement
if (temp.x > tempRangeX.x && temp.x < tempRangeX.y && temp.y > tempRangeY.x && temp.y < tempRangeY.y)
{
return dir;
}
else
{
if (canBounce)
{
isBouncing = true;
curBounceTime = 0f;
Vector3 bounceDirection = dir;

// Determine bounce direction
if (temp.x <= tempRangeX.x)
{
bounceDirection.x *= 1f;
GetComponent<Rigidbody>().velocity = new Vector3(0f, GetComponent<Rigidbody>().velocity.y, 0f);
}
else if (temp.x >= tempRangeX.y)
{
bounceDirection.x *= -1f;
GetComponent<Rigidbody>().velocity = new Vector3(0f, GetComponent<Rigidbody>().velocity.y, 0f);
}

if (temp.y <= tempRangeY.x)
{
bounceDirection.y *= 1f;
GetComponent<Rigidbody>().velocity = new Vector3(GetComponent<Rigidbody>().velocity.x, 0f, 0f);
}
else if (temp.y >= tempRangeY.y)
{
bounceDirection.y *= -1f;
GetComponent<Rigidbody>().velocity = new Vector3(GetComponent<Rigidbody>().velocity.x, 0f, 0f);
}

return bounceDirection;
}
else
{
return Vector3.zero;
}
}
}

Vector3 RotateObject(Vector3 dir)
{
Vector3 tempRot = transform.rotation.eulerAngles;

// Float gradually to origin when not tilted
if (dir.x < 0.05f && dir.x > 0f && tempRot.z > 1f && tempRot.z < maxRotateAngle)
{
dir.x = -0.1f;
return dir;
}
else if (dir.x > -0.05f && dir.x < 0f && tempRot.z < 359f && tempRot.z > 360f + minRotateAngle)
{
dir.x = 0.1f;
return dir;
}

// Clamp to edges if beyond them
if (tempRot.z > maxRotateAngle + 0.1f && tempRot.z < 180f)
{
// Clamp to right side
GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, maxRotateAngle);
return Vector3.zero;
}
else if (tempRot.z < minRotateAngle + 360f && tempRot.z > 180f)
{
// Clamp to left side
GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, minRotateAngle);
return Vector3.zero;
}
else
{
// Slow down movement when approaching edges
if (tempRot.z >= maxRotateAngle - 5f && tempRot.z < maxRotateAngle && dir.x > 0f)
{
// Approaching right edge
if (GetComponent<Rigidbody>().angularVelocity.z > 0f)
dir.x *= -0.5f;
}
else if (tempRot.z <= 365f + minRotateAngle && tempRot.z > 360f + minRotateAngle && dir.x < 0f)
{
// Approaching left edge
if (GetComponent<Rigidbody>().angularVelocity.z < 0f)
dir.x *= -0.5f;
}
else if ((tempRot.z >= maxRotateAngle && tempRot.z < 180f && dir.x > 0f) || (tempRot.z <= 360f + minRotateAngle && tempRot.z > 180f && dir.x < 0f))
return Vector3.zero;

return dir;
}
}

#if UNITY_EDITOR
void OnDrawGizmos() {
if (!rotateAroundAnchor)
{
if (Application.isPlaying)
{
// Draw floating range
if (canUseGyro)
Gizmos.color = new Color(0,1,0,0.25f);
else
Gizmos.color = new Color(0,0,1,0.25f);
Gizmos.DrawCube(origPos, new Vector3(floatingRange.x * 2f, floatingRange.y * 2f, 0.2f));
}
else
{
// Draw floating range
Gizmos.color = new Color(0,1,0,0.25f);
Gizmos.DrawCube(transform.position, new Vector3(floatingRange.x * 2f, floatingRange.y * 2f, 0.2f));

// Draw start position
Gizmos.color = new Color(1, 0, 1, 0.4f);
Gizmos.DrawWireSphere(transform.position + new Vector3(startPos.x, startPos.y, 0f), 0.1f);
}
}
}

void OnDrawGizmosSelected() {
if (!rotateAroundAnchor)
{
/*if (Application.isPlaying)
{
// Draw floating range
Gizmos.color = new Color(0,1,0,0.5f);
Gizmos.DrawCube(origPos, new Vector3(floatingRange.x * 2f, floatingRange.y * 2f, 0.2f));
}
else*/if (!Application.isPlaying)
{
// Draw floating range
Gizmos.color = new Color(0,1,0,0.5f);
Gizmos.DrawCube(transform.position, new Vector3(floatingRange.x * 2f, floatingRange.y * 2f, 0.2f));

// Draw start position
Gizmos.color = new Color(1, 0, 1, 0.75f);
Gizmos.DrawSphere(transform.position + new Vector3(startPos.x, startPos.y, 0f), 0.1f);
}
}
}
#endif

/*void OnGUI() {
if (canUseGyro)
{
GUI.Box(new Rect(10,10,110,90), "Gyro Raw");
if (isGyroEnabled)
{
GUI.Box(new Rect(15,35,100,20), Input.acceleration.x.ToString());
GUI.Box(new Rect(15,55,100,20), Input.acceleration.y.ToString());
//GUI.Box(new Rect(15,75,100,20), Input.acceleration.z.ToString());
}
else
{
GUI.Box(new Rect(15,35,100,20), "0");
GUI.Box(new Rect(15,55,100,20), "0");
GUI.Box(new Rect(15,75,100,20), "0");
}

GUI.Box(new Rect(130,10,110,90), "Gyro");
if (isGyroEnabled)
{
Vector3 dir = GetGyroInput();
GUI.Box(new Rect(135,35,100,20), dir.x.ToString());
GUI.Box(new Rect(135,55,100,20), dir.y.ToString());
}
else
{
GUI.Box(new Rect(135,35,100,20), "0");
GUI.Box(new Rect(135,55,100,20), "0");
GUI.Box(new Rect(135,75,100,20), "0");
}

//GUI.Box(new Rect(10,110,110,70), "Target");
//GUI.Box(new Rect(15,135,100,20), targetPos.x.ToString());
//GUI.Box(new Rect(15,155,100,20), targetPos.y.ToString());

//GUI.Box(new Rect(10,110,110,70), "Velocity");
//GUI.Box(new Rect(15,135,100,20), velocity.x.ToString());
//GUI.Box(new Rect(15,155,100,20), velocity.y.ToString());

//GUI.Box(new Rect(10,210,110,70), "Current Pos");
//GUI.Box(new Rect(15,235,100,20), currentPos.x.ToString());
//GUI.Box(new Rect(15,255,100,20), currentPos.y.ToString());
}
}*/

}