
?Unity 进阶 之 简单模仿鼠标交互(场景:手机屏幕当做触摸板Touch Pad,移动鼠标,鼠标确定等操作)
目录
?Unity 进阶 之 简单模仿鼠标交互(场景:手机屏幕当做触摸板Touch Pad,移动鼠标,鼠标确定等操作)
一、简单介绍
二、实现原理
三、注意事项
四、效果预览
五、实现步骤
六、关键代码
一、简单介绍
Unity中的一些知识点整理。
本节简单介绍在Unity开发中的,因为项目的开发需要,需要把手机屏幕当做触控板,模拟鼠标移动和点击交互等,所以这里简单的整理一些,或许场景不同,你可能需要进行屏幕适配,这里仅供参考学习使用,如果你有新的方式也可以留言,多谢。
二、实现原理
1、这里使用 Input.GetMouseButtonDown(0) 、Input.GetMouseButton(0) 、Input.GetMouseButtonUp(0) 相关事件来获取位置相关信息进行处理,用来当做UI射线交互的位置
2、获取当前的 UI 的 EventSystem,然后进行对应改写,关键代码如下
m_eventSystem = EventSystem.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); // 这里就是模拟鼠标位置
List<RaycastResult> raycastResults = new List<RaycastResult>(); m_eventSystem.RaycastAll(m_pointerEvent, raycastResults);
三、注意事项
1、使用场景不同,可能需要做适当的屏幕适配
2、因为使用模拟鼠标交互,EventSystem 上默认的 Standalone Input Module 最好移除或者禁用,不然可能影响模拟的鼠标交互操作
3、可能有些情况模拟的鼠标会被遮住,你可以进行对应处理,可以调整UI层级,可以换种方式显示模拟鼠标,可以添加材质调整渲染队列,等
四、效果预览

五、实现步骤
1、打开 Unity ,新建空工程

2、布置场景,一个是模拟的鼠标点,一些事交互控件

3、创建脚本,编写对应的逻辑代码,实现对应功能,IMouseGesturePointerCallback 回调接口,MousePointerMoveWrapper 鼠标位置,ScreenRayRaycasterUIWrapper 获取改写EventSystem当前的UI交互等等

4、 把脚本挂载到场景中,并对应把模拟的鼠标赋值,如图

5、这里Button 设置如下,并挂载一个脚本,用来点击交互,计数使用,方便效果演示

6、EventSystem 上默认的 Standalone Input Module 最好移除或者禁用,不然可能影响模拟的鼠标交互操作

7、运行场景,点击屏幕,移动,就可看到对应鼠标移动,并能简单交互? ,效果如上

六、关键代码
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)
{
// 把鼠标的位置传 Ray 发射位置
mMousePointerMoveWrapper.Init(this);
}
if (mScreenRayRaycasterUIWrapper != null)
{
// 把鼠标的位置传 Ray 发射位置
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>
/// 根据需要做指针位置修正处理
/// </summary>
/// <param name="deltrPos"></param>
/// <returns></returns>
Vector2 ModifyPointerPos(Vector2 deltrPos)
{
return deltrPos;
}
/// <summary>
/// 显示指针位置
/// </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>
/// 简单的模拟指针选中的按钮脚本
/// (可以不用这个,也可重写,仅做参考)
/// </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()
{
// 没有数据屏幕中心(即为 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>
/// 判断是否是缓动
/// </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>
/// 选择操作
/// </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);
}
}

|