Я сейчас пытаюсь привязать объекты (кубы, пирамиды, тора) вместе.Я назначил каждой грани ограничивающего прямоугольника объекты переменную «привязка разрешена» и при столкновении пытаюсь найти две ближайшие стороны друг к другу.Затем я перемещаю основной объект в сторону столкновения и поворачиваю его соответствующим образом.
Код выглядит следующим образом:
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)
тоже не сработало.
Что я пропустил?Спасибо за вашу помощь!