上一篇博客 可以看到Unity自带的EventSystem系统掌管了鼠标输入、触摸输入两大输入类型,并且可根据BaseRayCaster进行射线发射来判断鼠标点击在了哪个物体上,进而可以自定义点击事件响应方法(如下图)来完成一个workflow:

鼠标控制视角unity_自定义

但是现在有一个问题,我的输入类型不是鼠标也不是触摸,比如说我目前的输入就是一个已知的坐标。我该怎么模拟一次点击效果呢?

 有朋友可能会说,你要实现什么样的效果= =,比如说正统的鼠标点击我可以这么写,我把这个cs文件挂载到一个cube上,发现当我的鼠标点击到cube以后,cube就会被变色:

void Update()
    {
         
        if(Input.GetMouseButtonDown(0))
        {
            Debug.Log("Input.GetMouseButtonDown response");
        }
    }
    void OnMouseDown()
    {
        Debug.Log("OnMouseDown response");
        //该物体变色
        
    }

    void OnGUI()
    {
        if(Event.current!=null && Event.current.type == EventType.MouseDown)
        {
            Debug.Log("EventType.mouseDown response");
        }
    }

如果你的输入不是鼠标而是一个已知的(x,y)坐标,那你直接这么写,不行吗?

public Vector2 position;
void Update()
{
    position = xx.GetPosition();
    if(position)
       OnSimuMouseDown();
}
void OnSimuMouseDown()
{
    if(position)
        //该物体变色
    
}

不。这有一个缺陷,在第一个情况里,OnMouseDown()是当鼠标真的点击在cube上的时候才会被触发,但是第二种情况是我获取到了position就会触发OnSimuMouseDown(),如果这个position的位置不在cube身上,却让cube变色了,是不是背离初衷?所以代码就会变成了只能加上判断位置,就会变得相当麻烦。

void OnSimuMouseDown()

{
    if(position在Cube身上)
        //该物体变色
}

还有一种情况就是,如果我不想让物体变色呢?我是想拖动物体移动呢?真正的鼠标点击很好办,这么写就行了,因为Unity已经给封装好了事件:

void OnMouseDrag()
    {
        //获取到鼠标的位置(鼠标水平的输入和竖直的输入以及距离)
        Vector3 mousePosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance);
        //物体的位置,屏幕坐标转换为世界坐标
        Vector3 objectPosition = Camera.main.ScreenToWorldPoint(mousePosition);
        //把鼠标位置传给物体
        transform.position = objectPosition;
    }

如果只给你一个坐标,然后每1s给你一个新的坐标,让你“拖动”Cube随着这个坐标运动你会怎么写?是不是想想都觉得头大?万一你的项目中需要很多这样的操作呢?


所以我们要模拟一个假鼠标。这里我们用到了TouchScript插件。首先来看一个例子我们来了解一下TouchScript对Unity的一个基本Event做了哪些改动。

鼠标控制视角unity_touchscript_02

这个Standard Layer是干嘛的,其实就是从摄像机发射射线的,可以判断鼠标点击在了哪个物体上。这里我们只让该射线判断3D物体。

这个组件大概是重写了Unity自带的PhysicsRaycaster组件还有canvas上边的GraphicRaycaster组件:

鼠标控制视角unity_鼠标控制视角unity_03

鼠标控制视角unity_touchscript_04

然后是Cursors这个预制体,一切照常,不用管,TouchManager我们不用StandardInput,而是用TUIO Input,因为这个雷达更能表示一个单纯的坐标,更具有代表性:

鼠标控制视角unity_鼠标控制视角unity_05

鼠标控制视角unity_touchscript_06

EventSystem是神经枢纽,无论是在Unity自带的Event还是在TouchScript里都一样,非常重要。这里我们的EventSystem很简约。是不是发现少了点东西?是的,Standalone Input Module我们没用,个人感觉TouchScript的StandardInput已经把它重写了(虽然我们也没加),TUIOInput算是一个custom Input Module,假装可以被EventSystem处理:

鼠标控制视角unity_鼠标控制视角unity_07

鼠标控制视角unity_sed_08

最后是Cube,作为一个3D物体,要想检测到摄像机射线,Collider是少不了的。那么Transformer和Transformer Gesture这两个组件是干嘛?来对比一下右图(上一篇博客)就知道了:

鼠标控制视角unity_touchscript_09

