[Fix] Closest Quaternion
This commit is contained in:
@@ -619,9 +619,9 @@ RectTransform:
|
|||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 1599947843}
|
- {fileID: 1599947843}
|
||||||
- {fileID: 959545886}
|
- {fileID: 959545886}
|
||||||
|
- {fileID: 4208645783119030842}
|
||||||
- {fileID: 3765562131710099388}
|
- {fileID: 3765562131710099388}
|
||||||
- {fileID: 4795592279549688925}
|
- {fileID: 4795592279549688925}
|
||||||
- {fileID: 4208645783119030842}
|
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
|||||||
@@ -44,6 +44,12 @@ namespace YachtDice.Dice
|
|||||||
return e.Value;
|
return e.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Quaternion GetClosestTopAlignedWorldRotation(Quaternion currentWorldRotation)
|
||||||
|
{
|
||||||
|
var e = GetExtremeEntryByWorldY(isTop: true);
|
||||||
|
return GetClosestAlignedWorldRotation(e.Point, currentWorldRotation);
|
||||||
|
}
|
||||||
|
|
||||||
public int AlignToBottomByLocalAngles()
|
public int AlignToBottomByLocalAngles()
|
||||||
{
|
{
|
||||||
var e = GetExtremeEntryByWorldY(isTop: false);
|
var e = GetExtremeEntryByWorldY(isTop: false);
|
||||||
@@ -82,6 +88,28 @@ namespace YachtDice.Dice
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Quaternion GetClosestAlignedWorldRotation(Transform facePoint, Quaternion currentWorldRotation)
|
||||||
|
{
|
||||||
|
if (!facePoint) throw new InvalidOperationException("Dice: facePoint == null.");
|
||||||
|
|
||||||
|
var baseWorldRotation = GetAlignedWorldRotation(facePoint);
|
||||||
|
var bestWorldRotation = baseWorldRotation;
|
||||||
|
var smallestAngle = Quaternion.Angle(currentWorldRotation, baseWorldRotation);
|
||||||
|
|
||||||
|
for (var i = 1; i < 4; i++)
|
||||||
|
{
|
||||||
|
var candidateWorldRotation = Quaternion.AngleAxis(90f * i, Vector3.up) * baseWorldRotation;
|
||||||
|
var candidateAngle = Quaternion.Angle(currentWorldRotation, candidateWorldRotation);
|
||||||
|
|
||||||
|
if (candidateAngle >= smallestAngle) continue;
|
||||||
|
|
||||||
|
smallestAngle = candidateAngle;
|
||||||
|
bestWorldRotation = candidateWorldRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestWorldRotation;
|
||||||
|
}
|
||||||
|
|
||||||
private Entry GetExtremeEntryByWorldY(bool isTop)
|
private Entry GetExtremeEntryByWorldY(bool isTop)
|
||||||
{
|
{
|
||||||
if (_entrySet == null || _entrySet.Count == 0)
|
if (_entrySet == null || _entrySet.Count == 0)
|
||||||
@@ -118,11 +146,23 @@ namespace YachtDice.Dice
|
|||||||
return a > 180f ? a - 360f : (a < -180f ? a + 360f : a);
|
return a > 180f ? a - 360f : (a < -180f ? a + 360f : a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Quaternion GetAlignedWorldRotation(Transform facePoint)
|
||||||
|
{
|
||||||
|
var parentRotation = transform.parent != null ? transform.parent.rotation : Quaternion.identity;
|
||||||
|
return parentRotation * GetAlignedLocalRotation(facePoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Quaternion GetAlignedLocalRotation(Transform facePoint)
|
||||||
|
{
|
||||||
|
if (!facePoint) throw new InvalidOperationException("Dice: facePoint == null.");
|
||||||
|
return Quaternion.Inverse(facePoint.localRotation);
|
||||||
|
}
|
||||||
|
|
||||||
private void AlignByFaceLocalAngles(Transform facePoint)
|
private void AlignByFaceLocalAngles(Transform facePoint)
|
||||||
{
|
{
|
||||||
if (!facePoint) throw new InvalidOperationException("Dice: facePoint == null.");
|
if (!facePoint) throw new InvalidOperationException("Dice: facePoint == null.");
|
||||||
|
|
||||||
transform.localEulerAngles = Vector3.Scale(facePoint.localEulerAngles, new Vector3(-1f, -1f, -1f));
|
transform.localRotation = GetAlignedLocalRotation(facePoint);
|
||||||
|
|
||||||
var e = transform.localEulerAngles;
|
var e = transform.localEulerAngles;
|
||||||
transform.localEulerAngles = new Vector3(Norm180(e.x), Norm180(e.y), Norm180(e.z));
|
transform.localEulerAngles = new Vector3(Norm180(e.x), Norm180(e.y), Norm180(e.z));
|
||||||
|
|||||||
@@ -157,14 +157,12 @@ namespace YachtDice.Dice
|
|||||||
// ── 4. Ждём пока кубик успокоится ───────────────────────────
|
// ── 4. Ждём пока кубик успокоится ───────────────────────────
|
||||||
var stillTimer = 0f;
|
var stillTimer = 0f;
|
||||||
var sqrThreshold = settleSpeed * settleSpeed;
|
var sqrThreshold = settleSpeed * settleSpeed;
|
||||||
var didTimeout = false;
|
|
||||||
var maxDuration = Mathf.Max(0.1f, maxRollDuration);
|
var maxDuration = Mathf.Max(0.1f, maxRollDuration);
|
||||||
|
|
||||||
while (stillTimer < settleDelay)
|
while (stillTimer < settleDelay)
|
||||||
{
|
{
|
||||||
if (Time.time - rollStartedAt >= maxDuration)
|
if (Time.time - rollStartedAt >= maxDuration)
|
||||||
{
|
{
|
||||||
didTimeout = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,13 +187,7 @@ namespace YachtDice.Dice
|
|||||||
|
|
||||||
// ── 6. Плавный доворот до ровного положения ─────────────────
|
// ── 6. Плавный доворот до ровного положения ─────────────────
|
||||||
Quaternion startRot = transform.rotation;
|
Quaternion startRot = transform.rotation;
|
||||||
|
Quaternion targetRot = dice.GetClosestTopAlignedWorldRotation(startRot);
|
||||||
// Вычисляем целевой поворот через Dice.AlignToTopByLocalAngles
|
|
||||||
dice.AlignToTopByLocalAngles();
|
|
||||||
Quaternion targetRot = transform.rotation;
|
|
||||||
|
|
||||||
// Откатываемся обратно — будем интерполировать
|
|
||||||
transform.rotation = startRot;
|
|
||||||
|
|
||||||
var elapsed = 0f;
|
var elapsed = 0f;
|
||||||
var snapTime = Mathf.Max(0.01f, snapDuration);
|
var snapTime = Mathf.Max(0.01f, snapDuration);
|
||||||
|
|||||||
Reference in New Issue
Block a user