我正在开发一个游戏,您可以将对象拖放到盒子中,但我不知道检测我的对象是否在盒子中的最佳和最有效的方法是什么。
我很清楚对撞机,我正在使用 BoxColliders 和触发器来确定我的对象是否正在接触一个盒子,但我想检测我的对象的时刻(为了简单起见,我们可以假设它是球体,但稍后会是一个网格)完全在我的盒子触发器/对撞机内。
我读到了对撞机的“包含”方法,但 IIRC 他们只是检查该对撞机内是否有一个点,但我很想知道整个对象是否在对撞机内。
先谢谢各位了。
我正在开发一个游戏,您可以将对象拖放到盒子中,但我不知道检测我的对象是否在盒子中的最佳和最有效的方法是什么。
我很清楚对撞机,我正在使用 BoxColliders 和触发器来确定我的对象是否正在接触一个盒子,但我想检测我的对象的时刻(为了简单起见,我们可以假设它是球体,但稍后会是一个网格)完全在我的盒子触发器/对撞机内。
我读到了对撞机的“包含”方法,但 IIRC 他们只是检查该对撞机内是否有一个点,但我很想知道整个对象是否在对撞机内。
先谢谢各位了。
所有的盒子都有一个 boxCollider。如果一个物体接触到第二个盒子,则该物体必须在第一个盒子内。
这不是一个好的解决方案,但也许它会有用。
Short answer: If you want 100% accuracy, your algorithm will never be better than O(|V|) (worst case) where V = {all vertices in mesh}, meaning you'd run .Collides() over every vertex and break if you find one that is outside your container.
Longer answer: Several methods exist to subdivide mesh surfaces, examples include: KD-Trees, OcTrees. These are beyond the scope of an SO answer to provide a full implementation, I suggest you see the wiki pages for details.
You could use these methods to divide your mesh up in to smaller sets of vertices. To speed up your algorithm you would start at the root of your subdivision tree and test if that node is contained in your container box. Keep working through the tree until you find a node that is not contained by your box. This will allow your "contains" test to fail faster but ultimately you'll wind up testing every vertex if your box contains your mesh.
Caveat: This solution does not work if your mesh is animated. In that case your best bet is to use the bounds around things like arms, feet, legs, etc and use that information to cull your Contains() tests. Again, you'll end up having to test every vertex if the mesh is fully inside your box.
使用Renderer.bounds属性获取对象的边界框。
根据您拥有的对象以及您希望检查它在对撞机内的准确度,您可能会使用一种简单的方法来确定它。
上面的盒子解决方案中的盒子是一个不错的选择,但如果这不起作用(由于可变大小/形状的对象),您也许可以使用Physics.Raycast或 Collider.Raycast 完成某些事情。我有一个类似的问题,我需要测试碰撞器中是否包含任意点(其中许多是不寻常的斑点凹形物体)。
基本思想是“钉床”方法,我从多个方向向该点投射光线。如果我在所有光线上击中外部对撞机,那么我可以非常确信该点包含在对撞机内(但仍不能完全确定)。这是一张照片:
在这张图片中,我们试图查看蓝色点是否在黄色对撞机内。绿色箭头代表成功的光线投射(黄色对撞机被击中),粉红色的箭头不成功(黄色对撞机未被击中)。
这是说明这一点的代码片段:
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。如果射线击中对撞机以外的任何物体,那么您就知道目标对象并不完全在对撞机中。
以获得更精致和更清洁的方法。这对你正在做的事情来说是完美的。您可以检查您拖动的对象和框之间的距离。
盒子的 ax,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");
}
}
因此您的游戏对象将在框中。
简单地说,您可以在容器底部放置一个盒子对撞机。如果您的球体或任何物体接触到它,那么它完全在容器内。
添加一个围绕您正在测试的整个对象的 BoxCollider,并检查其边界 min 和 max 是否包含在 BoxCollider 的输入范围内......这可能不适合复杂的网格对象,但您可能能够摆脱它并且它便宜
虽然有一种方法....不是那么准确,但会起作用: