游戏的运行过程中会伴随各种各样的输入事件,很多时候我们需要在不同的状态下对相同的输入做不同的处理,本文提供一种处理输入事件的方式以供参考。
一共涉及到了四个类,
1.用于管理输入事件及状态的 MouseEvent(其实不应该叫MouseEvent,它不仅仅是处理鼠标事件)
2.所有输入事件状态的基类MouseState
3.MonoEvent和Singlenton在本文只扮演工具的角色,我在https://blog.csdn.net/xdedzl/article/details/85039761中做了详细的介绍
1.MouseStateType
首先是一个枚举,它和MouseState的子类一一对应,DefaultState是默认状态,必须要有,其余的自己加就可以了
public enum MouseStateType
{
/// <summary>
/// 默认空状态
/// </summary>
DefaultState,
/// <summary>
/// 地形编辑
/// </summary>
TerrainModifier,
}
2.MouseState
这是所有鼠标状态的类的基类,可以将其改写为抽象类,它提供了一系列的虚方法,包括输入事件状态的初始化和结束以及在该状态下的一系列的鼠标事件,由于在我的运用过程中,对于鼠标的处理比较多,所以我将鼠标左键右键的几种输入响应从Update中剥离了出来,其他的比如键盘输入可以在子类重写的Update中调用,注释写的很详细,这些可以根据实际情况调整。
using UnityEngine;
public class MouseState
{
/// <summary>
/// 是否已经初始化
/// </summary>
public bool isInited { get; private set; }
public MouseState() { isInited = false; }
/// <summary>
/// 状态初始化,只会执行一次
/// </summary>
public virtual void OnInit() { isInited = true; }
/// <summary>
/// 状态激活时
/// </summary>
/// <param name="para"></param>
public virtual void OnActive(object para = null, params object[] args) { }
/// <summary>
/// 状态结束时
/// </summary>
public virtual void OnDisactive() { }
/// <summary>
/// 左键按下
/// </summary>
public virtual void OnLeftButtonDown() { }
/// <summary>
/// 左键保持按下状态
/// </summary>
public virtual void OnLeftButtonHold() { }
/// <summary>
/// 右键保持按下状态
/// </summary>
public virtual void OnRightButtonHold() { }
/// <summary>
/// 左键抬起
/// </summary>
public virtual void OnLeftButtonUp() { }
/// <summary>
/// 右键按下
/// </summary>
public virtual void OnRightButtonDown() { }
/// <summary>
/// 右键抬起
/// </summary>
public virtual void OnRightButtonUp() { }
/// <summary>
/// 每帧调用
/// </summary>
public virtual void Update() { }
}
/// <summary>
/// 默认鼠标状态
/// </summary>
public class MouseDefaultState : MouseState { }
3.MouseEvent
这个类继承字单例类。
首先看成员变量和构造函数,在构造函数中初始化了状态字典,并把自身的的Update函数注册到MonoEvent中,MonoEvent是一个继承了MonoBehaviour的单例,这个都在前文提到的链接中有介绍。InitDic方法在后面实现
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class MouseEvent : Singleton<MouseEvent>
{
/// <summary>
/// 当前鼠标状态
/// </summary>
public MouseState CurrentState { get; private set; }
/// <summary>
/// 存储状态枚举和状态类对应关系的字典
/// </summary>
private Dictionary<MouseStateType, MouseState> stateDic;
public MouseStateType CurrentStateType { get; private set; }
/// <summary>
/// 鼠标在上一帧的位置
/// </summary>
private Vector3 lastPosition;
/// <summary>
/// 鼠标是否移动
/// </summary>
public bool MouseMove { get; private set; }
public MouseEvent()
{
InitDic();
CurrentState = stateDic[MouseStateType.DefaultState];
MonoEvent.Instance.UPDATE += Update;
}
然后是Update函数,很简单,就是处理了一些事件输入,可以自行调整。
void Update()
{
//处理鼠标事件 当点击UI面板时不处理
if (!EventSystem.current.IsPointerOverGameObject())
{
if (Input.GetMouseButtonDown(0))
{
CurrentState.OnLeftButtonDown();
}
if (Input.GetMouseButton(0))
{
CurrentState.OnLeftButtonHold();
}
if (Input.GetMouseButton(1))
{
CurrentState.OnRightButtonHold();
}
if (Input.GetMouseButtonUp(0))
{
CurrentState.OnLeftButtonUp();
}
if (Input.GetMouseButtonDown(1))
{
CurrentState.OnRightButtonDown();
}
if (Input.GetMouseButtonUp(1))
{
CurrentState.OnRightButtonUp();
}
if (Input.GetMouseButtonDown(2))
{
//OnMouseRollDown();
}
}
CurrentState.Update();
if (Input.mousePosition != lastPosition)
{
lastPosition = Input.mousePosition;
MouseMove = true;
}
else
{
MouseMove = false;
}
}
输入事件的状态需要由外界控制,状态切换的时候,相应状态的开始和结束事件也会被调用
/// <summary>
/// 改变当前鼠标状态(带参数: 实体单位)
/// </summary>
/// <param name="_type"></param>
/// <param name="para"></param>
public void ChangeState(MouseStateType _type, object para = null, params object[] args)
{
// 状态未改变
if (CurrentStateType == _type)
{
CurrentState.OnActive(para, args);
return;
}
CurrentState.OnDisactive();
CurrentState = stateDic[_type]; // 更新状态
if (!CurrentState.isInited)
CurrentState.OnInit();
CurrentState.OnActive(para, args);
CurrentStateType = _type; // 赋值当前状态类型
}
最后是字典的初始化以及一个小工具
/// <summary>
/// 获取特定类型的状态
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="type"></param>
/// <returns></returns>
public T GetState<T>(MouseStateType type) where T : MouseState
{
return (T)stateDic[type];
}
/// <summary>
/// 初始化字典
/// </summary>
private void InitDic()
{
stateDic = new Dictionary<MouseStateType, MouseState>
{
{ MouseStateType.DefaultState, new MouseDefaultState() },
{ MouseStateType.TerrainModifier, new MouseTerrainModifierState() },
};
}
}