深入了解Unity的Physics类:一份详细的技术指南(七)(上篇)

前言

Unity的Physics类是Unity物理系统的核心,提供了一套用于处理和控制物理模拟的API。这个类提供了用于控制物理系统的全局属性和方法,以及检测和施加力到游戏对象,处理碰撞和触发器事件等。为了让开发者都能更好理解这个Physics类,它的属性都狠详细解释,导致篇章过长,故拆分来讲解。


为了使Unity的Physics类的属性和方法更为清晰,我们可以将它们根据用途和功能进行分类:

1. 基础物理属性:

①全局物理特性:(这些属性设置了物理模拟的一般行为)
Physics.gravity: 定义在游戏世界中的重力值。
Physics.defaultContactOffset: 两个碰撞物体之间的接触点偏移。
Physics.defaultSolverIterations: 物理求解器用于求解接触和关节的迭代次数。
Physics.defaultSolverVelocityIterations: 物理求解器用于改进关节和联系点精度的默认求解器速度迭代次数。
Physics.defaultMaxAngularSpeed:物体的最大角速度。
Physics.defaultMaxDepenetrationVelocity:物体出现穿透时的最大速度。
Physics.autoSimulation:是否自动模拟物理。
Physics.autoSyncTransforms:是否在每次模拟后自动同步物体的变换(Transforms)。
Physics.defaultPhysicsScene:Unity中的默认物理场景。

②碰撞检测设置:(这些属性主要负责碰撞检测的参数设置)
Physics.bounceThreshold: 两个物体相互碰撞时的最小速度(速度阈值),低于这个阈值的碰撞会被当作是非弹性碰撞。
Physics.sleepThreshold: 对象进入休眠状态前的最小阈值,速度低于此值的物体会进入休眠状态。
Physics.queriesHitBackfaces:是否检测背面,这个布尔属性定义了射线投射是否会命中背面。
Physics.queriesHitTriggers:是否检测触发器,这个布尔属性定义了物理查询(射线投射、球体投射等)是否会检测触发器。
Physics.reuseCollisionCallbacks:是否应在同一帧中多次触发同一对碰撞物体的碰撞回调(是否重用碰撞回调)。

③布料与互碰撞:(这些属性与布料的物理行为和物体间的互碰撞有关)
Physics.clothGravity:布料的重力。
Physics.interCollisionDistance:设置布料间碰撞的最小分离距离。
Physics.interCollisionStiffness:设置布料间互碰撞的刚度。
Physics.interCollisionSettingsToggle:是否开启布料互碰撞设置。


Physics.gravity

Physics.gravity是一个 Vector3 类型,它用于表示全局重力的方向和大小。这个值对 Unity 中所有的 Rigidbody 物体都生效,除非 Rigidbody 物体的 useGravity 属性被设置为 false

默认值是 (0, -9.81, 0),模拟了真实世界的重力(向下,加速度为 9.81 m/s²)。
你可以修改这个值来改变游戏世界的重力。

例如,你可以通过以下代码增加重力:

Physics.gravity = new Vector3(0, -20.0f, 0);

或者你可以创建一个向右的重力:

Physics.gravity = new Vector3(9.81f, 0, 0);

这些代码可以在任何地方调用,但常见的做法是在游戏启动时(如在 MonoBehaviour 的 Start 方法内)进行设置。
注意:修改 Physics.gravity 将影响所有 Rigidbody 物体,这可能会对游戏的物理行为产生大影响,所以在修改之前要充分考虑。


Physics.defaultContactOffset

Physics.defaultContactOffset 是一个表示默认接触偏移的浮点数。接触偏移是在接触点周围形成接触的碰撞器间的空隙,用于确保稳定的物理模拟。这个空隙允许Unity预测两个物体之间的碰撞。

 
当物体接近到相对于它们的半径或者大小的一小部分的距离时,Unity就会开始计算它们之间的碰撞。defaultContactOffset定义了这个“一小部分”的大小。比如,一个半径为1的球体和一个半径为2的球体,如果defaultContactOffset设置为0.1,那么当这两个球体相距小于或等于0.3时,Unity就会开始计算它们之间的碰撞。

默认情况下,这个值是0.01,适用于大多数游戏。你可以根据需要修改这个值,但要注意的是,如果这个值设置得太大,可能会导致物体在看起来没有接触的地方就产生了碰撞;如果这个值设置得太小,可能会导致物理模拟不稳定,特别是在物体高速移动或者旋转的情况下。

以下是如何设置这个值的例子:

// 设置默认接触偏移为0.02
Physics.defaultContactOffset = 0.02f;

Physics.defaultSolverIterations

Physics.defaultSolverIterations 控制了物理引擎在解决约束(如关节或碰撞)时要进行多少迭代。

 
当物体在Unity的物理环境中互相作用时,为了正确地模拟这些交互,物理引擎必须"解决"一系列的数学约束。这包括事物如何碰撞、如何反弹、如何在碰撞中互相影响等等。由于这些约束可能会相互影响,因此物理引擎必须多次迭代地解决它们,以确保结果的准确性。

迭代次数的设定是一个权衡:

较高的迭代次数:可以提供更精确和稳定的物理模拟,但可能增加计算的复杂性和CPU的负载。

较低的迭代次数:可能会更快,但可能导致不准确或不稳定的模拟,特别是在复杂的物理交互中。

默认情况下,defaultSolverIterations 的值为6。这是Unity团队找到的一个折中的数值,旨在为大多数游戏提供合理的精确性和性能。

如果你在游戏中遇到物理模拟的不稳定性(例如,关节在受到压力时分离,或物体在高速运动时穿过其他物体),你可以考虑增加这个值。但要记住,增加迭代次数会增加CPU的负载,所以在进行此类更改时应该进行性能测试。

// 设置默认求解器迭代次数为8
Physics.defaultSolverIterations = 8;

Physics.defaultSolverVelocityIterations

Physics.defaultSolverVelocityIterations是控制 Unity 物理引擎进行速度约束求解时的迭代次数的属性。这个值表示当解决速度约束(例如物体间的冲突如何影响它们的速度)时,求解器应执行的默认迭代次数。

 
物理模拟中的速度约束是描述物体如何因碰撞而改变其速度的数学方程。求解器的工作就是找到满足这些约束的速度值,这通常需要多次迭代,因为每次迭代都会为约束找到一个稍微更好的解决方案。

同样地,迭代次数的设置也是一个权衡:

较高的迭代次数:将提供更精确的速度模拟结果,但会增加计算的复杂性和CPU负载。

较低的迭代次数:可能会更快,但可能导致速度模拟不够准确。

默认情况下,defaultSolverVelocityIterations 的值为 1,这是为大多数应用场景提供合理的速度模拟准确性和性能的设置。

如果你发现游戏中的物体在碰撞后速度表现不稳定或不准确,可以考虑增加这个值。但与前面所述的类似,增加迭代次数会增加计算负担,因此在进行更改时应进行性能测试。

Physics.defaultSolverVelocityIterations = 3;

注意:更改这个值时最好在实际的游戏环境中测试,以确认更改是否提高了速度模拟的准确性,并确保没有导致性能问题。


Physics.defaultMaxAngularSpeed

Physics.defaultMaxAngularSpeed定义了一个物体在物理模拟中可能达到的最大角速度(以弧度/秒为单位)。当你改变这个值时,它会影响所有新创建的刚体(Rigidbody),但不会影响已经存在的刚体。

 
Angular speed(角速度)描述了物体绕其旋转轴旋转的速度。如果一个物体的角速度过高,可能会导致物理模拟出现不真实或者不稳定的结果。通过设定一个全局的最大角速度上限,你可以在一定程度上确保物理模拟的稳定性。

应用场景:
改善物理模拟的稳定性:
如果你的游戏中有物体在碰撞后旋转得非常快,可能会导致模拟出现问题,例如物体穿过其他物体而不是与其正确碰撞。通过限制角速度,你可以避免这类问题。

特定的游戏逻辑:
在某些游戏中,你可能想要限制物体的旋转速度。例如,在一个飞行模拟游戏中,你可能不希望飞机在空中进行太快的旋转。

例子:
假设你创建了一个可以被击打的球,而当它被击打时,它的角速度增加。但你不希望它旋转得太快,以致于看起来不真实。

void Start()
{
    Physics.defaultMaxAngularSpeed = 10.0f;
    Rigidbody rb = gameObject.AddComponent<Rigidbody>();
}
void OnCollisionEnter(Collision collision)
{
    // 当球被击打时增加角速度
    if (collision.gameObject.CompareTag("Bat"))
    {
        Rigidbody rb = GetComponent<Rigidbody>();
        rb.angularVelocity = new Vector3(0, 15, 0); // 试图设置一个很大的角速度
    }
}

上述代码中,即使我们试图为球设定一个非常高的角速度,由于 Physics.defaultMaxAngularSpeed 的限制,它的角速度将不会超过 10.0 弧度/秒


Physics.defaultMaxDepenetrationVelocity

Physics.defaultMaxDepenetrationVelocity控制了当两个物体重叠时,物理引擎试图分开它们的最大速度。在物理模拟中,理想情况下,两个物体不应该相互穿透或重叠,但在实际情况中,因为计算的离散性或者其他原因,物体可能会重叠。当这种情况发生时,物理引擎会试图通过施加一个"解穿透"速度来修正这种重叠,使得两个物体重新分开。

 
这个属性定义了解决这种物体重叠问题的速度上限。较高的值会使物体更快地分开,但也可能导致模拟不稳定。较低的值可能会使得物体较慢地分开,但可能会看起来更为自然。

