- Home /
Weird Spring Oscillation Error
I am coding a spring-mass dampener system in Unity and I am having trouble keeping a consistent oscillation. When the damping value is 0, the spring should oscillate indefinitely (while maintaining the same amplitude). All the formulas I am using are checked by a professor, so no issue there. But my spring keeps overshooting or undershooting the amplitude if I leave it running for a while. How can I fix this?
Since you checked your formulas with your professor, then I assume you're controlling these physics yourself. Can you link the code you're using and, more importantly, where you're using it?
What do you mean where I am using it? The script is attached to the actual mass if that's what you're asking.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpringScript : $$anonymous$$onoBehaviour
{
private Rigidbody2D gObject;
private Vector2 appliedForce, displacement, staticDisplacement;
private static readonly float GRAVITY = 9.81f;
public float mass, stiffness, damping;
void Start()
{
//default values
stiffness = 40f;
damping = 0.5f;
staticDisplacement = transform.localPosition;
gObject = GetComponent<Rigidbody2D>();
mass = gObject.mass;
}
private void SetStaticDisplacement()
{
staticDisplacement.x = GetWeight().x / stiffness;
staticDisplacement.y = GetWeight().y / stiffness;
}
private void SetDisplacement()
{
SetStaticDisplacement();
displacement.x = staticDisplacement.x - transform.localPosition.x;
displacement.y = staticDisplacement.y - transform.localPosition.y;
}
private Vector2 GetSpringForce()
{
SetDisplacement();
return stiffness * displacement;
}
private Vector2 GetDampingForce()
{
return damping * gObject.velocity;
}
private Vector2 GetAppliedForce()
{
return GetWeight() + GetSpringForce() - GetDampingForce();
}
private Vector2 GetWeight()
{
mass = gObject.mass;
return new Vector2(0, -1 * mass * GRAVITY);
}
// Update is called once per frame
void FixedUpdate()
{
//Debug.Log("Position: " + transform.position);
//Debug.Log("Velocity: " + gObject.velocity);
//Debug.Log("weight: " + GetWeight());
//Debug.Log("SpringForce: " + GetSpringForce());
//Debug.Log("DampingForce: " + GetDampingForce());
//Debug.Log("Applied force: " + GetAppliedForce());
//Debug.Log("Displacement: " + displacement);
//Debug.Log("Static Displacement: " + staticDisplacement);
gObject.AddForce(GetAppliedForce(), Force$$anonymous$$ode2D.Force);
}
}
You're creating and applying gravitational force yourself. Is built-in gravity turned off for the Rigidbody2D?
Answer by Eno-Khaon · Oct 03, 2018 at 06:48 PM
The inaccuracy you're seeing is likely the result of iterative physics calculations being performed. For an idea of why, consider this:
When you apply spring force, you're applying as much as the current frame (physics-based, so FixedUpdate()) will provide. As a baseline, that means you should have 1/50-second granularity.
But let's say you have 1-second granularity instead. The force applied by the spring at each given calculation would be 50 times stronger, when the true, realistic application of force is constantly applied.
This results in forces being applied which will be either stronger or weaker than expected, depending on where the last calculation was made relative to each new one. For instance, when the timing winds up just right, points can be skipped where a strong-enough force would be applied to stop its motion at an end, resulting in a larger range of oscillation.
Inaccuracy will occur as a direct result, with the margin of error reduced by the number of calculations made in the same span of time.
Edit: Added a little more detail
To follow up, game physics systems are meant to be fast and dirty. Someone probably worked hard to get a 30% speed-up in exchange for merely 1% more error.
The math for springs is pretty easy. $$anonymous$$ay as well code it all yourself.
Thanks, that helps me understand the issue. But is there no feasible was to fix those irregularities?
Because right now it sounds like it's an issue with how often each calculation is computed (which is out of my hands). And I did code the spring mechanism by myself ins$$anonymous$$d of using the SpringJoint2D component (it didn't have the right parameters that I needed).