65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Unity* 3D 中使用 TouchScript 实现手势序列

starIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

1.00/5 (1投票)

2014 年 9 月 12 日

CPOL

10分钟阅读

viewsIcon

8936

本文介绍如何使用触摸目标配置场景来控制第一人称控制器(FPC)。

引言

在配置触摸目标以控制场景中的其他元素时,重要的是要最小化控制元素占据的屏幕空间。这样,您可以将更多 Ultrabook™ 设备的可视屏幕区域用于显示视觉动作,而将更少的区域用于用户交互。实现此目的的一种方法是配置触摸目标以处理多种手势组合,从而无需在屏幕上添加更多触摸目标。一个例子是持续点击图形用户界面(GUI)小部件,使炮塔在开火时旋转,而不是使用一个用于开火的专用 GUI 小部件和另一个用于旋转炮塔的专用 GUI 小部件(或 Unity* 3D 场景中的另一个资源)。

本文介绍如何使用触摸目标配置场景来控制第一人称控制器(FPC)。最初,您将配置触摸目标以实现基本的 FPC 位置和旋转;然后,为其添加额外功能。此额外功能是通过现有的 GUI 小部件实现的,无需添加几何体。生成的场景将演示 Unity 3D 在 Windows* 8 上作为处理多种序列中使用的手势的可行平台。

配置 Unity* 3D 场景

我开始设置场景,通过导入一个具有抬高高程和树木的 FBX 场景模型,这些模型是我从 Autodesk 3ds Max* 导出的。然后,我在场景模型中心放置一个 FPC。

我将场景主摄像机(FPC 的子对象)的景深设置为 -1。我创建了一个专用的 GUI 小部件摄像机,它具有正交投影,宽度为 1,高度为 0.5,并设置为“Don’t Clear”标志。然后,我创建了一个 GUIWidget 层,并将其设置为 GUI 小部件摄像机的剔除掩码。

接下来,我将用于 FPC 操作的基本 GUI 小部件放置在场景中,使其位于专用正交摄像机的视野内。对于左手,我为每个手指配置了一个球体。左手小指球体使 FPC 向左移动,左手无名指球体使其向前移动,左手中指球体使其向右移动,左手食指球体使其向后移动。左手拇指球体使 FPC 跳跃并以顺时针 30 度角发射球形弹丸。

对于右手 GUI 小部件,我创建了一个立方体(通过正交投影使其变成方形)。我将一个平移手势配置给此立方体,并将其链接到 MouseLook.cs 脚本。此小部件提供的功能类似于 Ultrabook 触摸板。

我将这些 GUI 小部件放置在主摄像机视野之外,并将其层设置为 GUIWidget。图 1 显示了运行时场景,其中使用这些 GUI 小部件发射弹丸和操作 FPC 的位置。

图 1. 带有场景模型和发射的球形弹丸的 FPC 场景

从 FPC 发射的弹丸会穿过场景中的树木。要解决此问题,我需要为每棵树配置一个网格或盒子碰撞器。此场景的另一个问题是,如果我使用触摸板让 FPC 向下看,同时按住无名指向前移动,则前向速度会很慢。要解决此问题,我在按下“向前移动”按钮时限制了“向下看”的角度。

多次点击

基础场景包含一个 FPC,该 FPC 以指定的偏离中心角度发射弹丸(参见图 1)。此偏离中心角度的默认值为俯视 FPC 时顺时针 30 度。

我将场景配置为多次点击,其时间间隔小于指定时间差,以改变弹丸发射的角度,然后发射弹丸。通过操作左手拇指跳跃脚本中的浮点变量,我可以将此行为配置为随着序列中点击次数的增加而呈指数级增加角度。这些浮点变量控制发射角度并跟踪自上次发射弹丸以来的时间。

	private float timeSinceFire = 0.0f;
	private float firingAngle = 30.0f;

然后,我配置左手拇指跳跃脚本中的 Update 循环,如果跳跃球体点击手势的时间间隔小于半秒,则减小发射角度。如果点击间隔大于半秒,或者发射角度已减小到 0 度,则发射角度将重置为 30 度。代码如下:

		timeSinceFire += Time.deltaTime;

			if(timeSinceFire <= 0.5f)
			{
				firingAngle += -1.0f;

			}
			else
			{
				firingAngle = 30.0f;
			}
			
			timeSinceFire = 0.0f;
			
			if(firingAngle <= 0)
			{
				firingAngle = 30;
			}


			projectileSpawnRotation = Quaternion.AngleAxis(firingAngle,CH.transform.up);

