0

我目前正在尝试将对象(立方体、金字塔、圆环)捕捉在一起。我为对象边界框的每个面分配了一个“允许捕捉”变量,并在碰撞时尝试找到彼此最近的两侧。然后我将主要对象移动到碰撞侧并相应地旋转它。

代码如下:

private static Vector3[] sides = {
    Vector3.up,
    Vector3.forward,
    Vector3.right,
    Vector3.down,
    Vector3.back,
    Vector3.left
};

private void Snap() {
    if (!snappedObject)
        return;

    if (lastSnapping > LeftController.GetLastSnappingToggle()) {
        //we dont calculate new sides, only use the old ones
        //but we have to check whether we are now further away 
        float dis = Vector3.Distance(GetWorldPositionFace(this.gameObject, lastSelf),
                                     GetWorldPositionFace(snappedObject, lastOther));
        float max = Mathf.Max(Mathf.Abs(size.x), Mathf.Max(Mathf.Abs(size.y), Mathf.Abs(size.z)));
        if (dis > max)
            return;

        ApplyToOther(lastSelf, lastOther, snappedObject);
    } else {
        //we need to find both new closest sides
        MeshSnapping other = snappedObject.GetComponent<MeshSnapping>();
        float otherDis = float.MaxValue;
        int otherSide = -1;
        //find the closest side from the other object
        for (int i = 0; i < NUM_SIDES; i++) {
            float dis = Vector3.Distance(transform.position, GetWorldPositionFace(snappedObject, i));
            if (dis < otherDis && other.sidesAllowed[i]) {
                otherDis = dis;
                otherSide = i;
            }
        }

        //find the closest side of our object
        float selfDis = float.MaxValue;
        int selfSide = 0;
        for (int i = 0; i < NUM_SIDES; i++) {
            float dis = Vector3.Distance(GetWorldPositionFace(this.gameObject, i),
                                            GetWorldPositionFace(snappedObject, otherSide));
            if (dis < selfDis && sidesAllowed[i]) {
                selfDis = dis;
                selfSide = i;
            }
        }


        //are we to far away or at a prohibited side?
        float max = Mathf.Max(Mathf.Abs(size.x), Mathf.Max(Mathf.Abs(size.y), Mathf.Abs(size.z)));
        if (selfDis > max)
            return;

        ApplyToOther(selfSide, otherSide, snappedObject);
        //save the sides for next iteration
        lastSelf = selfSide;
        lastOther = otherSide;
    }

    lastSnapping = Time.time;
}


private void OnCollisionEnter(Collision collision) {
    snappedObject = collision.gameObject;
}

private void OnCollisionExit(Collision collision) {
    snappedObject = null;
}

private Vector3 GetWorldPositionFace(GameObject other, int i) {
    //get the side in local coordinates, scaled to size
    Vector3 otherLocalSize = other.transform.localScale;
    Vector3 otherSidePoint = new Vector3(otherLocalSize.x * sides[i].x, otherLocalSize.y * sides[i].y, otherLocalSize.z * sides[i].z) / 2f;
    //rotate it according to world position
    Vector3 dir = (other.transform.rotation * otherSidePoint);
    //actually move it to world position
    Vector3 center = other.transform.position + dir;
    return center;
}


private void ApplyToOther(int selfI, int otherI, GameObject other) {
    //first get the midpoint of face of other go
    Vector3 edge = GetWorldPositionFace(other, otherI);
    Vector3 dir = edge - other.transform.position;

    RotateSides(selfI, otherI, dir);

    selfI = (selfI + NUM_SIDES / 2) % NUM_SIDES;

    //get midpoint of face of self go
    edge += GetWorldPositionFace(this.gameObject, selfI) - transform.position;
    //now move towards the combination
    transform.position = edge;
}

private void RotateSides(int selfI, int otherI, Vector3 dir) {
    //rotate self side towards this point
    switch (selfI) {
        case 0: transform.up = -dir; break;
        case 1: transform.forward = -dir; break;
        case 2: transform.right = -dir; break;
        case 3: transform.up = dir; break;
        case 4: transform.forward = dir; break;
        case 5: transform.right = dir; break;
    }

}

我可以通过变换方向向量、应用对象当前的旋转和位置来找到边界框的每个中点(参见 GetWorldPositionFace() )。找到最佳组合后,ApplyToOther() 将对象移动到某个位置并根据选定的面法线旋转它。到目前为止一切顺利,但结果不一致。如您所见,正面并不朝向同一方向,即我想将上部立方体围绕 transform.up 轴旋转这个量。将是我想要的结果。

但是,如果我添加

float angle = Vector3.Angle(transform.forward, snappedObject.transform.forward);
transform.Rotate(transform.up, angle);

到 RotateSides() 函数,结果是this。旋转轴不对。

使用

Quaternion.FromToRotation(transform.up, snappedObject.transform.up)

也没有工作。

我错过了什么?谢谢你的帮助!

4

1 回答 1

0

我发现了我的问题。通过分别设置transform.forward 和transform.up(例如,使用transform.rotate 绕轴),其中只有一个是正确的。使用Quaternion.LookRotation()解决了这个问题。

于 2018-12-10T10:02:45.777 回答