在 Raycast 指向的地方放置一个对象,但在 Unity3D 中考虑碰撞
Place an object where Raycast points but taking collisions into account in Unity3D
我正在尝试将对象放置在我的 Raycast 指向的位置(Raycast 发现碰撞的位置)。但我得到的是你在所附图片中看到的(2 种不同的情况)。该对象确实放置在我指向的位置,但我想考虑碰撞,以便对象不会相互穿过。
每个对象都有自己的 Collider。
有人知道怎么解决吗?谢谢。
一月
编辑:
我试过像这样实现 @31eee384 给出的解决方案:
RaycastHit hit;
Game.MuebleAEditarGO.transform.position = CameraFacing.transform.position;
if (Game.MuebleAEditarGO.GetComponentInChildren<Rigidbody>().SweepTest(CameraFacing.transform.rotation * Vector3.forward, out hit, 50f))
{
Game.MuebleAEditarGO.transform.position += CameraFacing.transform.forward * hit.distance;
}
MuebleAEditarGO 是一个刚体。墙壁(和一般的房子)不是刚体,它们每个都有 MeshoColliders。
但后来我得到了一个部分有效的解决方案。当 RaycastHit 只发现一次碰撞时,它似乎工作正常(见下图)。
您的问题很大程度上取决于您的规格。
您可以从计算生成游戏对象的碰撞器的宽度开始并应用偏移量,但它仅在面对平面时有效。在目标位置周围添加光线投射也可以让您管理角落。
处理更一般的情况(不规则表面、比您的物体小的角等)将导致更复杂的解决方案。
利用 Unity 的 OnTriggerEnter
on OnTriggerExit
方法来确定是否可以将对象放置在特定位置。
例如,您可以跟踪您正在放置的对象与之发生碰撞的对象的数量,方法是每次有东西进入它的触发器时将数字加一。然后,当某些东西离开它的触发器时,从那个数字中减去一个。如果对象中的碰撞器数量为零,则可以安全放置对象。
public class PlaceableObject : MonoBehaviour
{
int CollidersInTrigger = 0;
void OnTriggerEnter(Collider col)
{
CollidersInTrigger++;
}
void OnTriggerExit(Collider other)
{
CollidersInTrigger--;
}
bool CanPlace()
{
return CollidersInTrigger == 0;
}
}
请注意,当您的对象在 "Placing Mode" 中时,它的碰撞器的 IsTrigger 属性 必须设置为 true。
超出我的想象:
辐射 4 有点像:
您很可能对您持有的物品有参考。将一个脚本附加到它上面,该脚本将保存一个 public 布尔变量来标记它是否在任何给定时刻与任何东西相交。在 OnTriggerEnter() 和 OnTriggerExit() 中切换 bool 的值。如果 bool 为真,则不允许用户放下物体(并且可能在物体上使用另一层红色或其他让他们知道的东西)
传送门2方式:
您很可能有一些描述您可以抓取的对象的脚本。添加一个大小变量来描述你的对象的代理大小——比一个轴上的最大比例多一点。 (例如,如果沙发尺寸为 2x5x10,则让代理为 11)
禁用您持有的物体上的碰撞器。因此,光线投射将适用于您看到的所有其他内容。
如果射线击中任何东西,则取 ray.point。从那时起,取一些大于对象大小的任意值,然后将对象向你移动那么多。
据我了解,您的目标是在不同的地方生成不同的对象。
我看到这里有 2 种可以结合使用的方法。
您有 objects-free 个区域并在那里随机生成对象。但是,如果您不能释放此区域对象,就会出现问题。至少你可以用 OverlapSphere 或其他东西检查你的区域是否空闲。如果没有,您选择另一个区域进行检查并在该区域内的随机位置生成
你 "drop" 你的物体从不可能在其他物体内部产生的高度。比你可以让物体掉落或垂直追踪障碍物之前的位置并在此时产生。
最直接的解决方案是使用 Unity 的物理引擎:Rigidbody.SweepTest
。它使用碰撞器扫描您的实际刚体(没有像边界框或手动距离检查那样的抽象),并且它将通过物理引擎可以提供的所有优化和广义计算来完成。
要使用它,请查看 SweepTest
文档页面上的示例,为了完整性复制到此处:
RaycastHit hit;
if (rb.SweepTest(transform.forward, out hit, collisionCheckDistance))
{
aboutToCollide = true;
distanceToCollision = hit.distance;
}
然后使用transform.forward * distanceToCollision
来确定物体在第一次碰撞之前要移动多远。例如:
RaycastHit hit;
couch.transform.position = transform.position;
if (couch.SweepTest(transform.forward, out hit, 50f))
{
couch.transform.position += transform.forward * hit.distance;
}
确保您的对象位于不同的物理层上,这样沙发就不会与玩家的碰撞器发生碰撞。
我正在尝试将对象放置在我的 Raycast 指向的位置(Raycast 发现碰撞的位置)。但我得到的是你在所附图片中看到的(2 种不同的情况)。该对象确实放置在我指向的位置,但我想考虑碰撞,以便对象不会相互穿过。 每个对象都有自己的 Collider。
有人知道怎么解决吗?谢谢。
一月
编辑:
我试过像这样实现 @31eee384 给出的解决方案:
RaycastHit hit;
Game.MuebleAEditarGO.transform.position = CameraFacing.transform.position;
if (Game.MuebleAEditarGO.GetComponentInChildren<Rigidbody>().SweepTest(CameraFacing.transform.rotation * Vector3.forward, out hit, 50f))
{
Game.MuebleAEditarGO.transform.position += CameraFacing.transform.forward * hit.distance;
}
MuebleAEditarGO 是一个刚体。墙壁(和一般的房子)不是刚体,它们每个都有 MeshoColliders。
但后来我得到了一个部分有效的解决方案。当 RaycastHit 只发现一次碰撞时,它似乎工作正常(见下图)。
您的问题很大程度上取决于您的规格。 您可以从计算生成游戏对象的碰撞器的宽度开始并应用偏移量,但它仅在面对平面时有效。在目标位置周围添加光线投射也可以让您管理角落。 处理更一般的情况(不规则表面、比您的物体小的角等)将导致更复杂的解决方案。
利用 Unity 的 OnTriggerEnter
on OnTriggerExit
方法来确定是否可以将对象放置在特定位置。
例如,您可以跟踪您正在放置的对象与之发生碰撞的对象的数量,方法是每次有东西进入它的触发器时将数字加一。然后,当某些东西离开它的触发器时,从那个数字中减去一个。如果对象中的碰撞器数量为零,则可以安全放置对象。
public class PlaceableObject : MonoBehaviour
{
int CollidersInTrigger = 0;
void OnTriggerEnter(Collider col)
{
CollidersInTrigger++;
}
void OnTriggerExit(Collider other)
{
CollidersInTrigger--;
}
bool CanPlace()
{
return CollidersInTrigger == 0;
}
}
请注意,当您的对象在 "Placing Mode" 中时,它的碰撞器的 IsTrigger 属性 必须设置为 true。
超出我的想象:
辐射 4 有点像:
您很可能对您持有的物品有参考。将一个脚本附加到它上面,该脚本将保存一个 public 布尔变量来标记它是否在任何给定时刻与任何东西相交。在 OnTriggerEnter() 和 OnTriggerExit() 中切换 bool 的值。如果 bool 为真,则不允许用户放下物体(并且可能在物体上使用另一层红色或其他让他们知道的东西)
传送门2方式:
您很可能有一些描述您可以抓取的对象的脚本。添加一个大小变量来描述你的对象的代理大小——比一个轴上的最大比例多一点。 (例如,如果沙发尺寸为 2x5x10,则让代理为 11)
禁用您持有的物体上的碰撞器。因此,光线投射将适用于您看到的所有其他内容。
如果射线击中任何东西,则取 ray.point。从那时起,取一些大于对象大小的任意值,然后将对象向你移动那么多。
据我了解,您的目标是在不同的地方生成不同的对象。
我看到这里有 2 种可以结合使用的方法。
您有 objects-free 个区域并在那里随机生成对象。但是,如果您不能释放此区域对象,就会出现问题。至少你可以用 OverlapSphere 或其他东西检查你的区域是否空闲。如果没有,您选择另一个区域进行检查并在该区域内的随机位置生成
你 "drop" 你的物体从不可能在其他物体内部产生的高度。比你可以让物体掉落或垂直追踪障碍物之前的位置并在此时产生。
最直接的解决方案是使用 Unity 的物理引擎:Rigidbody.SweepTest
。它使用碰撞器扫描您的实际刚体(没有像边界框或手动距离检查那样的抽象),并且它将通过物理引擎可以提供的所有优化和广义计算来完成。
要使用它,请查看 SweepTest
文档页面上的示例,为了完整性复制到此处:
RaycastHit hit;
if (rb.SweepTest(transform.forward, out hit, collisionCheckDistance))
{
aboutToCollide = true;
distanceToCollision = hit.distance;
}
然后使用transform.forward * distanceToCollision
来确定物体在第一次碰撞之前要移动多远。例如:
RaycastHit hit;
couch.transform.position = transform.position;
if (couch.SweepTest(transform.forward, out hit, 50f))
{
couch.transform.position += transform.forward * hit.distance;
}
确保您的对象位于不同的物理层上,这样沙发就不会与玩家的碰撞器发生碰撞。