鼠标控制视角unity_鼠标模拟_10

可以看到Unity本身的Event是可以自定义相应函数的,比如说当我监听到PointerClick的时候,我就可以怎么怎么样:

public void OnPointerClickHandler() //在cube上挂上EventTrigger并指定该方法

{

Debug.Log("????");
//获取该物体的材质并让该物体变色

}

那么Transformer和Transformer Gesture有异曲同工之妙,比如说当我的系统里有一个Pointer pressed,那么我就可以怎么怎么样,我们来看Transformer Gesture部分源码:

鼠标控制视角unity_touchscript_11

而Transformer组件是获取Transformer Gesture的transform 数据并apply到真实的物体上的,比如说移动啊,旋转啊,放大缩小啊。我们要想实现该物体变色可以这样写

/**
*┌──────────────────────────────────────────────────────────────┐
*│ Description:                                                    
*│ Author:#AUTHOR#                                              
*│ Version:#VERSION#                                                
*│ Date:#DATE#  
*│  UnityVersion: #UNITYVERSION#                            
*└──────────────────────────────────────────────────────────────┘
*┌──────────────────────────────────────────────────────────────┐                                   
*│ ClassName:#SCRIPTFULLNAME#                                      
*└──────────────────────────────────────────────────────────────┘
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TouchScript;
using TouchScript.Gestures;
using TouchScript.Gestures.TransformGestures;

public class TestTouchScript : TransformGesture
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }


    private void OnTriggerEnter2D(Collider2D other)
    {
        Debug.Log(other.name);
    }
    void OnMouseDown()  //针对的是鼠标点击
    {
        Debug.Log("OnMouseDown");
    }

    protected override void pointersPressed(IList<TouchScript.Pointers.Pointer> pointers)
    {
        base.pointersPressed(pointers);
        Debug.Log("aaaa");
        //获取该物体的材质并让该物体变色
        
    }
    protected override void pointersReleased(IList<TouchScript.Pointers.Pointer> pointers)
    {
        base.pointersReleased(pointers);
        Debug.Log("?????????????????");
    }

}

可以看到我们定义了一个类继承了TransformGesture,并重写了它的反应函数,就相当于是OnMousedown()函数一样了。也相当于是这种自定义的响应函数,参照上一篇博客:

public void OnPointerDown(PointerEventData eventData)
    {
        Debug.Log(eventData.button);
        Debug.Log(eventData);
        Debug.Log(Input.mousePosition);

        Debug.Log(eventData.pointerPressRaycast.gameObject.name);
        Debug.Log("press");
    }

做实验,发现通过雷达模拟器,我们可以让该Cube有所动作,并且可以让Cube随着虚拟指针进行移动:

鼠标控制视角unity_touchscript_12

 

同样我们不用TUIOInput而是用TouchScript自定义的StandardInput的话:

鼠标控制视角unity_touchscript_13

效果是这样的,依然可以通过鼠标移动Cube,并且还会触发OnMouseDown(),因为这是真实的鼠标点击:

鼠标控制视角unity_鼠标控制视角unity_14

鼠标控制视角unity_鼠标控制视角unity_15

 


二更:

后来我发现TouchScript有一个Press Gesture组件,已经把点击这一动作给封装好了,所以可以直接在cube上用这个:

鼠标控制视角unity_鼠标模拟_16

重点是Press Action.cs,这个是我自己加的,它就相当于是分发press事件以后,自定义反应的:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using TouchScript;
using TouchScript.Utils;
using TouchScript.Gestures;
using System;


public class PressAction : MonoBehaviour//,IPointerDownHandler
{
    private PressGesture pressGesture;

    // Start is called before the first frame update
    void Start()
    {
        
    }
    private void OnEnable()
    {
        pressGesture = GetComponent<PressGesture>();
        pressGesture.Pressed += pressedHandler;
    }
    private void OnDisable()
    {   
        pressGesture.Pressed -= pressedHandler;
    }

    //相当于是void MouseDown()或者void OnPointerDown(PointerEventData eventData)
    private void pressedHandler(object sender, EventArgs e)
    {
        Debug.Log("变色吧,皮卡丘!");
        
    }



    // Update is called once per frame
    void Update()
    {
         
    }

}

但是很遗憾的是,TouchScript在2017年以后就不再更新了,所以决定不用这个插件了。。。= =。

蛋疼。。。。