The [Sci-Fi Effects] assets comes with some great looking turrets and effects.
I used the [WebGL Speech Detection] package to add speech commands.
And to make speech work in the Unity editor, I added the [Chrome Speech Proxy].
To make Speech Detection work in the Turret example, I made some edits to the `F3DPlayerTurretController.cs` script.
// reference to the proxy private ProxySpeechDetectionPlugin _mProxySpeechDetectionPlugin = null; enum FireState { IDLE, DETECTED_FIRE, FIRE_ONCE, FIRE_IDLE, DETECTED_STOP, STOP_ONCE } // detect the word once in all updates private static FireState _sFireState = FireState.IDLE; // make sure all turrets detect the async word in their update event private static bool _sReadyForLateUpdate = false; // init the speech proxy private IEnumerator Start() { while (null == WebGLSpeechDetectionPlugin.GetInstance() || null == ProxySpeechDetectionPlugin.GetInstance() || !ProxySpeechDetectionPlugin.GetInstance().IsAvailable()) { yield return null; } // reference to the plugin WebGLSpeechDetectionPlugin plugin = WebGLSpeechDetectionPlugin.GetInstance(); // subscribe to events plugin.OnDetectionResult += HandleDetectionResult; // reference to the proxy _mProxySpeechDetectionPlugin = ProxySpeechDetectionPlugin.GetInstance(); // abort and clear existing words _mProxySpeechDetectionPlugin.Abort(); } // Handler for speech detection events void HandleDetectionResult(object sender, WebGLSpeechDetectionPlugin.SpeechDetectionEventArgs args) { if (null == args.detectionResult) { return; } WebGLSpeechDetectionPlugin.SpeechRecognitionResult[] results = args.detectionResult.results; if (null == results) { return; } bool doAbort = false; foreach (WebGLSpeechDetectionPlugin.SpeechRecognitionResult result in results) { WebGLSpeechDetectionPlugin.SpeechRecognitionAlternative[] alternatives = result.alternatives; if (null == alternatives) { continue; } foreach (WebGLSpeechDetectionPlugin.SpeechRecognitionAlternative alternative in alternatives) { if (string.IsNullOrEmpty(alternative.transcript)) { continue; } string lower = alternative.transcript.ToLower(); Debug.LogFormat("Detected: {0}", lower); if (lower.Contains("fire")) { if (_sFireState == FireState.IDLE) { _sFireState = FireState.DETECTED_FIRE; } doAbort = true; } if (lower.Contains("stop")) { if (_sFireState == FireState.FIRE_IDLE) { _sFireState = FireState.DETECTED_STOP; } doAbort = true; } } } // abort detection on match for faster matching on words instead of complete sentences if (doAbort) { _mProxySpeechDetectionPlugin.Abort(); } } // make the async detected word, detectable at the start of all the update events void LateUpdate() { if (_sReadyForLateUpdate) { _sReadyForLateUpdate = false; switch (_sFireState) { case FireState.DETECTED_FIRE: _sFireState = FireState.FIRE_ONCE; break; case FireState.FIRE_ONCE: _sFireState = FireState.FIRE_IDLE; break; case FireState.DETECTED_STOP: _sFireState = FireState.STOP_ONCE; break; case FireState.STOP_ONCE: _sFireState = FireState.IDLE; break; } } } void Update() { CheckForTurn(); CheckForFire(); // After update, use one late update to detect the async word _sReadyForLateUpdate = true; } void CheckForFire() { // Fire turret //if (!isFiring && Input.GetKeyDown(KeyCode.Mouse0)) if (!isFiring && _sFireState == FireState.FIRE_ONCE) { isFiring = true; fxController.Fire(); } // Stop firing //if (isFiring && Input.GetKeyUp(KeyCode.Mouse0)) if (isFiring && _sFireState == FireState.STOP_ONCE) { isFiring = false; fxController.Stop(); } }
To be able to call out the names of weapons, I made some edits to the `F3DFXController` script.
// reference to the proxy private ProxySpeechDetectionPlugin _mProxySpeechDetectionPlugin = null; enum WeaponState { IDLE, DETECTED_LEFT, LEFT_ONCE, DETECTED_RIGHT, RIGHT_ONCE } // detect the word once in all updates private static WeaponState _sWeaponState = WeaponState.IDLE; // make sure all turrets detect the async word in their update event private static bool _sReadyForLateUpdate = false; // Singleton instance public static F3DFXController instance; // init the speech proxy private IEnumerator Start() { while (null == WebGLSpeechDetectionPlugin.GetInstance() || null == ProxySpeechDetectionPlugin.GetInstance() || !ProxySpeechDetectionPlugin.GetInstance().IsAvailable()) { yield return null; } // reference to the plugin WebGLSpeechDetectionPlugin plugin = WebGLSpeechDetectionPlugin.GetInstance(); // subscribe to events plugin.OnDetectionResult += HandleDetectionResult; // reference to the proxy _mProxySpeechDetectionPlugin = ProxySpeechDetectionPlugin.GetInstance(); // abort and clear existing words _mProxySpeechDetectionPlugin.Abort(); } // Handler for speech detection events void HandleDetectionResult(object sender, WebGLSpeechDetectionPlugin.SpeechDetectionEventArgs args) { if (null == args.detectionResult) { return; } WebGLSpeechDetectionPlugin.SpeechRecognitionResult[] results = args.detectionResult.results; if (null == results) { return; } bool doAbort = false; foreach (WebGLSpeechDetectionPlugin.SpeechRecognitionResult result in results) { WebGLSpeechDetectionPlugin.SpeechRecognitionAlternative[] alternatives = result.alternatives; if (null == alternatives) { continue; } foreach (WebGLSpeechDetectionPlugin.SpeechRecognitionAlternative alternative in alternatives) { if (string.IsNullOrEmpty(alternative.transcript)) { continue; } string lower = alternative.transcript.ToLower(); Debug.LogFormat("Detected: {0}", lower); if (lower.Contains("left")) { if (_sWeaponState == WeaponState.IDLE) { _sWeaponState = WeaponState.DETECTED_LEFT; } doAbort = true; } else if (lower.Contains("right")) { if (_sWeaponState == WeaponState.IDLE) { _sWeaponState = WeaponState.DETECTED_RIGHT; } doAbort = true; } else if (lower.Contains("lightning")) { DefaultFXType = F3DFXType.LightningGun; doAbort = true; } else if (lower.Contains("beam")) { DefaultFXType = F3DFXType.PlasmaBeam; doAbort = true; } } } // abort detection on match for faster matching on words instead of complete sentences if (doAbort) { _mProxySpeechDetectionPlugin.Abort(); } } // make the async detected word, detectable at the start of all the update events void LateUpdate() { if (_sReadyForLateUpdate) { _sReadyForLateUpdate = false; switch (_sWeaponState) { case WeaponState.DETECTED_LEFT: _sWeaponState = WeaponState.LEFT_ONCE; break; case WeaponState.LEFT_ONCE: _sWeaponState = WeaponState.IDLE; break; case WeaponState.DETECTED_RIGHT: _sWeaponState = WeaponState.RIGHT_ONCE; break; case WeaponState.RIGHT_ONCE: _sWeaponState = WeaponState.IDLE; break; } } } void Update() { // Switch weapon types using keyboard keys //if (Input.GetKeyDown(KeyCode.RightArrow)) if (_sWeaponState == WeaponState.LEFT_ONCE) NextWeapon(); //else if (Input.GetKeyDown(KeyCode.LeftArrow)) if (_sWeaponState == WeaponState.RIGHT_ONCE) PrevWeapon(); // After update, use one late update to detect the async word _sReadyForLateUpdate = true; }