Simple imitation of mouse interaction in Unity advanced (scenario: mobile phone screen as Touch Pad, moving mouse, mouse confirmation, etc.)
catalogue
1, Brief introduction
Organize some knowledge points in Unity.
This section briefly introduces the in Unity development. Due to the development needs of the project, the mobile phone screen needs to be used as a touch pad to simulate mouse movement and click interaction, so it is simple to sort it out here. Maybe the scene is different, you may need to adapt the screen. It is only for reference and learning. If you have a new way, you can also leave a message. Thank you.
2, Implementation principle
1. Use input GetMouseButtonDown(0) ,Input.GetMouseButton(0) ,Input.GetMouseButtonUp(0) related events to obtain location related information for processing, which is used as the location of UI ray interaction
2. Get the EventSystem of the current UI and rewrite it accordingly. The key codes are as follows
m_eventSystem = EventSystem.current; // Get the current eventsystem
m_pointerEvent = new PointerEventData(m_eventSystem);
m_pointerEvent.button = PointerEventData.InputButton.Left;
m_pointerEvent.position = mFunPointerPos != null ? mFunPointerPos.Invoke() : new Vector2(Screen.width * 1 / 2, Screen.height / 2); // Here is the simulated mouse position
List<RaycastResult> raycastResults = new List<RaycastResult>();
m_eventSystem.RaycastAll(m_pointerEvent, raycastResults);
3, Precautions
1. Due to different usage scenarios, appropriate screen adaptation may be required
2. Because the simulated mouse interaction is used, the default Standalone Input Module on the EventSystem should be removed or disabled, otherwise the simulated mouse interaction may be affected
3. In some cases, the simulated mouse may be covered. You can perform corresponding processing, adjust the UI level, display the simulated mouse in another way, add materials, adjust the rendering queue, etc
4, Effect preview
5, Implementation steps
1. Open Unity to create a new empty project
2. Arrange the scene. One is the simulated mouse point and some interactive controls
3. Create script, write corresponding logic code and realize corresponding functions, imusegesturepointercallback callback interface, mousepointmovewrapper mouse position, screenraycasteruiwrapper obtain and rewrite the current UI interaction of EventSystem, etc
4. Mount the script into the scene, and assign values to the simulated mouse, as shown in the figure
5. Here, the Button is set as follows, and a script is mounted for click interaction, counting and use, which is convenient for effect demonstration
6. Run the scene, click the screen and move to see the corresponding mouse movement and simple interaction. The effect is as follows
6, Key code
1,TestMousePointerInteraction
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace XANUtil { public class TestMousePointerInteraction : MonoBehaviour,IMouseGesturePointerCallback { public RectTransform PointerImageRectTrans; private MousePointerMoveWrapper mMousePointerMoveWrapper = new MousePointerMoveWrapper(); private ScreenRayRaycasterUIWrapper mScreenRayRaycasterUIWrapper = new ScreenRayRaycasterUIWrapper(); void Start() { Init(); } void Update() { if (mMousePointerMoveWrapper != null) { mMousePointerMoveWrapper.Update(); } if (mScreenRayRaycasterUIWrapper != null) { mScreenRayRaycasterUIWrapper.Update(); } } void Init() { if (mMousePointerMoveWrapper != null) { // Transfer the mouse position to the Ray emission position mMousePointerMoveWrapper.Init(this); } if (mScreenRayRaycasterUIWrapper != null) { // Transfer the mouse position to the Ray emission position mScreenRayRaycasterUIWrapper.Init(() => { return PointerImageRectTrans.anchoredPosition; }); } } #region PointerImageRectTrans void SetPointerImageRectTrans(Vector2 deltrPos) { if (PointerImageRectTrans != null) { Vector2 val = PointerImageRectTrans.anchoredPosition; val += ModifyPointerPos(deltrPos); PointerImageRectTrans.anchoredPosition = ClampValue(val); } } /// <summary> ///Correct the pointer position as needed /// </summary> /// <param name="deltrPos"></param> /// <returns></returns> Vector2 ModifyPointerPos(Vector2 deltrPos) { return deltrPos; } /// <summary> ///Display pointer position /// </summary> /// <param name="val"></param> /// <returns></returns> Vector2 ClampValue(Vector2 val) { val.x = val.x < 0 ? 0 : val.x; val.y = val.y < 0 ? 0 : val.y; val.x = val.x > Screen.width ? Screen.width : val.x; val.y = val.y > Screen.height ? Screen.height : val.y; return val; } #endregion #region Interface IMouseGesturePointerCallback public void MousePointerMoveDeltraPos(Vector2 deltraPos) { SetPointerImageRectTrans(deltraPos); } #endregion } }
2,SimulationPointerButtonItem
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace XANUtil { /// <summary> ///Simple simulation pointer selected button script ///(this can be omitted or rewritten for reference only) /// </summary> public class SimulationPointerButtonItem : MonoBehaviour { private Button mBtn; private Text mBtnText; Action mOnClick; private int mCounter = 0; private void Awake() { Init(null); } public void Init(Action onClick) { mBtn = this.GetComponent<Button>(); mBtnText = this.GetComponentInChildren<Text>(); mCounter = 0; mOnClick = onClick; mBtn.onClick.AddListener(OnClick); } public void OnClick() { mCounter++; mBtnText.text = mCounter.ToString(); mOnClick?.Invoke(); } } }
3,ScreenRayRaycasterUIWrapper
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace XANUtil { public class ScreenRayRaycasterUIWrapper { // Prevents loop over the same selectable Selectable m_excluded; Selectable m_currentSelectable = null; RaycastResult m_currentRaycastResult; IPointerClickHandler m_clickHandler; IDragHandler m_dragHandler; EventSystem m_eventSystem; PointerEventData m_pointerEvent; Func<Vector2> mFunPointerPos; private bool mIsClick = false; private bool mIsSwipe = false; private bool mIsDrag = false; private Vector2 oldPos; private Vector2 lastPos; private const float MOVE_LENGTH_LIMIT = 10; public void Init(Func<Vector2> funPointerPos) { m_eventSystem = EventSystem.current; m_pointerEvent = new PointerEventData(m_eventSystem); m_pointerEvent.button = PointerEventData.InputButton.Left; mFunPointerPos = funPointerPos; } public void Update() { // No data screen center (i.e. width * 3/4, height * 1/2) // Set pointer position m_pointerEvent.position = mFunPointerPos != null ? mFunPointerPos.Invoke() : new Vector2(Screen.width * 1 / 2, Screen.height / 2); List<RaycastResult> raycastResults = new List<RaycastResult>(); m_eventSystem.RaycastAll(m_pointerEvent, raycastResults); // Detect selectable if (raycastResults.Count > 0) { foreach (var result in raycastResults) { var newSelectable = result.gameObject.GetComponentInParent<Selectable>(); if (newSelectable) { if (newSelectable != m_excluded && newSelectable != m_currentSelectable) { Select(newSelectable); m_currentRaycastResult = result; } break; } } } else { if (m_currentSelectable || m_excluded) { Select(null, null); } } // Target is being activating if (m_currentSelectable) { if (m_clickHandler != null && Input.GetMouseButtonUp(0) && mIsSwipe == false) { m_clickHandler.OnPointerClick(m_pointerEvent); Select(null, null); } else if (m_dragHandler != null && mIsClick /*&& mIsSwipe == false*/) { mIsDrag = true; m_pointerEvent.pointerPressRaycast = m_currentRaycastResult; m_dragHandler.OnDrag(m_pointerEvent); } if (m_dragHandler == null) { mIsClick = false; mIsSwipe = false; } if (m_clickHandler != null || m_dragHandler != null) { if (Input.GetMouseButtonDown(0)) { oldPos = Input.mousePosition; mIsClick = true; } else if (Input.GetMouseButtonUp(0)) { mIsSwipe = false; mIsClick = false; mIsDrag = false; Select(null, null); } else { lastPos = Input.mousePosition; mIsSwipe = JudgeISSwipe(oldPos, lastPos); } } } else { mIsClick = false; mIsSwipe = false; Select(null, null); } if (Input.GetMouseButtonUp(0)) { mIsSwipe = false; mIsClick = false; mIsDrag = false; Select(null, null); } } /// <summary> ///Judge whether it is jog /// </summary> /// <param name="oldPos"></param> /// <param name="lastPos"></param> /// <returns></returns> private bool JudgeISSwipe(Vector2 oldPos, Vector2 lastPos) { return Vector3.Distance(oldPos, lastPos) > MOVE_LENGTH_LIMIT; } /// <summary> ///Select operation /// </summary> /// <param name="s"></param> /// <param name="exclude"></param> void Select(Selectable s, Selectable exclude = null) { if (mIsDrag == true) { return; } m_excluded = exclude; if (m_currentSelectable) m_currentSelectable.OnPointerExit(m_pointerEvent); m_currentSelectable = s; if (m_currentSelectable) { m_currentSelectable.OnPointerEnter(m_pointerEvent); m_clickHandler = m_currentSelectable.GetComponent<IPointerClickHandler>(); m_dragHandler = m_currentSelectable.GetComponent<IDragHandler>(); } else { m_clickHandler = null; m_dragHandler = null; } } } }
4,MousePointerMoveWrapper
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace XANUtil { public class MousePointerMoveWrapper { private Vector2 mOldPos; private Vector2 mLastPos; private IMouseGesturePointerCallback mIMouseGesturePointerCallback; public void Init(IMouseGesturePointerCallback callback) { mIMouseGesturePointerCallback = callback; } public void Update() { if (Input.GetMouseButtonDown(0)) { mOldPos = Input.mousePosition; } else if (Input.GetMouseButton(0)) { mLastPos = Input.mousePosition; Vector2 deltaPosition = (mLastPos - mOldPos); mIMouseGesturePointerCallback?.MousePointerMoveDeltraPos(deltaPosition); mOldPos = mLastPos; } } } }
5,IMouseGesturePointerCallback
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace XANUtil { public interface IMouseGesturePointerCallback { void MousePointerMoveDeltraPos(Vector2 deltraPos); } }