protected override bool DetectSetup() { finalDirection = direction; SetConstraints(finalDirection); return(true); }
private float CalculateValue() { if (!subDirectionFound) { float angleX = Mathf.Abs(transform.localRotation.eulerAngles.x - initialLocalRotation.x) % 90; float angleY = Mathf.Abs(transform.localRotation.eulerAngles.y - initialLocalRotation.y) % 90; float angleZ = Mathf.Abs(transform.localRotation.eulerAngles.z - initialLocalRotation.z) % 90; angleX = (Mathf.RoundToInt(angleX) >= 89) ? 0 : angleX; angleY = (Mathf.RoundToInt(angleY) >= 89) ? 0 : angleY; angleZ = (Mathf.RoundToInt(angleZ) >= 89) ? 0 : angleZ; if (Mathf.RoundToInt(angleX) != 0 || Mathf.RoundToInt(angleY) != 0 || Mathf.RoundToInt(angleZ) != 0) { subDirection = angleX < angleY ? (angleY < angleZ ? KnobDirection.z : KnobDirection.y) : (angleX < angleZ ? KnobDirection.z : KnobDirection.x); subDirectionFound = true; } } float angle = 0; switch (subDirection) { case KnobDirection.x: angle = transform.localRotation.eulerAngles.x - initialLocalRotation.x; break; case KnobDirection.y: angle = transform.localRotation.eulerAngles.y - initialLocalRotation.y; break; case KnobDirection.z: angle = transform.localRotation.eulerAngles.z - initialLocalRotation.z; break; } angle = Mathf.Round(angle * 1000f) / 1000f; // not rounding will produce slight offsets in 4th digit that mess up initial value // Quaternion.angle will calculate shortest route and only go to 180 float value = 0; if (angle > 0 && angle <= 180) { value = 360 - Quaternion.Angle(initialRotation, transform.rotation); } else { value = Quaternion.Angle(initialRotation, transform.rotation); } // adjust to value scale value = Mathf.Round((min + Mathf.Clamp01(value / 360f) * (max - min)) / stepSize) * stepSize; if (min > max && angle != 0) { value = (max + min) - value; } return(value); }
private KnobDirection DetectDirection() { KnobDirection direction = KnobDirection.x; Bounds bounds = Utilities.GetBounds(transform); // shoot rays in all directions to learn about surroundings RaycastHit hitForward; RaycastHit hitBack; RaycastHit hitLeft; RaycastHit hitRight; RaycastHit hitUp; RaycastHit hitDown; Physics.Raycast(bounds.center, Vector3.forward, out hitForward, bounds.extents.z * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal); Physics.Raycast(bounds.center, Vector3.back, out hitBack, bounds.extents.z * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal); Physics.Raycast(bounds.center, Vector3.left, out hitLeft, bounds.extents.x * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal); Physics.Raycast(bounds.center, Vector3.right, out hitRight, bounds.extents.x * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal); Physics.Raycast(bounds.center, Vector3.up, out hitUp, bounds.extents.y * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal); Physics.Raycast(bounds.center, Vector3.down, out hitDown, bounds.extents.y * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal); // shortest valid ray wins float lengthX = (hitRight.collider != null) ? hitRight.distance : float.MaxValue; float lengthY = (hitDown.collider != null) ? hitDown.distance : float.MaxValue; float lengthZ = (hitBack.collider != null) ? hitBack.distance : float.MaxValue; float lengthNegX = (hitLeft.collider != null) ? hitLeft.distance : float.MaxValue; float lengthNegY = (hitUp.collider != null) ? hitUp.distance : float.MaxValue; float lengthNegZ = (hitForward.collider != null) ? hitForward.distance : float.MaxValue; // TODO: not yet the right decision strategy, works only partially if (Utilities.IsLowest(lengthX, new float[] { lengthY, lengthZ, lengthNegX, lengthNegY, lengthNegZ })) { direction = KnobDirection.z; } else if (Utilities.IsLowest(lengthY, new float[] { lengthX, lengthZ, lengthNegX, lengthNegY, lengthNegZ })) { direction = KnobDirection.y; } else if (Utilities.IsLowest(lengthZ, new float[] { lengthX, lengthY, lengthNegX, lengthNegY, lengthNegZ })) { direction = KnobDirection.x; } else if (Utilities.IsLowest(lengthNegX, new float[] { lengthX, lengthY, lengthZ, lengthNegY, lengthNegZ })) { direction = KnobDirection.z; } else if (Utilities.IsLowest(lengthNegY, new float[] { lengthX, lengthY, lengthZ, lengthNegX, lengthNegZ })) { direction = KnobDirection.y; } else if (Utilities.IsLowest(lengthNegZ, new float[] { lengthX, lengthY, lengthZ, lengthNegX, lengthNegY })) { direction = KnobDirection.x; } return(direction); }
protected override bool DetectSetup() { finalDirection = direction; if (cjCreated) { cj.angularXMotion = ConfigurableJointMotion.Locked; cj.angularYMotion = ConfigurableJointMotion.Locked; cj.angularZMotion = ConfigurableJointMotion.Locked; switch (finalDirection) { case KnobDirection.x: cj.angularXMotion = ConfigurableJointMotion.Free; break; case KnobDirection.y: cj.angularYMotion = ConfigurableJointMotion.Free; break; case KnobDirection.z: cj.angularZMotion = ConfigurableJointMotion.Free; break; } } if (cj) { cj.xMotion = ConfigurableJointMotion.Locked; cj.yMotion = ConfigurableJointMotion.Locked; cj.zMotion = ConfigurableJointMotion.Locked; if (connectedTo) { cj.connectedBody = connectedTo.GetComponent <Rigidbody>(); } } return(true); }
protected override bool DetectSetup() { finalDirection = direction; if (cjCreated) { cj.angularXMotion = ConfigurableJointMotion.Locked; cj.angularYMotion = ConfigurableJointMotion.Locked; cj.angularZMotion = ConfigurableJointMotion.Locked; switch (finalDirection) { case KnobDirection.x: cj.angularXMotion = ConfigurableJointMotion.Free; break; case KnobDirection.y: cj.angularYMotion = ConfigurableJointMotion.Free; break; case KnobDirection.z: cj.angularZMotion = ConfigurableJointMotion.Free; break; } } if (cj) { cj.xMotion = ConfigurableJointMotion.Locked; cj.yMotion = ConfigurableJointMotion.Locked; cj.zMotion = ConfigurableJointMotion.Locked; if (connectedTo) { cj.connectedBody = connectedTo.GetComponent<Rigidbody>(); } } return true; }
private void SetConstraints(KnobDirection direction) { if (!rb) { return; } rb.constraints = RigidbodyConstraints.FreezeAll; switch (direction) { case KnobDirection.x: rb.constraints -= RigidbodyConstraints.FreezeRotationX; break; case KnobDirection.y: rb.constraints -= RigidbodyConstraints.FreezeRotationY; break; case KnobDirection.z: rb.constraints -= RigidbodyConstraints.FreezeRotationZ; break; } }
private KnobDirection DetectDirection() { KnobDirection direction = KnobDirection.x; Bounds bounds = Utilities.GetBounds(transform); // shoot rays in all directions to learn about surroundings RaycastHit hitForward; RaycastHit hitBack; RaycastHit hitLeft; RaycastHit hitRight; RaycastHit hitUp; RaycastHit hitDown; Physics.Raycast(bounds.center, Vector3.forward, out hitForward, bounds.extents.z * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal); Physics.Raycast(bounds.center, Vector3.back, out hitBack, bounds.extents.z * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal); Physics.Raycast(bounds.center, Vector3.left, out hitLeft, bounds.extents.x * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal); Physics.Raycast(bounds.center, Vector3.right, out hitRight, bounds.extents.x * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal); Physics.Raycast(bounds.center, Vector3.up, out hitUp, bounds.extents.y * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal); Physics.Raycast(bounds.center, Vector3.down, out hitDown, bounds.extents.y * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal); // shortest valid ray wins float lengthX = (hitRight.collider != null) ? hitRight.distance : float.MaxValue; float lengthY = (hitDown.collider != null) ? hitDown.distance : float.MaxValue; float lengthZ = (hitBack.collider != null) ? hitBack.distance : float.MaxValue; float lengthNegX = (hitLeft.collider != null) ? hitLeft.distance : float.MaxValue; float lengthNegY = (hitUp.collider != null) ? hitUp.distance : float.MaxValue; float lengthNegZ = (hitForward.collider != null) ? hitForward.distance : float.MaxValue; // TODO: not yet the right decision strategy, works only partially if (Utilities.IsLowest(lengthX, new float[] { lengthY, lengthZ, lengthNegX, lengthNegY, lengthNegZ })) { direction = KnobDirection.z; } else if (Utilities.IsLowest(lengthY, new float[] { lengthX, lengthZ, lengthNegX, lengthNegY, lengthNegZ })) { direction = KnobDirection.y; } else if (Utilities.IsLowest(lengthZ, new float[] { lengthX, lengthY, lengthNegX, lengthNegY, lengthNegZ })) { direction = KnobDirection.x; } else if (Utilities.IsLowest(lengthNegX, new float[] { lengthX, lengthY, lengthZ, lengthNegY, lengthNegZ })) { direction = KnobDirection.z; } else if (Utilities.IsLowest(lengthNegY, new float[] { lengthX, lengthY, lengthZ, lengthNegX, lengthNegZ })) { direction = KnobDirection.y; } else if (Utilities.IsLowest(lengthNegZ, new float[] { lengthX, lengthY, lengthZ, lengthNegX, lengthNegY })) { direction = KnobDirection.x; } return direction; }
private float CalculateValue() { if (!subDirectionFound) { float angleX = Mathf.Abs(transform.localRotation.eulerAngles.x - initialLocalRotation.x) % 90; float angleY = Mathf.Abs(transform.localRotation.eulerAngles.y - initialLocalRotation.y) % 90; float angleZ = Mathf.Abs(transform.localRotation.eulerAngles.z - initialLocalRotation.z) % 90; angleX = (Mathf.RoundToInt(angleX) >= 89) ? 0 : angleX; angleY = (Mathf.RoundToInt(angleY) >= 89) ? 0 : angleY; angleZ = (Mathf.RoundToInt(angleZ) >= 89) ? 0 : angleZ; if (Mathf.RoundToInt(angleX) != 0 || Mathf.RoundToInt(angleY) != 0 || Mathf.RoundToInt(angleZ) != 0) { subDirection = angleX < angleY ? (angleY < angleZ ? KnobDirection.z : KnobDirection.y) : (angleX < angleZ ? KnobDirection.z : KnobDirection.x); subDirectionFound = true; } } float angle = 0; switch (subDirection) { case KnobDirection.x: angle = transform.localRotation.eulerAngles.x - initialLocalRotation.x; break; case KnobDirection.y: angle = transform.localRotation.eulerAngles.y - initialLocalRotation.y; break; case KnobDirection.z: angle = transform.localRotation.eulerAngles.z - initialLocalRotation.z; break; } angle = Mathf.Round(angle * 1000f) / 1000f; // not rounding will produce slight offsets in 4th digit that mess up initial value // Quaternion.angle will calculate shortest route and only go to 180 float value = 0; if (angle > 0 && angle <= 180) { value = 360 - Quaternion.Angle(initialRotation, transform.rotation); } else { value = Quaternion.Angle(initialRotation, transform.rotation); } // adjust to value scale value = Mathf.Round((min + Mathf.Clamp01(value / 360f) * (max - min)) / stepSize) * stepSize; if (min > max && angle != 0) { value = (max + min) - value; } return value; }