应用场景:
增强物理稳定性: 如果你的游戏中有大量物体经常发生重叠,或者有大型的物体经常重叠,可以适当增加这个值,使得这些物体能够更快地分开。

特定的游戏逻辑: 在某些情况下,你可能想要让物体在重叠后更慢地分开,以实现某种特定的效果或游戏逻辑。

例子:
假设你在开发一个塔防游戏,游戏中的敌人在某些情况下可能会重叠。你希望在敌人重叠时它们能够较快地分开,以避免看起来不真实的情况。

void Start()
{
    Physics.defaultMaxDepenetrationVelocity = 5.0f;
}

通过上述代码,我们提高了解穿透速度的上限,这将使得重叠的敌人能够更快地分开。


Physics.autoSimulation

Physics.autoSimulation控制了Unity是否在每一帧自动执行物理模拟。当此属性设置为true(默认情况下),物理模拟会在每一帧自动进行,这意味着所有的刚体、碰撞器和其他物理相关的组件都会根据物理规则进行模拟。

 
如果将此属性设置为false,则物理模拟不会自动执行。这意味着开发者需要显式调用 Physics.Simulate 方法来手动进行物理模拟。

应用场景:
控制物理模拟的时间: 有时,你可能需要在特定的时刻或者特定的条件下进行物理模拟,而不是在每一帧。此时,可以关闭自动模拟,并手动调用 Physics.Simulate。

暂停与继续: 例如,如果你希望在游戏暂停菜单中停止所有的物理活动,你可以将 autoSimulation 设置为 false。当玩家从暂停菜单返回到游戏时,再次将其设置为 true。

高级物理效果: 在某些情况下,你可能希望在一帧内进行多次物理模拟来实现特定的效果或精确度。关闭自动模拟并手动调用模拟可以实现这一点。

例子:
假设在游戏中,当玩家按下“P”键时,游戏会暂停,此时所有的物理活动也应该暂停。

void Update()
{
    if (Input.GetKeyDown(KeyCode.P))
    {
        if (Physics.autoSimulation)
            Physics.autoSimulation = false;
        else
            Physics.autoSimulation = true;
    }
}

上述代码会根据玩家的输入切换 Physics.autoSimulation 的状态,从而暂停或继续物理模拟。


Physics.autoSyncTransforms

Physics.autoSyncTransforms 控制了物理系统是否在每帧结束时自动同步刚体的Transforms。

当此属性设置为 true(默认值),在每帧结束后,物理模拟对于刚体的Transforms结果会自动应用到其对应的Transforms组件(Transform component)上。这意味着,如果你在Unity中观察一个刚体的位置或旋转,它会反映物理模拟的最新结果。

相反,当 Physics.autoSyncTransforms 设置为 false 时,物理模拟的结果不会自动更新到Transform组件。为了应用物理模拟的结果,你需要显式地调用 Physics.SyncTransforms。

应用场景:
手动控制更新时间:在某些情况下,开发者可能希望有更细粒度的控制权来确定何时同步物理模拟的结果。例如,当需要在某些特定操作或计算后才同步结果时。

优化性能:在某些特定场景下,你可能不需要每帧都同步物理结果。例如,当模拟一大批物体但只需要偶尔更新它们的可见状态时。

例子:
假设你有一个场景,其中包含大量的刚体,但你只希望每隔0.5秒同步它们的变换结果,而不是每帧都同步。

private float syncInterval = 0.5f;
private float timeSinceLastSync = 0f;

void Start()
{
    Physics.autoSyncTransforms = false;
}

void Update()
{
    timeSinceLastSync += Time.deltaTime;
    if (timeSinceLastSync >= syncInterval)
    {
        Physics.SyncTransforms();
        timeSinceLastSync = 0f;
    }
}

上述代码首先禁用了自动同步。然后,它在 Update 方法中累计时间,并在达到指定间隔时调用 Physics.SyncTransforms 来手动同步物理模拟的结果。


Physics.defaultPhysicsScene

在Unity中,物理场景(Physics Scene)是物理模拟的容器。每个物理场景管理着自己的一组物体、碰撞器以及其他物理属性,允许开发者单独地模拟物理效果,而不会与其他物理场景冲突。

 
Physics.defaultPhysicsScene 返回当前加载的主场景中的默认物理场景。在大多数常见的应用场景中,这就是唯一存在的物理场景。但当使用多物理场景功能时,这个属性提供了一种方式来引用主物理场景,而不需要通过其它方法来获取它。

使用多物理场景功能可以实现很多有趣的效果,比如:

  • 并行模拟两个或多个完全独立的物理环境。
  • 创建一个仅用于计算的“离屏”物理场景,其结果并不直接反映到游戏的可见状态。

应用场景:
查询默认物理场景的状态:例如,你可能想知道默认物理场景中是否有任何活跃的刚体。

if (Physics.defaultPhysicsScene.IsActive())
{
    // //如果默认物理场景处于活动状态,执行操作
}

在默认物理场景中执行特定的物理模拟:比如,你想在默认物理场景中进行一次特定的射线检测。

RaycastHit hit;
if (Physics.defaultPhysicsScene.Raycast(origin, direction, out hit, maxDistance))
{
    // 处理光线投射结果
}

总结:Physics.defaultPhysicsScene 提供了对当前主场景中默认物理场景的引用。这在大多数情况下很有用,但特别是当使用多物理场景功能时,它成为了获取主物理场景的关键方法。


Physics.bounceThreshold

Physics.bounceThreshold是一个用于确定两个碰撞物体何时应当反弹的速度阈值。这是一个浮点数值,单位是米/秒。

在Unity物理引擎中,当两个物体发生碰撞时,如果它们的相对速度超过这个阈值,那么物体就会发生反弹。相对速度是指两个物体在碰撞瞬间沿着碰撞法线的速度之差。

默认情况下,这个阈值是2米/秒。这意味着,如果两个物体碰撞时的相对速度大于2米/秒,那么物体就会反弹。如果两个物体的相对速度小于这个阈值,那么物体就不会反弹,而是会按照物理材料的摩擦力来处理碰撞。

你可以根据你的游戏需求来修改这个阈值,比如,如果你想让你的游戏中的物体更容易反弹,你可以把这个阈值设低一些。反之,如果你想让你的游戏中的物体更难反弹,你可以把这个阈值设高一些。

以下是如何设置这个值的例子:

// 设置反弹阈值为1米/秒
Physics.bounceThreshold = 1.0f;

Physics.sleepThreshold

Physics.sleepThreshold定义了一个物体要进入睡眠状态所需要的最小能量,这是一个浮点值。

 
在Unity的物理引擎中,物体可能会进入所谓的"睡眠"状态。当物体的能量(或说其动量)下降到一个非常低的水平并且在一段时间内没有其他的交互时,该物体将"睡眠"。这意味着物理引擎将不再为其计算物理交互,直到某个外部的力量或碰撞再次作用于它,使它"唤醒"。这是一个优化措施,它可以显著地减少对不活跃物体的不必要的物理计算,从而提高游戏的性能。

默认情况下,sleepThreshold 的值为0.005。这意味着,如果物体的能量低于这个值,它将被标记为睡眠状态,直到它受到足够的外力使其再次变得活跃。

你可以根据游戏的需求调整此阈值。例如,如果你想让物体更容易进入睡眠状态,你可以提高这个阈值;反之,如果你想让物体保持活跃状态更长的时间,你可以降低这个阈值。

以下是如何设置这个值的示例:

// 设置睡眠阈值为0.01
Physics.sleepThreshold = 0.01f;

注意:调整这个值可能会影响游戏的物理行为,特别是当物体开始和停止交互时。所以在更改这个值时需要进行充分的测试,确保它不会对游戏的玩法产生不良影响


Physics.queriesHitBackfaces

Physics.queriesHitBackfaces这个属性决定是否允许物理射线投射 (raycasts)、球形投射 (sphere casts)、胶囊投射 (capsule casts) 和盒形投射 (box casts) 检测到3D模型的背面。3D模型的“背面”是指那些在模型外部看不到的部分,也就是那些法线朝向模型内部的面。

当 queriesHitBackfaces 为 true 时: 物理查询能够检测到模型的背面。
当 queriesHitBackfaces 为 false 时: 物理查询将忽略模型的背面。

应用场景:
碰撞检测: 当你希望物理查询只与模型的外部交互时,通常会禁用背面检测。这是默认设置,因为大多数场合下你不希望,例如,一个从模型内部射出的射线与模型的内部碰撞。

特定的游戏逻辑: 如果你的游戏中有一个需要检测模型内部的场景或者机制(例如,在一个透明的模型内部显示某种效果),那么允许背面检测就会非常有用。

例子:
假设你有一个半透明的球体,并希望玩家能从球体的内部发射射线,并检测到球体的内部碰撞点。在这种情况下,你需要设置 Physics.queriesHitBackfaces 为 true,这样射线就能检测到球体的内部。

void Start() 
{
    Physics.queriesHitBackfaces = true;

    Ray ray = new Ray(sphereCenter, Vector3.forward);
    RaycastHit hit;
    if (Physics.Raycast(ray, out hit)) 
    {
        Debug.Log("击中球体内部点: " + hit.point);
    }
}

上述代码片段会输出球体内部的碰撞点,但前提是你已经设置了queriesHitBackfaces为true。


Physics.queriesHitTriggers

