0
\$\begingroup\$

How can I limit the position of a rigidbody, between two values ​​if I use this code:

public Vector3 dir;

Rigidbody rb;

void Awake()
{
    rb = GetComponent<Rigidbody>();
}

void FixedUpdate()
{
    rb.velocity = new Vector3(0f, 0f, 6f);

    rb.AddForce(dir * 1f, ForceMode.VelocityChange);
}

If I use Vector3.Clamp then the object will shake

\$\endgroup\$
  • 1
    \$\begingroup\$ This body appears to be able to move in 3 dimensions. Do you want to limit it to within an axis-aligned rectangular prism in worldspace, or some other shape of volume? And are there any other physics interactions acting on this body, such as collisions from other objects? \$\endgroup\$ – DMGregory Mar 25 at 14:28
  • \$\begingroup\$ Do you happen to have some kind of "play area" and are looking for some way to prevent objects from leaving it? \$\endgroup\$ – Philipp Mar 25 at 16:04
  • \$\begingroup\$ @DMGregory, In world space along the x axis. Yes, I have a play area. \$\endgroup\$ – Aimon Z. Mar 25 at 18:01
  • \$\begingroup\$ And can this object move on any other axes? Should we permit/preserve motion on those axes? \$\endgroup\$ – DMGregory Mar 25 at 18:03
  • \$\begingroup\$ @DMGregory, Yes, on other axes the object can move \$\endgroup\$ – Aimon Z. Mar 25 at 18:04
2
\$\begingroup\$

Your problem is the use of FixedUpdate() for position clamping. You are correct to apply the forces in FixedUpdate() but clamping the position should be done in Update() or LateUpdate().

public Vector3 dir;
public Vector3 min;
public Vector3 max;

Rigidbody rb;

void Awake()
{
    rb = GetComponent<Rigidbody>();
}

void FixedUpdate()
{
    rb.velocity = new Vector3(0f, 0f, 6f);

    rb.AddForce(dir * 1f, ForceMode.VelocityChange);
}

void Update()
{
    transform.position = new Vector3(
        Mathf.Clamp(transform.position.x, min.x, max.x),
        Mathf.Clamp(transform.position.y, min.y, max.y),
        Mathf.Clamp(transform.position.z, min.z, max.z));
}

FixedUpdate() is frame-rate independent, which means that there are frames happening in between those calculations. The GameObject's position however is recalculated for every frame. The reason you are seeing shaking when clamping in FixedUpdate() is that there is a force on the object that would cause it to move, causing the position in each frame to be calculated as the distance moved from the last frame, but then you are clamping it at a different rate than the framerate so it returns to the clamped value every few frames.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I don't recommend mixing physics and non-physics (transform) manipulation on a single object. This will disable interpolation on the rigidbody, which can make your movement look juddery, and can teleport the object into obstacles, leading to tunnelling or other incorrect collision resolution. \$\endgroup\$ – DMGregory Mar 26 at 10:38
2
\$\begingroup\$

We can also use physics itself to do the clamping, at the end of each FixedUpdate:

// Project where our velocity will take us by the end of the frame.
Vector3 positionAtEndOfStep = rb.position + rb.velocity * Time.deltaTime;

// Limit that projected position to within our allowed bounds.
positionAtEndOfStep.x = Mathf.Clamp(positionAtEndOfStep.x, min, max);

// Compute a velocity that will take us to this clamped position instead.
Vector3 neededVelocity = (positionAtEndOfStep - rb.position)/Time.deltaTime;

// You can also calculate this as the needed velocity change/acceleration,
// and add it as a force instead if you prefer.
rb.velocity = neededVelocity;

In a step where we're moving toward the edge and about to cross it, this will slow but not quite stop the x velocity, without shifting the other components, so we arrive at the edge without crossing.

In a step where we're skating along the edge, this will zero-out the x velocity so we don't go past it. Velocity inward, away from the boundary, is preserved.

Note that if an object collides with this one midway through the step, that could add more velocity and nudge us past the barrier, but we'll correct in the next step.

For even tighter control, you can use a Joint component to limit the object's slide over one axis while leaving the others free. The physics engine will try to iteratively solve these constraints together with collisions that happen in the frame.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.