Unity API 解析(9)—— Rigidbody 类
模拟 GameObject 对象在现实世界中的物理特性(重力,阻力,质量,速度)
对Rigidbody 对象属性的赋值代码通常放在脚本的OnFixedUpdate 方法中
collisonDetectionMode 属性 —— 碰撞检测模式
刚体的碰撞检测模式有3种
Discrete —— 静态离散检测模式
Continuous —— 静态连续监测模式 ,一般用在高速运动刚体的目标碰撞体上
ContinousDynamic —— 最强的连续动态检测模式
drag 属性 —— 刚体阻力
drag 值越大刚体速度减慢的越快,当drag >0 时,刚体在增加到一定速度后会匀速运动
刚体在自由落体运动中的最大速度值只与gravity 和drag值有关,与mass无关
inertiaTensor 属性 —— 惯性张量
在距离重心同等的条件下,刚体会向张量值大的一边倾斜
rigidbody.inertiaTensor = new Vector3(5.0f,10.0f,1.0f)
using UnityEngine; using System.Collections; public class inertiaTensor_ts : MonoBehaviour { void OnGUI() { if (GUI.Button(new Rect(10.0f, 10.0f, 160.0f, 45.0f), "X轴惯性张量大于Y轴")) { transform.position = new Vector3(0, 4, 0); //transform绕Z轴旋转45度 transform.rotation = Quaternion.Euler(0.0f, 0.0f, 45.0f); //设置rigidbody的惯性张量 //X轴分量值大于Y轴,则刚体会向X轴方向倾斜 rigidbody.inertiaTensor = new Vector3(15.0f, 10.0f, 1.0f); } if (GUI.Button(new Rect(10.0f, 60.0f, 160.0f, 45.0f), "Y轴惯性张量大于X轴")) { transform.position = new Vector3(0, 4, 0); transform.rotation = Quaternion.Euler(0.0f, 0.0f, 45.0f); //设置rigidbody的惯性张量 //X轴分量值小于Y轴,则刚体会向Y轴方向倾斜 rigidbody.inertiaTensor = new Vector3(5.0f, 10.0f, 1.0f); } if (GUI.Button(new Rect(10.0f, 110.0f, 160.0f, 45.0f), "X轴和Y轴惯性张量相同")) { transform.position = new Vector3(0, 4, 0); transform.rotation = Quaternion.Euler(0.0f, 0.0f, 45.0f); //设置rigidbody的惯性张量 //X轴和Y轴惯性张量相同,则刚体会保持静止 rigidbody.inertiaTensor = new Vector3(10.0f, 10.0f, 1.0f); } } }
mass 属性 —— 刚体质量
一般刚体质量取值在0.1 附近模拟最佳,最大不要超过10,否则容易出现模拟不稳定的情况
mass 的主要作用是物体发生碰撞时计算碰撞后的物体的速度
velocity 属性 —— 刚体速度
在脚本中无论是给刚体赋予一个vector3类型的速度向量,还是获取当前刚体的速度,v的方向都是相对世界坐标系而言
velocity 的单位是米每秒 —— 米是Unity中默认的长度单位
AddExplosionForce 方法 —— 模拟爆炸力
爆炸力的大小,爆炸点的坐标,爆炸力的有效半径
AddForceAtPosition —— 增加刚体点作用力
为参数position点增加一个力force
AddForce 方法对刚体施加力时不会产生扭矩使物体发生旋转,但此方法会
using UnityEngine; using System.Collections; public class AddExplosionForce_ts : MonoBehaviour { public Rigidbody A; public Transform Z;//Scene视图中显示爆炸点坐标 Vector3 E = Vector3.zero;//爆炸点坐标 float F, R, y_m; bool is_change = false; void Start() { //初始位置使得爆炸点和A的x,y轴坐标值相等 //可以更改F及R的大小查看运行时结果 E = A.position - new Vector3(0.0f, 0.0f, 3.0f); F = 40.0f; R = 10.0f; y_m = 0.0f; A.transform.localScale = Vector3.one * 2.0f; Z.position = E; } void FixedUpdate() { if (is_change) { A.AddExplosionForce(F, E, R, y_m); is_change = false; } } void OnGUI() { //当爆炸点和A的重心的两个坐标轴相等时,A将平移不旋转 if (GUI.Button(new Rect(10.0f, 10.0f, 200.0f, 45.0f), "刚体移动不旋转")) { is_change = true; inits(); } //虽然受力大小不变,但产生扭矩发生旋转 if (GUI.Button(new Rect(10.0f, 60.0f, 200.0f, 45.0f), "刚体发生移动但受力大小不变")) { inits(); A.position += new Vector3(0.5f, -0.5f, 0.0f); is_change = true; } if (GUI.Button(new Rect(10.0f, 110.0f, 200.0f, 45.0f), "按最近表面距离计算力的大小")) { inits(); A.position += new Vector3(0.0f, 2.0f, 0.0f); is_change = true; } //y 轴的偏移改变了A的原始方向 // 可以更改y_m的值查看不同的效果 if (GUI.Button(new Rect(10.0f, 160.0f, 200.0f, 45.0f), "Y?á·¢éú??ò?")) { inits(); is_change = true; A.position += new Vector3(0.0f, 2.0f, 0.0f); y_m = -2.0f; } } //初始化数据 void inits() { A.velocity = Vector3.zero; A.angularVelocity = Vector3.zero; A.position = E + new Vector3(0.0f, 0.0f, 3.0f); A.transform.rotation = Quaternion.identity; y_m = 0.0f; } }
AddTorque 方法 —— 刚体添加扭矩
using UnityEngine; using System.Collections; public class AddTorque_ts : MonoBehaviour { public Rigidbody R; Vector3 m_torque = new Vector3(0.0f,10.0f,0.0f); void Start () { R.transform.localScale = new Vector3(2.0f,2.0f,2.0f); R.mass = 1.0f; R.angularDrag = 0.0f; Debug.Log("刚体默认的最大角速度"+R.maxAngularVelocity); // 可以使用如下代码更改刚体的最大角速度 //R.maxAngularVelocity = 10.0f; } void FixedUpdate () { // 每帧给物体添加一个扭矩,使其转速不断加快 R.AddTorque(m_torque,ForceMode.Force); Debug.Log("刚体当前角速度"+R.angularVelocity); } }
ClosestPointOnBounds 方法 —— 爆炸点到刚体最短距离
此方法通常用在 AddExplosionForce 中计算爆炸力的大小
GetPointVelocity —— 刚体点速度
获取世界坐标系中worldPoint点在刚体局部坐标系中的速度 ,速度的计算会受刚体角速度的影响
GetRelativePointVelocity —— 刚体点相对速度
MovePosition —— 刚体位置移动
对刚体的位置进行移动,通常用在刚体失去动力学模拟的情况下 —— isKinematic 为 true时
Sleep —— 刚体休眠
SweepTest —— 检测碰撞器
检测在刚体的direction方向是否有碰撞器对象,且对象的有效探测距离不大于distance
using UnityEngine; using System.Collections; public class SweepTest_ts : MonoBehaviour { public GameObject A, B; RaycastHit hit; float len = 10.0f;// 有效探测距离 void Start() { A.transform.position = new Vector3(1.0f, 1.0f, 1.0f); B.transform.position = new Vector3(4.0f, 1.0f, 1.0f); } void FixedUpdate() { // 探测刚体A右侧len距离内是否存在物体 if (A.rigidbody.SweepTest(A.transform.right, out hit, len)) { Debug.Log("A物体右侧存在物体" + hit.transform.name + " 其距A的距离为" + hit.distance); } else { Debug.Log("A物体右侧" + len + "米范围没有检测到带碰撞器的物体"); } } void OnGUI() { if (GUI.Button(new Rect(10.0f, 10.0f, 200.0f, 45.0f), "设置B坐标使A无法探测到")) { // 重置B的position,使得物体A,B的间距大于len值 B.transform.position = new Vector3(12.0f, 1.0f, 1.0f); } if (GUI.Button(new Rect(10.0f, 60.0f, 200.0f, 45.0f), "取消B中的Rigidbody组件")) { // 销毁B物体中的Rigidbody组件 // 运行程序可以发现,B物体中是否存在Rigidbody对探测结果没有影响 if (B.GetComponent<Rigidbody>()) { Destroy(B.GetComponent<Rigidbody>()); } } if (GUI.Button(new Rect(10.0f, 110.0f, 200.0f, 45.0f), "取消B中的Collider组件")) { // 销毁B物体中的Collider组件 // 运行程序发现,如果B中无Collider组件则A无论如何也探测不到B的存在 if (B.GetComponent<Collider>()) { Destroy(B.GetComponent<Collider>()); } } // 对B物体的状态重置 if (GUI.Button(new Rect(10.0f, 160.0f, 200.0f, 45.0f), "重置")) { B.transform.position = new Vector3(4.0f, 1.0f, 1.0f); if (!B.GetComponent<Collider>()) { B.AddComponent<BoxCollider>(); } if (!B.GetComponent<Rigidbody>()) { B.AddComponent<Rigidbody>(); B.rigidbody.useGravity = false; } } } }
SweepTestAll —— 探测碰撞器
探测刚体的direction方向的distance距离内是否有碰撞器,并返回所有探测到的物体的RaycastHit
using UnityEngine; using System.Collections; public class SweepTestAll_ts : MonoBehaviour { public GameObject A, B, C, D; RaycastHit[] hits; float len = 10.0f;//有效探测距离 void Start() { A.transform.position = new Vector3(1.0f, 1.0f, 1.0f); B.transform.position = new Vector3(4.0f, 1.0f, 1.0f); C.transform.position = new Vector3(7.0f, 1.0f, 1.0f); //D 物体超出了A的有效探测距离,不会被探测到 D.transform.position = new Vector3(12.0f, 1.0f, 1.0f); hits = A.rigidbody.SweepTestAll(A.transform.right, len); float l = hits.Length; Debug.Log("A 探测到的物体个数" + l + " 他们分别是"); // 遍历 foreach (RaycastHit hit in hits) { Debug.Log(hit.transform.name); } } }
WakeUp 方法 —— 唤醒刚体
自动被唤醒的情况 —— 其他刚体与休眠中的刚体发生碰撞,使用关节链接的刚体发生移动,刚体属性发生改变,给休眠中的刚体施加了一个力
useGravity 用来确定刚体是否接受重力加速度的感应
isKinematic 属性 —— 用来确定是否接受动力学模拟(重力感应,速度,阻力,质量)
刚体velocity 的值只与Gravity ,drag及Kinematic有关,与质量mass及物体的sacle无关
若在脚本中未使用 Rigidbody.SetDensity 方法设置刚体的密度,则刚体的质量mass值为在Inspector面板中mass的大小,此mass与transform中的scale无关,否则有关
两物体碰撞符合动量守恒定律
作用力方式 ForceMode 的功能注解
ForceMode.Force —— 使用刚体质量计算,以每帧间隔时间为单位计算动量
ForceMode.Acceleration
ForceMode.Impulse
ForceMode.VelocityChange
onTriggerXXX onCollisionXX
若A中无Rigidbody 组件,B中无论是否含有Rigidbody组件,A都将穿越B物体,并且A和B脚本中的OnTriger 和 OnCollision 都不会被调用
要激活以上两方法,必须使移动的物体中含有Rigidbody组件
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。