//--------------------------------------------------------------------------- UPDATE public void OnUpdate_Cursor() { // Called in CGame.update() to update our cursor //=== Switch edit mode if the corresponding key was pressed === //###DESIGN!!!!! How / when to map these important keys??? ###TODO!!!! Only change mode when in pose edit mode, enforce 'play mode' to always move! if (CGame.INSTANCE._bGameModeBasicInteractions == false) { if (Input.GetKeyDown(KeyCode.T)) { // Toggle between move and rotate mode when not in basic game interaction mode if (_EditMode == EEditMode.Move) SetEditMode(EEditMode.Rotate); else SetEditMode(EEditMode.Move); } } //=== Determine which layer we search for hotspot on === int nLayerTarget = C_Layer_HotSpot; //###BUG??? Send this layer mask to derived classes??? //if (Input.GetKey(KeyCode.Space)) //###CHECK: Proper? Hunt for hotspots on hand layer if proper key pressed // nLayerTarget = C_Layer_HotSpotHands; uint nLayerTargetMask = (uint)1 << nLayerTarget; //###WEAK? The changes above to cursor mode operation are specific to the game and take away some of the generic behavior that may be useful for other purposes if (Input.GetKeyDown(KeyCode.W)) SetEditMode(EEditMode.Move); // W = Move else if (Input.GetKeyDown(KeyCode.T)) SetEditMode(EEditMode.Rotate); // T = roTate //###WEAK: Conflicts with reset! Which to keep?? //else if (Input.GetKeyDown(KeyCode.E)) SetEditMode(EEditMode.Scale); // E = Expand = Scale //###DESIGN: Any value in scale / select for game?? //else if (Input.GetKeyDown(KeyCode.Q)) SetEditMode(EEditMode.Select); // Q = Select //=== Test what collider is under the mouse cursor. This is used to process the various stages of mouse interactivity as well as to adjust the '3D depth' of the cursor === CGame.SetGuiMessage(EGameGuiMsg.CursorStat1, "Cursor Mode: " + _eModeCursor.ToString()); _oRayHit_LayerHotSpot = GetHitOnLayerAtMousePos(0xFFFFFFFF); if (_oRayHit_LayerHotSpot.collider != null) CGame.SetGuiMessage(EGameGuiMsg.CursorStat2, "Cursor Collider: " + _oRayHit_LayerHotSpot.transform.name); else CGame.SetGuiMessage(EGameGuiMsg.CursorStat2, "Cursor Collider: None"); _oRayHit_LayerHotSpot = GetHitOnLayerAtMousePos(nLayerTargetMask); if (_oRayHit_LayerHotSpot.collider != null) _nDepth = _oRayHit_LayerHotSpot.distance * _DefaultCursorDepthOnHotspots; // We adjust the '3D depth' of mouse cursor only when a collider is found. ###IMPROVE: Implement slerp to gracefully change depth? // GameObject oSelectedUI = EventSystem.current.currentSelectedGameObject; // EventSystem.current.IsPointerOverGameObject()) { // If cursor is over Unity UI widget set cursor directly there and don't process further cursor functionality // if (oSelectedUI != null) { // CGame.SetGuiMessage(EGameGuiMsg.CursorStat3, "Cursor GUI: " + oSelectedUI.name); // //transform.position = Camera.main.ScreenToWorldPoint(; // //PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current); // //eventDataCurrentPosition.position = screenPosition; // //GraphicRaycaster uiRaycaster = canvas.gameObject.GetComponent<GraphicRaycaster>(); // //List<RaycastResult> results = new List<RaycastResult>(); // //uiRaycaster.Raycast(eventDataCurrentPosition, results); // //return results.Count > 0; // _nDepth = Vector3.Distance(oSelectedUI.transform.position, Camera.main.transform.position); //} else { // CGame.SetGuiMessage(EGameGuiMsg.CursorStat3, "(Cursor: No GUI control)"); // } if (_oCurrentGuiObject_HACK != null) //###CHECK: Proper transforms for VR?? For SpaceNavigator?? _nDepth = Vector3.Distance(_oCurrentGuiObject_HACK.position, Camera.main.transform.position); //###DESIGN: Override hotspot depth above?? ###IDEA: Have cursor a child of panel when it is hovering on top?? Vector3 vecMouse2D = new Vector3(Input.mousePosition.x, Input.mousePosition.y, _nDepth); //###OPT: Cache localPosition?? Vector3 vecMouse3D = Camera.main.ScreenToWorldPoint(vecMouse2D); transform.position = vecMouse3D; if (_oCurrentGuiObject_HACK != null) return; //####SOON ####PROBLEM: Detecting what widget for width (solution offered in post) bool bClickLeftDown = Input.GetMouseButtonDown(0); bool bClickRightDown = Input.GetMouseButtonDown(1); bool bClickMiddleDown = Input.GetMouseButtonDown(2); bool bClickDown = bClickLeftDown || bClickRightDown || bClickMiddleDown; //=== Process the finite state machine that systematically walks through each step of hotspot search, hovering, activation with bridge to hotspot's OnUpdate_HotSpot() for further 'OnUpdate()' processing === switch (_eModeCursor) { case EModeCursor.S1_SearchingForHotspot: // Default/startup mode: We don't have an interactive selected and are looking for one through 'mouse hover' if (_oRayHit_LayerHotSpot.collider != null) { _oHotSpotCurrent = _oRayHit_LayerHotSpot.collider.GetComponent<CHotSpot>(); if (_oHotSpotCurrent) { _oHotSpotCurrent.OnHoverBegin(); _eModeCursor = EModeCursor.S2_HoveringOverHotspot; } } else { //if (iGUICode_Root.INSTANCE._oPaneContextMenu != null) { // We kill panel when we're not hovering over any Gui collider and panel exists. (makes it have a very short lifespan exactly like a 'tooltip') // iGUICode_Root.INSTANCE._oPaneContextMenu.removeAll(); // iGUICode_Root.INSTANCE._oPaneContextMenu.setEnabled(false); //###IMPROVE!!! Implement 'tooltip-like' functionality for popup menu? // iGUICode_Root.INSTANCE._oPaneContextMenu = null; //} } break; case EModeCursor.S2_HoveringOverHotspot: // The user is now hovering over a valid Hotspot, but has not yet selected it with left mouse button. (3D cursor displays name of Hotspot for visual feedback) if (bClickDown) { if (CGame.INSTANCE._bGameModeBasicInteractions == false || bClickRightDown) { // If we're in full edit mode we wait for up-click, activate and display full gizmo. _eModeCursor = EModeCursor.S3_WaitingForMouseUp; } else { // If we're in reduced edit mode, we fast-track to immediate movement along Y,Z axis without showing gizmo _oHotSpotCurrent.OnActivate(bClickLeftDown, bClickRightDown, bClickMiddleDown); _eModeCursor = EModeCursor.S4_ActivatedHotspot; } _nTimeAtMouseButtonDown = Time.time; // Remember the start time of mouse button down to prevent acting on very long mouse clicks _vecPosAtMouseButtonDown = Input.mousePosition; // Remember mouse position so we can cancel if too far on mouse up } else { // No click on hovering hotspot, check to see if we're still on a hotspot and cancel if not. CHotSpot oHotSpot = _oRayHit_LayerHotSpot.collider ? _oRayHit_LayerHotSpot.collider.GetComponent<CHotSpot>() : null; if (oHotSpot != _oHotSpotCurrent) { _oHotSpotCurrent.OnHoverEnd(); _oHotSpotCurrent = null; _eModeCursor = EModeCursor.S1_SearchingForHotspot; } } break; case EModeCursor.S3_WaitingForMouseUp: // The user has down-clicked a hotspot. We await up-click to see if same hotspot is still under the mouse before activating the hotspot bool bClickLeftUp = Input.GetMouseButtonUp(0); bool bClickRightUp = Input.GetMouseButtonUp(1); bool bClickMiddleUp = Input.GetMouseButtonUp(2); if (bClickLeftUp|| bClickRightUp) { if (_nTimeAtMouseButtonDown + C_TimeMaxForMouseClick >= Time.time && (Input.mousePosition - _vecPosAtMouseButtonDown).magnitude < 10) { CHotSpot oHotSpot = _oRayHit_LayerHotSpot.collider ? _oRayHit_LayerHotSpot.collider.GetComponent<CHotSpot>() : null; if (oHotSpot == _oHotSpotCurrent) { // User has released mouse button on the same hotspot as mouse down. Activate the hotspot _oHotSpotCurrent.OnActivate(bClickLeftUp, bClickRightUp, bClickMiddleUp); _eModeCursor = EModeCursor.S4_ActivatedHotspot; } else { // User has released button on nothing or on another hotspot. Return to start state _oHotSpotCurrent.OnHoverEnd(); _oHotSpotCurrent = null; _eModeCursor = EModeCursor.S1_SearchingForHotspot; } } else { // User took too long, just ignore both mouse down & mouse up and return to search state _eModeCursor = EModeCursor.S1_SearchingForHotspot; } } break; case EModeCursor.S4_ActivatedHotspot: // The user is now hovering over a valid Hotspot, but has not yet selected it with left mouse button. (3D cursor displays name of Hotspot for visual feedback) if (bClickDown) { RaycastHit oRayHit_LayerHotSpotAndGizmo = GetHitOnLayerAtMousePos(nLayerTargetMask | CCursor.C_LayerMask_Gizmo); // Test to see if user clicked on nothing in gizmo or hotspot layers (in 'void') if (oRayHit_LayerHotSpotAndGizmo.collider == null) { // If user didn't click on anything we cancel hotspot activation and return to start state. _oHotSpotCurrent.OnDeactivate(); _oHotSpotCurrent.OnHoverEnd(); _oHotSpotCurrent = null; _eModeCursor = EModeCursor.S1_SearchingForHotspot; //} else { // We hit a valid hotspot or gizmo collider... //###BROKEN! Was creating multiple gizmos! // CHotSpot oHotSpot = _oRayHit_LayerHotSpot.collider ? _oRayHit_LayerHotSpot.collider.GetComponent<CHotSpot>() : null; // if (oHotSpot != null) { // if (oHotSpot == _oHotSpotCurrent) { // If user clicked same hotspot simply route the 'activate' call to it so it can display menu or start editing // _oHotSpotCurrent.OnActivate(bClickLeftDown, bClickRightDown); //###IMPROVE: Test and add quick activation?? // //} else { // If user clicked another hotspot we deactivate the old one and activate the new // // _oHotSpotCurrent.OnDeactivate(); // // _oHotSpotCurrent.OnHoverEnd(); // // _oHotSpotCurrent = oHotSpot; // // _oHotSpotCurrent.OnHoverBegin(); // // _oHotSpotCurrent.OnActivate(bClickLeftDown, bClickRightDown); //###CHECK! // } // } // In this if clause is also the possibility of a left/right click on a gizmo collider. This is handled below by hotspot } } if (_oHotSpotCurrent != null) { // Only the active hotspot gets the chance to trap events (typically to reroute to the gizmo it manages) === _oHotSpotCurrent.OnUpdate_ActiveHotspot(); //=== Handle special case if we're not showing helper object and the left or middle mouse button is not pressed -> destroy everything and returning to start state to complete the highly transient operation if (CGame.INSTANCE._bGameModeBasicInteractions && Input.GetMouseButton(0) == false && Input.GetMouseButton(2) == false) { _oHotSpotCurrent.OnDeactivate(); _oHotSpotCurrent.OnHoverEnd(); _oHotSpotCurrent = null; _eModeCursor = EModeCursor.S1_SearchingForHotspot; } } break; } }
public void CancelEditing() { // Cancels editing by deactivating hots pot which will destroy gizmo if it exists. if (_oHotSpotCurrent) { _oHotSpotCurrent.OnDeactivate(); _oHotSpotCurrent.OnHoverEnd(); } _oHotSpotCurrent = null; _eModeCursor = EModeCursor.S1_SearchingForHotspot; }