目的是将检测和响应分离开,降低耦合性,提高易用性;
主要功能:鼠标(手柄)指向、移开、点击物体(这里的物体可以是游戏物体、模型、UGUI、NGUI等等,可以说几乎任何需要交互的对象都适用),响应这三个操作;
基本原理:通过射线(Ray)来检测目标对象;
主要脚本:1、ButtonSetFather(定义一个父类主要包含三个响应方法,无需挂载)
2、OnTagetButton(挂在目标物体上,注册三个响应事件)
3、NormalButtonSet(挂在目标物体上重写父类方法,实现各自需求的功能)
4、InteroperatToRay(用来发射射线来检测碰触到的物体,随便挂载一个物体上)
5、还有一点不要忘记,目标物体上一定要有BoxCollider,大小自己调整
public abstract class ButtonSetFather : MonoBehaviour
{
public abstract void OnFocusRespons(); //鼠标指向响应
public abstract void OnLoseFocusRespons(); //鼠标离开响应
public abstract void OnClickRespons(); //鼠标点击响应
}
public class OnTagetButton: MonoBehaviour
{
//定义三个事件,这里需要引用命名空间“using UnityEngine.Events;”
public UnityEvent OnClick, OnFocus, OnLoseFocus;
private void Awake()
{
//这里可以设置每个物体的层级方便控制点击层级
this.transform.gameObject.layer = 8;
ButtonSetFather Bsf = this.GetComponent<ButtonSetFather>(); //实例化父类
OnClick.AddListener(Bsf.OnClickRespons); //监听点击事件
OnFocus.AddListener(Bsf.OnFocusRespons); //鉴听指向事件
OnLoseFocus.AddListener(Bsf.OnLoseFocusRespons); //监听移开事件
}
public void GetFocus()
{
OnFocus.Invoke(); //响应指向
}
public void LoseFocus()
{
OnLoseFocus.Invoke(); //响应移开
}
public void GetClicked()
{
OnClick.Invoke(); //响应点击
}
}
public class NormalButtonSet : ButtonSetFather
{
//在这里可以根据自己需求改写这三个方法,我这里写的是指向变大,移开缩小
Vector3 startScale;
private void Start()
{
startScale = new Vector3(1f,1f,1f);
}
public override void OnClickRespons()
{
}
public override void OnFocusRespons()
{
Debug.Log("射线指向于此");
this.transform.localScale = startScale * 1.4f; //指向物体(UI)变大
}
public override void OnLoseFocusRespons()
{
Debug.Log("Loset");
this.transform.localScale = startScale; //移开物体(UI)变小
}
}
public class InteroperatToRay : MonoBehaviour
{
private OnTagetButton _currentButton; //定义一个先接触到的对象
public OnTagetButton CurrentButton
{
get
{
return _currentButton;
}
}
private OnTagetButton_lastButton; //定义一个在_currentButton之前接触到的对象
private Ray ray = new Ray(); //使用射线来检测碰触到的物体
private RaycastHit hitInfo;
private OnTagetButton hitButton; //用来临时存储碰触到的对象
private void Update()
{
//射线从相机为远点发出指向鼠标位置
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hitInfo, Mathf.Infinity, 1 << 8))
{
try
{
//使用try catch试着得到射线接触到的物体
hitButton = hitInfo.transform.GetComponent<OnTagetButton>();
}
catch
{
Debug.LogError("标记为button的物体,没有mybutton script " + hitInfo.transform.name);
}
//如果得到了碰触到的物体
if (hitButton != null)
{
//使用_currentButton来存储碰触到的物体
_currentButton = hitButton;
if (_lastButton != _currentButton)//若这次和上次碰触到的不是一个对象
{
//次目标响应指向事件,这里可以根据自己需求写点击移开指向事件
_currentButton.GetFocus();
if (_lastButton != null)//若上次的目标不为空,那么上次目标响应移开事件
_lastButton.LoseFocus();
_lastButton = CurrentButton;//这次目标付给_lastButton
}
}
else
{
_currentButton = null;
if (_lastButton != null)
{
_lastButton.LoseFocus();
_lastButton = null;
}
}
}
else
{
_currentButton = null;
if (_lastButton != null)
{
_lastButton.LoseFocus();
_lastButton = null;
}
}
}
}