此代码产生了横向移动效果,即连续点击会导致在发射弹丸的同时减小发射角度(参见图 2)。这种效果可以由用户自定义,或者在模拟或游戏中特定条件下可用。

图 2. 连续点击会改变发射弹丸的航向。

缩放后跟平移

我将图 1 右下角的正方形配置为功能类似于键盘上的触摸板。在正方形上平移不会移动正方形,而是通过向 FPS 的 MouseLook 脚本馈送数据来使场景主摄像机上下左右旋转。同样,正方形接收的缩放手势(类似于其他平台上的捏合手势)不会缩放正方形,而是会改变主摄像机的视场(FOV),允许用户放大和缩小主摄像机当前正在查看的内容(参见图 3)。我将配置一个在缩放手势之后不久开始的平移手势,以将 FOV 重置为默认的 60 度。

我通过设置一个布尔变量 panned 和一个浮点变量来存储自上次缩放手势以来的时间来配置此功能。

	private float timeSinceScale;
	private float timeSincePan;
	private bool panned;

当启动缩放手势时,我将 `timeSinceScale` 变量设置为 0.0f,当启动平移手势时,将 `panned` 变量设置为 True。场景主摄像机的 FOV 在 Update 循环中按如下方式调整,该循环附加在触摸板立方体上的脚本中:

		timeSinceScale += Time.deltaTime;
		timeSincePan += Time.deltaTime;
		
		if(panned && timeSinceScale >= 0.5f && timeSincePan >= 0.5f)
		{
			fieldOfView += 5.0f;
			panned = false;
		}
		
		if(panned && timeSinceScale <= 0.5f)
		{
			fieldOfView = 60.0f;
			panned = false;
		}
			
		Camera.main.fieldOfView = fieldOfView;

以下是 `onScale` 和 `onPan` 函数。请注意 `timeSincePan` 浮点变量,它可防止在将触摸板用于摄像机时 FOV 持续增加。

	private void onPanStateChanged(object sender, GestureStateChangeEventArgs e)
    {
        switch (e.State)
        {
            case Gesture.GestureState.Began:
            case Gesture.GestureState.Changed:
                var target = sender as PanGesture;
                Debug.DrawRay(transform.position, target.WorldTransformPlane.normal);
                Debug.DrawRay(transform.position, target.WorldDeltaPosition.normalized);
                
                var local = new Vector3(transform.InverseTransformDirection(target.WorldDeltaPosition).x, transform.InverseTransformDirection(target.WorldDeltaPosition).y, 0);
                targetPan += transform.InverseTransformDirection(transform.TransformDirection(local));
				
                //if (transform.InverseTransformDirection(transform.parent.TransformDirection(targetPan - startPos)).y < 0) targetPan = startPos;
                timeSincePan = 0.0f;
				panned = true;
				break;

        }

    }
	
	private void onScaleStateChanged(object sender, GestureStateChangeEventArgs e)
    {
        switch (e.State)
        {
            case Gesture.GestureState.Began:
            case Gesture.GestureState.Changed:
                var gesture = (ScaleGesture)sender;

                if (Math.Abs(gesture.LocalDeltaScale) > 0.01 )
                {
					fieldOfView *= gesture.LocalDeltaScale;
				
					if(fieldOfView >= 170){fieldOfView = 170;}
					if(fieldOfView <= 1){fieldOfView = 1;}
				
					timeSinceScale = 0.0f;


                }
                break;
        }
    }

图 3. 场景主摄像机通过右侧 GUI 触摸板模拟器“放大”远处的景物。

按下并释放后跟轻扫

以下手势序列在左手小球体收到按下和释放手势,并在半秒内紧接着一个轻扫手势时,会增加 FPC 的水平速度。

为了添加此功能,我首先添加一个浮点变量来跟踪自球体收到释放手势以来的时间,以及一个布尔变量来跟踪球体是否收到轻扫手势。

	private float timeSinceRelease;
	private bool flicked;

