I am doing an experiment that I want to apply a force in one frame to a rigidbody using add force and I want it to be stop by friction at some displacement. I tried to calculate the force I need in the following code:
hitPosition = this.transform.position;
isHitRecord = true;
hitTime = DateTime.Now;
var gravityDivide = Vector3.ProjectOnPlane(Physics.gravity, groundNormal) * ridbody.mass;
var gravityFrictionDivide = Physics.gravity - gravityDivide;
var frictionForceAcceleration = bodyCollider.material.dynamicFriction * gravityFrictionDivide.magnitude;
var desiredV0 = (float)Math.Sqrt((2 * frictionForceAcceleration * distance));
var acceleration = desiredV0 / Time.fixedDeltaTime;
to calculate my desired v0 and apply the force with m * a, but the result is not quite what I want. What am I doing wrong? Any help appreciated
For instance, for displacement, the formula is speed = speed_initial^2 + 2accelerationdisplacement. Speed is 0, because you want to stop,
So drag (acceleration) = -speed_initial^2/(2*expected_displacement)
If you need an instant stop, you can generate an impulse opposite to the movement
Here’s an example
using UnityEngine;
public class Stop : MonoBehaviour
{
public Rigidbody rb;
public Vector3 dragAcc;
public bool doDrag;
public float expectedTime = 1;
public float expectedDisplacement = 5f;
public Vector3 positionStamp;
public float timeStamp;
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
OneFrameStop();
}
if (Input.GetKeyDown(KeyCode.X))
{
//dragAcc = CalculateDragWithTime(rb.velocity, expectedTime);
dragAcc = CalculateDragWithDisplacement(rb.velocity, expectedDisplacement);
rb.useGravity = false;
doDrag = true;
positionStamp = transform.position;
timeStamp = Time.time;
}
}
private void OneFrameStop()
{
Vector3 impulse = -rb.velocity; //just for testing
rb.AddForce(impulse, ForceMode.VelocityChange);
rb.useGravity = false;
}
private void FixedUpdate()
{
if (doDrag && rb.velocity.magnitude < 0.01f)
{
doDrag = false;
float displacement = (transform.position - positionStamp).magnitude;
float time = Time.time - timeStamp;
print($"Time: Expected {expectedTime}. Actual {time}. Displacement: Expected {expectedDisplacement}. Actual {displacement}");
}
if (doDrag)
{
rb.AddForce(dragAcc, ForceMode.Acceleration);
}
}
private static Vector3 CalculateDragWithTime(Vector3 velocity, float expectedTime)
{
return -velocity / expectedTime;
}
private static Vector3 CalculateDragWithDisplacement(Vector3 velocity, float expectedDisplacement)
{
float speed = velocity.magnitude;
return (-speed * speed) / (2f * expectedDisplacement) * velocity.normalized;
}
}