ControllerButtonHints.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. //
  3. // Purpose: Displays text and button hints on the controllers
  4. //
  5. //=============================================================================
  6. using UnityEngine;
  7. using System.Collections;
  8. using System.Collections.Generic;
  9. using UnityEngine.UI;
  10. using System.Text;
  11. namespace Valve.VR.InteractionSystem
  12. {
  13. //-------------------------------------------------------------------------
  14. public class ControllerButtonHints : MonoBehaviour
  15. {
  16. public Material controllerMaterial;
  17. public Material urpControllerMaterial;
  18. public Material usingMaterial
  19. {
  20. get
  21. {
  22. #if UNITY_URP
  23. return urpControllerMaterial;
  24. #else
  25. return controllerMaterial;
  26. #endif
  27. }
  28. }
  29. public Color flashColor = new Color( 1.0f, 0.557f, 0.0f );
  30. public GameObject textHintPrefab;
  31. public SteamVR_Action_Vibration hapticFlash = SteamVR_Input.GetAction<SteamVR_Action_Vibration>("Haptic");
  32. public bool autoSetWithControllerRangeOfMotion = true;
  33. [Header( "Debug" )]
  34. public bool debugHints = false;
  35. private SteamVR_RenderModel renderModel;
  36. private Player player;
  37. private List<MeshRenderer> renderers = new List<MeshRenderer>();
  38. private List<MeshRenderer> flashingRenderers = new List<MeshRenderer>();
  39. private float startTime;
  40. private float tickCount;
  41. private enum OffsetType
  42. {
  43. Up,
  44. Right,
  45. Forward,
  46. Back
  47. }
  48. //Info for each of the buttons
  49. private class ActionHintInfo
  50. {
  51. public string componentName;
  52. public List<MeshRenderer> renderers;
  53. public Transform localTransform;
  54. //Text hint
  55. public GameObject textHintObject;
  56. public Transform textStartAnchor;
  57. public Transform textEndAnchor;
  58. public Vector3 textEndOffsetDir;
  59. public Transform canvasOffset;
  60. public Text text;
  61. public TextMesh textMesh;
  62. public Canvas textCanvas;
  63. public LineRenderer line;
  64. public float distanceFromCenter;
  65. public bool textHintActive = false;
  66. }
  67. private Dictionary<ISteamVR_Action_In_Source, ActionHintInfo> actionHintInfos;
  68. private Transform textHintParent;
  69. private int colorID;
  70. public bool initialized { get; private set; }
  71. private Vector3 centerPosition = Vector3.zero;
  72. SteamVR_Events.Action renderModelLoadedAction;
  73. protected SteamVR_Input_Sources inputSource;
  74. //-------------------------------------------------
  75. void Awake()
  76. {
  77. renderModelLoadedAction = SteamVR_Events.RenderModelLoadedAction( OnRenderModelLoaded );
  78. #if UNITY_URP
  79. colorID = Shader.PropertyToID( "_BaseColor" );
  80. #else
  81. colorID = Shader.PropertyToID( "_Color" );
  82. #endif
  83. }
  84. //-------------------------------------------------
  85. void Start()
  86. {
  87. player = Player.instance;
  88. }
  89. //-------------------------------------------------
  90. private void HintDebugLog( string msg )
  91. {
  92. if ( debugHints )
  93. {
  94. Debug.Log("<b>[SteamVR Interaction]</b> Hints: " + msg );
  95. }
  96. }
  97. //-------------------------------------------------
  98. void OnEnable()
  99. {
  100. renderModelLoadedAction.enabled = true;
  101. }
  102. //-------------------------------------------------
  103. void OnDisable()
  104. {
  105. renderModelLoadedAction.enabled = false;
  106. Clear();
  107. }
  108. //-------------------------------------------------
  109. private void OnParentHandInputFocusLost()
  110. {
  111. //Hide all the hints when the controller is no longer the primary attached object
  112. HideAllButtonHints();
  113. HideAllText();
  114. }
  115. public virtual void SetInputSource(SteamVR_Input_Sources newInputSource)
  116. {
  117. inputSource = newInputSource;
  118. if (renderModel != null)
  119. renderModel.SetInputSource(newInputSource);
  120. }
  121. //-------------------------------------------------
  122. // Gets called when the hand has been initialized and a render model has been set
  123. //-------------------------------------------------
  124. private void OnHandInitialized(int deviceIndex)
  125. {
  126. //Create a new render model for the controller hints
  127. renderModel = new GameObject( "SteamVR_RenderModel" ).AddComponent<SteamVR_RenderModel>();
  128. renderModel.transform.parent = transform;
  129. renderModel.transform.localPosition = Vector3.zero;
  130. renderModel.transform.localRotation = Quaternion.identity;
  131. renderModel.transform.localScale = Vector3.one;
  132. renderModel.SetInputSource(inputSource);
  133. renderModel.SetDeviceIndex(deviceIndex);
  134. if ( !initialized )
  135. {
  136. //The controller hint render model needs to be active to get accurate transforms for all the individual components
  137. renderModel.gameObject.SetActive( true );
  138. }
  139. }
  140. private Dictionary<string, Transform> componentTransformMap = new Dictionary<string, Transform>();
  141. //-------------------------------------------------
  142. void OnRenderModelLoaded(SteamVR_RenderModel renderModel, bool succeess)
  143. {
  144. //Only initialize when the render model for the controller hints has been loaded
  145. if (renderModel == this.renderModel)
  146. {
  147. //Debug.Log("<b>[SteamVR Interaction]</b> OnRenderModelLoaded: " + this.renderModel.renderModelName);
  148. if (initialized)
  149. {
  150. Destroy(textHintParent.gameObject);
  151. componentTransformMap.Clear();
  152. flashingRenderers.Clear();
  153. }
  154. renderModel.SetMeshRendererState(false);
  155. StartCoroutine(DoInitialize(renderModel));
  156. }
  157. }
  158. private IEnumerator DoInitialize(SteamVR_RenderModel renderModel)
  159. {
  160. while (renderModel.initializedAttachPoints == false)
  161. yield return null;
  162. textHintParent = new GameObject("Text Hints").transform;
  163. textHintParent.SetParent(this.transform);
  164. textHintParent.localPosition = Vector3.zero;
  165. textHintParent.localRotation = Quaternion.identity;
  166. textHintParent.localScale = Vector3.one;
  167. //Get the button mask for each component of the render model
  168. var renderModels = OpenVR.RenderModels;
  169. if (renderModels != null)
  170. {
  171. string renderModelDebug = "";
  172. if (debugHints)
  173. renderModelDebug = "Components for render model " + renderModel.index;
  174. for (int childIndex = 0; childIndex < renderModel.transform.childCount; childIndex++)
  175. {
  176. Transform child = renderModel.transform.GetChild(childIndex);
  177. if (componentTransformMap.ContainsKey(child.name))
  178. {
  179. if (debugHints)
  180. renderModelDebug += "\n\t! Child component already exists with name: " + child.name;
  181. }
  182. else
  183. componentTransformMap.Add(child.name, child);
  184. if (debugHints)
  185. renderModelDebug += "\n\t" + child.name + ".";
  186. }
  187. //Uncomment to show the button mask for each component of the render model
  188. HintDebugLog(renderModelDebug);
  189. }
  190. actionHintInfos = new Dictionary<ISteamVR_Action_In_Source, ActionHintInfo>();
  191. for (int actionIndex = 0; actionIndex < SteamVR_Input.actionsNonPoseNonSkeletonIn.Length; actionIndex++)
  192. {
  193. ISteamVR_Action_In action = SteamVR_Input.actionsNonPoseNonSkeletonIn[actionIndex];
  194. if (action.GetActive(inputSource))
  195. CreateAndAddButtonInfo(action, inputSource);
  196. }
  197. ComputeTextEndTransforms();
  198. initialized = true;
  199. //Set the controller hints render model to not active
  200. renderModel.SetMeshRendererState(true);
  201. renderModel.gameObject.SetActive(false);
  202. }
  203. //-------------------------------------------------
  204. private void CreateAndAddButtonInfo(ISteamVR_Action_In action, SteamVR_Input_Sources inputSource)
  205. {
  206. Transform buttonTransform = null;
  207. List<MeshRenderer> buttonRenderers = new List<MeshRenderer>();
  208. StringBuilder buttonDebug = new StringBuilder();
  209. buttonDebug.Append("Looking for action: ");
  210. buttonDebug.AppendLine(action.GetShortName());
  211. buttonDebug.Append("Action localized origin: ");
  212. buttonDebug.AppendLine(action.GetLocalizedOrigin(inputSource));
  213. string actionComponentName = action.GetRenderModelComponentName(inputSource);
  214. if (componentTransformMap.ContainsKey(actionComponentName))
  215. {
  216. buttonDebug.AppendLine(string.Format("Found component: {0} for {1}", actionComponentName, action.GetShortName()));
  217. Transform componentTransform = componentTransformMap[actionComponentName];
  218. buttonTransform = componentTransform;
  219. buttonDebug.AppendLine(string.Format("Found componentTransform: {0}. buttonTransform: {1}", componentTransform, buttonTransform));
  220. buttonRenderers.AddRange(componentTransform.GetComponentsInChildren<MeshRenderer>());
  221. }
  222. else
  223. {
  224. buttonDebug.AppendLine(string.Format("Can't find component transform for action: {0}. Component name: \"{1}\"", action.GetShortName(), actionComponentName));
  225. }
  226. buttonDebug.AppendLine(string.Format("Found {0} renderers for {1}", buttonRenderers.Count, action.GetShortName()));
  227. foreach ( MeshRenderer renderer in buttonRenderers )
  228. {
  229. buttonDebug.Append("\t");
  230. buttonDebug.AppendLine(renderer.name);
  231. }
  232. HintDebugLog( buttonDebug.ToString() );
  233. if ( buttonTransform == null )
  234. {
  235. HintDebugLog( "Couldn't find buttonTransform for " + action.GetShortName());
  236. return;
  237. }
  238. ActionHintInfo hintInfo = new ActionHintInfo();
  239. actionHintInfos.Add( action, hintInfo );
  240. hintInfo.componentName = buttonTransform.name;
  241. hintInfo.renderers = buttonRenderers;
  242. //Get the local transform for the button
  243. for (int childIndex = 0; childIndex < buttonTransform.childCount; childIndex++)
  244. {
  245. Transform child = buttonTransform.GetChild(childIndex);
  246. if (child.name == SteamVR_RenderModel.k_localTransformName)
  247. hintInfo.localTransform = child;
  248. }
  249. OffsetType offsetType = OffsetType.Right;
  250. /*
  251. switch ( buttonID )
  252. {
  253. case EVRButtonId.k_EButton_SteamVR_Trigger:
  254. {
  255. offsetType = OffsetType.Right;
  256. }
  257. break;
  258. case EVRButtonId.k_EButton_ApplicationMenu:
  259. {
  260. offsetType = OffsetType.Right;
  261. }
  262. break;
  263. case EVRButtonId.k_EButton_System:
  264. {
  265. offsetType = OffsetType.Right;
  266. }
  267. break;
  268. case Valve.VR.EVRButtonId.k_EButton_Grip:
  269. {
  270. offsetType = OffsetType.Forward;
  271. }
  272. break;
  273. case Valve.VR.EVRButtonId.k_EButton_SteamVR_Touchpad:
  274. {
  275. offsetType = OffsetType.Up;
  276. }
  277. break;
  278. }
  279. */
  280. //Offset for the text end transform
  281. switch ( offsetType )
  282. {
  283. case OffsetType.Forward:
  284. hintInfo.textEndOffsetDir = hintInfo.localTransform.forward;
  285. break;
  286. case OffsetType.Back:
  287. hintInfo.textEndOffsetDir = -hintInfo.localTransform.forward;
  288. break;
  289. case OffsetType.Right:
  290. hintInfo.textEndOffsetDir = hintInfo.localTransform.right;
  291. break;
  292. case OffsetType.Up:
  293. hintInfo.textEndOffsetDir = hintInfo.localTransform.up;
  294. break;
  295. }
  296. //Create the text hint object
  297. Vector3 hintStartPos = hintInfo.localTransform.position + ( hintInfo.localTransform.forward * 0.01f );
  298. hintInfo.textHintObject = GameObject.Instantiate( textHintPrefab, hintStartPos, Quaternion.identity ) as GameObject;
  299. hintInfo.textHintObject.name = "Hint_" + hintInfo.componentName + "_Start";
  300. hintInfo.textHintObject.transform.SetParent( textHintParent );
  301. hintInfo.textHintObject.layer = gameObject.layer;
  302. hintInfo.textHintObject.tag = gameObject.tag;
  303. //Get all the relevant child objects
  304. hintInfo.textStartAnchor = hintInfo.textHintObject.transform.Find( "Start" );
  305. hintInfo.textEndAnchor = hintInfo.textHintObject.transform.Find( "End" );
  306. hintInfo.canvasOffset = hintInfo.textHintObject.transform.Find( "CanvasOffset" );
  307. hintInfo.line = hintInfo.textHintObject.transform.Find( "Line" ).GetComponent<LineRenderer>();
  308. hintInfo.textCanvas = hintInfo.textHintObject.GetComponentInChildren<Canvas>();
  309. hintInfo.text = hintInfo.textCanvas.GetComponentInChildren<Text>();
  310. hintInfo.textMesh = hintInfo.textCanvas.GetComponentInChildren<TextMesh>();
  311. hintInfo.textHintObject.SetActive( false );
  312. hintInfo.textStartAnchor.position = hintStartPos;
  313. if ( hintInfo.text != null )
  314. {
  315. hintInfo.text.text = hintInfo.componentName;
  316. }
  317. if ( hintInfo.textMesh != null )
  318. {
  319. hintInfo.textMesh.text = hintInfo.componentName;
  320. }
  321. centerPosition += hintInfo.textStartAnchor.position;
  322. // Scale hint components to match player size
  323. hintInfo.textCanvas.transform.localScale = Vector3.Scale( hintInfo.textCanvas.transform.localScale, player.transform.localScale );
  324. hintInfo.textStartAnchor.transform.localScale = Vector3.Scale( hintInfo.textStartAnchor.transform.localScale, player.transform.localScale );
  325. hintInfo.textEndAnchor.transform.localScale = Vector3.Scale( hintInfo.textEndAnchor.transform.localScale, player.transform.localScale );
  326. hintInfo.line.transform.localScale = Vector3.Scale( hintInfo.line.transform.localScale, player.transform.localScale );
  327. }
  328. //-------------------------------------------------
  329. private void ComputeTextEndTransforms()
  330. {
  331. //This is done as a separate step after all the ButtonHintInfos have been initialized
  332. //to make the text hints fan out appropriately based on the button's position on the controller.
  333. centerPosition /= actionHintInfos.Count;
  334. float maxDistanceFromCenter = 0.0f;
  335. foreach ( var hintInfo in actionHintInfos )
  336. {
  337. hintInfo.Value.distanceFromCenter = Vector3.Distance( hintInfo.Value.textStartAnchor.position, centerPosition );
  338. if ( hintInfo.Value.distanceFromCenter > maxDistanceFromCenter )
  339. {
  340. maxDistanceFromCenter = hintInfo.Value.distanceFromCenter;
  341. }
  342. }
  343. foreach ( var hintInfo in actionHintInfos )
  344. {
  345. Vector3 centerToButton = hintInfo.Value.textStartAnchor.position - centerPosition;
  346. centerToButton.Normalize();
  347. centerToButton = Vector3.Project( centerToButton, renderModel.transform.forward );
  348. //Spread out the text end positions based on the distance from the center
  349. float t = hintInfo.Value.distanceFromCenter / maxDistanceFromCenter;
  350. float scale = hintInfo.Value.distanceFromCenter * Mathf.Pow( 2, 10 * ( t - 1.0f ) ) * 20.0f;
  351. //Flip the direction of the end pos based on which hand this is
  352. float endPosOffset = 0.1f;
  353. Vector3 hintEndPos = hintInfo.Value.textStartAnchor.position + ( hintInfo.Value.textEndOffsetDir * endPosOffset ) + ( centerToButton * scale * 0.1f );
  354. if (SteamVR_Utils.IsValid(hintEndPos))
  355. {
  356. hintInfo.Value.textEndAnchor.position = hintEndPos;
  357. hintInfo.Value.canvasOffset.position = hintEndPos;
  358. }
  359. else
  360. {
  361. Debug.LogWarning("<b>[SteamVR Interaction]</b> Invalid end position for: " + hintInfo.Value.textStartAnchor.name, hintInfo.Value.textStartAnchor.gameObject);
  362. }
  363. hintInfo.Value.canvasOffset.localRotation = Quaternion.identity;
  364. }
  365. }
  366. //-------------------------------------------------
  367. private void ShowButtonHint( params ISteamVR_Action_In_Source[] actions )
  368. {
  369. renderModel.gameObject.SetActive( true );
  370. renderModel.GetComponentsInChildren<MeshRenderer>( renderers );
  371. for ( int i = 0; i < renderers.Count; i++ )
  372. {
  373. Texture mainTexture = renderers[i].material.mainTexture;
  374. renderers[i].sharedMaterial = usingMaterial;
  375. renderers[i].material.mainTexture = mainTexture;
  376. // This is to poke unity into setting the correct render queue for the model
  377. renderers[i].material.renderQueue = usingMaterial.shader.renderQueue;
  378. }
  379. for ( int i = 0; i < actions.Length; i++ )
  380. {
  381. if ( actionHintInfos.ContainsKey( actions[i] ) )
  382. {
  383. ActionHintInfo hintInfo = actionHintInfos[actions[i]];
  384. foreach ( MeshRenderer renderer in hintInfo.renderers )
  385. {
  386. if ( !flashingRenderers.Contains( renderer ) )
  387. {
  388. flashingRenderers.Add( renderer );
  389. }
  390. }
  391. }
  392. }
  393. startTime = Time.realtimeSinceStartup;
  394. tickCount = 0.0f;
  395. }
  396. //-------------------------------------------------
  397. private void HideAllButtonHints()
  398. {
  399. Clear();
  400. if (renderModel != null && renderModel.gameObject != null)
  401. renderModel.gameObject.SetActive( false );
  402. }
  403. //-------------------------------------------------
  404. private void HideButtonHint( params ISteamVR_Action_In_Source[] actions )
  405. {
  406. Color baseColor = usingMaterial.GetColor( colorID );
  407. for ( int i = 0; i < actions.Length; i++ )
  408. {
  409. if ( actionHintInfos.ContainsKey(actions[i] ) )
  410. {
  411. ActionHintInfo hintInfo = actionHintInfos[actions[i]];
  412. foreach ( MeshRenderer renderer in hintInfo.renderers )
  413. {
  414. renderer.material.color = baseColor;
  415. flashingRenderers.Remove( renderer );
  416. }
  417. }
  418. }
  419. if ( flashingRenderers.Count == 0 )
  420. {
  421. renderModel.gameObject.SetActive( false );
  422. }
  423. }
  424. //-------------------------------------------------
  425. private bool IsButtonHintActive(ISteamVR_Action_In_Source action )
  426. {
  427. if ( actionHintInfos.ContainsKey(action) )
  428. {
  429. ActionHintInfo hintInfo = actionHintInfos[action];
  430. foreach ( MeshRenderer buttonRenderer in hintInfo.renderers )
  431. {
  432. if ( flashingRenderers.Contains( buttonRenderer ) )
  433. {
  434. return true;
  435. }
  436. }
  437. }
  438. return false;
  439. }
  440. //-------------------------------------------------
  441. private IEnumerator TestButtonHints()
  442. {
  443. while ( true )
  444. {
  445. for (int actionIndex = 0; actionIndex < SteamVR_Input.actionsNonPoseNonSkeletonIn.Length; actionIndex++)
  446. {
  447. ISteamVR_Action_In action = SteamVR_Input.actionsNonPoseNonSkeletonIn[actionIndex];
  448. if (action.GetActive(inputSource))
  449. {
  450. ShowButtonHint(action);
  451. yield return new WaitForSeconds(1.0f);
  452. }
  453. yield return null;
  454. }
  455. }
  456. }
  457. //-------------------------------------------------
  458. private IEnumerator TestTextHints()
  459. {
  460. while ( true )
  461. {
  462. for (int actionIndex = 0; actionIndex < SteamVR_Input.actionsNonPoseNonSkeletonIn.Length; actionIndex++)
  463. {
  464. ISteamVR_Action_In action = SteamVR_Input.actionsNonPoseNonSkeletonIn[actionIndex];
  465. if (action.GetActive(inputSource))
  466. {
  467. ShowText(action, action.GetShortName());
  468. yield return new WaitForSeconds(3.0f);
  469. }
  470. yield return null;
  471. }
  472. HideAllText();
  473. yield return new WaitForSeconds( 3.0f );
  474. }
  475. }
  476. //-------------------------------------------------
  477. void Update()
  478. {
  479. if ( renderModel != null && renderModel.gameObject.activeInHierarchy && flashingRenderers.Count > 0 )
  480. {
  481. Color baseColor = usingMaterial.GetColor( colorID );
  482. float flash = ( Time.realtimeSinceStartup - startTime ) * Mathf.PI * 2.0f;
  483. flash = Mathf.Cos( flash );
  484. flash = Util.RemapNumberClamped( flash, -1.0f, 1.0f, 0.0f, 1.0f );
  485. float ticks = ( Time.realtimeSinceStartup - startTime );
  486. if ( ticks - tickCount > 1.0f )
  487. {
  488. tickCount += 1.0f;
  489. hapticFlash.Execute(0, 0.005f, 0.005f, 1, inputSource);
  490. }
  491. for ( int i = 0; i < flashingRenderers.Count; i++ )
  492. {
  493. Renderer r = flashingRenderers[i];
  494. r.material.SetColor( colorID, Color.Lerp( baseColor, flashColor, flash ) );
  495. }
  496. if ( initialized )
  497. {
  498. foreach ( var hintInfo in actionHintInfos )
  499. {
  500. if ( hintInfo.Value.textHintActive )
  501. {
  502. UpdateTextHint( hintInfo.Value );
  503. }
  504. }
  505. }
  506. }
  507. }
  508. //-------------------------------------------------
  509. private void UpdateTextHint( ActionHintInfo hintInfo )
  510. {
  511. Transform playerTransform = player.hmdTransform;
  512. Vector3 vDir = playerTransform.position - hintInfo.canvasOffset.position;
  513. Quaternion standardLookat = Quaternion.LookRotation( vDir, Vector3.up );
  514. Quaternion upsideDownLookat = Quaternion.LookRotation( vDir, playerTransform.up );
  515. float flInterp;
  516. if ( playerTransform.forward.y > 0.0f )
  517. {
  518. flInterp = Util.RemapNumberClamped( playerTransform.forward.y, 0.6f, 0.4f, 1.0f, 0.0f );
  519. }
  520. else
  521. {
  522. flInterp = Util.RemapNumberClamped( playerTransform.forward.y, -0.8f, -0.6f, 1.0f, 0.0f );
  523. }
  524. hintInfo.canvasOffset.rotation = Quaternion.Slerp( standardLookat, upsideDownLookat, flInterp );
  525. Transform lineTransform = hintInfo.line.transform;
  526. hintInfo.line.useWorldSpace = false;
  527. hintInfo.line.SetPosition( 0, lineTransform.InverseTransformPoint( hintInfo.textStartAnchor.position ) );
  528. hintInfo.line.SetPosition( 1, lineTransform.InverseTransformPoint( hintInfo.textEndAnchor.position ) );
  529. }
  530. //-------------------------------------------------
  531. private void Clear()
  532. {
  533. renderers.Clear();
  534. flashingRenderers.Clear();
  535. }
  536. //-------------------------------------------------
  537. private void ShowText(ISteamVR_Action_In_Source action, string text, bool highlightButton = true )
  538. {
  539. if ( actionHintInfos.ContainsKey(action) )
  540. {
  541. ActionHintInfo hintInfo = actionHintInfos[action];
  542. hintInfo.textHintObject.SetActive( true );
  543. hintInfo.textHintActive = true;
  544. if ( hintInfo.text != null )
  545. {
  546. hintInfo.text.text = text;
  547. }
  548. if ( hintInfo.textMesh != null )
  549. {
  550. hintInfo.textMesh.text = text;
  551. }
  552. UpdateTextHint( hintInfo );
  553. if ( highlightButton )
  554. {
  555. ShowButtonHint(action);
  556. }
  557. renderModel.gameObject.SetActive( true );
  558. }
  559. }
  560. //-------------------------------------------------
  561. private void HideText(ISteamVR_Action_In_Source action)
  562. {
  563. if ( actionHintInfos.ContainsKey(action) )
  564. {
  565. ActionHintInfo hintInfo = actionHintInfos[action];
  566. hintInfo.textHintObject.SetActive( false );
  567. hintInfo.textHintActive = false;
  568. HideButtonHint(action);
  569. }
  570. }
  571. //-------------------------------------------------
  572. private void HideAllText()
  573. {
  574. if (actionHintInfos != null)
  575. {
  576. foreach (var hintInfo in actionHintInfos)
  577. {
  578. hintInfo.Value.textHintObject.SetActive(false);
  579. hintInfo.Value.textHintActive = false;
  580. }
  581. HideAllButtonHints();
  582. }
  583. }
  584. //-------------------------------------------------
  585. private string GetActiveHintText(ISteamVR_Action_In_Source action )
  586. {
  587. if ( actionHintInfos.ContainsKey(action) )
  588. {
  589. ActionHintInfo hintInfo = actionHintInfos[action];
  590. if ( hintInfo.textHintActive )
  591. {
  592. return hintInfo.text.text;
  593. }
  594. }
  595. return string.Empty;
  596. }
  597. //-------------------------------------------------
  598. // These are the static functions which are used to show/hide the hints
  599. //-------------------------------------------------
  600. //-------------------------------------------------
  601. private static ControllerButtonHints GetControllerButtonHints( Hand hand )
  602. {
  603. if ( hand != null )
  604. {
  605. ControllerButtonHints hints = hand.GetComponentInChildren<ControllerButtonHints>();
  606. if ( hints != null && hints.initialized )
  607. {
  608. return hints;
  609. }
  610. }
  611. return null;
  612. }
  613. //-------------------------------------------------
  614. public static void ShowButtonHint( Hand hand, params ISteamVR_Action_In_Source[] actions )
  615. {
  616. ControllerButtonHints hints = GetControllerButtonHints( hand );
  617. if ( hints != null )
  618. {
  619. hints.ShowButtonHint( actions );
  620. }
  621. }
  622. //-------------------------------------------------
  623. public static void HideButtonHint( Hand hand, params ISteamVR_Action_In_Source[] actions )
  624. {
  625. ControllerButtonHints hints = GetControllerButtonHints( hand );
  626. if ( hints != null )
  627. {
  628. hints.HideButtonHint( actions );
  629. }
  630. }
  631. //-------------------------------------------------
  632. public static void HideAllButtonHints( Hand hand )
  633. {
  634. ControllerButtonHints hints = GetControllerButtonHints( hand );
  635. if ( hints != null )
  636. {
  637. hints.HideAllButtonHints();
  638. }
  639. }
  640. //-------------------------------------------------
  641. public static bool IsButtonHintActive( Hand hand, ISteamVR_Action_In_Source action )
  642. {
  643. ControllerButtonHints hints = GetControllerButtonHints( hand );
  644. if ( hints != null )
  645. {
  646. return hints.IsButtonHintActive(action);
  647. }
  648. return false;
  649. }
  650. //-------------------------------------------------
  651. public static void ShowTextHint( Hand hand, ISteamVR_Action_In_Source action, string text, bool highlightButton = true )
  652. {
  653. ControllerButtonHints hints = GetControllerButtonHints( hand );
  654. if ( hints != null )
  655. {
  656. hints.ShowText(action, text, highlightButton );
  657. if (hand != null)
  658. {
  659. if (hints.autoSetWithControllerRangeOfMotion)
  660. hand.SetTemporarySkeletonRangeOfMotion(SkeletalMotionRangeChange.WithController);
  661. }
  662. }
  663. }
  664. //-------------------------------------------------
  665. public static void HideTextHint( Hand hand, ISteamVR_Action_In_Source action)
  666. {
  667. ControllerButtonHints hints = GetControllerButtonHints( hand );
  668. if ( hints != null )
  669. {
  670. hints.HideText(action);
  671. if (hand != null)
  672. {
  673. if (hints.autoSetWithControllerRangeOfMotion)
  674. hand.ResetTemporarySkeletonRangeOfMotion();
  675. }
  676. }
  677. }
  678. //-------------------------------------------------
  679. public static void HideAllTextHints( Hand hand )
  680. {
  681. ControllerButtonHints hints = GetControllerButtonHints( hand );
  682. if ( hints != null )
  683. {
  684. hints.HideAllText();
  685. }
  686. }
  687. //-------------------------------------------------
  688. public static string GetActiveHintText( Hand hand, ISteamVR_Action_In_Source action)
  689. {
  690. ControllerButtonHints hints = GetControllerButtonHints( hand );
  691. if ( hints != null )
  692. {
  693. return hints.GetActiveHintText(action);
  694. }
  695. return string.Empty;
  696. }
  697. }
  698. }