一、鼠标控制移动
原理:每次鼠标点击地面时获取该点的坐标,通过Camera.main.ScreenPointToRay()方法从摄像机发射一条射线到该点,再通过Physics.Raycast()方法获取到该点的信息,将其坐标设置为Player的导航代理的终点(destination)
该方法需要传入一个坐标值作为射线终点,此处传入的应为鼠标点击的位置(Input.mousePosition):
传入一条射线到此方法,同时设置一个变量用于接收out出来的射线碰撞信息:
由于需要在PlayerController中跨脚本调用MouseManager来设置代理的终点,故将MouseManager设置为单例模式;同时,为实现鼠标点击一触发就为player agent设置终点,我们创建一个C#自带的Action<>事件,设置为需传入一个Vector3类型的形参,并在PlayerController脚本中为Move()方法订阅该事件
以下为MouseManager脚本的设置
public class MouseManager : MonoBehaviour
{
public static MouseManager Instance; //创建单例
private RaycastHit hitInfo; //接收射线信息
public event Action<Vector3> ClickEvent; //创建事件提供订阅
private void Awake()
{
if(Instance != null) //防止重复创建
{
Destroy(gameObject);
}
else
{
Instance = this;
}
}
private void Update()
{
MouseHit();
OnMouseClick();
}
/// <summary>
/// 实时发射射线检测鼠标点击位置
/// </summary>
private void MouseHit()
{
Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hitInfo);
}
/// <summary>
/// 鼠标点击地面控制移动
/// </summary>
public void OnMouseClick()
{
if(Input.GetMouseButtonDown(0) && hitInfo.collider != null && hitInfo.collider.gameObject.CompareTag("Ground"))
{
ClickEvent?.Invoke(hitInfo.point); //触发事件
}
}
}
以下为PlayerController脚本的设置
public class PlayerController : MonoBehaviour
{
private NavMeshAgent agent;
private void Awake()
{
agent = GetComponent<NavMeshAgent>();
}
private void Start()
{
MouseManager.Instance.ClickEvent += Move; //订阅MouseManager中的事件
}
private void Move(Vector3 destination)
{
agent.SetDestination(destination);
}
}
二、鼠标贴图切换
导入贴图素材后,如下设置
为实现鼠标贴图的切换,我们需要定义Texture2D类型的变量存储贴图。由于在实现移动的过程中我们已经获取了鼠标点击位置的信息(hitInfo),故只需要检索该点的gameObject的tag类型即可
我们使用以下方法更改鼠标贴图
由于鼠标图标中只有左上角的点有触发作用,故我们需要设置偏移值修正点击的位置。在该案例中,鼠标贴图的偏移值如图
public Texture2D point, doorway, attack, target, arrow;
//······//
/// <summary>
/// 切换鼠标贴图
/// </summary>
public void SwitchCursor()
{
switch (hitInfo.collider.gameObject.tag)
{
case "Ground":
{
Cursor.SetCursor(target, new Vector2(16, 16), CursorMode.Auto);
break;
}
//设置其他贴图
default:
{
break;
}
}
}
MouseManager完整代码如下
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MouseManager : MonoBehaviour
{
public static MouseManager Instance; //创建单例
private RaycastHit hitInfo; //接收射线信息
public event Action<Vector3> ClickEvent; //创建事件提供订阅
public Texture2D point, doorway, attack, target, arrow;
private void Awake()
{
if(Instance != null) //防止重复创建
{
Destroy(gameObject);
}
else
{
Instance = this;
}
}
private void Update()
{
MouseHit();
OnMouseClick();
SwitchCursor();
}
/// <summary>
/// 实时发射射线检测鼠标点击位置
/// </summary>
private void MouseHit()
{
Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hitInfo);
}
/// <summary>
/// 鼠标点击地面控制移动
/// </summary>
public void OnMouseClick()
{
if(Input.GetMouseButtonDown(0) && hitInfo.collider != null && hitInfo.collider.gameObject.CompareTag("Ground"))
{
ClickEvent?.Invoke(hitInfo.point); //触发事件
}
}
/// <summary>
/// 切换鼠标贴图
/// </summary>
public void SwitchCursor()
{
switch (hitInfo.collider.gameObject.tag)
{
case "Ground":
{
Cursor.SetCursor(target, new Vector2(16, 16), CursorMode.Auto);
break;
}
//设置其他贴图
default:
{
break;
}
}
}
}