Skip to content

Instantly share code, notes, and snippets.

@pppoe252110
Last active March 27, 2025 08:08
Show Gist options
  • Save pppoe252110/b57bdb1f51934f1711b552124525db15 to your computer and use it in GitHub Desktop.
Save pppoe252110/b57bdb1f51934f1711b552124525db15 to your computer and use it in GitHub Desktop.
using UnityEngine;
[System.Serializable]
public class RotationConstraints
{
public Vector2 x = new Vector2(-30, 30);
public Vector2 y = new Vector2(-30, 30);
public Vector2 z = new Vector2(-5, 5);
}
public class FakeBreastSpring : MonoBehaviour
{
[Header("Spring Settings")]
[SerializeField] private float _springStrength = 6f;
[SerializeField] private float _damping = 2f;
[Header("Movement Sensitivity")]
[SerializeField] private float _positionSensitivity = 0.1f;
[SerializeField] private float _rotationSensitivity = 0.5f;
[Header("Rotation Constraints")]
[SerializeField] private RotationConstraints _rotationConstraints;
private Quaternion _initialLocalRotation;
private Quaternion _velocity;
private Vector3 _lastParentPosition;
private Quaternion _lastParentRotation;
private void Start()
{
_lastParentPosition = transform.parent.position;
_lastParentRotation = transform.parent.rotation;
_initialLocalRotation = transform.localRotation;
}
private void Update()
{
float deltaTime = Time.deltaTime;
// Calculate position-based rotation
Vector3 localPositionDelta = transform.InverseTransformVector(transform.parent.position - _lastParentPosition);
Vector3 positionRotation = new Vector3(
-localPositionDelta.y * _positionSensitivity * Mathf.Rad2Deg,
localPositionDelta.x * _positionSensitivity * Mathf.Rad2Deg,
0f);
// Calculate rotation-based rotation
Quaternion parentRotationDelta = transform.parent.rotation * Quaternion.Inverse(_lastParentRotation);
Vector3 rotationEuler = new Vector3(
FixAngle(parentRotationDelta.eulerAngles.x) * _rotationSensitivity,
FixAngle(parentRotationDelta.eulerAngles.y) * _rotationSensitivity,
FixAngle(parentRotationDelta.eulerAngles.z) * _rotationSensitivity);
// Apply both rotations
transform.localRotation *= Quaternion.Euler(positionRotation + rotationEuler);
// Spring physics
Quaternion targetVelocity = Quaternion.Inverse(transform.localRotation) * _initialLocalRotation;
// Damping
targetVelocity = Quaternion.Slerp(targetVelocity, Quaternion.Euler(Vector3.zero), deltaTime * _damping);
_velocity = Quaternion.Slerp(_velocity, targetVelocity, _springStrength * deltaTime);
transform.localRotation *= _velocity;
// Damping
transform.localRotation = Quaternion.Slerp(transform.localRotation, _initialLocalRotation, _damping * deltaTime);
// Apply constraints
Vector3 currentEuler = (transform.localRotation * Quaternion.Inverse(_initialLocalRotation)).eulerAngles;
currentEuler.x = Mathf.Clamp(FixAngle(currentEuler.x), _rotationConstraints.x.x, _rotationConstraints.x.y);
currentEuler.y = Mathf.Clamp(FixAngle(currentEuler.y), _rotationConstraints.y.x, _rotationConstraints.y.y);
currentEuler.z = Mathf.Clamp(FixAngle(currentEuler.z), _rotationConstraints.z.x, _rotationConstraints.z.y);
transform.localRotation = Quaternion.Euler(currentEuler) * _initialLocalRotation;
// Store current state for next frame
_lastParentPosition = transform.parent.position;
_lastParentRotation = transform.parent.rotation;
}
private float FixAngle(float angle)
{
// Normalize angle to [-180, 180] range
angle %= 360f;
if (angle > 180f) angle -= 360f;
if (angle < -180f) angle += 360f;
return angle;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment