Unity 4 3D开发实战详解

978-7-115-32923-3
作者: 吴亚峰 杜化美 张月霞 索依娜
译者:
编辑: 张涛
分类: Unity

图书目录:

详情

本书结合unity 4 最新的版本,对这种多平台的集成引擎和编辑器知识进行讲解,介绍如何使用unity创建游戏、添加交互性,以及修饰游戏并发布游戏的所有知识。每一章都介绍一个独立的案例和开发技术,并且循序渐进地讲述新的知识,并用综合的游戏项目贯穿全书,使读者学以致用。

图书摘要

Unity 4 开发实战详解

吴亚峰 杜化美 索依娜 编著

人民邮电出版社

北京

随着Unity 3D的迅猛发展,该游戏引擎通过不断优化与改进已经升级到 4.0。在Unity 4.0中增加了许多新的特性,如全新的动画系统、支持移动平台的实时阴影、最新的状态机技术等。本书随着游戏引擎的升级加入了许多新的内容,主要内容如下。

第1章 Unity 3D基础以及开发环境的搭建,简要介绍了Unity 3D开发环境的搭建及其运行机制;第2章 Unity集成开发环境详解,主要对Unity集成开发环境进行详细介绍;第 3章 Unity 3D开发脚本简介,讲解了特定于Unity的 JavaScript脚本和C#脚本编写的语法和技巧;第 4章 Unity 3D图形用户界面基础及常用对象,主要对Unity开发过程中经常使用的图形用户界面控件及对象进行详细介绍;第 5章 Unity 3D第三方2D组件库——NGUI,介绍了游戏开发中非常流行的第三方UI界面开发组件库——NGUI的知识;第 6 章 物理引擎,介绍了 Unity 开发平台的完整的物理引擎体系,包括刚体、碰撞器、粒子系统及关节等开发技术;第 7章 3D游戏开发技术,介绍了天空盒、虚拟按钮与摇杆、声音、光源、地形引擎、角色动画,以及角色控制器等常用技术;第 8 章 着色器——Shaders,介绍了 Unity 中的着色器和着色器语言——ShaderLab,为各种高级特效的开发打下良好的基础;第9章杂项,介绍了PlayerPrefs类、Network Class(网络类)、加速度传感器的使用、视频贴图等开发技巧;第10章 综合案例——火力篮球,详细介绍了火力篮球项目的开发过程及用到的各种相关技术;第11章 综合案例——3D保龄球,详细介绍了3D保龄球项目的开发过程及用到的各种相关技术。

本书适合游戏开发的读者学习,也适合程序员学习用书,以及各院校相关专业师生的学习用书和培训学校的教材。

♦编著 吴亚峰 杜化美 索依娜

责任编辑 张涛

责任印制 程彦红

♦人民邮电出版社出版发行  北京市崇文区夕照寺街14号

邮编 100061  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

北京  印刷

♦开本:787×1092 1/16

印张:30.5

字数:848千字  2013年10月第1版

印数:1 – 000册  2013年10月北京第1次印刷

定价: 元(附光盘)

读者服务热线:(010)67132692 印装质量热线:(010)67129223

反盗版热线:(010)67171154

广告经营许可证:京崇工商广字第0021号

为什么要写这样的一本书

近几年,Android平台游戏、iPhone平台游戏以及Web的网页游戏发展迅猛,已然成为带动游戏发展的新生力量。遗憾的是,目前除了少数的成功作品外,大部分的游戏都属宣传攻势大于内容品质的平庸之作。面对这种局面,3D游戏成为独辟蹊径的一种选择,而为3D游戏研发提供强大技术支持的Unity 3D引擎,以其创造高质量的3D游戏和真实视觉效果的核心技术,为开发3D游戏提供了强大的源动力。

Unity 3D是由Unity Technologies开发的一个轻松创建三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

本书通过对Unity 3D集成开发环境的搭建、集成开发环境各个界面的详细介绍,再到脚本的编写、开发过程经常应用的技术和对象的讲解,以及最后用两个经典案例进行实战介绍,给读者以由浅入深、循序渐进的学习过程,相信每一位读者都会通过本书得到意想不到的收获。

未来几年内必定是Unity 3D大行其道的时代,因其开发群体的迅速扩大,Web player装机率的快速上升,使Unity 3D迅速爆发的时机已经到来。在此引用业内知名人士的一句话:“不要再对所谓的Flash 3D抱有什么希望,也不要再去花心思学习那些杂七杂八的Flash 3D插件,赶紧学习Unity 3D才是正经。”

由于最近几年Unity 3D的迅猛发展,该游戏引擎通过不断地优化与改进已经升级到 4.0。在Unity 4.0中增加了许多新的特性,如全新的动画系统、支持移动平台的实时阴影、最新的状态机技术等。本书也随着该游戏引擎的升级加入了许多新的内容。

经过半年多见缝插针式的奋战,本书终于交稿了。回顾写书的这半年多时间,不禁为自己能最终完成这个耗时费力的“大制作”而感到欣慰。同时也为自己能将从事游戏开发近十年来积累的宝贵经验以及编程感悟分享给正在开发阵线上埋头苦干的广大编程人员而感到高兴。

本书特点

1.内容丰富,由浅入深

本书组织上本着“起点低,终点高”的原则,内容覆盖了从学习Unity 3D必知必会的基础知识,到基于着色器语言所实现的高级特效,最后还给出了两个完整的大型 3D 游戏案例。这样的内容组织使得初学3D开发的读者可以一步一步成长为3D开发的达人,符合绝大部分想学习3D开发的学生与技术人员,以及正在学习3D开发人员的需求。

2.结构清晰,讲解到位

本书中配合每个需要讲解的知识点都给出了丰富的插图与完整的案例,使得初学者易于上手,有一定基础的读者便于深入。书中所有的案例均是根据笔者多年的开发心得进行设计的,结构清晰明朗,便于读者进行学习与参考。同时书中还给出了笔者多年来积累的编程技巧以及心得,具有很高的参考价值。

3.实用的光盘内容

为了便于读者的学习,本书附赠的光盘中包含了书中所有案例的完整源代码,最大限度地帮助读者掌握开发技术。

内容导读

全书共分为11章,内容按照必知必会的基础知识、基于Unity集成开发环境及真实大型游戏案例的顺序进行详细讲解。

本书内容从基本知识到高级特效,从简单的应用程序到完整的3D游戏案例,适合不同需求、不同水平层次的各类读者。

● 初学Unity 3D应用开发的读者

本书包括在 Android 平台下进行 3D 应用开发各方面的知识,内容由浅入深,配合详细的案例。非常适合初学者循序渐进地学习,最终成为3D游戏应用开发达人。

● 有一定 3D开发基础读者,可以进一步深入学习Unity 3D高级开发技术

本书不仅包括了Unity 3D开发的基础知识,同时也包括基于着色器语言、关节、动画等技术所实现的高级特效,以及Unity 3D强大的物理引擎与完整的游戏案例,有利于有一定基础的开发人员进一步提高开发水平与能力。

● 其他平台的3D开发人员

由于Unity 3D是跨平台的,可以开发基于各个平台的项目,因此,适合其他各种平台的 3D开发人员。

本书作者

吴亚峰,毕业于北京邮电大学,后留学澳大利亚卧龙岗大学取得硕士学位。1998年开始从事Java应用的开发,有十多年的 Java开发与培训经验。主要的研究方向为OpenGL ES、手机游戏、Java EE以及搜索引擎。同时为手机游戏、Java EE独立软件开发工程师,并兼任百纳科技 Java培训中心首席培训师。近十年来为多家著名企业培养了上千名高级软件开发人员,曾编写过《菜鸟成长之路——Java程序员职场全攻略》、《Android 3D游戏案例开发大全》、《Android平板电脑开发实战详解和典型案例》、《Android游戏开发大全》、《Android应用案例开发大全》、《Unity 3D游戏开发技术详解与典型案例》等多本畅销技术书籍。2008年年初开始关注Android平台下的应用开发,并开发出一系列优秀的Android 3D应用程序与游戏。

杜化美,西安电子科技大学硕士,有多年的Java程序开发与培训经验。曾参与两项国家自然科学基金项目,在国内外刊物上发表论文十余篇。同时兼任嵌入式独立软件开发工程师,在软件领域有8年的从业经验,最近3年致力于Android嵌入式系统的研究。

张月霞,博士,毕业于北京邮电大学。主要从事无线协同通信技术、超宽带技术、无线定位技术、移动互联网等技术研究。主持省部级项目1项,参与国家自然科学基金重大项目两项,发表论文十余篇,申请国家专利7项,编著1部,译著1部。2012年获北京市教学成果奖一等奖, 2013年获吴文俊人工智能科学奖三等奖。从2010年开始致力于Android系统开发,参与开发了多款手机应用软件。

索依娜,毕业于燕山大学,从业于计算机软件领域十余年,在软件开发与计算机教学方面有着丰富的经验。工作期间曾参与省级科研项目两项,发表论文多篇。从2008年起开始关注Android平台下的应用开发,参与开发了多款手机娱乐应用。

本书在编写过程中得到了唐山百纳科技有限公司Java培训中心的大力支持,同时刘文洲、陈伟、赵鑫磊、谷新蕾、佘伟伟、刘喆、刘敏智、董振宇以及作者的家人为本书的编写提供了很多帮助,在此表示衷心的感谢!光盘中包括所有源程序。

由于编者的水平和学识有限,且书中涉及的知识较多,难免有错误疏漏之处,敬请广大读者批评指正,并提出宝贵意见。编辑联系邮箱为zhangtao@ptpress.com.cn。

编者

对于一个游戏开发平台来说,除了比较友好的开发环境,还必须拥有其完整的物理引擎体系。现实生活中的所有事物都遵循自然界的物理法则,要达到模拟现实的效果必须有同自然物理法则相对应的物理引擎作辅助。

Unity 3D游戏引擎内置的PhysX物理引擎是Unity的核心部分。物理引擎通过为刚性物体赋予真实的物理属性的方式来计算它们的运动、旋转和碰撞反应。Unity 已经将该物理引擎完美地集成起来,开发中只需要简单地操作就可以使物体按照物理运动规律进行运动。

在Unity内建物理引擎中,首先要介绍的是刚体(Rigidbody)的概念。包含有该类组件的游戏对象,会遵循万有引力定律,在重力的作用下,使物体垂直下落。刚体组件还会影响物体发生碰撞时的反应,使物体遵循惯性定律,并在其他物体运动冲击作用下产生速度或者形变。

刚体作为物理引擎中的最基本组件,保证了所有物体受到重力的约束。Unity 开发平台中,对刚体设置了很多属性和变量,并对应封装了多个相关方法,下面进行分别介绍。

1.刚体属性

为了利于开发者控制物理系统,Unity 提供了多个属性接口。开发者可以通过更改这些参数来控制物体的物理状态。实际开发中,这些参数都被详细地罗列在属性查看器中,开发者很容易就可以对其进行更改。接下来对这些属性进行介绍。

(1)质量(Mass)

该属性表示刚体的质量,其数据类型是float,默认值为1。其在属性查看器中的位置如图6-1所示。该属性的大小是有严格要求的,一般来说,大部分物体的质量属性值接近 0.1 才符合日常生活的感官感受,一旦超过10.0,就会失去仿真所需达到的效果。

(2)平移阻力(Drag)

该属性是物体的平移阻力,其数据类型是float,初始值为0。Drag属性在属性查看器中的位置如图6-2所示。在现实生活中,物体会受到各方面的影响,速度会渐渐衰减,为了模拟这一效果,Unity设定了平移阻力属性。这一属性值越高,物体的速度衰减越严重。

(3)旋转阻力(Angular Drag)

该属性表示物体的旋转阻力,其数据类型是float,初始值为0.05。其在属性查看器中的位置如图6-3所示。当一个物体进行旋转的时候,其旋转的角速度也会受各方面影响衰减,为模拟这一现象,Unity设定了旋转阻力属性。此属性值越高,物体的角速度衰减越严重。

▲图6-1 质量

▲图6-2 平移阻力

(4)使用重力(Use Gravity)

该属性表示的是该物体是否受到重力的影响,其数据类型是boolean,初始值为true。其在属性查看器中的位置如图6-4所示。这一属性被设为false时可以模拟物体在外太空状态下的失重状态。有时候也可以根据需要用于某些特殊的场合。

▲图6-3 旋转阻力

▲图6-4 使用重力

注意

当该值被设定为false的时候,物体将不受重力影响,但刚体的其他特性还是存在的。

(5)是否遵循运动学(Is Kinematic)

该属性表示本游戏对象是否遵循牛顿运动学物理定律,其数据类型是boolean,初始值为false。其在属性查看器中的位置如图6-5所示。如果该属性被置为true,本物体的运动状态将不受外力、碰撞和关节的影响,而只受到动画以及附加在物体上的脚本的影响。

另外,虽然当该属性被置为true时物体将不受物理定律的约束,但是该物体还是会影响其他的物体,改变其他物体的运动状态。在游戏开发中此属性会被经常用到,想象一下在第一人称射击游戏中,敌人被击杀后会倒地不动,因为这个敌人对象Rigidbody的 Is Kinematic属性被设置为了true。

(6)插值(Interpolate)

该属性表示的是该物体运动的插值模式。其在属性查看器中的位置如图6-6所示。在默认状态下,插值Interpolate是被禁用的,可以选择Interpolate模式,在此模式下物理引擎会在物体的运动帧之间进行插值,使得运动更加自然。

▲图6-5 是否遵循运动学

▲图6-6 插值

不得不提的是,插值导致了物理模拟和渲染的不同步,进而产生物体轻微抖动的现象。建议在开发中,对主要角色使用插值,而其他的则禁用此功能,以达到折中效果。

(7)冻结旋转(Freeze Rotation)

该属性表示的是该物体的旋转是否受到物理定律的约束。其在属性查看器中的位置如图 6-7所示。默认状态下任意轴的旋转是受物理定律控制的。该属性的值是修改在每个轴上的旋转属性来实现的,实际开发中可以灵活地使用。

在第一人称射击游戏中,通过此属性去除物理属性对旋转的控制,可以使玩家完全控制视角旋转。

(8)碰撞检测模式(Collision Detection)

该属性表示的是碰撞检测模式。其在属性查看器中的位置如图6-8所示。默认状态下,碰撞检测模式是 Discrete。在没有碰撞检测的情况下,碰撞物体会穿过对方,产生所谓的“穿透”现象。为避免此类问题的发生,碰撞检测工作是必须做的。

▲图6-7 冻结旋转

▲图6-8 碰撞检测模式

关于碰撞模式的选择,可选的有不连续模式(Discrete)、连续模式(Continuous)和动态连续模式(ContinuousDynamic),其中动态连续模式适用于高速运动的物体,但是耗费资源较大。连续模式仅仅可以用于球体、胶囊和盒子碰撞者的刚体,而且会严重影响物体的运动表现。所以大部分的物体采用不连续模式作为碰撞检测模式。

2.刚体变量

为了获取或者更改物体的运动状态,Unity 还预留了多个变量接口,这些接口使得运动处理变得相当简单。接下来将具体地介绍一下这些变量。

(1)刚体的速度(velocity)

此变量表示物体的速度值,在Unity中单位1表示现实生活中的1米。在开发过程中,直接更改此变量的值并不是一种明智的做法,因为 Unity 中物体的运动经过非常复杂的计算使得物体的运动自然平滑,如果有外加干预,会迫使物体的运动模拟失真。

下面的代码可以实现一个物体的速度骤增,以实现瞬移效果,具体代码如下:

1 function FixedUpdate () {

2  if (Input.GetButtonDown ("GO")) {    //按下按钮“GO”

3   rigidbody.velocity = Vector3(10,0,0);  //给予x方向速度

4  }}

(2)是否使用重力(useGravity)

此变量表示当前的物体是否受到重力的约束。在开发过程中,灵活地更改此变量可以达到一些特殊的场景要求,比如在外太空环境下的失重状态。

可以编写代码实现物体的失重状态,具体代码如下:

1 function Start (other : Collider) {     //脚本被激活

2  if (other.attachedRigidbody) {      //此物体包含有刚体组件

3   other.attachedRigidbody.useGravity = false;  //设置物体不受重力约束

4  }}

(3)冻结旋转(freezeRotation)

此变量表示当前的物体的旋转是否受到物理定律的约束。通过此变量,可以更改 x、y、z 三个方向中的某个方向的旋转约束,以达到开发者想要达到的旋转效果。

该变量使用的具体语法代码如下所示:

1 rigidbody.freezeRotation = true;

(4)刚体的位置(position)

此变量表示了刚体的位置,改变此变量时,引擎会在物理阶段结束后,将物体放置到指定的位置。

下面的脚本实现了将物体放置于原点的功能,具体代码如下:

1 function Start () {        //脚本被激活

2  rigidbody.position = Vector3.zero;   //将物体放置在(0,0,0)位置

3 }

说明

这种做法不适用于旋转物体,可以使用MovePosition代替。

(5)刚体的旋转(rotation)

此变量表示了物体的旋转状态,改变此变量时,引擎会在物理阶段结束后,将物体旋转到指定的状态。

下面的脚本实现了设置物体无旋转,具体代码如下:

1 function Start () {       //脚本被激活

2  rigidbody.rotation = Quaternion.identity;//将物体的旋转状态设置为原始态(无旋转)

3 }

说明

这种做法不适用于旋转物体。可以使用MoveRotation方法来代替。

3.刚体常用方法

在讲解了刚体的属性与变量后,有必要讲解一下Unity提供的相关方法。

(1)给刚体施加力(AddForce)

此方法被调用时,将会施加给刚体一个瞬时力,然后物体在力的作用下,产生一个初速度,接着物体在初速度的作用下开始运动。

下面的代码实现了对物体施加竖直向上的力,具体代码如下:

1 function FixedUpdate () {

2  rigidbody.AddForce (Vector3.up * 10);   //施加竖直向上的力

3 }

注意

AddForce方法尽量不要用在Update方法中,因为这样的方法在Update中会被不停地调用,与被调用一次不同,这种是模拟了一种加速度的效果。

(2)移动刚体位置(MovePosition)

此方法被调用时,会使刚体按照参数移动到某个位置。此方法经常用于FixedUpdate方法中。具体用法如下列代码所示:

1 private var speed : Vector3 = Vector3 (3, 0, 0); //声明速度向量

2 function FixedUpdate () {

3 rigidbody.MovePosition(rigidbody.position + speed * Time.deltaTime);//按照speed为速度平移刚体

4 }

(3)旋转刚体(MoveRotation)

此方法被调用时,会使刚体按照参数旋转到某个方位。此方法经常用于FixedUpdate方法中。具体用法如下列代码所示:

1 var eulerAngleVelocity : Vector3 = Vector3 (0, 100, 0);  //声明角速度

2 function FixedUpdate () {

3  var deltaRotation : Quaternion = Quaternion.Euler(eulerAngleVelocity * Time.

deltaTime);

4  rigidbody.MoveRotation(rigidbody.rotation * deltaRotation);//以eulerAngleVelocity为角速度旋转

5 }

前面的内容简单介绍了刚体的属性、变量和常用方法。接下来这一部分将讲解一下物理管理器(Physics Manager)的相关内容。

Unity作为一个优秀的游戏开发平台,其出色的管理模式是令人称赞的。在Unity中,不仅可以对单个分组进行属性设置,也可以对场景全局进行设置。这一部分讲解 Unity 中场景的全局物理参数是如何设置的。

1.物理管理器预览

(1)打开Unity开发平台,在菜单栏中选择“Edit”选项,会弹出编辑列表,如图6-9所示。在编辑列表中,选择“Project Settings”选项,弹出全局设置列表,如图 6-10所示。在全局设置列表中选择“Physics”,即可进入物理管理器。

▲图6-9 选择projectsetting

▲图6-10 选择physics

(2)按照第(1)步进行操作以后,会在属性查看器中呈现物理管理器编辑器,如图6-11所示。

▲图6-11 物理管理器

2.物理管理器参数

在前面的内容中,讲解了物理管理器的打开操作。接下来介绍的是物理管理器中的相关参数的含义和用法。

(1)重力(Gravity)。

该属性表示的是项目中的重力加速度,该参数将被应用于所有刚体。其在物理管理器中的位置如图6-12所示,该属性3个数值分别指定在x、y、z方向上的重力加速度,一般重力是竖直向下的,所以只有y轴上有一个负值,大小默认为单位是−9.81米/(秒 ^2 )。

(2)默认材质(Default Material)。

该属性表示当物体没有被指定物理材质的时候,该物体的默认材质。其在物理管理器中的位置,如图6-13所示。默认状态下是没有指定值的,因为在Unity中,每个物体的物理材质可能会有很大的不同,有时候指定默认材质并不是有太大的用途。

▲图6-12 重力

▲图6-13 默认材质

(3)反弹阈值(Bounce Threshold)。

该属性表示的是项目中的反弹阈值,该参数将被应用于所有刚体。其在物理管理器中的位置如图6-14所示,如果两个碰撞体的相对速度低于该值,那么将不会反弹。该值也用于减少抖动,所以不建议设置为很低的值。

(4)休眠速度(Sleep Velocity)。

该属性表示的是项目中刚体自动进入休眠时状态的速度值。其在物理管理器中的位置如图6-15所示。该值是休眠的默认线速度,低于该速度的物体将会进入休眠。如果没有这种机制,项目中的所有物体将永远都在计算中,对于资源的回收利用很不利。

▲图6-14 反弹阈值

▲图6-15 休眠速度

(5)休眠角速度(Sleep Angular Velocity)。

该属性表示的是项目中的休眠角速度,该参数将被应用于所有刚体。其在物理管理器中的位置如图6-16所示,如果角速度低于该值,物体将进入休眠状态。

(6)最大角速度(Max Angular Velocity)。

该属性表示的是项目中刚体最大的角速度值。其在物理管理器中的位置如图6-17所示,设定最大值可以避免角速度数值不稳定现象的发生。在脚本中可以用语法 Rigidbody.maxAngular Velocity来更改此值。

▲图6-16 休眠角速度

▲图6-17 最大角速度

(7)最小穿透禁区(Min Penetration For Penalty)。

该属性表示的是项目中的最小穿透禁区,该参数将被应用于所有刚体。其在物理管理器中的位置如图6-18所示,该属性的具体含义是在碰撞检测器将两个物体分开前,可以穿透多少米的距离。较高的值会导致较多的物体穿透,不过可以减少抖动。

(8)求解迭代次数(Solver Iteration Count)。

该属性表示的是项目中关节和连接计算过程中的迭代次数。其在物理管理器中的位置如图6-19所示,决定了关节和连接的计算精度。求解迭代次数越高精度越高,但是次数过高会浪费过多的资源,不利于项目的正常运行,一般来说此值设置为7就可以适用于大多数情况。

(9)射线检测命中触发器(Raycasts Hit Triggers)。

该属性表示的是项目中的射线检测命中触发器,该参数将被应用于所有刚体。其在物理管理器中的位置如图6-20所示。如果启用,那么进行射线检测时命中碰撞体会返回一个命中消息,如果关闭,则不返回命中消息。

(10)层碰撞矩阵(Layer Collision Matrix)。

该属性表示的是项目中的层碰撞矩阵,该参数将被应用于所有刚体。其在物理管理器中的位置如图6-21所示。定义层碰撞检测系统的行为。

▲图6-18 最小穿透禁区

▲图6-19 求解迭代次数

▲图6-20 射线检测命中触发器

▲图6-21 层碰撞矩阵

说明

层碰撞矩阵在后面的介绍中会有比较详细的解释,此处不再赘述。

1.碰撞的使用

与碰撞相关的内容包括碰撞器(Collision)类、碰撞检测模式选择和最小穿透禁区设置,后两个内容已经在前面的内容中进行了详细的介绍,这里不再赘述。下面重点讲解一下碰撞器类及其相关方法的使用。

(1)碰撞器类的变量如表6-1所示,碰撞器有很多变量供碰撞处理使用,其中除了碰撞接触点(contacts)变量,其他变量都是只读的,读者请务必注意。

表6-1 Col ision类的相关变量

(2)碰撞器相关方法。

● 碰撞触发(OnCollisionEnter)

此方法在碰撞发生时被系统自动调用。该方法会传递一个Collision类,该类包含了碰撞点和相对速度等信息。开发者可以利用这些信息对物体进行碰撞处理,下面的代码就是一个简单的例子:

1 var explosionPrefab : Transform;

2 function OnCollisionEnter(collision : Collision) { //碰撞开始

3 var contact : ContactPoint = collision.contacts[0]; //获取0号碰撞点

4 var rot : Quaternion =

5 Quaternion.FromToRotation(Vector3.up, contact.normal);//旋转以使y轴面向接触点法向量

6  Instantiate(explosionPrefab, pos, rot);   //实例化爆炸对象

7  Destroy (gameObject);        //销毁游戏对象

8 }

说明

该方法只有在两个物体都遵循物理定律的情况下发生,即两者的Iskinematic属性都为false。

● 碰撞状态(OnCollisionStay)

此方法在碰撞时两物体接触过程中被调用。该方法同样会传递一个Collision类,该类包含了碰撞点和相对速度等信息,下面的代码就是一个简单的例子:

1 function OnCollisionStay(collisionInfo : Collision) { //碰撞进行中

2 for (var contact : ContactPoint in collisionInfo.contacts) {

3 Debug.DrawRay(contact.point, contact.normal * 10, Color.white);//绘制所有的接触点和其法向量

4 }}

● 退出碰撞(OnCollisionExit)

此方法在碰撞时停止触碰刚体或者碰撞的时候调用。该方法同样会传递一个Collision类,该类包含了碰撞点和相对速度等信息,下面的代码就是一个简单的例子:

1 function OnCollisionExit(collisionInfo : Collision) {  //碰撞结束

2  print("不再和" + collisionInfo.transform.name+"发生碰撞。"); //打印碰撞结束信息

3 }

2.睡眠的使用

(1)睡眠(Sleep)。

该方法被调用时,会强制一个刚体进入睡眠状态至少一帧的时间。一般用在Awake方法中,设置脚本开始执行时刚体睡眠。刚体进入睡眠后,物体相当于没有刚体存在,其具体的语法如下:

1 rigidbody.Sleep();

(2)强制唤醒(WakeUp)。

该方法被调用时,会强制使一个处于睡眠状态刚体被唤醒,其具体的语法如下:

1 rigidbody.WakeUp();

在上一节中,讲解了刚体的主要特性,在本节中将对碰撞器(Collider)进行具体介绍。碰撞器是 Unity 内建物理引擎中另外一个很重要的概念。弄清楚碰撞器的概念对于 Unity 开发新手来说是很重要的。

Unity中内建的碰撞器主要包括6种,具体情况如下所述。

● 盒子碰撞器——BoxCollider

盒子碰撞器是一个基本的方形碰撞器原型,可以被调整成不同大小的长方体,能够很好地用于门、墙、平台等,也能够用于角色的躯干或者车辆等交通工具的外壳。

一般地,盒子碰撞器都是用于较规则的物体上,恰好将所作用的对象的主要部分包裹住。因此,适当的使用该碰撞器可以减少物理计算,提高性能。

● 球体碰撞器——SphereCollider

球体碰撞器是一个基本的球形碰撞器原型,在三维上可以均等地调节大小,但不能只改变某一维。适合用于落石、乒乓球、弹球等。

● 胶囊碰撞器——CapsuleCollider

胶囊碰撞器由一个圆柱体连接两个半球体组成,是一个胶囊状碰撞器原型。胶囊碰撞器的半径和高度都可以单独调节。可用于角色控制器或者和其他碰撞器结合用于不规则的形状。

● 网格碰撞器——MeshCollider

网格碰撞器利用一个网格资源并在其上构建碰撞器。对于复杂网状模型上的碰撞检测,它要比应用原型碰撞器精确的多。其通过附加在游戏对象上的网格构建碰撞效果,并严格按照所附加对象的Transform属性来设定其位置和大小比例。

● 车轮碰撞器——WheelCollider

车轮碰撞器是一个特殊的地面车辆碰撞器。其具有内置的碰撞检测、车轮物理引擎和一个基于滑动的轮胎摩擦模型。当然,也可以用于其他对象,但其是专门为有轮子的车辆设计的。车轮的碰撞检测是通过自身中心向外投射一条y轴方向的射线来实现的。

车轮碰撞器将在后面的交通工具章节有更详细的介绍和具体使用,这里不再赘述。

● 地形碰撞器——TerrianCollider

地形碰撞器主要作用于地形与其上的物体之间的碰撞,给地形加上地形碰撞器可以防止添加了刚体属性的对象会无限的往下落。

说明

实际开发中,常常将多种碰撞器组合来使用,这样可以保证碰撞的真实性。

Unity 开发平台下,如果开发者想要对游戏中的对象进行碰撞处理是很简单的事情,对于某个游戏对象,只需要对其附加上碰撞器即可实现。在Unity中,碰撞器作为游戏对象的一个组件,可以被随意地添加或者删除。下面将介绍碰撞器的添加方式。

1.碰撞器的基本添加方法

在这里仅仅介绍基本碰撞器的使用。对于某个物体,如果只是要求起到简单的碰撞效果,那么只要单纯地附加碰撞器即可,具体的步骤如下。

(1)首先创建一个立方体对象,按照 GameObject→CreateOther→Cube 顺序完成创建,如图6-22所示。

(2)在游戏组成对象列表中,找到第(1)步创建的立方体对象,选中此对象。在属性查看器中看到此立方体的所有属性,注意到其有一个名为BoxCollider的组件,这就是所谓的碰撞器,如图6-23所示。

(3)可以在“BoxCollider”处鼠标右键单击,在弹出的列表中选择“Remove Component”选项,通过此操作可以去除已经包含在游戏对象中的碰撞器,如图6-24所示。

(4)在立方体对象选中状态下,单击菜单栏中的“Component”选项。在弹出的菜单中选择“Physics”,在弹出的菜单中选择“Box Collider”,通过此操作为当前的立方体对象附加了碰撞器,如图6-25所示。

▲图6-22 创建 Cube游戏对象

▲图6-23 碰撞器组件

▲图6-24 删除盒子碰撞器

▲图6-25 添加盒子碰撞器

说明

一般情况下,只能直接为对象指定一个碰撞器,另外指定的碰撞器会替换当前的碰撞器,如果将要替换的碰撞器和当前的碰撞器是同一种类的,则提示不能完成操作。

2.碰撞器的组合使用

在基础项目的开发中,碰撞器的附加是很简单的,在前面的内容中已经进行了讲解。在某些场合中,由于 Unity 内建的碰撞器都是规则的形状类型,如果需要对一些非规则形状的物体进行碰撞事件处理,就让人有些手足无措,在这部分将为解决此类问题提供一种最适合的方案。

该方案的具体步骤如下。

(1)按照步骤 GameObject→CreateOther→Plane 新建一个平面做地面,并为其指定纹理,如图6-26所示。

▲图6-26 新建平面

(2)按照顺序GameObject→CreateOther→Capsule新建一个胶囊(Capsule),将纹理图拖曳到其上,指定好其纹理,将其放置到平面的上方,摄像机的正前方,作为碰撞器组合体的主体,如图6-27所示。

▲图6-27 新建胶囊

(3)分别按照顺序GameObject→CreateOther→Cube和顺序GameObject→CreateOther→Sphere新建一个立方体和一个球体。将立方体和球体分别放置在前面创建的胶囊的上方和下方,相对位置如图6-28所示。

▲图6-28 相对位置效果图

▲图6-29 更改碰撞器半径

(4)对球体进行缩放,直至胶囊把其完全掩盖住,在属性查看器中修改其 SphereCollider 组件的Radius值为1.5,如图6-29所示。将立方体进行如上操作,将其盒子碰撞器组件的size值设为(2.5,2.5,2.5),如图6-30所示,得到效果如图6-31所示。

▲图6-30 更改碰撞器大小

▲图6-31 效果图

(5)最后在游戏组成对象列表中,按住Ctrl键,同时选中立方体和球体对象,将两个对象拖曳到胶囊对象上,形成对象的父子关系,如图6-32所示。

▲图6-32 父子关系图

(6)选中胶囊对象,按照Component→Physics→Rigidbody为其添加刚体。单击游戏预览开始按钮,观看效果,如图6-33所示。

说明

本案例的场景文件位于随书光盘中源代码/第6章目录下的 PhysicsEngine/Assets/ Scene/ ColliderGroup。为了简化操作顺序,本案例采用胶囊作为不规则物体的替代物,读者可以举一反三,对更加复杂的模型进行碰撞器拼接,以达到预期效果。

▲图6-33 碰撞器组最终效果

在 Unity 开发过程中,对于某些游戏对象,如果两者之间进行的碰撞是毫无意义的或者不符合现实,那么就要规避两者之间的碰撞,在Unity平台下利用了碰撞过滤的概念来解决此类问题。

碰撞过滤就是在某些物体之间不进行碰撞检测。可以是层与层之间,也可以是两个物体之间。这就给开发者以很大的灵活性。

1.通过代码实现两两之间不进行碰撞检测

在 Unity 中,项目的物理环境不仅能够通过在开发环境下进行简单的菜单项设置,还可以通过脚本的编写来控制设置。设置两两之间不进行碰撞检测的原理是在脚本激活的时候,设置当前对象的忽略碰撞体为某一个对象。

下面以实现当前对象与两个对象进行碰撞检测为例说明,具体的代码如下所示:

1 var ballpre1:Transform;   //另外两个球的引用

2 var ballpre2:Transform;

3 function Start(){     //开始方法在对象被激活时开始执行

4   Physics.IgnoreCollision(ballpre1.collider, collider);//控制该对象不和ballpre1和ballpre2发生碰撞

5   Physics.IgnoreCollision(ballpre2.collider, collider);

6 }

● 第1-2行为获取不碰撞体的引用。需要在开发环境下的属性查看器中指定两个对象。

● 第3-6行为设置当前对象不与ballpre1和ballpre2进行碰撞。

2.层与层之间的碰撞过滤

前面的内容介绍了脚本控制碰撞过滤的用法,接下来将通过一个案例讲解层间碰撞过滤的具体使用方法。具体步骤如下。

(1)导入纹理图片资源,在资源列表中鼠标右键单击,在弹出的菜单中选择“Import New Assest…”选项,如图6-34所示,在出现的如图6-35对话框中选择要导入的图片资源,如图6-35所示。

▲图6-34 导入资源1

▲图6-35 导入资源2

(2)按照 GameObject→CreateOther→Plane 的顺序新建一个平面作为地面。并将前面导入的纹理图拖曳到该平面上,从而为其指定纹理,如图6-36所示。

(3)按照Edit→RenderSetting的顺序,打开渲染设置,如图6-37所示。

▲图6-36 新建平面

▲图6-37 打开渲染设置

(4)通过上一步的操作,会在属性查看器中呈现出场景的渲染设置编辑器。在其中设置“Ambient Light”,如图6-38所示,选择AmbientLight后面的属性框,在弹出的颜色选择框中选择白色,如图6-39所示。

(5)通过操作GameObject→CreateOther→Sphere创建一个球体,如图6-40所示。

(6)在资源列表中鼠标右键单击,在弹出的菜单中选择“Create”,在弹出的菜单中选择“Material”,如图6-41所示。在属性查看器中,设置MainColor为红色,Base为任意一张纹理图,如图6-42所示。

▲图6-38 环境光设置

▲图6-39 颜色选择框

▲图6-40 创建球体

▲图6-41 新建材质

▲图6-42 编辑材质

(7)为球体添加刚体,按照 Component→Physics→RigidBody 的顺序为球体添加刚体,如图6-43所示。

(8)添加一个层,选中球对象,单击属性查看器中的Layer属性,在弹出的菜单中选择“Add Layer”,如图6-44所示。在任意一个UserLayer后添加“red”,以添加层并命名为red,如图6-45所示。

(9)再次单击球体对象,在属性查看器中单击 Layer,如图 6-46 所示,此选择“red”。经过此操作就为该球体制定了所在层为“red”。

▲图6-43 添加刚体

(10)按照步骤(5)~步骤(7)的操作,分别创建出5个红色球,5个蓝色球,5个绿色球。

(11)按照步骤(8)~步骤(9)的操作,分别创建3个层。并将所有的红色球指定层为red,将所有的蓝色球指定为层“blue”,将所有的绿色球指定层为“green”,如图6-47所示。

▲图6-44 添加层1

▲图6-45 添加层1

▲图6-46 指定层

▲图6-47 新建3个层

(12)设置物理管理器。按照顺序 Edit→ProjectSettings→Physics 打开物理管理器。在属性查看器中会呈现物理管理器,如图6-48所示。

▲图6-48 打开物理管理器

(13)设置物理管理器。在物理管理器中,在Layer Collision Matrix属性中,去掉 green行与green列的对勾,red行与red列的对勾,blue行与blue列的对勾,以设置同一个层之间不进行碰撞检测,而不同的层之间进行碰撞检测,如图6-49所示。

(14)将球按照图6-49所示的相对位置进行摆放,单击运行查看效果,如图6-50所示。

▲图6-49 设置层间碰撞关系

▲图6-50 最终效果

说明

本案例的场景文件位于随书光盘中源代码/第6章目录下的 PhysicsEngine/Assets/ scene/ collisionfilter。在单击运行按钮后会发现图中第 1列、第 3列及第 5列的球没有进行碰撞发生了叠加现象,而第2列和第4列3个球发生碰撞,这就是通过设置层间碰撞状态达到的效果。

在 Unity 开发过程中,开发者往往会需要碰撞体实现特殊的碰撞效果,例如篮球撞击篮板的效果,铅球坠落到沙地的效果,实现这些都要使用物理材质的概念。

物理材质顾名思义就是指定了物体的物理特性。它定义了物体的弹性和摩擦因数,在实际开发过程中,开发者可以调节其属性已达到满意效果。

1.物理材质属性

物理材质有多个可调属性,这些属性关乎着物体的弹性和摩擦因数,并且还设定了碰撞体间的摩擦和弹性混合模式,为了适应某个物体的不同方向摩擦力不同而设定的各向异性方向。各主要参数如表6-2所示。

表6-2 物理材质属性

2.物理材质的创建

作为影响物体的碰撞反应的又一重要因素,物理材质规定了物体的弹性和摩擦特性。材质的差别可能很大程度上影响物体的运动表现。物理材质的创建可以通过两种操作实现。

(1)在菜单栏中单击“Assests”选项,会出现资源操作列表,选择“Create”选项,将会弹出创建列表,在创建列表中选择“Physics Material”。即可创建出一个物理材质,同时在属性查看器中出现物理材质的编辑器,如图6-51所示。

▲图6-51 新建物理材质 1

(2)在资源列表面板下,鼠标右键单击空白处同样会出现资源操作列表,选择“Create”选项,将会弹出创建列表,在创建列表中选择“Physics Material”,即可创建出一个物理材质。同时在属性查看器中出现物理材质的编辑器,如图6-52所示。

3.物理材质的设置

在开发过程中,物理材质的使用关乎到模拟现实是否成功的重要因素之一。Unity 为开发预留的变量使得调节物体的物理特性变得异常简单,但是关于如何决定材质的取值,就完全靠经验来确定了。下面介绍一些物理材质选择的小技巧,希望对读者有所启发。

物理材质的设定大概需要3方面的修改,如图6-53所示。

▲图6-52 新建物理材质2

▲图6-53 设置物理材质

(1)摩擦因子的设定。

滑动摩擦因子或静摩擦因子的取值范围为0~1,当滑动摩擦因子或静摩擦因子取值为0时,被此材质控制的对象将拥有冰的效果,摩擦时流畅感很强,而值为1时,受控物体就会像橡胶一样,与其发生摩擦的物体会有不流畅感。一般来说如果对摩擦力要求不是很高,动摩擦因子或者静摩擦因子调节为0.4即可。

(2)弹性因子的设定。

弹性因子的取值范围同样为0~1,当弹性因子取值为0,材质作用物体将不再拥有弹性,就像橡皮泥一样,被一个钢珠撞击时将不会有任何反弹,而是直接凹陷,能量被完全损耗。当弹性因子数值为1时,材质作用的物体就像钢珠一样,发生碰撞为完全弹性碰撞,没有能量的损耗。

(3)各向异性设定。

Unity 中采用了这一概念,使开发者可以实现这一情景:当材质所附物体向某一特定方向运动时,运动非常流畅,而像其他方向运动时会很缓慢。

在第一人称射击游戏中,我们会看到很多爆炸、浪花、血液喷溅等绚丽的特效。这些特效如果通过编程实现,将是一件很烦琐复杂的工作。为了简化这一过程,Unity 为开发者集成了粒子系统这一仿真工具,使粒子特效的开发变得更简单。

粒子系统不是一个简单的静态系统,在系统中粒子会随着时间的推移不仅不断变形和运动,而且系统会自动产生新的粒子,销毁旧的粒子。这就能表现出和雨、雪、雾、水波、火焰、焰火、烟尘、流星等现象极其相似的效果,极大地提高游戏的可观赏性。

粒子系统在 Unity 开发平台下可以很方便地引入,很多绚丽的特效都可以通过几步简单的操作制造出来。在本部分将介绍一下粒子系统的具体创建和应用的操作步骤。

1.基础粒子系统

在菜单栏单击GameObject选项,此时会弹出“游戏对象操作”菜单,选择“CreateOther”选项,则弹出“创建”菜单,接着选择“Particle System”选项。即完成粒子系统的创建,如图6-54所示。

▲图6-54 粒子系统创建

2.组件粒子系统

粒子系统不仅是作为一种游戏对象存在于Unity中的,它还可以作为一种组件(Component)依附在其他的游戏对象的。想象一下燃烧的木头,这就是通过在木头对象上依附了一个火焰粒子系统实现的。下面讲解一下粒子系统作为组件的创建方法。

(1)在菜单栏中单击“GameObject”选项,弹出对象创建菜单,在此菜单中选择“CreateOther”,则会弹出“创建其他”菜单,在菜单中选择“Cube”,创建出一个立方体对象,如图6-55所示。

(2)选中Cube对象,在菜单栏中单击“Component”选项,弹出组件添加菜单,在此菜单中选择 Effects,则会弹出效果添加菜单,在菜单中选择“Particle System”。这时就成功地为 Cube添加了一个粒子系统组件,如图6-56所示。

说明

本案例的场景文件位于随书光盘中源代码/第6章目录下的PhysicsEngine/Assets/ scene/ CubeParticle。

▲图6-55 创建立方体

▲图6-56 为对象添加粒子特效

粒子系统是一个相对较为复杂的游戏对象。一般来说,粒子系统包含的组件有粒子系统主体(ParticleSystem)、喷射(Emission)、形态(Shape)、渲染器(Render)。接下来对其进行详细的介绍。

(1)粒子系统主体。

单击选中粒子系统对象,会发现粒子系统开始动了起来,在属性查看器面板中呈现出的是粒子系统的属性设置器,在粒子系统的第1部分是ParticleSystem。在这一部分中,定义了粒子系统的大部分属性值。该组件在属性查看器中的位置如图6-57所示。

在这一组件中,包含的属性以及含义如表6-3所示。

表6-3 粒子系统主体属性

▲图6-57 粒子系统主体

(2)喷射(Emission)。

喷射中包含两个主要属性,定义了粒子系统的喷射特性,如图6-58所示。

频率(Rate)属性定义了喷射的频率,可以是以时间为标准定义每秒喷射的次数,也可以以距离为标准,定义每单位长度喷射的粒子个数,Rate的第1个参数是喷射次数,第2个参数是喷射基准,可选项为时间(Time)和距离(Distance)。

爆发(Bursts)定义了在某个特定时间喷射一定数量的粒子,这样可以轻松实现爆炸效果。单击该属性右下角的加号可以添加一个预设,第1列Time的数据为喷射的时刻,第2列Particles为瞬间喷射的粒子数目。

说明

Bursts只有在以时间为基准的喷射中才有效。

(3)形态(Shape)。

形态定义了粒子系统的喷射形态,如图6-59所示。粒子系统的形状既可以是系统自带的球体状、立方体状或者半球,也可以有开发者自行指定。这样给予了开发者很大的灵活性。

▲图6-58 粒子系统喷射组件

▲图6-59 粒子系统形态组件

形态属性定义了粒子可以被喷射的范围。可选项有球体(Sphere)、半球体(HemiSphere)、圆锥体(Cone)、盒子(Box)和网格(Mesh)。前4个选项可以直接通过单击“Shape”后的属性下拉列表选定,网格(Mesh)选项被单击后会弹出网格选择对话框。选择一个合适的Mesh作为限制范围。相关的属性含义如表6-4所示。

表6-4 喷射相关属性预览

(4)渲染器(Renderer)。

这一组件中的属性定义了粒子系统中粒子的渲染特性。本组件位于粒子系统修改器的最底端,如图6-60所示。修改这些属性可以更加灵活地使用粒子系统。

▲图6-60 渲染器

渲染器的相关参数直接影响了单个粒子的显示效果,这些参数的具体含义如表6-5所示。

表6-5 渲染器属性

说明

在粒子系统编辑器的最下端还有两个选项,第1个选项 Resimulate表示立即将当前的修改保存到仿真系统中并重新模拟。第2个选项WireFrame表示是否显示粒子系统的线框。

粒子系统不仅可以单独用来模拟风、霜、雨、雪等单纯的自然景观,也可以进行组合以后实现某些特殊模型的搭建,如火炬特效。火炬特效是实物模型和粒子系统组合实现的,下面通过介绍火炬的实现,重点讲解粒子系统与其他模型的组合使用方式。

(1)首先在3dMax中,将火炬柄模型导出为FBX格式文件放置在某一位置。

(2)导入模型文件,在 Unity 的资源列表中,鼠标右键单击空白位置,弹出资源操作菜单,选择 Import New Assest…,如图6-61所示。在弹出的资源选择对话框中选择刚刚导出的FBX文件。单击Import按钮,即可成功导入模型文件,如图6-62所示。

(3)导入模型文件成功以后,会在资源列表中出现所需的资源,如图6-63所示,将此模型资源左键拖曳至游戏组成对象列表中,调整火炬的位置使其在摄像机的视野之内。并将任意纹理图拖曳到该对象上,为其指定纹理图,如图6-64所示。

▲图6-61 导入资源

▲图6-62 导入FBX资源

▲图6-63 导入的资源

▲图6-64 实例化模型

(4)按照顺序GameObject→CreateOther→Sphere进行操作,新建一个球体,如图6-40所示。

(5)选中球体,按照顺序Component→Effects→Particle System进行操作,为球体添加一个粒子系统,如图6-65所示。

▲图6-65 添加粒子系统

(6)调节球体对象的位置,使其与火炬模型上端部分,具体的相对位置如图6-66所示,接下来缩小球体并将其放置在火炬的内部,使其不可见。

(7)选中球对象,在其粒子系统的Shape组件下,Shape的属性值为“Cone”,并调整球体的旋转状态,使粒子的喷射方向为竖直向上。这样保证了火焰是在燃料喷射方向上进行活动的,这符合日常生活中的火焰形态,如图6-67所示。

(8)在Sphere组件中,设置Duration值为5.0,looping为选中态。startLifeTime为1.5。startsize为1,startSpeed为2,StartColor为红色。MaxParticle值为1000,其他的属性保持默认即可,如图6-68所示。

(9)在Emission组件中设置喷射是按照时间为基准,即Rate的第2个参数为Time,第1个参数为200,Bursts没有任何设置,如图6-69所示。

(10)在Shape中设置Angle为10,Radius为0.01。其他的属性保持默认即可,如图6-70所示。

(11)在Renderer组件中,设置渲染模式(RnenderMode)为Mesh,在下面的Mesh属性选择Cube。其他的保持默认即可,如图6-71所示。

(12)接下来在游戏组成列表中进行设置,将 Sphere 左键拖动到火炬柄模型上(huoju),此时粒子系统就作为火炬柄的子对象绑定在了火炬柄上。这样粒子系统就会随着火炬柄的移动而移动。经过以上设置,即可达到火炬效果,如图6-72所示。

▲图6-66 放置球体

▲图6-67 旋转粒子系统

▲图6-68 Sphere设置

▲图6-69 Emission设置

▲图6-70 Shape设置

▲图6-71 渲染器设置

▲图6-72 火炬最终效果图

说明

本案例的场景文件位于随书光盘中源代码/第6章目录下的 PhysicsEngine/Assets/scene/particleSystem。读者可以举一反三,将此种方案加以推广,甚至可以将多个粒子系统加以组合达到更加细致精确的效果。

在现实生活中,大部分的运动物体并不是单独的一个简单基本体。对象要和其他对象进行交互,必须有其所谓的内在联系,例如枪械对象的设计。因为枪械对象的刚体组件不是简单的一个基本刚体组件组成的,需要多个子对象刚体组件的拼接来组成。这就需要关节中的固定关节来解决。

在Unity开发平台下,关节包括铰链关节(Hinge Joint)、固定关节(Fixed Joint)、弹簧关节(Spring Joint)、角色关节(Character Joint)及可配置关节(Configurable Joint)5种。通过关节组装可以轻松地实现人体、机车等游戏模型的模拟。下面将对各种关节一一地介绍。

在Unity基本关节中,铰链关节是用途很广的一个。利用铰链关节不仅可以做门的模型,风车的模型甚至还可以做机动车的模型。

铰链关节是将两个刚体束缚在一起,在两者之间产生一个铰链的效果。它不仅可以用来制造门的特效,也可以做链条之类的特效。它的具体属性如下所示。

1.连接体(Connected Body)

连接体是铰链关节的第一个重要属性,也是所有关节的必备属性。连接体是关节所依赖的可选刚体参考对象。如果没有设定,则关节连接到世界空间中。可以在属性查看器中为关节指定连接体,且连接体必须添加了刚体组件。

2.锚点(Anchor)

锚点是指主体摇摆所围绕的坐标点。该坐标点定义于局部空间中。局部空间指的是关节所作用对象的物体空间。该空间的中心位置坐标为(0, 0, 0)点。此属性可以在属性查看器中修改。

3.坐标轴(Axis)

坐标轴是指主体摇摆所围绕的坐标轴的方向。该方向定义于局部空间中。此属性可以在属性查看器中修改,其中坐标(1,0,0)、(0,1,0)、(0,0,1)分别表示绕x、y、z轴摆动。

4.使用弹簧(Use Spring)

使用弹簧属性是布尔型的属性,表示在关节组件中是否使用弹簧。而弹簧的作用是使刚体相对其连接的主体达到一个特定的角度。此属性可以在属性查看器中通过是否勾选来确定该属性的启用与否。

5.弹簧(Spring)

弹簧属性是对应于使用弹簧属性的,只有当使用弹簧属性被启用时,此属性的子属性才能被使用。弹簧属性的所有属性如下。

● 弹簧力(Spring)

弹簧力表示维持对象移动到一定位置的力。

● 阻尼(Damper)

阻尼表示物体运动所受束缚的大小,此值越大,对象移动越缓慢。

● 目标位置(Target Position)

目标位置表示的是弹簧旋转的目标角度。弹簧负责将对象拉到这个目标角度,该角度以角度为单位而非弧度。

6.使用马达(Use Motor)

使用马达属性规定了在关节组件中是否需要使用马达。马达可以使其作用的对象绕坐标轴旋转。设定此值可以做出风车或者车辆的模型。

7.马达(Motor)

马达属性是对应于使用马达属性的,只有当使用马达属性被启用时,此属性的子属性才能被使用。马达属性的所有属性如下。

● 目标速率(Target Velocity)

目标速率表示对象试图达到的速度,对象的速度将会以此速度为目标加速或者减速。

● 力(Force)

此属性表示用于达到目标速率的力。

● 自由转动(Free Spin)

此属性规定了受控对象的旋转是否会被破坏。如果启用此属性,马达永远不会破坏旋转,只会加速。

8.使用限制(Use Limits)

此属性规定了在关节下的旋转是否受限。如果启用,铰链的角度将被限制在最大和最小之间。

9.限制(Limits)

限制属性是对应于使用限制属性的,只有当使用限制属性被启用时,此属性的子属性才能被使用。限制属性的所有属性如下。

● 最小(Min)

该属性规定了该对象旋转所能达到的最小角度。

● 最大(Max)

该属性规定了该对象旋转所能达到的最大角度。

● 最小弹跳(Min Bounce)

此属性规定了物体达到最小限值时的弹跳值。

● 最大弹跳(Max Bounce)

此属性规定了物体达到最大限值时的弹跳值。

10.破坏力(Break Force)

此属性给出了一个力的限值,当关节受到的力超过此限值时关节就会损坏。

11.破坏扭矩(Break Torque)

此属性给出了一个扭矩的限值,当关节受到的扭矩超过此限值时关节就会损坏。

说明

下面介绍的其他关节中的相同属性大多数在本质上都是相似的,因此,其他关节中的相同的属性只作简单介绍,不再作详细说明。

上一小节介绍了铰链关节的特性,这一小节将介绍铰链关节的创建。在介绍关节之前请读者首先理解一点,关节是依附在刚体上的,也就是说必须有刚体的物体才能够添加铰链关节。铰链关节的创建步骤如下所示。

(1)创建一个圆柱体对象。在菜单栏中单击“GameObject”,将会弹出“游戏对象操作”菜单,在此菜单中单击选择“Create Other”,继而在弹出的“创建其他”菜单中选择“Cylinder”。即创建了一个圆柱对象,如图6-73所示。

▲图6-73 创建圆柱体

(2)创建一个立方体对象。在菜单栏中单击“GameObject”,将会弹出“游戏对象操作”菜单,在此菜单中单击选择“Create Other”,继而在弹出的“创建其他”菜单中选择“Cube”。即创建了一个圆柱对象,如图6-55所示。

(3)单击圆柱体对象,在属性查看器中,修改 Transform 组件中Position属性值为(0,0,0),如图6-74所示。单击选中立方体对象,在右侧的属性查看器中,修改其 Transform 组件中position属性的值为(0,0,0)。这样的设置是为了使圆柱和立方体位于摄像机的视野范围内,如图6-75所示。

▲图6-74 修改Position值

▲图6-75 对象位置摆放

(4)对立方体进行缩放,在y轴和x轴上进行拉伸,z轴上进行压缩。将其作为一个门板,并将圆柱和该门板方块摆放在如图6-76所示的位置。

(5)为两个对象添加刚体(Rigibody)。选中圆柱体,在菜单栏中选择Component,将会弹出“组件添加”菜单,在此菜单中单击选择“Physics”,继而在弹出的“物理”菜单中选择“Rigidbody”。选中立方体,重复上面的操作为圆柱体和方块添加刚体,如图6-77所示。

▲图6-76 摆放门

▲图6-77 添加刚体

(6)添加铰链关节。选中方块对象,在菜单栏中选择Component,将会弹出“组件添加”菜单,在此菜单中单击选择“Physics”,继而在弹出的“物理”菜单中选择“Hinge Joint”,如图6-78所示。

▲图6-78 添加铰链关节

(7)接下来在右侧的属性查看器中,修改关节参数,在Hinge Joint的Anchor属性组中修改参数分别为(−0.5,0,0),并修改Axis中的参数分别为(0,1,0)。设置出关节的位置,如图6-79所示。

(8)选中圆柱体,在属性查看器中修改属性,在Constraints内,将所有的坐标轴选中,冻结该圆柱的运动,这样就只有门板可动。以此就可以制作出一个门的模型,如图6-80所示。

▲图6-79 设置关节

▲图6-80 固定圆柱

说明

为了观察关节的效果,可以将两刚体的刚体属性的UseGravity属性值为false。

在 Unity 基本关节中,固定关节起到的往往是组装的任务,利用固定关节可以拼接刚体。固定关节将两个刚体束缚在一起,使两者之间的相对位置永远不发生变化。它的具体属性如下所示。

1.连接体(Connected Body)

连接体是关节所依赖的可选刚体参考对象。如果没有设定,则关节连接到世界空间中。

2.破坏力(Break Force)

此属性给出了一个力的限值,当关节受到的力超过此限值时关节就会损坏。

3.破坏扭矩(Break Torque)

此属性给出了一个扭矩的限值,当关节受到的扭矩超过此限值时关节就会损坏。

上一小节介绍了固定关节的特性,这一小节将介绍固定关节的创建。在介绍关节之前请读者首先理解一点,固定关节是用来连接刚体的。固定关节的创建步骤如下所示。

(1)创建两个球体对象,具体操作顺序为GameObject→CreateOther→Sphere。将以上操作进行两次,得到两个球体。分别命名为“ball1”和“ball2”,如图6-40所示。为球体添加刚体。具体操作为Component→Physics→Rigidbody。

(2)为其添加固定关节。选中球体对象,在菜单栏中选择Component选项,然后在弹出的“组件”菜单中,选择“Physics”,然后选择“Fixed Joint”,如图 6-81所示。

(3)为ball2指定固定关节的根,选中“ball2”游戏对象,在属性查看器中,单击Fixed Joint组件下的ConnectedRgidbody属性框,如图6-82所示。在弹出的刚体选择列表中选择ball1,如图6-83所示,即完成操作。

▲图6-81 添加固定关节

▲图6-82 设置连接体

▲图6-83 选择连接体

说明

为了观察关节的效果,可以将两刚体的刚体属性的UseGravity属性值设为false。

在 Unity 基本关节中,弹簧关节的效果极佳。利用弹簧关节可以模拟多种物理模型。弹簧关节将两个刚体束缚在一起,使两者之间像有一个弹簧的束缚一样。它的具体属性如下所示。

1.连接体(Connected Body)

连接体是关节所依赖的可选刚体参考对象。如果没有设定,则关节连接到世界空间中。

2.锚点(Anchor)

锚点表示的是对象基于局部空间的中心位置,是弹簧关节作用的位置。

3.弹簧(Spring)

此属性表示的是弹簧的劲度系数,此值越高,弹簧的弹性效果越强。

4.阻尼器(Damper)

此属性规定了弹簧在弹跳过程中,慢慢减速的特性。在此过程中会造成能量的损耗。

5.最小距离(Min Distance)

最小距离表示如果两物体的当前距离与初始距离差大于设定值,则不激活弹簧。

6.最大距离(Max Distance)

最大距离表示如果两物体的当前距离与初始距离差小于设定值,则不激活弹簧。

7.破坏力(Break Force)

此属性给出了一个力的限值,当关节受到的力超过此限值时关节就会损坏。

8.破坏扭矩(Break Torque)

此属性给出了一个扭矩的限值,当关节受到的扭矩超过此限值时关节就会损坏。

上一小节介绍了弹簧关节的特性,这一小节将介绍弹簧关节的创建。在介绍关节之前请读者首先理解一点,弹簧关节是依附在刚体上的,也就是说必须有刚体的物体才能够添加弹簧关节。弹簧关节的创建步骤如下所示。

( 1 )创建一个球体对象,具体操作顺序为 GameObject→CreateOther→Sphere,如图6-40所示。为球体添加刚体。具体操作为Component→Physics→Rigidbody。

(2)为球体添加固定关节。将世界空间作为弹簧关节的根。选中球体对象,在菜单栏中选择Component选项,然后在弹出的“组件”菜单中,选择“Physics”,然后选择“Spring Joint”,如图6-84所示。

▲图6-84 添加弹簧关节

在 Unity 基本关节中,角色关节是应用较广的一个基本关节。利用角色关节可以模拟人体模型。角色关节大多用于布娃娃特效角色关节,是扩展的球关节,可以用于限制关节在不同旋转轴下的旋转角度。它的具体属性如下所示。

1.连接体(Connected Body)

连接体是关节所依赖的可选刚体参考对象。如果没有设定,则关节连接到世界空间中。

2.锚点(Anchor)

锚点这里指游戏对象局部空间中的点,关节绕此点转动。

3.坐标轴(Axis)

坐标轴这里指关节的扭轴,以橙色的gizmo圆锥显示。

4.摆轴(Swing Axis)

摆轴是指角色对象上某两个部分的摆动所绕的轴。以绿色的gizmo圆锥显示。

5.扭轴下限(Low Twist Limit)

扭轴下限为关节扭轴指定了下限,关节扭曲的角度不可低于此下限。

6.扭轴上限(High Twist Limit)

扭轴上限为关节扭轴指定了上限,关节扭曲的角度不可高于此上限。

7.摆轴限制1(Swing 1 Limit)

摆轴限制1为关节的摇摆定义了下限参数,绕摆轴的摆动角不能低于此下限。摆轴限制1限制了绕摆轴的旋转(绿轴),对摆轴旋转角度的限制是对称的,因此,如设置摆轴1的限制角度为30,则表示摆轴1的旋转被限制在−30和30之间。

8.摆轴限制2(Swing 2 Limit)

摆轴限制2为关节的摇摆定义了上限参数,绕摆轴的摆动角不能高于此上限。摆轴限制2没有gizmo辅以显示,此轴垂直于扭轴和摆轴1构成的平面。与摆轴1相同,对摆轴2旋转角度的限制也是对称的,因此,如设置摆轴2的限制角度为40,则表示摆轴2的旋转被限制在−40和40之间。

9.破坏力(Break Force)

此属性给出了一个力的限值,当关节受到的力超过此限值时关节就会损坏。

10.破坏扭矩(Break Torque)

此属性给出了一个扭矩的限值,当关节受到的扭矩超过此限值时关节就会损坏。

上一小节介绍了角色关节的特性,这一小节将介绍角色关节的创建。在介绍关节之前请读者首先理解一点,角色关节是依附在刚体上的,也就是说必须有刚体的物体才能够添加角色关节。角色关节的创建步骤如下所示。

(1)创建两个立方体对象,具体操作顺序为GameObject→CreateOther→Cube。将以上操作进行两次,得到两个Cube。分别命名为“cube1”和“cube2”,如图6-22所示。为立方体添加刚体。具体操作为Component→Physics→Rigidbody。

(2)为其添加角色关节。选中球体对象,在菜单栏中选择Component选项,然后在弹出的“组件”菜单中,选择“Physics”,然后选择“Character Joint”,如图 6-85所示。

(3)选中“cube2”游戏对象,在属性查看器中,单击Character Joint组件下的ConnectedRgidbody属性框,如图6-86所示。在弹出的刚体选择列表中选择cube1,如图6-87所示,即完成操作。

▲图6-85 添加角色关节

▲图6-86 设置连接体

▲图6-87 选择连接体

说明

为了观察关节的效果,可以将两刚体的刚体属性的UseGravity属性值设为false。

此属性是朝着预定义方向的橡皮拉力。只有当模式中包含目标位置时才有效。

可配置关节是可定制的。可配置关节将PhysX引擎中所有与关节相关的属性都设置为可配置的,因此可以用此组件创造出与其他关节类型行为相似的关节。正是由于其强大的灵活性,也造成了其复杂性。下面将介绍一下可配置关节的主要属性。

1.锚点(Anchor)

锚点这里是关节的中心点,所有的物理模拟都使用此点作为中心进行计算。

2.主轴(Axis)

主轴这里是指局部旋转轴,定义了物理模拟下物体的自然旋转。

3.副轴(Secondary Axis)

主轴和副轴定义了关节的局部坐标系。第三个轴垂直于主轴和副轴。

4.x轴平移(Xmotion)

设置物体沿x轴的平移模式为自由的、锁定的或者受限于线性限制。

5.y轴平移(Ymotion)

设置物体沿y轴的平移模式为自由的、锁定的或者受限于线性限制。

6.z轴平移(Zmotion)

设置物体沿z轴的平移模式为自由的、锁定的或者受限于线性限制。

7.x轴角运动(Angular XMotion)

设置物体沿x轴的旋转模式为自由的、锁定的或者受限于基于x轴角运动下限和上限的限制。

8.y轴角运动(Angular YMotion)

设置物体沿y轴的旋转模式为自由的、锁定的或者受限于y轴角运动限制。

9.z轴角运动(Angular ZMotion)

设置物体沿z轴的旋转模式为自由的、锁定的或者受限于z轴角运动限制。

10.线性限制(Linear Limit)

以边界(离关节原点的距离)的形式定义的物体平移限制。

● 限制(Limit)

此属性是原点到边界的距离。

● 反弹力(Bouncyness)

此属性是当物体到达边界时对其施加的反弹力。

● 弹簧力(Spring)

此属性是将物体拉回限制(Limit)的力,任何非零数值将会隐式地软化边界。

● 阻尼器(Damper)

此属性是抵抗弹簧力的力量。

11.x轴角运动下限(Low Angular XLimit)

以边界(与关节初始旋转的差值)的形式定义的物体旋转下限。

● 限制(Limit)

此属性是对象旋转角度的下限值。

● 反弹力矩(Bouncyness)

此属性是当物体的旋转达到限制(Limit)时对其施加的反弹力矩。

● 弹簧力(Spring)

此属性是将物体拉回到限制(Limit)的力,任何非零数值将会隐式地软化边界。

● 阻尼器(Damper)

此属性是抵抗弹簧力的力量。

12.x轴角运动上限(High Angular XLimit)

此属性是以边界(与关节初始旋转的差值)的形式定义的物体旋转上限。

● 限制(Limit)

此属性是对象旋转角度的下限值。

● 反弹力矩(Bouncyness)

此属性是当物体的旋转达到限制(Limit)时对其施加的反弹力矩。

● 弹簧力(Spring)

此属性是将物体拉回到限制(Limit)的力,任何非零数值将会隐式地软化边界。

● 阻尼器(Damper)

此属性是抵抗弹簧力的力量。

13.y轴角运动限制(Angular YLimit)

以边界(与关节初始旋转的差值)的形式定义的物体旋转限制。

● 限制(Limit)

此属性是对象旋转角度的下限值。

● 反弹力矩(Bouncyness)

此属性是当物体的旋转达到限制(Limit)时对其施加的反弹力矩。

● 弹簧力(Spring)

此属性是将物体拉回到限制(Limit)的力,任何非零数值将会隐式地软化边界。

● 阻尼器(Damper)

此属性是抵抗弹簧力的力量。

14.z轴角运动限制(Angular ZLimit)

此属性是以边界(与关节初始旋转的差值)的形式定义的物体旋转限制。

● 限制(Limit)

此属性是对象旋转角度的下限值。

● 反弹力矩(Bouncyness)

此属性是当物体的旋转达到限制(Limit)时对其施加的反弹力矩。

● 弹簧力(Spring)

此属性是将物体拉回到限制(Limit)的力,任何非零数值将会隐式地软化边界。

● 阻尼器(Damper)

此属性是抵抗弹簧力的力量。

15.目标位置(Target Position)

此属性是关节应该到达的位置。

16.目标速度(Target Velocity)

此属性是关节应该到达的速度。

17.x轴驱动(XDrive)

此属性是定义关节如何沿x轴运动。

● 模式(Mode)

此属性可以设置为目标位置、目标速度或两者都是,默认是禁用(Disabled)模式。

● 位置弹力(Position Spring)

此属性是朝着预定义方向的橡皮拉力。只有当模式中包含目标位置时才有效。

● 位置阻尼(Position Damper)

此属性是抵抗位置弹力的力量。只有当模式中包含目标位置时才有效。

● 最大力(Maximum Force)

此属性是使物体达到预定义速度的力。只有当模式中包含目标速度时才有效。

18.y轴驱动(Ydrive)

此属性是定义关节如何沿y轴运动。

● 模式(Mode)

此属性可以设置为目标位置、目标速度或两者都是,默认是禁用(Disabled)模式。

● 位置弹力(Position Spring)

此属性是朝着预定义方向的橡皮拉力。只有当模式中包含目标位置时才有效。

● 位置阻尼(Position Damper)

此属性是抵抗位置弹力的力量。只有当模式中包含目标位置时才有效。

● 最大力(Maximum Force)

此属性是使物体达到预定义速度的力。只有当模式中包含目标速度时才有效。

19.z轴驱动(Zdrive)

此属性定义关节如何沿z轴运动。

● 模式(Mode)

此属性可以设置为目标位置、目标速度或两者都是,默认是禁用(Disabled)模式。

● 位置弹力(Position Spring)

此属性是朝着预定义的方向的橡皮拉力。只有当模式中包含目标位置时才有效。

● 位置阻尼(Position Damper)

此属性是抵抗位置弹力的力量。只有当模式中包含目标位置时才有效。

● 最大力(Maximum Force)

此属性是使物体达到预定义速度的力。只有当模式中包含目标速度时才有效。

20.目标旋转(Target Rotation)

此属性是用一个四元数来表示旋转。它定义了关节的旋转目标。

21.目标角速度(Target Angular Velocity)

此属性是用一个三维向量来表示角速度。它定义了关节的旋转角速度目标。

22.旋转驱动模式(Rotation Drive Mode)

此属性表示用x和yz角驱动或插值驱动控制物体的旋转。

23.x轴角驱动(Angular XDrive)

此属性定义关节如何绕x轴旋转。只有当旋转驱动模式为x&yz角驱动时才有效。

● 模式(Mode)

此属性可以设置为目标位置、目标速度或两者都是,默认是禁用(Disabled)模式。

● 位置弹力(Position Spring)

● 位置阻尼(Position Damper)

此属性是抵抗位置弹力的力量,只有当模式中包含目标位置时才有效。

● 最大力(Maximum Force)

此属性是使物体达到预定义方向的力。只有当模式中包含目标速度时才有效。

24.y、z轴角驱动(Angular YZDrive)

此属性定义关节如何绕y轴和z轴旋转。只有当旋转驱动模式为x&yz角驱动时才有效。

● 模式(Mode)

此属性可以设置为目标位置、目标速度或两者都是,默认是禁用(Disabled)模式。

● 位置弹力(Position Spring)

此属性是朝着预定义方向的橡皮拉力。只有当模式中包含目标位置时才有效。

● 位置阻尼(Position Damper)

此属性是抵抗位置弹力的力量。只有当模式中包含目标位置时才有效。

● 最大力(Maximum Force)

此属性是使物体达到预定义方向的力。只有当模式中包含目标速度时才有效。

25.插值驱动(Slerp Drive)

此属性定义关节如何绕所有局部旋转轴旋转。只有当旋转驱动模式为插值时才有效。

● 模式(Mode)

此属性可以设置为目标位置、目标速度或两者都是,默认是禁用(Disabled)模式。

● 位置弹力(Position Spring)

此属性是朝着预定义方向的橡皮拉力。只有当模式中包含目标位置时才有效。

● 位置阻尼(Position Damper)

此属性是抵抗位置弹力的力量。只有当模式中包含目标位置时才有效。

● 最大力(Maximum Force)

此属性是使物体达到预定义方向的力。只有当模式中包含目标速度时才有效。

26.投影模式(Projection Mode)

此属性表示当物体离开它受限的位置太远时让它迅速回到它受限的位置。

27.投影距离(Projection Distance)

此属性表示当物体与连接体的距离差异超过投影距离后,物体才会迅速回到一个可接受的位置。

28.投影角度(Projection Angle)

此属性表示当物体与连接体的角度差异超过投影角度后,物体才会迅速回到一个可接受的位置。

29.在世界空间中配置(Congfigure in World Space)

此属性表示如果启用了此选项,所有与目标相关的计算都会在世界空间中进行,而不是在物体的本地空间中进行。

30.破坏力(Break Force)

此属性给出了一个力的限值,当关节受到的力超过此限值时关节就会损坏。

31.破坏扭矩(Break Torque)

此属性给出了一个扭矩的限值,当关节受到的扭矩超过此限值时关节就会损坏。

说明

在所有的关节中,可编辑关节是最为灵活的一个,但是由于其复杂性,在一般关节可以解决的情况下,尽量不要应用此关节。

上一小节介绍了可配置关节的特性,这一小节将介绍可配置关节的创建。在介绍关节之前请读者首先理解一点,可配置关节是依附在刚体上的,也就是说必须有刚体的物体才能够添加可配置关节。可配置关节的创建步骤如下所示。

(1)创建两个立方体对象,具体操作顺序为GameObject→CreateOther→Cube。将以上操作进行两次,得到两个Cube。分别命名为“cube1”和“cube2”,如图6-22所示。为立方体添加刚体。具体操作为Component→Physics→Rigidbody。

(2)为其添加可配置关节。选中球体对象,在菜单栏中选择Component选项,然后在弹出的“组件”菜单中,选择“Physics”,然后选择“Configurable Joint”,如图 6-88所示。

▲图6-88 添加可设置关节

(3)选中“cube2”游戏对象,在属性查看器中,单击 Configurable Joint 组件下的ConnectedRgidbody属性框,如图6-89所示。在弹出的刚体选择列表中选择cube1,如图6-90所示,即完成操作。

说明

为了观察关节的效果,可以将两刚体的刚体属性的UseGravity属性值设为false。

▲图6-89 设置连接体

▲图6-90 选择连接体

在本小节中介绍了关节的相关基础知识。为了加深读者理解,熟悉在开发中关节的用法,将在此部分介绍一个机械手的开发过程。机械手的具体步骤如下所示。

(1)新建一个场景,在菜单栏中选择 File,打开文件操作按钮。选择New Scene,创建一个场景,如图6-91所示。按下快捷键Ctrl+S保存该场景,命名为“MachineArm”,如图6-92所示。

▲图6-91 新建场景

▲图6-92 保存场景

(2)新建一个平面。在菜单栏中选择“GameObject”选项,在弹出的“游戏对象操作”菜单中选择“Create Other”选项,在“创建其他”菜单中选择“Plane”。将此平面拖曳放置在摄像机视野之内,如图6-36所示。将资源列表中的地板纹理图资源拖拉到此平面上,为其指定纹理。

▲图6-93 添加天空盒

( 3 )选中摄像机“MainCamera”对象,在菜单栏中选择“Component”选项,在“组件添加”菜单中选择“Rendering”,在弹出的渲染菜单中选择“Skybox”,如图6-93所示。

(4)导入天空盒资源,在资源列表中的空白处鼠标右键单击,弹出资源操作列表,选择“Import Package”,如图6-94所示。在弹出的资源包列表中选择“Skyboxs”,如图6-95所示。经过此操作就导入了天空盒资源。

(5)为摄像机的天空盒指定类型,选中摄像机,在属性查看器中,单击Skybox的容器Custom Skybox属性右方的属性框,如图 6-96所示。此时会弹出天空盒选择框,选择Sunny2 Skybox,如图 6-97所示。

▲图6-94 导入资源

▲图6-95 导入天空盒资源

▲图6-96 设置天空盒

▲图6-97 选择天空盒

(6)新建一个球体对象。操作顺序为GameObject→CreateOther→Sphere,如图6-40所示。将球的纹理图拖曳到球体对象上,用于为球体指定纹理图,并对其适度缩放,效果如图6-98所示。

(7)新建4个Cube对象,具体操作步骤为GameObject→CreateOther→Cube,重复此操作的4个立方体对象,如图6-22所示。

(8)创建两个圆柱体对象,在菜单栏中单击GameObject,在弹出的游戏对象操作菜单中,选择“Create Other”,在弹出的菜单中选择Cylinder,重复两次这样的操作,如图 6-99所示。

▲图6-98 球效果图

▲图6-99 创建圆柱体

(9)将一个圆柱作为机械手的转轴,放置在摄像机的正前方,并对第(8)步所产生的立方体对象进行缩放平移。将一个圆柱进行缩放,作为机械手的连接杆,具体效果如图6-100所示。

(10)新建一个标签。选中转轴圆柱对象,在属性查看器中,单击Tag属性右侧的属性选择列表,选择Add Tag选项,如图 6-101所示。

(11)经过上述操作,进入了标签与层添加器中,在Tag属性的Size属性右侧的编辑框中填写2。在Element0后面的文本框中输入main,Element1中添加ball,用以新建两个标签,如图6-102所示。

▲图6-100 机械手摆放效果

▲图6-101 新建标签1

▲图6-102 新建标签2

(12)为转轴圆柱体指定标签。再次选中圆柱体对象,在属性查看器中的Tag属性下拉列表中选择main,为其指定标签为“main”,如图6-103所示。

(13)选中第(7)步创建的球体对象,在属性查看器中的Tag属性下拉列表中选择ball,为其指定标签为“ball”,如图6-104所示。

▲图6-103 指定圆柱体的标签

▲图6-104 指定球体的标签

(14)为6个立方体对象和两个圆柱体添加刚体。对6个对象进行如下同样的操作,选中操作对象,在菜单栏中选择Component,在弹出的组件菜单中选择Physics,然后在弹出的菜单中选择Rigidbody,即完成刚体的添加,如图6-77所示。

(15)接着依次选中对象,在属性查看器中,去掉刚体组件中 UseGravity 属性右侧的勾,以使所有对象不受重力作用,如图6-105所示。

(16)为各个物体进行命名。为6个立方体和两个圆柱体对象指定名称。所有的名称对应对象如图6-106所示。命名的方法为,选中要命名的对象,再次单击,然后依照所对应的名称输入内容即可,如图6-107所示。

说明

此处为对象命名,是为了方便后面指定关节关系。

(17)为各个物体添加关节。选中“zhou”对象,在菜单栏中选择 Component 选项,在弹出的菜单中选择“Physics”,然后在“物理”菜单中选择Fixed Joint,如图 6-81所示。

(18)选中“zhou”对象,在属性查看器中,单击Fixed Joint的Connected Body属性后的属性框,如图6-108所示,然后在弹出的刚体选择框中选择“gan”,如图6-109所示。

▲图6-105 去除重力约束

▲图6-106 为对象命名

▲图6-107 命名方法

▲图6-108 指定连接体

▲图6-109 选择连接体

(19)按照第(17)步和第(18)步的操作步骤,将left1、middle1和right1添加固定关节,并指定其连接体均为“zhou”。

(20)选中“left2”对象,在菜单栏中选择Component选项,在弹出的菜单中选择“Physics”,然后在“物理”菜单中选择Hinge Joint,如图 6-78所示。

(21)选中“left2”对象,在属性查看器中,单击Hingeoint的Connected Body属性后的属性框,如图6-110所示。然后在弹出的刚体选择框中选择“left1”,如图6-111所示。

▲图6-110 指定连接体

▲图6-111 选择连接体

(22)在属性查看器中设置铰链关节的属性值,首先是 Anchor 的值分别为 0,0.5,0。Axis的值为0、0、1。在Use Spring右侧打上勾表示选中,然后Spring的Damper值为2。Use Limits右侧打勾表示选中,Limits中的min值为0,Max值为5,如图6-112所示。

(23)按照步骤(20)~步骤(22)的操作,对middle2和right2进行设置,middle2所谓连接体为middle1,其Anchor的值为−1、0、0。right2的连接体为right1,其Anchor的值为0、0、−1。其他设置与left2完全相同。

(24)选中球体对象,将球体对象平移到机械手的正下方,如图6-113所示。

▲图6-112 设置铰链关节

▲图6-113 摆放球体

(25)在资源列表中鼠标右键单击,在弹出的菜单中选择 Create,继而在弹出的菜单中选择JavaScript,为脚本命名为“MachineAnimation”,按下回车,接着双击该脚本,打开脚本编辑器编写脚本,实现机械手的向下运动,并抓住球体继而向上运用,具体代码片段如下。

代码位置:见随书光盘中源代码/第6章目录下的 PhysicsEngine/Assets/script/MachineAnimation.js。

1 private var speed : Vector3 = Vector3 (0, -24, 0);  //声明下落速度

2 var i:int=0;

3 function Update()

4 {

5   if(this.transform.tag=="main"&&i==0)

6   {

7    rigidbody.MovePosition(rigidbody.position + speed * Time.deltaTime);//向下运动

8   }

9   if (i==1&&this.transform.tag=="main")    //表示机械手要上升

10  {

11    rigidbody.MovePosition(rigidbody.position - speed * Time.deltaTime);//向上运动

12  }

13  if(Input.GetKey(KeyCode.Escape))     //为返回键添加监听

14  {

15    Application.Quit();       //退出程序

16  }}

17 function OnCollisionEnter(coll:Collision)    //碰撞监听事件

18 {

19  if(coll.collider.tag=="ball")      //与球发生触碰

20  {

21    i=1;           //表示上升状态

22    this.rigidbody.freezeRotation=false;   //冻结机械手

23  }}

● 第 3-16 行为实现机械手的上升下降功能,并实现了返回键的事件监听功能。一旦返回键被按下,就退出程序。

● 第17-23行为碰撞监听事件的处理,一旦发生碰撞就锁定机械手的旋转,即可夹住球体。

说明

因为left2、middle2和right2这3部分在最初时虽然是受限的,但可以活动,在机械手下落至最低的时候,3部分会在惯性的作用下贴向球体,在此时将其旋转固定住,即可实行抓取。

(26)保存关闭脚本编辑器,在资源列表中进行操作,拖曳刚刚编写的脚本“MachineAnimation”至对象left1、left2、middle1、middle2、right1、right2、gan和zhou这8个对象上。

(27)游戏开发完毕,运行游戏查看游戏效果,游戏效果如图6-114、图6-115、图6-116和图6-117所示。

说明

本案例的场景文件位于随书光盘中源代码/第6章目录下的PhysicsEngine/Assets/scene/MachineArm。

▲图6-114 机械手效果1

▲图6-115 机械手效果2

▲图6-116 机械手效果3

▲图6-117 机械手效果4

在前面的内容中,讲解了Unity开发平台下物理引擎的相关内容,正是这一完善的物理引擎,使得模拟现实变得极其简单。在本小节中,将通过一个交通工具的小案例来模拟现实生活中汽车的各种运动。下面将对交通工具案例的开发步骤进行介绍。

1.案例的构思

在开发案例之前,这里先介绍一下本案例的设计思路。

(1)首先要明确案例要达到的目的。本案例是为了演示使用 Unity 物理引擎模拟现实生活中交通工具的运动特性。

(2)接着要明确案例场景的设计。在本案例中,使用了地形引擎系统,在地形上有一些任意位置形状的小山丘。同时,场景中有一辆汽车模型,在汽车正前方摆放有两个油桶和3个木箱。这些场景的设计是为了观察汽车在地形上的运动以及跟油桶和木箱的碰撞情况。

(3)然后是对汽车模型的开发。导入的汽车模型是不能够运动的,必须给其添加必要的组件。在本案例中,汽车模型整体被添加了刚体和相应的脚本组件,车轮也被添加了车轮碰撞器组件和相应的脚本组件。

(4)最后就是把PC端的程序移植到Android设备上。本案例中采用Unity引擎自带的Single Joystick预制件来实现Android设备上的操纵杆控制汽车。

2.案例场景的设计

在明确了案例的构思后,就可以按照构思的步骤来进行开发了。主要的开发步骤如下。

(1)首先新建一个项目,选择 File→New Project 选项创建一个新项目,并命名为“VehicleDemo”。然后,选择File→Save Scene(或者按下快捷键Ctrl+S)保存场景为Car。最后,选择GameObject→Create Other→Directional light来创建一个光源,如图 6-118所示。

(2)创建地形。选择Terrain→Create Terrain创建一个新的地形,然后使用地形编辑工具对地形进行适当的编辑,最终的地形效果如图6-119所示。

说明

因为地形引擎系统不是本小节的重点,该内容将在后续的章节里具体介绍,所以,本小节只是简单地说明,如果读者当前还不习惯使用地形引擎系统,可以创建一个平面来替代,相信对认真学习过前面章节内容的读者来说,创建一个平面应该不是什么难题。

▲图6-118 保存场景和创建灯光

▲图6-119 创建地形

(3)导入资源。将光盘中本章节对应文件夹下的“资源包”文件夹中的“Model.unitypackage”文件复制到第(1)步中新建项目时生成的“VehicleDemo”文件夹下。然后,选择Assets→Import Package→Custom Package导入“Model.unitypackage”中的所有文件,如图 6-120所示。

(4)在场景中创建汽车和油桶模型。将“Assets\Model\”文件夹下的“Car_Model”拖曳到Scene 视图中,如果汽车模型没有显示贴图,则可以将“Assets\Model\Materials”文件夹下的“Car_Material”材质分别拖曳到汽车模型的车身和4个车轮上。然后用同样的方法,在场景中创建两个油桶模型,分别命名为“OilTank1”和“OilTank2”,如图6-121所示。

(5)在场景中创建3个木箱。选择GameObject→Create Other→Cube分别创建3个立方体,且分别命名为“Box1”、“Box2”、“Box3”。然后将“Assets\Texture”文件夹下的“WoodBoxTex”纹理贴图分别拖曳到新创建的3个立方体上,调整场景中各个模型的Transform参数,如图6-122所示。

▲图6-120 导入资源

▲图6-121 创建汽车模型和油桶模型

▲图6-122 创建 3个木箱

3.案例主体部分设计

前面刚介绍完场景的搭建,接下来将介绍案例主体部分的设计。这部分主要是为了增加案例运行过程中的真实性和交互性,这就需要给场景中的各个游戏对象加上相应的组件,具体步骤如下。

(1)为油桶和木箱添加物理属性。选择Component→Physics→Rigidbody为油桶和木箱添加刚体,接着选择Component→Physics→Box Collider为油桶添加“Box Collider”组件(木箱已有该组件,不需重复添加)。同时,为木箱添加“Wood”材质,为油桶添加“Metal”材质,如图6-123所示。

▲图6-123 添加物理属性

(2)为汽车的车轮添加“Wheel Collider”组件。选择GameObject→Create Empty创建一个空对象,重命名为“FLCollider”,然后选择Component→Physics→Wheel Collider给“FLCollider”添加碰撞体,并将“FLCollider”的位置和汽车左前轮位置对齐。按照此操作步骤,依次创建“FRCollider”、“BLRCollider”、“BRCollider”,并组织好目录结构,如图6-124所示。

▲图6-124 添加“Wheel Collider”组件

(3)为汽车的车身添加“Box Collider”组件。选择GameObject→Create Empty创建一个空对象,重命名为“BottomCollider”,然后选择Component→Physics→Box Collider给“BottomCollider”添加碰撞体,并使碰撞体包裹住车身下半部分。按照此操作步骤,创建“TopCollider”并使其包裹住车身上半部分,并组织好目录结构,如图6-125所示。

▲图6-125 添加“Box Collider”组件

(4)为汽车的车轮编写脚本。该脚本的作用是控制车轮的位置和旋转参数,使车轮在车的移动过程中跟着转动,这样车轮的运动看起来更逼真。具体代码如下所示。

代码位置:见随书光盘中源代码/第6章目录下的 VehicleDemo/Assets/Scripts/ WheelAlignment.js。

1 var CorrespondingCollider : WheelCollider;//定义车轮碰撞器

2 private var RotationValue : float = 0.0;//定义车轮旋转值,初始值为0

3 function Update () {

4   var hit : RaycastHit;//为射线碰撞定义一个RaycastHit类型的变量

5   //定义碰撞中心点为车轮碰撞器的中心点

6   var ColliderCenterPoint : Vector3 =

7    CorrespondingCollider.transform.TransformPoint( CorrespondingCollider.center );

8   //以下代码实现了发生碰撞后车的移动

9 if ( Physics.Raycast( ColliderCenterPoint, -CorrespondingCollider.transform.up,

10 hit, CorrespondingCollider.suspensionDistance + CorrespondingCollider.radius ) ) {

11    transform.position = hit.point + (CorrespondingCollider.transform.up *CorrespondingCollider.radius);

12  }else{

13 transform.position = ColliderCenterPoint - (CorrespondingCollider.transform.up *

14           CorrespondingCollider.suspensionDistance);

15  }

16  //重置车轮旋转值,保证车在移动时车轮跟着转

17  transform.rotation = CorrespondingCollider.transform.rotation *

18    Quaternion.Euler(RotationValue,CorrespondingCollider.steerAngle,0);

19  //计算车轮旋转值,其中rpm表示车轮转速

20  RotationValue += CorrespondingCollider.rpm * ( 360/60 ) * Time.deltaTime;

21 }

● 第1-2行为变量的定义,第一个变量的值将在属性查看器中予以赋值。

● 第3-21行为Update方法的重写,主要是控制汽车模型的车轮的相关姿态,确保汽车在运动过程中车轮的运动和现实生活中相同。

( 5 )为汽车的车轮添加脚本。将“WheelAlignment.js”脚本挂载到车轮游戏对象“FrontLeftWheel”上,然后将“FLCollider”游戏对象拖曳到属性查看器的“CorrespondingCollider”变量处,如图6-126所示。同时,将该脚本分别挂载到其他3个车轮游戏对象上,做相同的操作。

(6)添加触摸操纵杆。选中“Assets”文件夹,右键选择 Import Package→Standard Assets(Mobile)后弹出“Importing package”对话框,然后选择其中的“Single Joystick.prefab”、“Joystick.js”、“ JoystickThumb.psd”3个文件导入。导入后,找到“Standard Assets (Mobile)\ Prefabs”文件夹下的“Single Joystick”预制件,并将其拖曳到“Hierarchy”视图中,如图 6-127所示。

▲图6-126 添加脚本组件

▲图6-127 添加操纵杆

(7)为汽车编写控制脚本。该脚本的作用是控制汽车的移动和转弯,如果是在 PC 上,则通过方向键或者“W”、“A”、“S”、“D”4 个键来控制汽车的方向;在 Android 设备上,则通过触摸操纵杆来控制其方向。具体代码如下所示。

代码位置:见随书光盘中源代码/第6章目录下的 VehicleDemo/Assets/Scripts/ CarControl.js。

1 var FrontLeftWheel : WheelCollider;//定义左前轮碰撞器

2 var FrontRightWheel : WheelCollider;//定义右前轮碰撞器

3 var GearRatio : float[];//定义齿轮比数组,程序会根据齿轮数比来决定应该给车轮多大的扭矩

4 var CurrentGear : int = 0;//定义当前齿轮索引

5 var EngineTorque : float = 600.0;//定义发动机转矩

6 var MaxEngineRPM : float = 3000.0;//定义发动机最大转速

7 var MinEngineRPM : float = 1000.0;//定义发动机最小转速

8 private var EngineRPM : float = 0.0;//定义发动机转速

9 var moveJoystick : Joystick;//定义操纵杆

10 function Start () {

11  //给汽车质心的Y方向的位置赋值,确定汽车质心的位置是为了保证汽车在运动过程中不容易翻车

12  rigidbody.centerOfMass.y = -1.5;

13 }

14 function Update () {

15 rigidbody.drag=0.15 +rigidbody.velocity.magnitude/25;//设置汽车运行阻力,限制汽车速度

16  //计算汽车转速

17 EngineRPM = (FrontLeftWheel.rpm + FrontRightWheel.rpm)/2 * GearRatio[CurrentGear];

18  ShiftGears();//调用方法

19 if(Application.platform == RuntimePlatform.Android) {//如果程序运行在Android平台上

20    var touchKey_x : float = moveJoystick.position.x; //获取操作杆的坐标x

21    var touchKey_y : float = moveJoystick.position.y; //获取操作杆的坐标y

22    //根据操纵杆的y位置计算汽车速度

23 FrontLeftWheel.motorTorque = EngineTorque / GearRatio[CurrentGear] * touchKey_y;

24 FrontRightWheel.motorTorque = EngineTorque / GearRatio[CurrentGear] * touchKey_y;

25    //根据操纵杆的y位置计算汽车转向

26    FrontLeftWheel.steerAngle = 10 * touchKey_x;

27    FrontRightWheel.steerAngle = 10 * touchKey_x;

28  }else {//如果是其他平台

29    //计算汽车速度,当按下前进键或后退键,计算两个前轮的马达转矩

30    FrontLeftWheel.motorTorque = EngineTorque / GearRatio[CurrentGear] *Input.GetAxis("Vertical");

31    FrontRightWheel.motorTorque = EngineTorque / GearRatio[CurrentGear] *Input.GetAxis("Vertical");

32    //控制汽车转弯,当按下左右按键时,计算两个前轮的旋转角度

33    FrontLeftWheel.steerAngle = 10 * Input.GetAxis("Horizontal");

34    FrontRightWheel.steerAngle = 10 * Input.GetAxis("Horizontal");

35  }}

36 function ShiftGears() {//转换齿轮数的方法

37  if ( EngineRPM >= MaxEngineRPM ) {//如果引擎转速大于等于最大引擎速度

38    var AppropriateGear : int = CurrentGear;//定义一个合适齿轮数

39    for ( var i = 0; i < GearRatio.length; i ++ ) {//遍历所有的齿轮数比

40     //如果左前轮转速和齿轮数比的乘积小于最大引擎转速

41     if ( FrontLeftWheel.rpm * GearRatio[i] < MaxEngineRPM ) {

42      AppropriateGear = i;//赋值

43      break;//跳出循环

44     }}

45    CurrentGear = AppropriateGear;//赋值

46  }

47  if ( EngineRPM <= MinEngineRPM ) {//如果引擎转速小于等于最大引擎速度

48    AppropriateGear = CurrentGear;//赋值

49    for ( var j = GearRatio.length-1; j >= 0; j -- ) {//遍历所有的齿轮数比

50     //如果左前轮转速和齿轮数比的乘积大于最小引擎转速

51     if ( FrontLeftWheel.rpm * GearRatio[j] > MinEngineRPM ) {

52      AppropriateGear = j;//赋值

53      break;//跳出循环

54     }}

55    CurrentGear = AppropriateGear;//赋值

56  }}

● 第1-9行为变量的定义,其中的非私有变量都可以在属性查看器中看到或者赋值。

● 第10-13行为Start方法的重写,主要是初始化汽车质心的y轴。

● 第14-56行为Update方法的重写,主要是判断程序的运行平台,针对不同的平台启用不同的控制模式(PC上用键盘控制,移动设备上用操纵杆控制),然后就是计算车速和汽车转弯的角度。

(8)添加汽车控制脚本组件。将编写好的“CarControl.js”脚本挂载到“Car_Model”对象上,然后将“FLCollider”和“FRCollider”分别拖曳到属性查看器中的“Front Left Wheel”和“Front Right Wheel”变量处,并为“Gear Ratio”数组赋值,最后将“Single Joystick”拖曳到“Move Joystick”变量处,如图6-128所示。

▲图6-128 添加汽车控制脚本组件

(9)为汽车添加刚体。选中“Car_Model”后选择Component→Physics→Rigidbody为汽车添加刚体,然后修改“Mass”变量值为1000,如图6-129所示。

(10)添加摄像机跟随脚本。选中“Assets”文件夹,右键选择 Import Package→Scripts后弹出“Importing package”对话框,选择其中的“SmoothFollow.js”脚本文件导入,然后选中“Main Camera”后,选择Component→Camera-Control→Smooth Follow(或者直接将该脚本拖曳到主摄像机对象上),最后将“Car_Model”拖曳到“Target”变量处,并修改其他参数,如图6-130所示。

▲图6-129 添加刚体

▲图6-130 添加摄像机跟随脚本

(11)修改玩家设置选项中的参数。选择File→Build Settings后进入“Build Settings”对话框,然后选择 Android 平台,单击“Player Settings”按钮,接着将属性查看器中“Resolution and Presentation”选项下的“Default Orentation”属性修改为“Landscape Left”,即完成了横屏设置,如图6-131所示。

▲图6-131 设置横屏

最后将“Other Settings”选项下的“Bundle Identifier”修改成合适的内容,这里修改为“com.bn.vehicle”,如图6-132所示。

▲图6-132 修改 Bundle Identifier参数

说明

“BundleIdentifier”中的内容必须修改,不能是系统默认值,否则,Unity引擎将不允许将程序发布到Android端。

4.案例的最终效果

至此,案例的开发基本完成了,本案例可以发布成 exe可执行文件在 PC 上运行,也可以直接点击Unity引擎里的运行按钮可以直接观看和体验运行效果,运行效果如图6-133所示。当然,也可以发布到Android设备上运行,其运行效果如图6-134所示。

▲图6-133 PC端运行效果图

▲图6-134 Android端运行效果图

说明

本案例的源文件位于随书光盘中源代码/第6章目录下的“VehicleDemo”文件。而本案例所用到的资源文件“Model.unitypackage”位于随书光盘中源代码/第 6 章/资源包目录下。如果读者想运行本案例,只需把“VehicleDemo”文件复制到非中文路径下,然后双击“VehicleDemo\Assets”目录下的“Car.unity”文件就能够打开运行了。

本节主要向读者介绍布料的相关知识,布料是Unity内建物理引擎中另外一个很重要的概念。弄清楚布料的概念对于 Unity 开发新手来说是很重要的。通过本节的学习,读者将对布料有一个基本的认识。

Unity 内建物理引擎中的布料是基于一个网格,来模拟类似布料行为的组件。如果场景中需要使用布料的效果,那么就用这个组件。

布料作为物理引擎的组件,包含有该类组件的特定属性,包括Transform、Interactive Cloth、Cloth Renderer,如图 6-135所示。并对应封装了多个相关方法,下面进行分别介绍。

▲图6-135 布料属性

为了利于开发者控制物理系统,Unity提供了多个属性接口,即 Interactive Cloth中的参数。开发者可以通过更改布料的属性参数来控制布料的物理形态。在实际开发中,这些参数都被详细地罗列在属性查看器中,开发者很容易就可以对其进行更改。接下来对这些属性进行介绍。

(1)抗弯刚度(Bending Stiffness)。

该属性表示布料的弯曲强度,其数据类型是 float,默认值为0。Bending Stiffness属性在属性查看器中的位置如图6-136所示。该属性的大小是有严格要求的,其范围在0到1之间,而且越接近1,表示布料越不容易弯曲。

(2)抗拉伸度(Stretching Stiffness)。

该属性表示布料的拉伸强度,其数据类型是 float,默认值为1。Stretching Stiffness属性在属性查看器中的位置如图6-137所示。该属性的大小也是有严格要求的,其范围在0到1之间,而且越接近1,表示布料越不容易拉伸。

▲图6-136 BendingStiffness

▲图6-137 StretchingStiffness

(3)阻尼(Damping)。

该属性表示布料运动的阻尼,其数据类型是float,默认值为0。Damping属性在属性查看器中的位置如图6-138所示。在现实生活中,布料物体会受到各方面的影响,速度会逐渐衰减,为了模拟这一效果,Unity设定了这一属性。这一属性值越高,布料物体的速度衰减越严重。

(4)厚度(Thickness)。

该属性表示布料的厚度,其数据类型是float,默认值为0.2。Thickness属性在属性查看器中的位置如图6-139所示。该属性的大小是有严格要求的,一般来说,大部分布料的Thickness属性值直接使用默认的数值,其数值一旦超过1,将会失去仿真所需达到的效果。

▲图6-138 Damping

▲图6-139 Thickness

(5)使用重力(Use Gravity)。

该属性表示的是布料是否受到重力的影响,其数据类型是boolean,初始值为true。UseGravity属性在属性查看器中的位置如图6-140所示。这一属性被设为false时可以模拟布料物体在外太空状态下的失重状态。

(6)自身碰撞(Self Collision)。

该属性表示的是布料是否自身碰撞,其数据类型是boolean,初始值为false。SelfCollision属性在属性查看器中的位置如图6-141所示。这一属性被设为true时,布料之间将存在碰撞,可以根据场景的需要设定不同的状态。

▲图6-140 UseGravity

▲图6-141 SelfCollision

(7)外部加速度(External Acceleration)。

该属性表示的是给布料设置一个固定的外部加速度,其数据类型是folate,初始值为0。External Acceleration属性在属性查看器中的位置如图6-142所示。从图6-142中可以看出,这一属性可以分别设置布料的x、y、z方向的加速度。

(8)随机加速度(Random Acceleration)。

该属性表示的是给布料设置一个随机的外部加速度,其数据类型是folate,初始值为0。Random Acceleration属性在属性查看器中的位置如图6-143所示。从图6-143中可以看出,这一属性可以分别设置布料的x、y、z方向的加速度。

(9)网格(Mesh)。

该属性表示的是用于模拟布料的网格。Mesh属性在属性查看器中的位置如图6-144所示。单击Mesh右侧的小圆圈可以选择需要的网格,以达到开发的需要。

▲图6-142 External Acceleration

▲图6-143 Random Acceleration

(10)摩擦力(Friction)。

该属性表示的是布料的摩擦系数,其数据类型是float,范围在0到1之间,初始值为0.5。Friction属性在属性查看器中的位置如图6-145所示。布料与其他物体接触时会产生摩擦的效果,此属性值越高,布料的摩擦力就越大。

▲图6-144 Mesh

▲图6-145 Friction

(11)密度(Density)。

该属性表示的是布料密度,其数据类型是float,初始值为1。Density属性在属性查看器中的位置如图6-146所示。该属性的大小一般来说选择默认的初值,在某些特定情况下,可以根据需要调整布料的密度大小。

▲图6-146 Density

(12)压力(Pressure)。

该属性表示的是布料内部的压力,其数据类型是float,初始值为0。Pressure属性在属性查看器中的位置如图 6-147 所示。该属性的大小一般来说选择默认的初值,当用于封闭布料时,可以模拟气球等。

(13)碰撞反应(Collision Response)。

该属性表示的是对撞上布料的刚体施加多大的力,其数据类型是 float,初始值为 0。Collision Response属性在属性查看器中的位置如图6-148所示。在现实生活中,物体之间相互碰撞会受到力的作用,这一属性值越高,物体碰撞后受到的力就越大。

▲图6-147 Pressure

▲图6-148 Collision Response

(14)附加撕裂系数(Attachment Tear Factor)。

该属性表示布料从挂接刚体撕裂的拉伸程度,挂接刚体必须勾选 tearable 才能生效,其数据类型是 float,初始值为 0.5。Attachment Tear Factor属性在属性查看器中的位置如图 6-149所示。布料受到超过一定力时就会从附加的刚体上撕裂,这一属性值越高,越不容易撕裂。

(15)附加反应(Attachment Response)。

该属性表示对挂接的刚体施加多少作用力,只有当挂接刚体勾选TwoWayInteraction才生效,其数据类型是 float,初始值为 0.2。Attachment Response属性在属性查看器中的位置如图 6-150所示。

▲图6-149 Attachment

▲图6-150 Attachment Response

(16)撕裂系数(Tear Factor)。

该属性表示布料的顶点之间距离多长会被撕开,其数据类型是 float,初始值为 0。Tear Factor属性在属性查看器中的位置如图6-151所示。在现实生活中,布料受到超过其可承受的力时会撕裂,为了模拟这一效果,Unity设定了这一属性。这一属性值越高,布料越不易被撕裂。

(17)附加碰撞器列表(Attached Collider)。

该属性表示的是一个包含布料挂接的所有碰撞体的数组,每个碰撞体都有TwoWayInteraction和Tearable两个选项。Attached Colliders属性在属性查看器中的位置如图 6-152所示。

前面介绍了布料基本物理状态的参数,除此之外,布料还具有渲染器Cloth Renderer属性。开发者可以通过更改布料的渲染设置控制布料的表现效果。在实际开发中,这些参数都被详细地罗列在属性查看器中,开发者很容易就可以对其进行更改。接下来对这些属性进行介绍。

▲图6-151 Tear Factor

▲图6-152 Attached Colliders

(1)投射阴影(Cast Shadows)。

该属性表示的是布料是否投射阴影,其数据类型是 boolean,初始值为 true。Cast Shadows属性在属性查看器中的位置如图6-153所示。这一属性被设为true时可以在场景中看到布料投射阴影的效果。

(2)接受阴影(Receive Shadows)。

该属性表示的是布料是否能被投影,其数据类型是 boolean,初始值为 true。Receive Shadows属性在属性查看器中的位置如图6-154所示。这一属性被设为true时,布料可以接受其他物体投射的阴影效果。

▲图6-153 Cast Shadows

▲图6-154 Receive Shadows

(3)材质(Materials)。

该属性表示的是布料所选择的材质。Materials属性在属性查看器中的位置如图6-155所示。

(4)使用光探测器(Use Light Probes)。

该属性表示的是如果勾选此选项,那么布料将开启光探测器,默认不选择。Use Light Probes属性在属性查看器中的位置如图6-156所示。

▲图6-155 Materials

▲图6-156 UseLight Probes

(5)光探针锚(Light Probe Anchor)。

该属性表示的是在分配的情况下,光照探测插入到渲染器边界的中心或者在锚点的位置,默认不选择。Light Probe Anchor属性在属性查看器中的位置如图 6-157所示。

(6)不可见时暂停(Pause When Not Visible)。

该属性表示的是如果勾选此选项,那么在摄像机可见的范围外,布料将不进行模拟运算。Pause When Not Visible属性在属性查看器中的位置如图 6-158所示。

▲图6-157 Light Probes Anchor

▲图6-158 Pause When Not Visible

布料是 Unity 自带物理引擎中十分重要的部分,熟练掌握布料的属性及参数设置,可以在开发中达到事半功倍的效果。

通过前面小节的学习,相信读者对布料有了一个简单的认识。本小节主要讲述如何在Unity 3D中创建以及使用布料,具体步骤如下。

在开发前首先要对案例开发需要的资源进行收集,主要需要的资源如表6-6所示。

表6-6 布料案例所需的资源

(1)双击桌面上的 Unity 快捷方式,进入 Unity 集成开发环境,导入所需的资源,具体的导入过程就单击Assets→Import New Assets菜单,会立刻弹出一个 Import New Assets对话框,在对话框中选择需要的资源,单击Import按钮即可完成导入,Project面板下的Assets包括的资源如图6-159所示。

▲图6-159 资源

(2)单击GameObject→Create Other→Plane菜单,在场景中创建 Plane,在此改名为 diban,并在属性查看器中设置具体的参数,具体参数如图6-160所示。

(3)单击GameObject→Create Other→Sphere菜单,在场景中创建一个球体,在此改名为Ball,并在属性查看器中设置具体的参数,具体参数如图6-161所示。

(4)单击GameObject→Create Other→Cloth菜单项,在场景中创建一个布料,命名为Cloth,并在属性查看器中设置具体的参数,其具体参数如图6-162所示。

提示

布料InteractiveCloth属性下的Mesh选择刚才导入的Cloth.FBX文件。

(5)选中摄像机,在属性查看器中调整摄像机的视角,使摄像机的视角正对场景中的游戏对象,具体参数设置如图6-163所示。

▲图6-160 diban参数设置

▲图6-161 Ball参数设置

▲图6-162 Cloth参数设置

▲图6-163 Camera参数设置

(6)为场景中添加适合的平行光光源,即单击GameObject→Create Other→Directional light菜单,创建平行光光源,并在属性查看器中设置其参数,具体参数如图6-164所示。

(7)单击Unity中的游戏播放按钮,在Game窗口下可以看到布料落下与小球发生碰撞的效果,如图6-165所示。

▲图6-164 灯光参数设置

▲图6-165 运行效果

到这里本案例的操作步骤以及各个游戏对象参数的设置已经全部讲解完毕,通过本案例的操作,希望读者可以掌握物理引擎中布料的基本使用,在今后的开发中可以熟练应用。

说明

本案例的源文件位于随书光盘中源代码/第6章目录下的Cloth文件。

前面已经详细介绍了 Unity 中物理引擎的基础知识,同时,通过一些小案例来具体介绍了物理引擎的相关应用。本小节将通过一个综合案例,使读者对Unity中的物理引擎有进一步的理解。

1.案例的构思

开发案例首先要有一个明确的思路,倘若思路混乱,就会导致案例的整体不协调。接下来介绍一下本案例的设计思路。

(1)首先要明确案例要达到的目的。本案例是为了演示物理引擎模拟现实的特性。

(2)接着要明确案例场景的周边环境,要确定场景的天气。本案例中,为了使用粒子系统,决定将情景设定为大雪纷飞的环境,所以天空盒要选择阴天。

(3)接着就是对案例的核心主题部分进行设计。在本案例中,将要搭建一个足球门,门前采用预制件技术产生5×5×5整齐堆放的立方体堆。

(4)关于界面的触控事件,本案例中采用每次触控都产生一个向前飞出的足球,以撞击方块堆,然后射入足球门中。此处也要采用预制件技术。

2.案例场景的设计

关于场景环境的设计首先是天空盒的选择,接着是大雪场景的制造。具体的操作过程如下。

(1)新建一个场景,在菜单栏中选择 File,打开文件操作按钮。选择New Scene,创建一个场景。按快捷键Ctrl+S保存该场景,命名为“football”。

(2)新建一个平面。在菜单栏中单击GameObject→Create Other→Plane菜单,将此平面拖曳到摄像机视野之内,然后将地板纹理图拖曳到此平面上,其参数如图6-166所示。

▲图6-166 Plane参数设置

(3)选择摄像机“MainCamera”对象,在菜单栏中选择“Component”选项,在“组件添加”菜单中选择“Rendering”,在弹出的渲染菜单中选择“Skybox”,如图6-167所示。

▲图6-167 添加 Skybox界面

(4)导入天空盒资源,在资源列表中的空白处单击鼠标右键,弹出资源操作列表,选择“Import Package”,如图6-168所示。在弹出的资源包列表中选择“Skyboxes”,如图6-169所示。经过此操作导入了天空盒资源。

▲图6-168 Import Package

▲图6-169 添加Skyboxes

(5)为摄像机的天空盒指定类型,选中摄像机,在属性查看器中,单击Skybox的属性Custom Skybox的右边的属性框,此时会弹出天空盒选择框,选择Eerie Skybox,如图 6-170所示。

(6)添加大雪效果,这就需要粒子系统技术了。在菜单栏中单击 GameObject 选项,在弹出的游戏对象操作菜单中选择Create Other,此时会弹出“创建其他”菜单,选择Particle System选项,如图6-171所示。

▲图6-170 Skybox

▲图6-171 添加粒子系统

(7)将粒子系统的Shape组件的Shape属性设置为Sphere,如图6-172所示。在场景设计面板中将粒子系统拖曳到摄像机的斜上方,使喷射器在摄像机视野内部不可见,即可达到大雪效果。

▲图6-172 更改 Shape

3.案例主体部分设计——足球门

(1)导入足球门的FBX模型。本案例中需要用到足球门的模型,模型的导入在后面的章节中会有详细的介绍。模型的资源文件“soccer_goal.FBX”位于随书光盘中源代码/第 6 章/资源包目录下。

(2)单击GameObject→Create Empty菜单,创建一个空游戏对象。然后单击Gameobject→Create Empty再次创建空游戏对象,命名为Structure,并将Structure拖曳到Gameobject下成为其子对象。

(3)选中Structure对象,单击Component→Mesh→Mesh Filter菜单,为Structure对象添加网格过滤器,如图6-173所示。然后在属性查看器中选择Mesh为前面导入的goal_metal_structure,如图6-174所示。

▲图6-173 添加Mesh Filter

▲图6-174 选择Mesh

(4)选中Structure对象,单击Component→Mesh→Mesh Renderer菜单,为Structure对象添加网格渲染器,如图6-175所示。然后在属性查看器中可以更改渲染器的设置,如图6-176所示。

▲图6-175 添加Mesh Renderer

▲图6-176 渲染器设置

提示

读者应该注意的是Mesh必须添加渲染器以后才会在场景中显现出来。

(5)选中Structure对象,单击Component→Physics→Mesh Collider菜单,为Structure对象添加网格碰撞组件,如图6-177所示。然后在属性查看器中可以看到添加的Mesh Collider,如图6-178所示。

▲图6-177 添加Mesh Collider

▲图6-178 Mesh Collider设置

(6)调整属性查看器中Structure的Transform属性,使其大小和位置符合场景的需要,具体参数设置如图6-179所示。同时调整摄像机的Transform参数,使其能够完全看到场景中的对象,具体参数如图6-180所示。

▲图6-179 Structure参数

▲图6-180 Camera参数

(7)接下来为球门添加门柱。单击 GameObject→Create Empty菜单创建空对象,重命名为Liang。然后将其拖曳到GameObject对象下,使其成为子对象。重复第(3)步、第(4)步操作,为对象添加组件,然后单击Component为对象添加Box Collider组件。最终Liang对象在属性查看器中的参数如图6-181所示。

(8)重复上述第(7)步操作,再次添加两个对象,使其分别位于球门的左右两侧充当门柱。其在属性查看器中的设置如图6-182和图6-183所示。

▲图6-181 参数设置

▲图6-182 参数设置

▲图6-183 参数设置

(9)经过上述操作,球门的基本框架已经搭建完成,其在Hierarchy面板的对应位置如图6-184所示。其在Scene面板中的场景如图6-185所示。

▲图6-184 Hierarchy面板

(10)接下来为球门添加球网。单击GameObject→Create Other→Cloth菜单,添加一个布料,如图6-186所示。

(11)调整查看器中布料的大小,并在布料的Attached Collider属性中设置Size为4,使每个Collider分别对应刚才创建的球门Structure以及门柱对象,如图6-187所示。然后在Cloth Renderer属性下为布料添加材质(实质是为球网贴一个球网的贴图),具体设置如图6-188所示。

▲图6-185 场景效果

▲图6-186 新建布料

▲图6-187 布料参数设置

▲图6-188 布料渲染设置

提示

球网的材质是使用一张透明的球网贴图制作的,材质制作的知识前面已经讲解过,贴图资源文件“net_01.png”位于随书光盘中源代码/第6章/资源包目录下。

经过以上的操作,案例中关于球门的部分已经搭建完成。点击 Unity 游戏播放按钮,可以在Game窗口中看到球门以及球网,如图6-189所示。

4.案例主体部分设计——发射足球及碰撞

本案例游戏的另外一个主体部分是可交互的。在此部分中包括堆叠的方块和发射的足球,在此部分中使用的是脚本和预制件技术。具体的开发过程如下。

(1)创建预制件,在资源列表中的空白处单击鼠标右键,在弹出的资源菜单中选择“Create”,在创建菜单中选择“Prefab”,如图6-190所示。接着重复操作创建一个名为“soccerBallRigidbody”的预制件。

▲图6-189 运行效果

▲图6-190 新建预制件

(2)单击GameObject→Create Other→Cube菜单,创建一个 Cube对象。选择此对象,单击Component→Physics→Rigidbody选项,为Cube对象添加刚体。

(3)将刚刚创建的cube游戏对象拖曳到第(1)步创建的预制件“cube”,以设置预制件。

(4)按照顺序GameObject→CreateOther→Sphere进行操作,创建一个球体。

(5)选中球体(Sphere)游戏对象,在菜单栏中点击“Component”选项,在弹出的组件添加菜单中分别为对象添加Mesh Filter、Mesh Renderer、Sphere Collider以及Rigidbody,如图6-191所示。

▲图6-191 球体参数设置

(6)将刚刚创建的球体游戏对象拖曳到第(1)步中创建的预制件“soccerBallRidibody”上,以设置足球预制件。

(7)为摄像机添加脚本。首先右击资源列表空白处,在资源列表中,选择“Create”选项,在弹出的创建菜单中选择“JavaScript”,则创建了一个Javascript脚本,如图6-192所示。选中刚创建的脚本,然后再次单击为其重命名为“initCube”。

▲图6-192 新建 Javascript脚本

(8)编写摄像机脚本。双击刚创建的脚本,等待片刻,则会进入脚本编辑器,在脚本编辑器中进行代码编写。摄像机需要完成方块堆的初始化工作,其具体代码如下所示。

代码位置:见随书光盘中源代码/第6章目录下的 PhysicsEngine/Assets/script/initCube.js。

1 var cube:Transform;         //定义cube对象

2 var zeroP:Vector3;         //定义坐标

3 function Start ()

4 {

5   zeroP=this.transform.position;     //获取当前摄像机位置

6 for(var i:int=0;i<5;i++)

7 {

8   for(var j:int=0;j<6;j++)

9   {

10    for(var k:int=0;k<5;k++)

11    {

12  GameObject.Instantiate(cube,Vector3((14.5+zeroP.x+i*0.3), (j*0.3+0.5),

13  (zeroP.z+k*0.3+35)), Quaternion.identity); //循环产生方块,并设置方块位

14  }}}}

● 第1-2行为变量的定义,非私有变量都可以在属性查看器中看到并且予以赋值。

● 第3-13行为Start方法的重写,主要是为了程序开始时在场景的某个固定的地方产生一堆立方体。

(9)关闭脚本编辑器,将资源列表中的脚本拖曳到游戏对象列表中的摄像机对象“MainCamera”上。选中摄像机对象,则可见摄像机中被添加了一个脚本组件“initCube”,如图6-193所示。

(10)将资源列表中的Cube预制件,拖曳到 Init Cube脚本组件中的Cube属性的右侧属性框中,完成对脚本的属性赋值,如图6-194所示。

▲图6-193 摄像机脚本

▲图6-194 属性赋值

(11)单击GameObject→Create Empty选项,新建一个空对象,重命名为FaQiu。为对象添加脚本控制足球的发射。首先在资源列表空白处单击鼠标右键,在资源列表中,选择“Create”选项,在弹出的创建菜单中选择“JavaScript”,则创建了一个Javascript脚本,重命名为“FaQiu”。

(12)编写FaQiu对象脚本。双击刚创建的脚本,等待片刻,则会进入脚本编辑器,在脚本编辑中进行代码编写。脚本需要控制完成发射足球的工作,其具体代码如下所示。

1 var rocket;          //定义变量

2 var soccerBall : Rigidbody;      //定义足球刚体

3 var speed = 30.0;        //定义速度变量

4 function Start ()

5 {

6   rocket = soccerBall;      //初始化rocket变量

7 }

8 function FireRocket ()       //定义发射球的方法

9 {

10 var rocketClone:Rigidbody;      //定义刚体

11 rocketClone = Instantiate(rocket, Vector3(7,1.7,-10),

12       transform.rotation); //产生预制件的坐标

13 rocketClone.velocity = transform.forward * speed;//设置足球发射的初始方向及速度

14 }

15 function Update ()

16 {

17  if (Input.GetButtonDown("Fire1"))

18  {

19   FireRocket();       //调用方法

20  }

21  transform.position.z = Mathf.Clamp (transform.position.z, -6.0, 6.0);

22 }

● 第1-3行为变量的定义,非私有变量都可以在属性查看器中看到并且予以赋值。

● 第4-7行为Start方法的重写,主要是初始化rocket变量。

● 第8-14行为定义FireRocket方法,主要是当调用该方法时生成一个rocket足球对象,然后给予该对象一个初速度。

● 第15-22行为Update方法的重写,主要是当触发“Fire1”事件时,就调用FireRocket方法发射出一个球。

(13)关闭脚本编辑器,将脚本拖曳到FaQiu对象上,并将资源列表中的soccerBallRigidbody预制件,拖曳到FaQiu脚本组件中的Soccer Ball属性的右侧属性框中,完成对脚本的属性赋值,如图6-195所示。

点击游戏运行按钮,观看案例运行效果,如图6-196所示。

▲图6-195 对象Transform属性

▲图6-196 运行效果

5.案例运行效果

至此案例的开发基本都完成了,本案例可以发布成 exe可执行文件在 PC 上运行,也可以点击Unity引擎里的运行按钮直接观看和体验运行效果。当然,也可以发布到Android设备上运行,运行效果如图6-197所示。

▲图6-197 Android端运行效果

6.案例开发总结

至此本案例的开发已经结束,细心的读者应该注意到了,在开发过程中有多处对参数的设置,这些修改都是凭借经验来进行的。没有经验的初学者可以在特定范围内进行尝试,以体验不同的取值带来的不同视觉感受,这一阶段对于初学者是必不可少的。

在本案例的开发过程中,同时使用了刚体、粒子系统和交互布料。将多种技术用在同一个场景中在案例开发过程中是很常见的,初学者要提高综合运用能力,才能对各种技术的理解更加深入,开发的思路也更加开阔。

说明

本案例的源文件位于随书光盘中源代码/第6章目录下的Football文件。

Unity 的便利之处在于,仅仅需要几步简单的操作,就可以使游戏中的物体严格按照物理法则运动。刚体和碰撞器特性模拟了物体的实体性,每个对象将不仅仅是呈现在屏幕上的虚假影像,它可以与游戏玩家发生仿真交互。

本章的内容不仅涉及了物理引擎的刚体和碰撞器特性,也介绍了关节和粒子系统的使用方法。在 Unity 学习中,最关键的是对对象的关键物理特性的理解。开发者应该时刻保持“仿真”的心态,以更加贴近现实为目标开发出最为真实的游戏场景。

相关图书

Unity游戏开发入门经典(第4版)
Unity游戏开发入门经典(第4版)
Unity  3D游戏开发技术详解与典型案例
Unity 3D游戏开发技术详解与典型案例
从零开始:快速入门Unity 3D游戏开发
从零开始:快速入门Unity 3D游戏开发
Unity 3D脚本编程与游戏开发
Unity 3D脚本编程与游戏开发
AR开发权威指南:基于AR Foundation
AR开发权威指南:基于AR Foundation
VR与AR开发高级教程:基于Unity(第2版)
VR与AR开发高级教程:基于Unity(第2版)

相关文章

相关课程