我正在开发一种将对象拖放到盒子中的游戏,我不知道检测对象是否在盒子中的最佳和最有效的方法是什么。
我很清楚碰撞器,我正在使用BoxColliders和触发器来查明我的物体是否正在接触一个盒子但是我想要检测我的物体的时刻(为了简单起见,我们可以假设它是球体但后来将是一个网格)完全在我的盒子触发器/对撞机内。
我读到了碰撞器的“包含”方法,但是IIRC他们只是检查碰撞器内是否有一个点,但我有兴趣知道整个物体是否在碰撞器内。
先谢谢你们。
答案 0 :(得分:2)
简答:如果你想要100%的准确度,你的算法永远不会比O(| V |)(最坏的情况)好,其中V = {网格中的所有顶点},这意味着你' d。在每个顶点上运行.Collides(),如果找到容器外的那个,则中断。
更长的答案:有几种方法可以细分网格曲面,例如:KD-Trees,OcTrees。这些超出了提供完整实现的SO答案的范围,我建议您查看维基页面以获取详细信息。
您可以使用这些方法将网格划分为较小的顶点集。要加速算法,您可以从细分树的根开始,并测试该节点是否包含在容器框中。继续在树中工作,直到找到未包含在框中的节点。这将允许您的“包含”测试更快地失败,但如果您的盒子包含您的网格,最终您将最终测试每个顶点。
警告:如果您的网格是动画的,则此解决方案不起作用。在这种情况下,最好的办法是使用手臂,脚,腿等周围的边界,并使用该信息来剔除Contains()测试。同样,如果网格完全位于框内,您将最终必须测试每个顶点。
答案 1 :(得分:2)
所有方框都有一个boxCollider。如果对象接触第二个框,则该对象必须位于第一个框内。
这不是一个好的解决方案,但也许它会很有用。
答案 2 :(得分:1)
使用Renderer.bounds属性获取对象的边界框。
根据您拥有的对象以及您想要将其检查到对手内部的准确程度,您可能会使用一种简单的方法来确定它。
答案 3 :(得分:1)
更精致,更清洁的方法。这对你正在做的事情来说是完美的。 你可以检查你拖动的物体和盒子之间的距离。
该框具有x,y,z值,表示其在空间中的位置。
所以当你拖动你的游戏对象时,x,y或z的距离可能只有0.2,远离你的盒子的中心。所以只需使用此方法计算拖动对象与框之间的距离。
var other :Transform;
function Update()
{
var dist = Vector3.Distance(other.position, transform.position);
// while dragging
if(dist <10)// 10 being on all 3 axiz .
{
//dragged object.position = box position
}
if (dist == 0)
{
print("i am in the centre of the box");
}
}
因此你的游戏对象将在框中。
答案 4 :(得分:1)
上面的box within a box解决方案是一个不错的选择,但是如果它不起作用(由于大小/形状可变的对象),您可能可以使用Physics.Raycast或Collider.Raycast完成某些操作。我有一个类似的问题,我需要测试碰撞器中是否包含任意点(其中许多是不寻常的凹陷凹面物体)。
基本思想是“钉床”方法,我将光线从多个方向投射到点。如果我在所有射线上击中外部对撞机,那么我可以非常确信该点包含在对撞机内(但仍然不完全确定)。这是一张照片:
在这张照片中,我们试图看看蓝点是否在黄色对撞机内。绿色箭头代表成功的光线投射(黄色对撞机被击中),而PINK则不成功(黄色对撞机未被击中)。
以下是一段代码摘要:
public static class CollisionUtils {
private static readonly Vector3[] raycastDirections;
// These are the directions that we shoot rays from to check the collider.
static UltrasoundCollisionUtils() {
raycastDirections = new Vector3[5];
raycastDirections[0] = new Vector3(0,1,0);
raycastDirections[1] = new Vector3(0,-1,-0);
raycastDirections[2] = new Vector3(0,0,1);
raycastDirections[3] = new Vector3(-1.41f, 0, -0.5f);
raycastDirections[4] = new Vector3(1.41f, 0, -0.5f);
}
public static bool IsContained (Vector3 targetPoint, Collider collider) {
// A quick check - if the bounds doesn't contain targetPoint, then it definitely can't be contained in the collider
if (!collider.bounds.Contains(targetPoint)) {
return false;
}
// The "100f * direction" is a magic number so that we
// start far enough from the point.
foreach (Vector3 direction in raycastDirections) {
Ray ray = new Ray(targetPoint - 100f * direction, direction);
RaycastHit dummyHit = new RaycastHit();
// dummyHit because collider.Raycast requires a RaycastHit
if (!collider.Raycast(ray, out dummyHit, 100f)) {
return false;
}
}
return true;
}
}
你可以调整这种算法的一种方法是使用Collider.Raycast,做一个Physics.Raycast。如果光线撞击了对撞机以外的任何物体,那么您就知道目标物体并非完全位于对撞机中。
答案 5 :(得分:0)
添加一个BoxCollider,它围绕您正在测试的整个对象并检查其界限min和max包含在其进入的BoxCollider中......这可能不适合复杂的网格物体,但您可能能够逃脱用它和便宜的
答案 6 :(得分:0)
简单地说, 您可以在容器底部放置一个盒子碰撞器。如果您的球体或任何物体接触到它,那么它完全位于容器内..
答案 7 :(得分:0)
虽然有一种方法。...虽然不那么准确,但可以使用:
答案 8 :(得分:-1)