Switching a velocity from one rigid body to another in unity

I have a set up where the ground and the player move with physics and a stationary camera.

I want the ground to move faster when the player is getting further away making it look that the player is moving faster without getting further away from the camera.

The way I first thought was to just add the player velocity to the ground velocity, since velocity doesn't care about mass, and set the player velocity to 0.

On the player script:

    public void MovePlayer(Vector3 force)
{
}

private void FixedUpdate()
{
if (rb.position.z > 10)
{
PlatformManager.PlayerVelocity = rb.velocity.z;
rb.velocity = new Vector3(rb.velocity.x, rb.velocity.y, 0);
}
else
{
PlatformManager.PlayerVelocity = 0;
}
}


On the ground script:

      //On the fixed update
if (playerVelocity > 0)
{
rb.velocity = (Vector3.back * speedMultiplier) - new Vector3(0, 0, playerVelocity);
}
else
{
rb.velocity = Vector3.back * speedMultiplier;
}


Although this way the player stops at the set limit, because in the next frame its velocity is 0 and the ground velocity is back to regular.

So how could I achieve this? Do I need to calculate manually the velocity that would result in the player movement (with the force in MovePlayer) and set it to the ground? I can't use the force on the ground due to its mass difference.

• It's difficult to understand what you're trying to achieve from your question. You wrote "I want the ground to move faster" but weren't clear about how the ground is moving in relation to the player. From your code, it looks like you want the ground to move with the player on the Z axis, but without a better explanation or an animation, it's hard to guess how it looks now or how you want it to look. Mar 14, 2023 at 1:33
• The ground is moving on the opposite direction from the player, on the z axis. Mar 14, 2023 at 9:07
• And I said the "ground move faster (...) making it look like the player is moving faster" I can try to edit the question later but I believe its pretty clear. I need something like the player to be freezed on the z axis, while all its z axis velocity is transferred to the ground, on the opposite direction, making the player look that is moving faster while in reality is not moving Mar 14, 2023 at 9:14
• It is not "pretty clear". Is your game side-view? Top-down? Isometric? What does "without getting further away from the camera" mean? You don't want the player to get further from the camera? Mar 15, 2023 at 2:06
• My best wild guess is that you have a top-down game and are trying to fake a jump by moving the ground down instead of the player up. That seems like an overly complicated, confusing solution. Maybe you should move the camera with the player if you want to maintain the distance from the player to the camera. Mar 15, 2023 at 2:08

Assuming that DMGregory's guess that you're making an endless runner is correct, your question suddenly makes sense and is answerable.

I think you are going about this the wrong way. Currently, you are moving the player with forces, but want a way to transfer the velocity from the player to the ground. As you've already discovered, this is somewhat of a headache.

I'd suggest not using forces for this, and controlling velocity manually. You would track the player's current speed separately from the physics engine. Then, you could offset the player on the Z-axis based on the current speed.

public class Player : MonoBehavior {
[SerializeField] private float currentSpeed;
[SerializeField] private float speedToDistanceFactor = .1f;
[SerializeField] private float maxDistance = 10f;
[SerializeField] private float collisionSlowdownFactor = 1f;
public float CurrentSpeed {
get => currentSpeed;
set {
currentSpeed = Mathf.Max(value, 0); //don't allow negative speed
}
}

//move us further away from the camera when we're going faster
void Update() {
var pos = transform.position;
pos.z = CurrentSpeed * speedToDistanceFactor;
pos.z = Mathf.Clamp(pos.z, 0, maxDistance);
transform.position = pos;
}

//slow down when we collide with a GO tagged "Obstacle", based on
//the mass of the object we hit.
//you will probably need to change/customize this logic
void OnCollisionEnter(Collision collision) {
if (collision.gameObject.CompareTag("Obstacle")) {
CurrentSpeed -= collision.body.mass * collisionSlowdownFactor;
}
}
}


Notice the OnCollisionEnter() function includes some basic logic for slowing the player down when they collide with an object. You can customize or replace this logic as needed.

Then the ground would move according to the current speed, for example:

public class Ground : MonoBehavior {
[SerializeField] private Player player;
[SerializeField] private Rigidbody body;

void Awake() { Assert.IsNotNull(player); }

void FixedUpdate() {
if (body != null) {
body.velocity = new Vector3(0, 0, -player.CurrentSpeed);
} else {
transform.Translate(0, 0, -player.CurrentSpeed * Time.deltaTime);
}
}
}


With this simple approach, we have one key value - player.CurrentSpeed. The player's z-position, and the movement of the ground, are both derived from this value. It's very simple and doesn't require transferring velocity from one object to another under certain conditions.

• I can only try to do this tomorrow, but will this emulate physics force? Speeding the player according to its mass? And moving on the update without the deltaTime wont create issues? Btw I am usic physics because i have collisions, this looks like wont be effective against higger speed collisions. Mar 17, 2023 at 7:08
• My suggestion is not to use forces. You can reduce the player speed when a collision occurs; I'll update my answer with an example. deltaTime is not necessary in the Player Update() function because the position is proportional to the player's speed. I'm not sure what you mean by "won't be effective against higher speed collisions". Are you referring to Continuous Collision Detection (CCD)? Mar 17, 2023 at 19:03
• I will have to try this method to see if it works as I intended, btw the obstacle should be "infinite" mass, the only mass I care is the player, that should affect the acceleration. And yes I am using CCD but I had a lot of trouble setting up a reliable collision set up since in most settings the player would "teleport" through the obstacles at reasonably low speeds. And changing position through transform.position seems that it will pass right through the obstacles Mar 17, 2023 at 19:25
• @Barreto You can rewrite the OnCollisionEnter() to slow down the player using whatever formula best suits your game. As far as moving the player, you can of course use rigidbody.MovePosition() instead of transform.position. This is a simple example, not a complete ready-to-ship solution. Mar 18, 2023 at 0:48
• I am very thankful for your efforts but after some thought and rest on the issue I have solved in a rather simple way I will post an answer when I have some time in case you are curious. This answers approach doesn't help much, since it changes the dynamics of the game and avoids the scenario proposed on the question. Apr 4, 2023 at 20:34