作为场景初始设置的一部分,我将附加在左手小球体上的脚本配置为可以访问 FPC 的 InputController 脚本,这允许左手小球体触发 FPC 向左移动。控制 FPC 水平速度的变量不在 InputController 中,而是在 FPC 的 CharacterMotor 中。授予左手小球体脚本对 CharacterMotor 的访问权限的配置类似如下:

		CH = GameObject.Find("First Person Controller");
		CHFPSInputController = (FPSInputController)CH.GetComponent("FPSInputController");
		CHCharacterMotor = (CharacterMotor)CH.GetComponent ("CharacterMotor");

脚本的 `onFlick` 函数仅将布尔变量 `flicked` 设置为 True。

脚本的 `Update` 函数(每帧调用一次)按如下方式调整 FPC 的水平移动速度:

		if(flicked && timeSinceRelease <= 0.5f)
		{
			CHCharacterMotor.movement.maxSidewaysSpeed += 2.0f;
			flicked = false;
		}
		
		timeSinceRelease += Time.deltaTime;
	}

此代码使用户能够通过按下并释放左手小球体,然后在半秒内轻扫左手小球体来增加 FPC 的水平移动速度。您可以配置以多种方式减少水平移动速度的功能,包括在按下并释放左手食指球体后进行轻扫手势。请注意,`CHCharacterMotor.movement` 方法不仅包含 `maxSidewaysSpeed`,还包含重力、`maxForwardsSpeed`、`maxBackwardsSpeed` 等参数。许多 TouchScript 手势以及接收它们的几何体与这些参数结合使用,为开发 Unity 3D 场景的触摸界面提供了许多选项和策略。在为这些类型的应用程序开发触摸界面时,请尝试这些选项,以筛选出最有效和最符合人体工程学用户体验的选项。

手势序列的问题

本文示例中配置的手势序列在很大程度上依赖于 Time.deltaTime 函数。我将此差值与差值之前和之后的各种手势结合使用来确定操作。配置这些示例时遇到的两个主要问题是时间差的幅度以及所使用的手势。

时间差

本文中使用的时间差为半秒。当我使用十分之一秒的较小幅度时,手势序列未被识别。尽管我觉得我敲击的速度足够快以识别手势序列,但预期的场景操作并未发生。这可能是硬件和软件延迟的结果。因此,在开发手势序列时,最好牢记目标硬件平台的性能特征。

手势

在配置此示例时,我最初计划让缩放和平移手势后跟点击和轻扫手势。在缩放和平移手势按预期工作后,我引入了点击手势,这导致缩放和平移手势停止工作。尽管我能够配置缩放后跟平移的序列,但这并不是最用户友好的手势序列。一个更有用的序列可能包括在小部件中设置另一个几何目标,以在缩放和平移手势之后接受点击和轻扫手势。

我在本例中使用半秒的时间差作为采取(或不采取)操作的断点。尽管它增加了用户界面(UI)的复杂性,但您可以将此示例配置为使用多个时间差。其中,按下并释放手势后半秒内的轻扫手势可能会增加水平速度,而按下并释放手势后半秒到 1 秒之间的轻扫手势可能会降低水平速度。以这种方式使用时间差不仅为 UI 提供了灵活性,而且还可以用于在场景本身中植入“复活节彩蛋”。

结论

本文配置的手势序列场景在运行 Windows 8 的 Ultrabook 设备上使用了 Unity 3D 和 TouchScript。实现的序列旨在减少用户与应用程序交互所需的触摸屏区域。用户交互占用的触摸屏区域越少,您就可以为更具视觉吸引力的内容分配更多区域。

当手势序列无法按预期执行时,我设法制定了一个可接受的替代方案。此性能调整的一部分是调整 Time.deltaTime 差值,以便在可用硬件上以期望的方式执行手势序列。因此,本文构建的 Unity 3D 场景表明,运行 Windows 8 的 Ultrabook 设备是开发使用手势序列的应用程序的可行平台。

相关内容

Intel®Developer Zone 提供跨平台应用程序开发工具和操作指南、平台和技术信息、代码示例以及同行专长,以帮助开发人员创新和取得成功。加入我们的物联网、Android*、Intel® RealSense™ 技术和 Windows* 社区,下载工具、访问开发套件、与志同道合的开发人员分享想法,并参与黑客马拉松、竞赛、路演和本地活动。

Intel、Intel 徽标、Ultrabook 和 VTune 是 Intel Corporation 在美国和其他国家/地区的商标。
*其他名称和品牌可能被声明为他方财产
版权所有© 2014 Intel Corporation。保留所有权利。

© . All rights reserved.