Physics.queriesHitTriggers决定了物理查询(例如射线投射或球形重叠检查)是否应该考虑与触发器碰撞器交互。

 
触发器碰撞器 (Collider 设置为触发器的物体) 与常规碰撞器在 Unity 中有所不同。它们不会导致物理响应,也就是说,当物体进入触发器时,它们不会推开或与触发器物体物理互动。相反,当物体进入触发器时,它会发送一系列的事件,例如 OnTriggerEnter、OnTriggerStay 和 OnTriggerExit。

Physics.queriesHitTriggers 用于确定当进行物理查询时,是否也要包括这些触发器碰撞器。当其值为 true 时,查询(如 Raycast 或 OverlapSphere)也会检测触发器碰撞器。当其值为 false 时,查询将忽略触发器碰撞器。这里就不举例演示了哈。


Physics.reuseCollisionCallbacks

Physics.reuseCollisionCallbacks 决定是否在连续的物理模拟帧中重复使用之前的碰撞回调。此属性在特定的性能优化场景中可能非常有用。

 
当物体在连续的物理模拟帧中保持碰撞状态时(例如,一个物体在另一个物体上),Unity 需要决定是否每一帧都触发碰撞回调(如 OnCollisionStay)。

如果 Physics.reuseCollisionCallbacks 设置为 true,则在连续的碰撞状态中,Unity 将不会为同一个碰撞对生成新的回调。这可以减少不必要的回调,并可能提高性能,特别是当场景中有大量持续碰撞发生时。

如果设置为 false(默认值),则每帧都会为持续的碰撞生成新的回调。

例子:
想象一个场景,其中有许多物体在地面上移动。地面和物体之间会持续产生碰撞。在这种情况下,每一帧都触发 OnCollisionStay 回调可能是没有必要的,而且可能浪费性能。

// 禁用重复使用碰撞回调
Physics.reuseCollisionCallbacks = false;

通过设置 Physics.reuseCollisionCallbacks 为 true,你告诉 Unity 在连续的模拟帧中,只要碰撞对保持不变,就重复使用上一帧的回调,而不是为每一帧生成新的回调。

注意事项:
使用此属性可能会影响游戏逻辑,因为在连续的碰撞中,某些回调可能不会触发。确保你的游戏逻辑不依赖于每帧都接收这些回调。


Physics.clothGravity

Physics.clothGravity表示布料模拟时所应用的全局重力向量。布料模拟在 Unity 中用于创建柔和的、可以与环境或其他对象交互的对象,如旗帜、衣服或帷幕。

 
通常情况下,布料物体会受到 Physics.gravity 的影响。但在某些情况下,你可能希望布料物体受到与场景中其他物理对象不同的重力影响。Physics.clothGravity 允许你为布料定义一个特定的重力向量,这在制作特定效果或进行优化时可能会很有用。

例子:
假设你正在制作一个游戏,其中玩家进入了一个宇宙空间站,而在宇宙空间站内部,由于某些科技,重力被部分抵消了。但你仍希望玩家的太空服上的布料像在地球上那样受到正常重力的影响。

// 设置全局重力为宇宙空间站的重力
Physics.gravity = new Vector3(0, -4.9f, 0); // 假设宇宙空间站内部的重力是地球的一半

// 设置布料的重力为正常的地球重力
Physics.clothGravity = new Vector3(0, -9.8f, 0);

注意事项:
设置 Physics.clothGravity 不会影响非布料物体。它只针对布料模拟有效。
如果你希望布料受到与其他物体相同的重力影响,确保 Physics.clothGravity 和 Physics.gravity 具有相同的值。


Physics.interCollisionDistance

Physics.interCollisionDistance 用于定义 Unity 的布料模拟中布料粒子间的互碰距离。布料模拟在 Unity 中是基于粒子的,其中每个粒子代表布料的一个部分,粒子之间的互动和连接确定了布料的行为和形状。

 
互碰距离定义了两个布料粒子之间最小的距离,当两个粒子靠得足够近以至于它们之间的距离小于这个设定的互碰距离时,它们会被推开,以确保它们保持这个最小的距离。

此设置对于避免布料中的穿帮和碰撞异常非常有用。例如,考虑一个飘动的帷幕或旗帜,你不希望它自己折叠到自己的背面或穿过自己。调整这个值可以帮助确保布料在模拟过程中保持物理上的正确性。

例子:
假设你有一个布料模拟的旗帜,到当风太强时,旗帜的某些部分会穿透其他部分。为了避免这种情况,你可以增加互碰距离:

// 增加布料的互碰距离
Physics.interCollisionDistance = 0.05f;

这将确保布料粒子之间保持至少 0.05 单位的距离。

注意事项:
调整这个值可能会对布料的性能产生影响。过高的值可能导致不真实的模拟或不必要的计算。
这个设置最好在运行时观察布料的行为后进行微调,以确保获得理想的结果。


Physics.interCollisionStiffness

