思考并回答以下问题:
1.如何通过脚本移动,旋转和缩放对象?
2.四元数是什么?如何使用?
3.如何自定义输入?
4.如何使用重力感应?
本章涵盖
- 移动、旋转和缩放游戏对象
- 工具类
- 输入控制
移动、旋转和缩放游戏对象
在3D世界中,任何一个游戏对象在创建的时候都会附带Transform组件,并且该组件是无法删除的。
Transform面板中一共包含3个属性:Position(位置),Rotation(旋转)和Scale(缩放)。既可在场景中使用移动工具来拖动和旋转模型,也可以直接在Inspector窗口下的Transform面板中手动填写对象的位置、旋转和缩放的数值。
游戏对象的位置
在3D世界中,任何一个模型的三维坐标都保存在Vector3容器中,该容器将记录物体在x轴、y轴和z轴方向的坐标。一旦在程序中修改该游戏对象的坐标,那么Scene视图中游戏对象的位置将发生改变。
移动游戏对象
游戏对象在原有位置的基础上继续移动,在代码中可以使用transform.Translate()函数实现,此函数的唯一参数为位移的数值:
transform.Translate(Vector3 offset);
该函数相当于transform.position = transform.position + offset。
缩放游戏对象
在Unity中,可以通过代码动态缩放游戏中的游戏对象。1
transform.localScale = new Vector3(x,y,z);
其中Vector3的x为x轴向的缩放,y为y轴向的缩放,z为z轴向的缩放。也可以通过下面的代码格式快速整体缩放:1
transform.localScale *= 1.2f; // 对象整体放大1.2倍
旋转游戏对象
游戏对象的旋转方式分为两种:第一种是自转;第二种是围绕旋转,也就是围绕一个点或者一个游戏对象来旋转。
- transform.Rotate():该函数用于设置游戏对象自转。
- transform.RotateAround():该函数用于设置游戏对象围绕某一个点旋转。
- Time.deltatime:上一帧所消耗的时间,这里用作模型旋转的速度系数。
- Vector3.right:x轴正方向。
- Vector3.up:y轴正方向。
- vector3.forward:z轴正方向。
实例
在本实例中,我们会通过点击按钮对游戏对象进行对应的移动缩放旋转操作,如代码所示。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37using UnityEngine;
using System.Collections;
public class testDemo : MonoBehaviour
{
public GameObject cube;
public GameObject cylinder;
void OnGUI()
{
if(GUILayout.Button("向左移动物体"))
{
cube.transform.Translate(new Vector3(-0.5f, 0f, 0f));
}
if(GUILayout.Button("向右移动物体"))
{
cube.transform.position = cube.transform.position + new Vector3(0.5f, 0f, 0f);
}
if (GUILayout.Button("放大物体"))
{
cube.transform.localScale *= 1.2f;
}
if(GUILayout.Button("缩小物体"))
{
cube.transform.localScale = 0.8f;
}
if (GUILayout.Button("旋转物体"))
{
cube.transform.Rotate(new Vector3(0, 10, 0));
}
if(GUILayout.Button("围绕圆柱体旋转物体")
{
cube.transform.RotateAround(cylinder.transform.position, Vector3.up, 10);
}
}
}
工具类
时间类
Unity提供了Time类,这个类主要用来得到与时间相关的信息。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16using UnityEngine;
using System.Collections;
public class TimeDemo : MonoBehavlour
{
void OnGUI()
{
GUILayout.Label("当前游戏时间" + Time.time);
GUILayout.Label("游戏时间的缩放" + Time.timeScale);
GUILayout.Label("上一帧所消耗的时间" + Time.deltaTime);
GUILayout.Label("固定增量时间" + Time.fixedTime);
GUILayout.Label("上一帧所消耗的固定时间" + Time.fixedDeltaTime);
GUILayout.Label("真实逝去时间" + Time.realtimeSinceStartup);
}
}
Time.time:从游戏开始时计时,截止到目前共运行的游戏时间,受Time.timeScale影响,游戏暂停时该时间不增加。
Time.timeScale:时间流逝的速度。当该值设置为1时表示和现实中的时间流逝一致;当该值设置为0.5时,表示真实时间逝去1秒时,游戏时间仅逝去0.5秒;当设置该值为2表示真实时间逝去1秒时,游戏时间逝去2秒。
Time.deltaTime:上一帧所消耗的时间。
Time.fixedTime:每一次执行FixedUpdate()函数的时间间隔。可通过导航菜单栏Edit->Project Settings->Time菜单项设置。
Time.fixedDeltaTime:固定更新上一帧所消耗的时间。
Time.realtimeSinceStartup:从游戏开始时计时,截止到目前共运行的真实时间,不受Time.timeScale影响,游戏暂停时该时间仍然增加。
随机数
在开发中,有时需要获取程序中的随机数,这可以使用Random类中的Random.Range()函数实现,其中该函数的第一个参数传入的是随机数的最小值,第二个参数传入的是随机数的最大值。两个参数共同决定了生成随机数的值域。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17using UnityEngine;
using System.Collections;
public class RandomDemo : MonoBehaviour
{
void OnGUI()
{
if(GUILayout.Button("生成随机数"))
{
// 生成随机数
int i = Random.Range(0, 10);
Debug.Log("随机生成的一个0~10之间的整数是:" + i);
float f = Random.Range(0f, 10f);
Debug.Log("随机生成的一个0~10之间的浮点数是:" + f);.
}
}
}
数学类
Unity提供了一个数学类Mathf,该类位于UnityEngine命名空间下。以下是Mathf类里常用的函数和属性。
- Mathf.Abs(a):返回a的绝对值,参数为整数或者浮点数。
- Mathf.Clamp(a, min, max):将a限制在min和max之间,参数为整数或者浮点数。
- Mathf.Lerp(from, to, a):插入值,返回值=from+to(1-a)。
- Mathf.Min(a, b, c):返回两个或n个数的最小值,参数为整数或者浮点数。
- Mathf.Max(a, b, c):返回两个或n个数的最大值,参数为整数或者浮点数。
- Mathf.Pow(a, b):a的b次方。
- Mathf.Deg2Rad:常量浮点数,0.0174532924f,用于将角度转换成弧度。
- Mathf.Rad2Deg:常量浮点数,57.29578f,用于将弧度转换成角度。
- Mathf.Pi:常量浮点数,表示圆周率。
- Mathf.Sin(a):返回弧度a的正弦值。
- Mathf.Cos(a):返回弧度a的余弦值。
- Mathf.Tan(a):返回弧度a的正切值。
四元数
四元数(Quaternion)是非常重要的工具类之一。在Unity中所有用到模型旋转的,其底层都是由四元数实现的,它可以精确地计算模型旋转的角度。在场景中创建一个立方体,并添加代码脚本。点击运行,立方体会一直旋转。
1 | using UnityEngine; |
我们使用Quaternion.Euler(Vector3 vec)函数,传入一个Vector3(x,y,z),分别代表围绕x、y、z轴旋转的角度,返回该角度对应的四元数,将四元数赋值给立方体的rotation旋转变量完成旋转。
输入控制
玩家点击鼠标左键开火、按住键盘w键前进等都属于输入控制,如何监测输入是非常重要的内容。
计算机输入
计算机设备的输入指的是仅对应键盘和鼠标的输入检测,一般单项检测分为3类:按下、拉住、抬起。
1 | using UnityEngine; |
自定义输入
但是键盘鼠标输入检测十分局限,一般仅用于计算机等设备,下面就来介绍另一种方法。
自定义输入可以设置输入类型名称、输入设备类型、输入键位等参数,从而方便地解决了计算机与家用机的输入兼容。
点击导航菜单栏->Edit->Project Settings->Input,打开输入设置界面。如下图所示,Unity提供了默认的输入设置,包括了“Horizontal”横向移动、“Vertical”纵向移动、“Fire1”开火按钮等输入。展开“Fire1”输入项,各项参数如图所示,参数说明见下表。
参数 | 说明 |
---|---|
Name | 名字 |
Descriptive Name | 控制设置中显示的正值名称 |
Descriptive Negative Name | 控制设置中显示的负值名称 |
Negative Button | 该按钮用于负方向移动轴 |
Positive Button | 该按钮用于正方向移动轴 |
Alt Negative Button | 备选按钮用于负方向移动轴 |
Alt Positive Button | 备选按钮用于正方向移动轴 |
Gravity | 当没有相关按钮按下时,回归0的速度。单位/秒 |
Dead | 模拟的死区大小。设定范围内所有模拟设备的值为0 |
Sensitivity | 灵敏度,单位/秒。仅用于数码设备 |
Snap | 如果启用,当按下相反方向的按钮,该轴值将重设为0 |
Invert | 如果启用,负按钮将提供正值,反之亦然 |
Type | 控制轴的输人设备类型 |
Axis | 连接设备的轴将控制这个轴 |
Joy Num | 连接操纵杆将控制这个轴 |
可以发现很多键如Horizontal都出现了重复,这是因为所有键位键盘鼠标是单独的一套键而手柄则是另一套。例如“Fire1”开火键1分为键盘鼠标版和手柄版,无论哪种都能触发脚本中对应的逻辑。
1.按钮
这里以开火按钮为例,如图3-16所示我们可以检测开火按钮的按下、按住、抬起3个状态下面就来介绍如何实现按钮输入。
□ 键盘鼠标。键盘鼠标实现按钮非常简单。
第一步:设置类型,首先将Type设置为Key or Mouse Button。
第二步:填写名字,这里Name填的是Fire1。
第三步:设置键位。因为是单一按钮,所以仅仅需要填写正向部分。Positive Button填left ctrl,Alt Positive Button填mouse 0,也就是键盘左侧的Control键或者鼠标左键都对应开火键。
□ 手柄。步骤和键盘鼠标完全一样,只是键位名称不一样而已,这里Positive Button填写的是joystick button 0。
□ 脚本。当在Input Manager界面中设置好键位后,我们可以通过脚本监测输入。
1 | using UnityEngine; |
2.方向轴
方向轴常用于控制玩家角色的左右移动或上下移动。它的设置界面和按钮是完全一样的,但用法却不一样,方向轴有两个按钮分别对应正负两个方向。以Horizontal方向轴为例,如下图所示,按下键盘右箭头是正值,按下键盘左简头是负值。输出的范围是[-1,1]的浮点数,我们可以用它来控制角色的左右移动。下面就来介绍如何实现。
□ 键盘鼠标。前几步和按钮一样,只是需要额外设置Gravity、Dead、Sensitivity、Snap等参数。
Gravity填写3表示当松开对应按钮后,输出值会以3/秒的速度迅速归零。Dead填写0.001表示当输出在[-0.001,0.001]之间时会被忽略不计,强制输出0。Sensitivity填写3表示当按钮下对应按钮后,输出值会以3秒的速度变化,当按下的是正向按钮时会迅速到达1,当按下的是负向按钮时会迅速到达-1。
□ 手柄。如下图所示,这里对应的不再是手柄的按钮而是手柄轴。
第一步:设置类型。首先将Type设置为Joystick Axis。
第二步:填写名字。这里Name填的是Horizontal,
第三步:设置手柄。Joy Num栏如果填Get Motion from all Joysticks表示对应所有手柄,也可以填lystick I等手柄序号。
第四步:设置轴,Axis栏这里填的是Xaxis,也就是手柄十字键的横向。
□ 脚本。脚本中获得轴的代码非常简单。
1 | using UnityEngine; |
移动设备输入
移动设备也就是手机、平板等通过手指点击屏幕操作的设备。Unity有专门的接口检测与屏幕互动的各个手指的位置状态等信息。
与屏幕接触的手指的信息对应名为Touch类的对象,可以通过Input.Touches变量得到所有Touch。Touch常用的参数见下表。
参数 | 说明 |
---|---|
FingerId | 手指的编号,整型 |
Phase | 手指的阶段,枚举类型。分为这几个阶段: Began开始接触屏幕 Moved移动 Stationary静止 Ended手指离开屏幕 Canceled系统关闭触控 |
Position | 手指触碰屏幕的位置,Vetor2类型。坐标以屏幕左下角为原点1像素对应一个单位,例如iPhone 4s的分辨率是960*640。所以如果应用是横屏的话,那么左下角的Position是(0,0),右上角的Position是(960,640) |
1.实测
如下代码所示,我们得到手指的信息并输出到屏幕。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15using UnityEngine;
using System.Collections;
public class MobileTouchDemo : MonoBehaviour
{
void OnGUI()
{
// 遍历所有的Touch
foreach (Touch touch in Input.touches)
{
// 输出Touch信息
GUILayout.Label(string.Format("手指:{0} 状态:{1} 位置:{2}", touch.fingerId, touch.phase.ToString(), touch.position));
}
}
}
2.重力感应
Acceleration,即加速度传感或者重力感应。有很多著名的手机游戏的主要操作是基于重力感应的;在手机赛车游戏中重力感应也可用于控制赛车的转向。重力感应的原理是当手握移动设备晃动时,移动设备内的加速度计会计算设备在X、 Y、Z这3个方向上的线性加速度变化。以设备为基准,X轴正向为设备向右的方向,Y轴正向为设备向上的方向,Z轴正向为设备向使用者的方向。在Unity中可以通过Input.acceleration得到重力感应的值,类型为vector3。每个轴向的值域是[-1, 1]。
可以通过以下代码将重力感应信息输出至屏幕。可以在设备上运行此场景,并观察设备以不同朝向转动时Input.acceleration值的变化。1
2
3
4
5
6
7
8
9
10
11
12using UnityEngine;
using System.Collections;
public class AccelerationDemo : MonoBehaviour
{
void OnGUI()
{
GUILayout.Label("X:" + Input.acceleration.x);
GUILayout.Label("Y:" + Input.acceleration.y);
GUILayout.Label("Z:" + Input.acceleration.z);
}
}
3.其他
Input还有一些接口可以在设备运行游戏时得到关于设备输入的信息。
- 通过Input.deviceOrientation可以得到当前游戏运行的朝向。
- 通过Input.touchSupported可以得到当前游戏是否支持手指触控操作。
- 通过Input.multiTouchEnabled可以设置游戏是否支持多点触控。
习题
1.使用OnGUI()函数做一个调查问卷,要求填写名字、性别以及年龄并在提交后将信息输出至控制台。
2.在平台上创建一个球体,实现通过键盘的WASD键对其进行前后左右移动操作。