WorldCursor.csusing UnityEngine;publicclass WorldCursor : MonoBehaviour
{private MeshRenderer meshRenderer;// Use this for initializationvoid Start(){// Grab the mesh renderer that's on the same object as this script.meshRenderer = this.gameObject.GetComponentInChildren<MeshRenderer>();}// Update is called once per framevoid Update(){// Do a raycast into the world based on the user's// head position and orientation.var headPosition = Camera.main.transform.position;var gazeDirection = Camera.main.transform.forward;RaycastHit hitInfo;if (Physics.Raycast(headPosition, gazeDirection, out hitInfo)){// If the raycast hit a hologram...// Display the cursor mesh.meshRenderer.enabled = true;// Move the cursor to the point where the raycast hit.this.transform.position = hitInfo.point;// Rotate the cursor to hug the surface of the hologram.this.transform.rotation = Quaternion.FromToRotation(Vector3.up, hitInfo.normal);}else{// If the raycast did not hit a hologram, hide the cursor mesh.meshRenderer.enabled = false;}}
}WorldCursor
GazeGestureManager.csusing UnityEngine;
using UnityEngine.VR.WSA.Input;publicclass GazeGestureManager : MonoBehaviour
{publicstatic GazeGestureManager Instance { get; privateset; }// Represents the hologram that is currently being gazed at.public GameObject FocusedObject { get; privateset; }GestureRecognizer recognizer;// Use this for initializationvoid Awake(){Instance = this;// Set up a GestureRecognizer to detect Select gestures.recognizer = new GestureRecognizer();recognizer.TappedEvent += (source, tapCount, ray) =>{// Send an OnSelect message to the focused object and its ancestors.if (FocusedObject != null){FocusedObject.SendMessageUpwards("OnSelect");}};recognizer.StartCapturingGestures();}// Update is called once per framevoid Update(){// Figure out which hologram is focused this frame.GameObject oldFocusObject = FocusedObject;// Do a raycast into the world based on the user's// head position and orientation.var headPosition = Camera.main.transform.position;var gazeDirection = Camera.main.transform.forward;RaycastHit hitInfo;if (Physics.Raycast(headPosition, gazeDirection, out hitInfo)){// If the raycast hit a hologram, use that as the focused object.FocusedObject = hitInfo.collider.gameObject;}else{// If the raycast did not hit a hologram, clear the focused object.FocusedObject = null;}// If the focused object changed this frame,// start detecting fresh gestures again.if (FocusedObject != oldFocusObject){recognizer.CancelGestures();recognizer.StartCapturingGestures();}}
}GazeGestureManager
?在Scripts 文件夾下創(chuàng)建一個新的腳本命名為 SphereCommands.
?展開Hierarchy面板中的OrigamiCollection 對象.
?拖拽SphereCommands 腳本到 Sphere1 對象上.
?拖拽SphereCommands 腳本到 Sphere2 對象上.
用VS打開這個腳本并編輯,將以下代碼復(fù)制粘貼到其中:
SphereCommands.csusing UnityEngine;publicclass SphereCommands : MonoBehaviour
{// Called by GazeGestureManager when the user performs a Select gesturevoid OnSelect(){// If the sphere has no Rigidbody component, add one to enable physics.if (!this.GetComponent<Rigidbody>()){var rigidbody = this.gameObject.AddComponent<Rigidbody>();rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous;}}
}SphereCommands
SpeechManager.csusing System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Windows.Speech;publicclass SpeechManager : MonoBehaviour
{KeywordRecognizer keywordRecognizer = null;Dictionary<string, System.Action> keywords = new Dictionary<string, System.Action>();// Use this for initializationvoid Start(){keywords.Add("Reset world", () =>{// Call the OnReset method on every descendant object.this.BroadcastMessage("OnReset");});keywords.Add("Drop Sphere", () =>{var focusObject = GazeGestureManager.Instance.FocusedObject;if (focusObject != null){// Call the OnDrop method on just the focused object.focusObject.SendMessage("OnDrop");}});// Tell the KeywordRecognizer about our keywords.keywordRecognizer = new KeywordRecognizer(keywords.Keys.ToArray());// Register a callback for the KeywordRecognizer and start recognizing!keywordRecognizer.OnPhraseRecognized += KeywordRecognizer_OnPhraseRecognized;keywordRecognizer.Start();}privatevoid KeywordRecognizer_OnPhraseRecognized(PhraseRecognizedEventArgs args){System.Action keywordAction;if (keywords.TryGetValue(args.text, out keywordAction)){keywordAction.Invoke();}}
}SpeechManager
?用VS打開SphereCommands 腳本.
更新為如下代碼:
SphereCommands.csusing UnityEngine;publicclass SphereCommands : MonoBehaviour
{Vector3 originalPosition;// Use this for initializationvoid Start(){// Grab the original local position of the sphere when the app starts.originalPosition = this.transform.localPosition;}// Called by GazeGestureManager when the user performs a Select gesturevoid OnSelect(){// If the sphere has no Rigidbody component, add one to enable physics.if (!this.GetComponent<Rigidbody>()){var rigidbody = this.gameObject.AddComponent<Rigidbody>();rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous;}}// Called by SpeechManager when the user says the "Reset world" commandvoid OnReset(){// If the sphere has a Rigidbody component, remove it to disable physics.var rigidbody = this.GetComponent<Rigidbody>();if (rigidbody != null){DestroyImmediate(rigidbody);}// Put the sphere back into its original local position.this.transform.localPosition = originalPosition;}// Called by SpeechManager when the user says the "Drop sphere" commandvoid OnDrop(){// Just do the same logic as a Select gesture. OnSelect();}
}SphereCommands
SphereSounds.csusing UnityEngine;publicclass SphereSounds : MonoBehaviour
{AudioSource audioSource = null;AudioClip impactClip = null;AudioClip rollingClip = null;bool rolling = false;void Start(){// Add an AudioSource component and set up some defaultsaudioSource = gameObject.AddComponent<AudioSource>();audioSource.playOnAwake = false;audioSource.spatialize = true;audioSource.spatialBlend = 1.0f;audioSource.dopplerLevel = 0.0f;audioSource.rolloffMode = AudioRolloffMode.Custom;// Load the Sphere sounds from the Resources folderimpactClip = Resources.Load<AudioClip>("Impact");rollingClip = Resources.Load<AudioClip>("Rolling");}// Occurs when this object starts colliding with another objectvoid OnCollisionEnter(Collision collision){// Play an impact sound if the sphere impacts strongly enough.if (collision.relativeVelocity.magnitude >= 0.1f){audioSource.clip = impactClip;audioSource.Play();}}// Occurs each frame that this object continues to collide with another objectvoid OnCollisionStay(Collision collision){Rigidbody rigid = this.gameObject.GetComponent<Rigidbody>();// Play a rolling sound if the sphere is rolling fast enough.if (!rolling && rigid.velocity.magnitude >= 0.01f){rolling = true;audioSource.clip = rollingClip;audioSource.Play();}// Stop the rolling sound if rolling slows down.elseif (rolling && rigid.velocity.magnitude < 0.01f){rolling = false;audioSource.Stop();}}// Occurs when this object stops colliding with another objectvoid OnCollisionExit(Collision collision){// Stop the rolling sound if the object falls off and stops colliding.if (rolling){rolling = false;audioSource.Stop();}}
}SphereSounds
TapToPlaceParent.csusing UnityEngine;publicclass TapToPlaceParent : MonoBehaviour
{bool placing = false;// Called by GazeGestureManager when the user performs a Select gesturevoid OnSelect(){// On each Select gesture, toggle whether the user is in placing mode.placing = !placing;// If the user is in placing mode, display the spatial mapping mesh.if (placing){SpatialMapping.Instance.DrawVisualMeshes = true;}// If the user is not in placing mode, hide the spatial mapping mesh.else{SpatialMapping.Instance.DrawVisualMeshes = false;}}// Update is called once per framevoid Update(){// If the user is in placing mode,// update the placement to match the user's gaze.if (placing){// Do a raycast into the world that will only hit the Spatial Mapping mesh.var headPosition = Camera.main.transform.position;var gazeDirection = Camera.main.transform.forward;RaycastHit hitInfo;if (Physics.Raycast(headPosition, gazeDirection, out hitInfo,30.0f, SpatialMapping.PhysicsRaycastMask)){// Move this object's parent object to// where the raycast hit the Spatial Mapping mesh.this.transform.parent.position = hitInfo.point;// Rotate this object's parent object to face the user.Quaternion toQuat = Camera.main.transform.localRotation;toQuat.x = 0;toQuat.z = 0;this.transform.parent.rotation = toQuat;}}}
} TapToPlaceParent
HitTarget.csusing UnityEngine;publicclass HitTarget : MonoBehaviour
{// These public fields become settable properties in the Unity editor.public GameObject underworld;public GameObject objectToHide;// Occurs when this object starts colliding with another objectvoid OnCollisionEnter(Collision collision){// Hide the stage and show the underworld.objectToHide.SetActive(false);underworld.SetActive(true);// Disable Spatial Mapping to let the spheres enter the underworld.SpatialMapping.Instance.MappingEnabled = false;}
}HitTarget
在Unity, 選擇 Target 對象.
在 Hit Target?組件中可見兩個公共屬性, 需要引用場景中的對象:
拖拽Hierarchy 面板下的 Underworld 對象到 Hit Target 組件下的 Underworld 屬性中.
拖拽Hierarchy 面板下的 Stage對象到 Hit Target 組件下的?Object to Hide屬性中。