Physics.interCollisionStiffness属性用于定义布料粒子间的互碰刚度。布料的刚度可以看作是阻止粒子之间的重叠或穿透的强度。

 
这个属性的值建议范围是0到1,其中0代表没有刚度,1代表较大刚度。较高的值会使布料在粒子之间的碰撞更加强劲,而较低的值则可能导致布料粒子之间的更多重叠。

例子:
假设你正在模拟一个较硬的布料,例如帆布,你可能希望粒子之间有很高的互碰刚度,这样布料的行为会更稳定、更少重叠。

// 设置布料的互碰刚度为较大值
Physics.interCollisionStiffness = 1.0f;

但如果你正在模拟一个柔软的、易于压缩的布料,例如棉花或丝绸,你可能希望粒子之间的互碰刚度较低:

// 设置布料的互碰刚度为较低值
Physics.interCollisionStiffness = 0.3f;

注意事项:
设置过高的 interCollisionStiffness 可能会导致不真实的效果或模拟的不稳定,特别是在布料的边缘或紧密的部分。
如果你在使用 interCollisionStiffness 时遇到任何问题,如模拟不稳定或效果不如意,尝试与 Physics.interCollisionDistance 属性一起调整该值,以获得最佳结果。


Physics.interCollisionSettingsToggle

Physics.interCollisionSettingsToggle是一个布尔属性,用于启用或禁用布料粒子间的互碰设置。当你使用 Unity 的布料模拟时,这个属性决定是否应用 Physics.interCollisionDistance 和 Physics.interCollisionStiffness 的设置。

 
当 interCollisionSettingsToggle 设置为 true 时,布料粒子之间的互碰会被启用,这时 interCollisionDistance 和 interCollisionStiffness 的值会影响布料的行为。

相反,如果 interCollisionSettingsToggle 设置为 false,则布料的粒子之间不会考虑互碰,无论 interCollisionDistance 和 interCollisionStiffness 的值是什么。

// 启用布料的互碰设置
Physics.interCollisionSettingsToggle = true;

注意事项:
启用布料粒子间的互碰可以增加模拟的真实性,但可能会降低性能。在启用此设置之前,考虑模拟的复杂性和所需的性能。


2. 射线投射和形状检测:

Physics.Linecast: 在两个点之间投射线,如果线与碰撞器碰撞,则返回True。
Physics.Raycast: 从射线的原点向射线的方向发射射线。
Physics.RaycastAll :将返回一个由场景中与射线交互的所有碰撞器组成的 RaycastHit 数组。
Physics.RaycastNonAlloc :与 RaycastAll 类似,但不会为结果分配新的数组。你需要提供一个 RaycastHit 数组,该方法会将结果填充到这个数组中。
Physics.CapsuleCast: 投射一个胶囊并返回一个布尔值,表示胶囊是否与任何碰撞器相交。
Physics.CapsuleCastAll :返回一个由场景中与胶囊交互的所有碰撞器组成的 RaycastHit 数组。
Physics.CapsuleCastNonAlloc: 与 CapsuleCastAll 方法相似,但需要你提供一个 RaycastHit 数组以填充结果。
Physics.BoxCast: 投射一个盒子并返回一个布尔值,表示盒子是否与任何碰撞器相交。
Physics.BoxCastAll :返回与此盒子交互的所有碰撞器组成的 RaycastHit 数组。
Physics.BoxCastNonAlloc: 与 BoxCastAll 方法类似,但需要提供一个 RaycastHit 数组以填充结果。
Physics.SphereCast: 投射一个球体并返回一个布尔值,表示球体是否与任何碰撞器相交。
Physics.SphereCastAll: 返回与这个球相交的所有碰撞器组成的 RaycastHit 数组。
Physics.SphereCastNonAlloc: 与 SphereCastAll 方法相似,但需要提供一个 RaycastHit 数组以填充结果。

NonAlloc版本的方法特别用于性能敏感的场景,因为它们避免了不必要的内存分配


Physics.Linecast

Physics.Linecast是 Unity 物理系统的一个重要方法,用于检测两点之间的直线路径上是否存在任何碰撞器。这种检测在很多情况下都是有用的,例如判断角色是否在玩家的视线中、触发器的活动以及其他需要直线路径碰撞检测的情况。

(下文所有定义,都使用传递最多参数的重载来说明)

