1
\$\begingroup\$

This code is for controlling a shark

I want to have continuous collision detection which won't work with MovePosition so I tried changing it other options but those are making the Shark Fly

Why does converting this line

Rb.MovePosition(transform.position + SharkCamera.transform.forward * CurrentSpeed * Time.fixedDeltaTime);

to this

Rb.velocity += SharkCamera.transform.forward * CurrentSpeed * Time.fixedDeltaTime; 

or this

Rb.AddForce(-transform.right * CurrentSpeed * Time.fixedDeltaTime, ForceMode.VelocityChange);

makes the Shark fly?

Note: Directly setting the velocity won't work because other forces are acting too

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

Let's recap some dimensional analysis:

  • a Displacement measured in \$m\$, which is different from...

  • a Velocity measured in \$\frac m s\$, which is different from...

  • a Force measured in \$\frac {kg \ m} s\$

Because these are different quantities, taking code for one and copying it into another will not yield the same effect.

Let's dimensionally analyze what you're trying to add:

SharkCamera.transform.forward * CurrentSpeed * Time.fixedDeltaTime

$$\require{cancel}\text{(dimensionless)} \cdot \frac m {\cancel s } \cdot \cancel s = m$$

So this is producing a value in metres, so it's a displacement. A displacement is not a velocity, so you can't add it to your velocity. What your code there does is keep adding more and more to your velocity every frame, so your object keeps getting faster and faster.

If you want to make the velocity point in a certain direction with a certain magnitude, just assign it with =, don't accumulate it with +=:

Rb.velocity = SharkCamera.transform.forward * CurrentSpeed;

Note that we don't need to multiply by delta time - we're not taking the speed and integrating it over a time interval to make a displacement, we're using the speed as a speed, natively. Repeating the dimensional analysis on this, we get \$ \frac m s\$, which is exactly the unit we expect for a velocity.

Try this exercise of checking whether your units make sense anytime you're doing anything with physics - it's a great debugger to spot when you're writing code that makes no sense.


To help this play more nicely with other forces, you can instead apply an acceleration toward your target velocity, rather than setting the velocity directly. That might look like this:

// Compute the velocity we want to have:
var targetVelocity = SharkCamera.transform.forward * CurrentSpeed;

// Compute its difference from our current velocity.
var deltaV = targetVelocity - Rb.velocity;

// Set a budget for how much we can change our velocity this frame.
var accelLimit = acceleration * Time.deltaTime;

// Scale our change so that it does not exceed the acceleration limit.
deltaV = Vector3.ClampMagnitude(deltaV, accelLimit);

// Apply the velocity change.
Rb.AddForce(deltaV, ForceMode.VelocityChange);

You can increase your acceleration parameter to make the controls tighter and more responsive, or decrease it to make more gradual ramp-up.

You can apply lots of other changes too - like taking some of Rb.velocity.y and blending it into targetVelocity.y, or scaling deltaV so that your vertical acceleration change is damped relative to horizontal, or scaling your acceleration limit by how closely the direction of velocity change aligns with the shark's forward axis, etc. Any of these techniques can help you dial in the right swimming feel.


You can also just get continuous collision detection with MovePosition and keep your existing code, contrary to your assumption that this is impossible.

Just scan for collisions before you move:

// Compute length of a full move.
var distance = CurrentSpeed * Time.deltaTime;

// Sweep a capsule from where we are to the end of the move.
if (Physics.CapsuleCast(
       transform.position - transform.forward * capsuleLength,
       transform.position + transform.forward * capsuleLength,
       capsuleRadius, 
       SharkCamera.transform.forward,
       out RaycastHit hitInfo,
       distance,
       obstacleLayers)
) {
    // If the swept test hits something, stop just a hair before the collision.
    distance = hitInfo.distance - 2 * Physics.defaultContactOffset;
}

Rb.MovePosition(transform.position + SharkCamera.transform.forward * distance);
\$\endgroup\$
1
  • \$\begingroup\$ Comments are not for extended discussion; this conversation has been moved to chat. \$\endgroup\$
    – Evorlor
    Commented Jul 1, 2022 at 20:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .