一、什么是物理引擎?
四个世纪前,物理学家牛顿发现了万有引力,并延伸出三大牛顿定理,为之后的物理学界的发展奠定了强大的理论基础。牛顿有句话是这么说的:“如果说我看得比较远的话,那是因为我站在巨人的肩膀上。”
日常工作生活中,我们写文档需要Word、Excel、Visio等办公软件,写程序需要Visual Studio、Eclipse等各种集成开发环境、美术设计需要3dsMax、Maya、Photoshop等,正是因为有了这些强大的工具,我们的工作效率才会越来越高效。所以用记事本写代码、用Windows画图画蒙娜丽莎什么的,只是个人能力的体现,保留一份敬佩的心情就好了,可别真应用到实际工作中哦,老板会疯掉的,么么嗒!
话说不知道当年那个给牛顿带来启迪的苹果,到底是掉在了地上还是真的掉在了牛顿的头上,总之它就是往下掉了。运用基本的初中物理知识我们就知道这是因为地球对苹果施加了重力。同样的还有在“愤怒的小鸟”中,我们把小鸟用弹弓弹向空中之后,始终都会掉落在地面上。
那么,在Unity3D的游戏开发中,是通过什么机制来实现物体的物理效果的呢?我们把目光转移到传说中的物理引擎上。物理引擎通过为刚性物体(游戏中的具体游戏对象-GameObject)赋予真实的物理属性的方式来模仿真实世界中的物体碰撞、跌落等反应。这里,我们可以简单地理解为Unity3D默认帮我们实现了一个让游戏对象具有真实物理对象的真实属性(就像微软给我们首先铺垫了.NET Framework,而我们要做的就是在.NET Framework为我们提供的强大CLR和FCL之上编写代码实现具体的项目,而具体的类和对象怎么创建、分配内存、释放资源和封装方法我们一般都交给.NET Framework去处理)。例如游戏引擎中提供了Rigid Body(刚体)组件,为对象加入了该组件之后,游戏对象如果判断脚下无支撑地面就会自动往下掉,就像当年从树上掉落砸到牛顿童鞋的苹果一样。
简而言之,物理引擎就是模拟真实世界中物体碰撞、跌落等反应的引擎。
扩展:Unity的物理引擎使用的是Nvidia的PhysX,PhysX 是一套由Nvidia设计的执行复杂的物理运算的技术。有关PhysX的相关信息请参阅:http://baike.baidu.com/link?url=kESZ9LXKgp-inbAF-tdjV3OUrwh9nxWnzqWBcGuXV51ightRio9evZ2nujXCnKdxlI3flDCWTwk2jXNH67KVb_
二、砸牛顿的苹果—为游戏对象增加Rigid Body(刚体)
当一个游戏对象被赋予Rigid Body(刚体)组件之后,游戏引擎就会对其进行物理效果模拟。同时我们也可以给这个对象施加各种作用力,让它运动起来。另外如果要实现重力的效果,那么相应的游戏物体都必须附上刚体组件。
那么,这里我们通过一个小例子来看看刚体组件的应用。
(1)在Hierarchy中Create以下游戏对象:一个Sphere,一个Direction Light,一个Plane(这里可以理解为地平面)。
首先将Plane的Position属性设置为(0,-2,0),让Plane显示在Sphere的下方,作为Sphere跌落的地平面;
然后将Sphere的Position属性设置为(0,2,0),让Sphere显示在Plane的上方,这样Sphere能够显示一个完整的跌落效果;
最后将Main Camera的Position属性设置为(0,0,-5),让主视角能够完整看到跌落效果,具体视角如下图所以:
(2)在Hierarchy中选中Sphere,在菜单栏中选择Component-Physics-RigidBody,便为Sphere增加了一个刚体组件。这下,这个Sphere便有了重力。点击预览按钮,我们可以看到Sphere跌落的效果。(如果不增加Plane,Sphere会一直往下跌落,有兴趣的朋友可以自己试试。)
(3)这里,可能有的读者会说,一个球如果谈到地上应该会自然地往上弹,弹一会之后才会平躺在地面上。也就是说,我们这个球不但应该具有重力,还应该具有弹力。没事!物理引擎早就帮我们想好了。在资源管理器中的Assets上单击鼠标右键,选择Import Package-Physic Material(也就是导入一个物料材质的包),在弹出的选择框中选中第一项Bouncy。
(4)在Assets中找到刚刚导入的Bouncy包,选中Bouncy并拖动到Hierarchy中的Sphere对象上,这样就为Sphere增加了一个弹力的物理材质。也就是说,现在我们这个球可以在跌落到地面之后反弹了。
(5)这下,我们再预览一下,看看效果:
(6)最后,我们来关注一下RigidBody的几个属性:
①Mass:质量—>学过物理的同学们都知道的吧,质量越大,惯性越大。这里的单位可以自己统一规定,但是官方给出的建议是场景中的物体质量最好不要相差100倍率以上。估计是防止两个质量相差太大的物体碰撞后会产生过大的速度,从而影响游戏性能吧。
②Drug:阻力(也可以表示为摩擦力)—>这里指的是空气阻力,当游戏物体收到某个作用力的时候,这个值越大越难移动。如果设置成无限的话,物体会立即停止移动。PS:上面那个Demo里边我就将Sphere的Drug设置为了0.5。
③Angular Drag:角阻力—>同样指的是空气阻力,只不过是用来阻碍物体旋转的。如果设置成无限的话,物体会立即停止旋转。
④Use Gravity:是否使用重力—> 勾选了这个项,游戏对象就会受到重力影响。
⑤Is Kinematic:是否动态—>勾选这个选项会使游戏对象不受物理引擎的影响,但这不等同于没有刚体组件。这通常用于需要用动画控制的刚体,这样就不会因为惯性而影响动画了。
另外,还有Interplate(差值类型)、Collision Detection(碰撞检测方式)以及Freeze Position/Rotation(冻结位置/旋转),如果你有兴趣,请参阅本文的参考文献之一:《物理引擎:刚体与力》。
三、要重力更要“给力”—为游戏对象增加力
相信大家都玩过Angry Birds—愤怒的小鸟吧,我们在弹弓上将小鸟射出。根据我们对弹弓的不同力度不同角度,小鸟飞出的距离有长有短,力量有轻有重。
(1)在刚刚的Demo基础上增加一个C# Script,命名为AddForce。双击该脚本文件,在Update方法中写入以下代码:
using UnityEngine;
using System.Collections; public class AddForce : MonoBehaviour
{ // Use this for initialization
void Start()
{ } // Update is called once per frame
void Update()
{
// 判断用户是否按下了鼠标左键(0为左键,1为中建,2为右键)
if (Input.GetMouseButtonDown())
{
// 参数一:朝哪个方向使力?使多大的力?
// 参数二:给什么类型的力?
this.gameObject.rigidbody.AddForce(Vector3.forward * , ForceMode.Impulse);
}
}
}
(2)编写完成之后,还是老规矩:将脚本拖动到Sphere对象上进行绑定(也可以说是将脚本依附于游戏对象)。绑定完成之后,即可预览该“给力”效果。在Sphere跌落到地平面的时候,点击鼠标左键,该Sphere便迅速向前飞出。
PS:rigidbody.AddForce(Vector3.forward*50,ForceMode.Impulse)表示给一个向前(up为向上,down则为向下,back为向后)为50的力->所以Sphere会弹得那么有力!Impulse表示默示冲击力。代码中首先判断用户是否点击了鼠标左键,如果点击了则给Sphere对象增加一个向前的力。
(3)那么,看到这里也许玩过很多游戏的你会说:能不能让小球朝着我鼠标指的方向飞呢?答案是肯定的,Unity3D早就为我们提供了这样的方法,让我们可以“指哪打哪”!这里就涉及到一个如何将鼠标所指示的屏幕坐标转换为世界坐标(3D游戏中所能识别的正确坐标—NGUI坐标)的问题,在Unity中可以使用Camera.main.ScreenToWorldPoint(new Vector3(x,y,z))方法来实现。那么,现在就来实践一下,修改刚刚的脚本代码如下:
void Update()
{
// Demo1: 判断用户是否按下了鼠标左键(0为左键,1为中建,2为右键)
//if (Input.GetMouseButtonDown(0))
//{
// // 参数一:朝哪个方向使力?使多大的力?
// // 参数二:给什么类型的力?
// this.gameObject.rigidbody.AddForce(Vector3.forward * 50, ForceMode.Impulse);
//} // Demo2:朝着用户指定的区域为游戏对象给“力”
if (Input.GetMouseButtonDown())
{
Vector3 screenSpace = Camera.main.WorldToScreenPoint(transform.position);
Vector3 targetPos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,
Input.mousePosition.y, screenSpace.z));
Vector3 dirPos = targetPos - Camera.main.transform.position; this.gameObject.rigidbody.AddForce(dirPos * , ForceMode.Impulse);
}
}
(4)保存之后,再次预览效果,差不多达到预期效果了,指哪打哪!
四、小结
本篇主要介绍了物理引擎最重要的刚体组件,它让游戏对象一秒具有现实物理对象的重力效果。而为对象增加冲击力,可以让对象实现显示对象中的冲击效果,对于制作游戏有着重要的作用,也是后续篇制作打箱子游戏的基础。转眼之间,今天就是正月十四了,后天就要回学校了,回到成都了。抓紧时间,把最后一篇也是本系列初探Unity3D的完结篇完成,也算对得起自己这一段时间的成果了,同时也谢谢各位园友给我的鼓励!最后,再谢谢杨中科老师在上一篇博客中给我的鼓励,谢谢以下参考文献的作者!
参考文献与资料
(1)Unity3D基础教程之组件介绍—物理引擎:http://www.narkii.com/club/thread-289321-1.html
(2)Unity3D学习笔记(十一):物理引擎之刚体与力:http://bbs.9ria.com/thread-186986-1-1.html
(3)传智播客Unity3D公开课:http://net.itcast.cn/subject/Unity3D/index.html
(4)物理引擎-百度百科:http://baike.baidu.com/link?url=ff2cOmwhuHmwPPJT5ntk7_5UxqnUdQxrJuar3iLIzvM55ZEbCW3vS2SQ6nAYX4aD