Unity 之 记录一个关于刚体穿透的问题

Unity 之 记录一个关于刚体穿透的问题

一,需求描述

需求:使得杆能够接住,依靠重力下落的球。
可是实现起来却和想象的不太一样,当杆移动速度快了就传过去了。
效果如下:
重力


二,遇到问题

看需求感觉还挺简单的。实现思路:几个球根据重力下落,一个“杆”跟随鼠标移动。步骤如下:

  • 创建几个球并 Rigidbody 组件,并勾选 useGravity 选项。
  • 搭建场景如下图:场景
  • 再创建一个Cube放大点(用来接住下落的球),也添加上Rigidbody 组件并添加 MouseMove 脚本:
using UnityEngine;

public class MouseMove : MonoBehaviour
{
    void Update()
    {
        if (Input.GetMouseButton(0))
        {
            // 根据鼠标位置 设置为 物体位置
            Vector3 screenPos = Camera.main.WorldToScreenPoint(this.transform.position);
            Vector3 mousePos = Input.mousePosition;
            mousePos.z = screenPos.z;
            Vector3 worldPos = Camera.main.ScreenToWorldPoint(mousePos);            
            // 控制物体移动
            transform.position = worldPos;
        }
    }
}


三,尝试解决

记得Rigidbody组件,可以通过Collision Detection属性来用于防止快速移动的对象穿过,这下面的检测方式都尝试了,也没有解决上述问题。
刚体组件

Unity 官方API:

Collision Detection用于防止快速移动的对象穿过其他对象而不检测碰撞。
Discrete对场景中的所有其他碰撞体使用离散碰撞检测。其他碰撞体在测试碰撞时会使用离散碰撞检测。用于正常碰撞(这是默认值)。
Continuous对动态碰撞体(具有刚体)使用离散碰撞检测,并对静态碰撞体(没有刚体)使用基于扫掠的连续碰撞检测。设置为__连续动态 (Continuous Dynamic)__ 的刚体将在测试与该刚体的碰撞时使用连续碰撞检测。其他刚体将使用离散碰撞检测。用于__连续动态 (Continuous Dynamic)__ 检测需要碰撞的对象。(此属性对物理性能有很大影响,如果没有快速对象的碰撞问题,请将其保留为 Discrete 设置)
Continuous Dynamic对设置为__连续 (Continuous)__ 和__连续动态 (Continuous Dynamic)__ 碰撞的游戏对象使用基于扫掠的连续碰撞检测。还将对静态碰撞体(没有刚体)使用连续碰撞检测。对于所有其他碰撞体,使用离散碰撞检测。用于快速移动的对象。
Continuous Speculative对刚体和碰撞体使用推测性连续碰撞检测。这也是可以设置运动物体的唯一 CCD 模式。该方法通常比基于扫掠的连续碰撞检测的成本更低。

测试小结

  • 测试时也尝试了快速移动时的检测逻辑,在速度不是特别快的情况下,修改Collsion Detection选项调成Continues Dynamic是可以满足条件的,但是超过一定速度还是能穿透过去。
  • 记得在尝试过程中还看到过:调整ProjectSetting -> Time-> FixedTimestep的检测间隔进一步缩小。(例如0.003;提高物理系统的更新速度)【测试也没成功】
  • 若是发射子弹这种逻辑,可以使用射线检测的方式,在子弹发射的时候发射射线检测到的碰撞点进行逻辑判断处理。

四,实现需求

最后使用移动刚体的方式,来移动“杆”,测试结果如下:
刚体
修改后的代码:

using UnityEngine;

public class MouseMove : MonoBehaviour
{
    private Rigidbody _rigidbody;
    void Start()
    {
        _rigidbody = transform.GetComponent<Rigidbody>();
        // 取消重力
        _rigidbody.useGravity = false;
        // 设置为不再受物理引擎的影响
        _rigidbody.isKinematic = true;
    }

    void Update()
    {
        if (Input.GetMouseButton(0))
        {
            // 根据鼠标位置 设置为 物体位置
            Vector3 screenPos = Camera.main.WorldToScreenPoint(this.transform.position);
            Vector3 mousePos = Input.mousePosition;
            mousePos.z = screenPos.z;
            Vector3 worldPos = Camera.main.ScreenToWorldPoint(mousePos);
            
            // 控制物体移动
            //transform.position = worldPos;
            // 修改为刚体控制移动 --> 则不会被穿透了
            _rigidbody.MovePosition(worldPos);
        }
    }
}

若还有不明白的地方,可以评论咨询,或者点击链接查看示例源码:源码链接


### 回答1: Unity的裁剪(Culling)功能可以用来优化游戏性能,从而提高游戏的帧率和流畅度。在Unity中,裁剪分为视野裁剪和物体裁剪两种类型。 视野裁剪是指Unity只绘制玩家可以看到的物体,而不渲染不在视野内的物体。这种裁剪是基于相机的视锥体实现的,Unity会计算出相机所在位置的视锥体范围内的物体,然后只渲染这些物体。 物体裁剪是指Unity只绘制在相机视锥体内的可见物体,而不渲染被其他物体遮挡的物体。这种裁剪是基于物体的边界框实现的,Unity会计算出边界框与相机视锥体的交集,然后只渲染这些可见物体。 为了更好地利用裁剪功能,你可以使用Unity中的一些优化技巧,如合批处理和静态批处理等。这些技巧可以减少游戏中需要绘制的物体数量,从而提高游戏的性能表现。 ### 回答2: 在Unity中,实现穿透一小块区域可以通过以下步骤进行: 1. 创建一个新的物体作为玩家或其他角色,将其命名为"Player"。 2. 创建一个小块区域的碰撞体,作为障碍物,将其命名为"Obstacle"。 3. 将Player和Obstacle分别添加到场景中。 4. 在Player物体上添加一个刚体组件,使其可以受到物理引擎的控制。 5. 在Player物体上添加一个脚本组件,用于控制玩家的移动。 6. 在脚本中,使用Raycast射线检测来判断玩家是否与障碍物碰撞。 7. 当玩家接触到障碍物时,可以通过修改刚体组件的isKinematic属性为true,使玩家忽略物理碰撞,并且穿透障碍物。 8. 当玩家离开障碍物时,可以将刚体组件的isKinematic属性重新设置为false,恢复物理碰撞。 通过以上步骤,可以在Unity中实现玩家对小块区域的穿透。请注意,这只是一个简单的示例,实际情况还需要根据具体需求进行适当的调整和优化。 ### 回答3: Unity中的碰撞体组件提供了一种简单的方法来实现穿透一小块区域的效果。下面是一个简单示例,并使用代码解释了如何实现: 首先,在Unity中创建一个游戏对象并将其添加一个刚体组件。然后创建一个空的GameObject并将其作为子对象添加到刚刚创建的游戏对象上。 然后,在子对象上添加一个Box Collider组件,并将其大小设置为您想要实现穿透的区域大小。确保将此碰撞体的Trigger属性勾选上,以便让它成为一个触发器。 然后,在主游戏对象上添加以下代码来实现穿透效果: ```csharp using UnityEngine; public class PenetrateArea : MonoBehaviour { private Collider areaCollider; private void Start() { areaCollider = GetComponentInChildren<Collider>(); } private void OnTriggerEnter(Collider other) { if (other.gameObject.CompareTag("Player")) { // 忽略触发穿透区域的碰撞体碰撞 Physics.IgnoreCollision(other, areaCollider); } } private void OnTriggerExit(Collider other) { if (other.gameObject.CompareTag("Player")) { // 恢复对触发穿透区域的碰撞体碰撞 Physics.IgnoreCollision(other, areaCollider, false); } } } ``` 在上述代码中,我们首先获取子对象上的碰撞体组件。然后,在触发器函数中,我们使用`Physics.IgnoreCollision`方法来忽略或恢复碰撞。当玩家对象进入穿透区域时,我们忽略碰撞,这样玩家对象就可以穿过该区域了。当玩家对象离开穿透区域时,我们则恢复对其的碰撞。 通过使用上述代码,您可以实现Unity穿透一小块区域的效果。当玩家对象进入该区域时,玩家对象将能够穿过该区域,而不会被阻挡。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈言必行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值