定义

 public static bool Linecast(Vector3 start, Vector3 end, out RaycastHit hitInfo, [UnityEngine.Internal.DefaultValue("DefaultRaycastLayers")] int layerMask, [UnityEngine.Internal.DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction);

参数:

  • start:线投射的起始位置
  • end:线投射的结束位置
  • hitInfo:如果线投射与任何碰撞器相交,此参数将包含关于交点的详细信息(如交点位置、交点的碰撞器等)
  • layerMask:用于过滤与线投射相交的物体的层。这使得可以指定哪些层应该被考虑进来,哪些层应该被忽略
  • queryTriggerInteraction:指定如何处理触发器碰撞器。可以是UseGlobal、Ignore或Collide

返回值:
如果线段与碰撞器相交,则返回true,否则返回false。

示例:

public class LinecastExample : MonoBehaviour
{
    public Transform pointA;  //A点
    public Transform pointB;  //B点

    void Update()
    {
        RaycastHit hit;
        if (Physics.Linecast(pointA.position, pointB.position, out hit))
        {
            Debug.Log("击中障碍物!");
            Debug.DrawLine(pointA.position, hit.point, Color.red); 
        }
        else
        {   
            Debug.Log("没有击中障碍物!");
            Debug.DrawLine(pointA.position, pointB.position, Color.green);  
        }
    }
}

在这个例子中,我们每一帧都在pointA和pointB之间进行Linecast检测。如果线段与任何物体相交,我们在场景视图中绘制一条红线到交点;否则,我们绘制一条绿线。
这个方法的一个常见用途是在策略游戏中检测单位之间是否有障碍物,或者在第一人称射击游戏中检测玩家是否可以看到某个目标。


Physics.Raycast

Physics.Raycast用于从指定的位置和方向发射一条射线,并返回该射线是否与任何碰撞器相交。这在很多游戏场景中都有广泛的应用,如射击游戏中的子弹轨迹、角色视线检测等。

定义:

public static bool Raycast(Vector3 origin, Vector3 direction, out RaycastHit hitInfo, float maxDistance, int layerMask, QueryTriggerInteraction queryTriggerInteraction);

参数:

  • origin:射线的起始点。
  • direction:射线的方向。
  • hit:如果射线与任何碰撞器相交,此参数将接收有关击中的信息。
  • maxDistance:射线的最大长度。默认为无限大,意味着射线将继续直到击中物体或无限远。
  • layerMask:可用于筛选应被考虑的层。例如,你可能只想测试某几层中的物体。
  • queryTriggerInteraction:定义如何处理触发器。可取值为UseGlobal、Ignore或Collide。

返回值:

如果射线与碰撞器相交,则返回 true;否则返回 false。

示例:

using UnityEngine;

public class RaycastExample : MonoBehaviour
{
    public float rayLength = 10f; //最大长度
    public LayerMask hitLayers;   //层级

    void Update()
    {
        RaycastHit hit;
        Vector3 rayDirection = transform.TransformDirection(Vector3.forward); //游戏对象的前进方向
        
        if (Physics.Raycast(transform.position, rayDirection, out hit, rayLength, hitLayers))
        {
            Debug.Log("击中障碍物: " + hit.collider.name);
            Debug.DrawRay(transform.position, rayDirection * hit.distance, Color.red); 
        }
        else
        {
            Debug.DrawRay(transform.position, rayDirection * rayLength, Color.green);
        }
    }
}

在这个示例中,每一帧都发射一条从物体的当前位置沿其前方方向的射线。如果射线击中了指定层中的任何物体,将在控制台中打印击中物体的名称,并在场景视图中绘制一条红线到击中点;否则,将绘制一条绿线。

通过合理使用 Physics.Raycast,开发人员可以实现许多复杂的交互和游戏逻辑,例如检测物体是否被遮挡、计算弹道、触发交互事件等。


Physics.CapsuleCast

Physics.CapsuleCast用于模拟从指定的位置发射一个胶囊形状,并检测其是否与场景中的任何碰撞器发生交互。这种胶囊投射在各种游戏场景中都非常有用,特别是在需要检测一个体积较大的物体移动时是否会与其他物体碰撞的情境下。

定义:

 public static bool CapsuleCast(Vector3 point1, Vector3 point2, float radius, Vector3 direction, out RaycastHit hitInfo, [UnityEngine.Internal.DefaultValue("Mathf.Infinity")] float maxDistance, [UnityEngine.Internal.DefaultValue("DefaultRaycastLayers")] int layerMask, [UnityEngine.Internal.DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction);

参数:

  • point1 和 point2:定义胶囊的两个端点。胶囊的线段部分是通过连接这两个点得到的。
  • radius:胶囊的半径。
  • direction:胶囊投射的方向。
  • hitInfo:如果胶囊与任何碰撞器交互,此参数将接收关于交互点的详细信息。
  • maxDistance:胶囊投射的最大距离。
  • layerMask:用于过滤应被考虑的层。
  • queryTriggerInteraction:定义如何处理触发器。可取值为 UseGlobal、Ignore 或 Collide。

返回值:

如果胶囊与场景中的任何碰撞器交互,则返回 true;否则返回 false。

示例:

public class CapsuleCastExample : MonoBehaviour
{
    public float capsuleHeight = 2f;   //胶囊高度
    public float capsuleRadius = 0.5f; //胶囊半径
    public float castDistance = 10f;  //投射最大距离
    public LayerMask hitLayers;       //层级

    void Update()
    {
        Vector3 top = transform.position + Vector3.up * (capsuleHeight / 2);
        Vector3 bottom = transform.position - Vector3.up * (capsuleHeight / 2);
        Vector3 direction = transform.TransformDirection(Vector3.forward);

        RaycastHit hit;
        if (Physics.CapsuleCast(top, bottom, capsuleRadius, direction, out hit, castDistance, hitLayers))
        {
            Debug.Log("Hit: " + hit.collider.name);
        }
    }
}

在这个示例中,胶囊投射从游戏对象的位置开始,沿其前方方向。如果胶囊与指定层中的任何物体交互,将在控制台中打印交互物体的名称。


Physics.BoxCast

Physics.BoxCast用于模拟从指定的位置发射一个盒形,并检测它是否与场景中的任何碰撞器发生交互。这种盒形投射可以用于各种游戏场景,例如检测一个矩形物体移动时是否会与其他物体碰撞。

定义:

public static bool BoxCast(Vector3 center, Vector3 halfExtents, Vector3 direction, out RaycastHit hitInfo, [UnityEngine.Internal.DefaultValue("Quaternion.identity")] Quaternion orientation, [UnityEngine.Internal.DefaultValue("Mathf.Infinity")] float maxDistance, [UnityEngine.Internal.DefaultValue("DefaultRaycastLayers")] int layerMask, [UnityEngine.Internal.DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction);

参数:

  • center: 投射盒子的中心点。
  • halfExtents: 表示盒子的一半大小的 Vector3。包括长度、宽度和高度。
  • direction: 盒子投射的方向。
  • hitInfo: 如果盒子与任何碰撞器交互,此参数将接收关于交互点的详细信息。
  • orientation: 盒子的方向。使用Quaternion来定义。
  • maxDistance: 投射的最大距离。
  • layerMask: 用于过滤应被考虑的层。
  • queryTriggerInteraction: 定义如何处理触发器。可取值为 UseGlobal、Ignore 或 Collide。

返回值:

如果盒子与场景中的任何碰撞器交互,则返回 true;否则返回 false。

示例:

public class BoxCastExample : MonoBehaviour
{
    public Vector3 boxSize = new Vector3(1f, 1f, 1f);
    public float castDistance = 5f;
    public LayerMask hitLayers;

    void Update()
    {
        Vector3 direction = transform.TransformDirection(Vector3.forward);
        RaycastHit hit;
        if (Physics.BoxCast(transform.position, boxSize / 2, direction, out hit, transform.rotation, castDistance, hitLayers))
        {
            Debug.Log("Hit: " + hit.collider.name);
        }
    }
}

在这个示例中,盒子投射从游戏对象的位置开始,并沿其前方方向。如果盒子与指定层中的任何物体交互,将在控制台中打印交互物体的名称。


Physics.SphereCast

Physics.SphereCast用于模拟一个虚拟的球体在指定方向上进行投射,并检测这个球体是否与场景中的任何碰撞器发生交互。这种球形投射在游戏开发中常常用于各种目的,如检测前方的障碍物、模拟声纳等。

定义:

public static bool SphereCast(Vector3 origin, float radius, Vector3 direction, out RaycastHit hitInfo, float maxDistance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal);

参数:

  • origin: 投射球体的起始点。
  • radius: 球体的半径。
  • direction: 球体投射的方向。
  • hitInfo: 如果球体与任何碰撞器交互,此参数将接收关于交互点的详细信息。
  • maxDistance: 投射的最大距离。
  • layerMask: 用于过滤应被考虑的层。
  • queryTriggerInteraction: 定义如何处理触发器。可取值为 UseGlobal、Ignore 或 Collide。

返回值:
如果球体与场景中的任何碰撞器交互,则返回 true;否则返回 false。

示例:

public class SphereCastExample : MonoBehaviour
{
    public float sphereRadius = 0.5f;   // 半径
    public float castDistance = 5f;     //最大距离
    public LayerMask hitLayers;

    void Update()
    {
        Vector3 direction = transform.TransformDirection(Vector3.forward);
        RaycastHit hit;
        if (Physics.SphereCast(transform.position, sphereRadius, direction, out hit, castDistance, hitLayers))
        {
            Debug.Log("Hit: " + hit.collider.name);
        }
    }
}

在这个示例中,球体投射从游戏对象的位置开始,并沿其前方方向进行。如果球体与指定层中的任何物体交互,将在控制台中打印交互物体的名称。


温馨提示:使用这个Physics类,特别是涉及物理模拟的部分,需要理解物理学的基本原理。如果对物理学的理解不足,可能会遇到预期外的结果。一般来说,尽量避免创建不真实的物理条件(如零摩擦力,无限大的力等)。

为了使文章不过于冗长,在下一章,我会接着把Physics类剩下的属性和方法进行讲解

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>