using System; using System.Collections; using System.Collections.Generic; using EZXR.Glass.Core; using EZXR.Glass.Inputs; using EZXR.Glass.SixDof; using UnityEngine; namespace EZXR.Glass.Inputs { [ScriptExecutionOrder(-48)] public class ControllerInfo : InputInfoBase { public Transform handleOrigin; public Transform tipPoint; /// /// 手柄当前是否已配对 /// protected bool isBinding = false; public bool IsBinding { get { return isBinding; } } /// /// 手柄当前是否已连接 /// protected bool isConnected = false; public bool IsConnected { get { return isConnected; } } /// /// 手柄当前电量 /// protected float powerStats = 0.0f; public float PowerStats { get { return powerStats; } } /// /// 手柄当前是否被握持 /// protected bool isHeld; public bool IsHeld { get { return isHeld; } } /// /// 手柄当前是否被静置 /// protected bool isSilent; public bool IsSilent { get { return isSilent; } } protected Vector2 axis2DCoord; /// /// 监听手柄的生命状态改变(立即发生) /// private bool bindingChanged = false; private bool connectedChanged = false; private bool powerChanged = false; private bool holdChanged = false; private bool silenceChanged = false; /// /// 监听到生命状态改变的回调(在Update中发生) /// 可能立即发生也可能滞后一帧 /// private Action bindingAction; private Action connectedAction; private Action powerChangedAction; private Action holdChangedAction; private Action silenceChangedAction; /// 保存按键状态(在Update中发生,可能立即发生也可能滞后一帧) private Dictionary buttonState; /// 监听按键状态的改变(立即发生) private Dictionary buttonStateChanged; //private Dictionary buttonDownTimeSpan; private bool isPaused = false; /// /// 当前眼镜视野中是否存在这个手 /// public override bool Exist { get { if (Application.isEditor) { return true; } return isConnected; } } /// /// 手掌正在朝向头部 /// /// /// public override bool isPalmFacingHead(float angle = 90) { return false; } #region 手交互能力开关 /// /// 设置或获得当前手的显示状态(仅仅影响显示,并不影响交互) /// private bool visibility = true; public override bool Visibility { get { /*if (handType == HandType.Left) return false; else */return visibility; } set { // 判断是否开发者自定义了手柄模型 //if (handType == HandType.Right) { var dummy = handType == HandType.Left ? "LeftDummy" : "RightDummy"; // 若在handleOrigin下添加自定义的手柄模型,则隐藏默认手柄 var hasAlter = handleOrigin.GetComponentsInChildren().Length > 0; if (!hasAlter) transform.Find(dummy).gameObject.SetActive(value); else handleOrigin.gameObject.SetActive(value); visibility = value; } } } /// /// 设置或获得远距离射线交互状态 /// public override bool RaycastInteraction { get { return GetComponent().enabled; } set { GetComponent().enabled = value; } } /// /// 设置或获得近距离交互状态 /// public override bool TouchInteraction { get { return false; } set { } } /// /// 设置或获得手部的物理碰撞交互状态 /// public override bool PhysicsInteraction { get { return false; } set { } } #endregion protected override void Awake() { base.Awake(); buttonState = new Dictionary(); //buttonDownTimeSpan = new Dictionary(); buttonStateChanged = new Dictionary(); } protected override void Update() { base.Update(); UpdateStatus(); if (handleOrigin != null) { //射线方向 if (!(HandleControllerManager.SetRayDirByExternal != null && HandleControllerManager.SetRayDirByExternal(this, ref rayDirection))) { rayDirection = handleOrigin.forward; } //射线起点 if (!(HandleControllerManager.SetRayStartPointByExternal != null && HandleControllerManager.SetRayStartPointByExternal(this, ref rayPoint_Start))) { rayPoint_Start = handleOrigin.position + rayDirection * rayStartDistance; } } } private void OnApplicationPause(bool pause) { //Debug.Log($"HandleControllerInfo, OnApplicationPause: pause = {pause} handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats} ({Time.frameCount})"); if (!pause) { isBinding = HandleControllerManager.Instance.GetBindState(handType); isConnected = HandleControllerManager.Instance.GetConnectState(handType); powerStats = HandleControllerManager.Instance.GetPowerStats(handType); Debug.Log($"HandleControllerInfo, OnApplicationPause: pause = {pause} handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats}"); } isPaused = pause; //UpdatePinching(); buttonState.Clear(); buttonStateChanged.Clear(); startPinch = false; endPinch = false; isPinching = false; } private void OnEnable() { //Debug.Log($"HandleControllerInfo, OnEnable: handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats} ({Time.frameCount})"); isBinding = HandleControllerManager.Instance.GetBindState(handType); isConnected = HandleControllerManager.Instance.GetConnectState(handType); powerStats = HandleControllerManager.Instance.GetPowerStats(handType); Debug.Log($"HandleControllerInfo, OnEnable: handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats}"); //UpdatePinching(); buttonState.Clear(); buttonStateChanged.Clear(); startPinch = false; endPinch = false; isPinching = false; } private void OnDisable() { //UpdatePinching(); buttonState.Clear(); buttonStateChanged.Clear(); startPinch = false; endPinch = false; isPinching = false; Debug.Log($"HandleControllerInfo, OnDisable: handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats} ({Time.frameCount})"); } public override void Init(HandType handType) { base.Init(handType); //if (handType == HandType.Right) { // 若在handleOrigin下添加自定义的手柄模型,则隐藏默认手柄 var hasAlter = handleOrigin.GetComponentsInChildren().Length > 0; // fix: 控制器切换时不能任意设置手柄显示 if (hasAlter) transform.Find(handType == HandType.Left ? "LeftDummy" : "RightDummy").gameObject.SetActive(!hasAlter); } isBinding = HandleControllerManager.Instance.GetBindState(handType); isConnected = HandleControllerManager.Instance.GetConnectState(handType); powerStats = HandleControllerManager.Instance.GetPowerStats(handType); Debug.Log($"HandleControllerInfo, Init: handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats}"); StartCoroutine(CheckStatus()); } public void UpdateBindingState(bool status, Action callback) { if (isBinding == status) return; isBinding = status; bindingChanged = true; bindingAction = callback; Debug.Log($"HandleControllerInfo, UpdateBinding: handType = {this.handType} isBinding = {status}"); if (isPaused || !gameObject.activeInHierarchy) UpdateStatus(); } public void UpdateConnectedState(bool connected, Action callback) { if (isConnected == connected) return; isConnected = connected; connectedChanged = true; connectedAction = callback; Debug.Log($"HandleControllerInfo, UpdateConnectedState: handType = {this.handType} isConnected = {connected}"); if (!connected) { buttonState.Clear(); buttonStateChanged.Clear(); } if (!connected) { startPinch = false; endPinch = false; isPinching = false; } if (isPaused || !gameObject.activeInHierarchy) UpdateStatus(); } public void UpdatePowerStats(float power, Action callback) { Debug.Log($"HandleControllerInfo, UpdatePowerStats: handType = {this.handType} power = {power}"); if (powerStats == power) return; powerStats = power; powerChanged = true; powerChangedAction = callback; if (isPaused || !gameObject.activeInHierarchy) UpdateStatus(); } public void UpdateButtonState(HandleKeyCode keyCode, bool pressed) { if (isPaused || !gameObject.activeInHierarchy) return; //Debug.Log($"HandleControllerInfo, {handType} {keyCode} StateChanged to {(pressed ? "pressed" : "released")} ({Time.frameCount})"); if (!buttonState.ContainsKey(keyCode)) { buttonState[keyCode] = pressed ? HandleKeyEvent.Idle : HandleKeyEvent.Pressing; buttonStateChanged[keyCode] = true; } else if ((pressed && buttonState[keyCode] == HandleKeyEvent.Idle) || (!pressed && buttonState[keyCode] == HandleKeyEvent.Pressing)) { buttonStateChanged[keyCode] = true; } } public void UpdateAxis2D(Vector2 coord) { if (isPaused || !gameObject.activeInHierarchy) return; axis2DCoord = coord; } public void UpdateHoldState(bool isHeld, Action callback) { if (this.isHeld == isHeld) return; this.isHeld = isHeld; holdChanged = true; holdChangedAction = callback; //Debug.Log($"HandleControllerInfo, UpdateHoldState: handType = {this.handType} isHeld = {isHeld} ({Time.frameCount})"); if (isPaused || !gameObject.activeInHierarchy) UpdateStatus(); } public void UpdateSilenceState(bool isSilent, Action callback) { if (this.isSilent == isSilent) return; this.isSilent = isSilent; silenceChanged = true; silenceChangedAction = callback; //Debug.Log($"HandleControllerInfo, UpdateSilenceState: handType = {this.handType} isSilent = {isSilent} ({Time.frameCount})"); if (isPaused || !gameObject.activeInHierarchy) UpdateStatus(); } public bool GetButtonDown(HandleKeyCode keyCode) { if (!isPaused && isConnected && buttonState.ContainsKey(keyCode)) return buttonState[keyCode] == HandleKeyEvent.Down; return false; } public bool GetButtonUp(HandleKeyCode keyCode) { if (!isPaused && isConnected && buttonState.ContainsKey(keyCode)) return buttonState[keyCode] == HandleKeyEvent.Up; return false; } public bool GetButton(HandleKeyCode keyCode) { if (!isPaused && isConnected && buttonState.ContainsKey(keyCode)) return buttonState[keyCode] == HandleKeyEvent.Pressing; return false; } public Vector2 GetAxis2D() { return axis2DCoord; } protected override void UpdatePinching() { var keys = new List(buttonStateChanged.Keys); for (int j = 0; j < keys.Count; ++j) { var keyCode = keys[j]; if (!buttonStateChanged[keyCode]) continue; if (buttonState[keyCode] == HandleKeyEvent.Idle) { buttonState[keyCode] = HandleKeyEvent.Down; //Debug.Log($"HandleControllerInfo, {handType} {keyCode} change to Down from Idle ({Time.frameCount})"); //按下扳机键触发开始捏合动作 if (keyCode == HandleKeyCode.Trigger) startPinch = true; } else if (buttonState[keyCode] == HandleKeyEvent.Pressing) { buttonState[keyCode] = HandleKeyEvent.Up; //Debug.Log($"HandleControllerInfo, {handType} {keyCode} change to Up from Pressing ({Time.frameCount})"); //松开扳机键触发结束捏合动作 if (keyCode == HandleKeyCode.Trigger) endPinch = true; } //buttonStateChanged.Remove(keyCode); } keys = new List(buttonState.Keys); for (int i = 0; i < keys.Count; ++i) { var keyCode = keys[i]; if (buttonStateChanged.ContainsKey(keyCode)) { buttonStateChanged.Remove(keyCode); continue; } if (buttonState[keyCode] == HandleKeyEvent.Down) { buttonState[keyCode] = HandleKeyEvent.Pressing; //Debug.Log($"HandleControllerInfo, {handType} {keyCode} change to Pressing from Down ({Time.frameCount})"); // startPinch结束,触发持续捏合 if (keyCode == HandleKeyCode.Trigger) { startPinch = false; isPinching = true; } } else if (buttonState[keyCode] == HandleKeyEvent.Up) { buttonState[keyCode] = HandleKeyEvent.Idle; //Debug.Log($"HandleControllerInfo, {handType} {keyCode} change to Idle from Up ({Time.frameCount})"); // endPinch结束,触发结束捏合 if (keyCode == HandleKeyCode.Trigger) { endPinch = false; isPinching = false; } } } } private void UpdateStatus() { if (bindingChanged) { if (bindingAction != null) bindingAction(isBinding); bindingChanged = false; } if (connectedChanged) { if (connectedAction != null) connectedAction(isConnected); connectedChanged = false; Visibility = isConnected; RaycastInteraction = isConnected; TouchInteraction = isConnected; PhysicsInteraction = isConnected; } if (powerChanged) { if (powerChangedAction != null) powerChangedAction(powerStats); powerChanged = false; } if (holdChanged) { if (holdChangedAction != null) holdChangedAction(isHeld); holdChanged = false; } if (silenceChanged) { if (silenceChangedAction != null) silenceChangedAction(isSilent); silenceChanged = false; } } // for fix public IEnumerator CheckStatus() { yield return new WaitUntil(() => SessionManager.Instance != null && SessionManager.Instance.IsInited); isBinding = HandleControllerManager.Instance.GetBindState(handType); isConnected = HandleControllerManager.Instance.GetConnectState(handType); powerStats = HandleControllerManager.Instance.GetPowerStats(handType); Debug.Log($"HandleControllerInfo, Check: handType = {this.handType} isBinding = {isBinding}, isConnected = {isConnected}, powerStats = {powerStats} ({Time.frameCount})"); Visibility = isConnected; RaycastInteraction = isConnected; TouchInteraction = isConnected; PhysicsInteraction = isConnected; } } }