# How to make a ball move with constant velocity after a collision?

In my scene there is a player and a ball a few units above the ground. The ball has a rigidbody2D attached with zero gravity.

I built a "cage" with square sprites to simulate the edges.

I would like that after the player has hit the ball, the ball moves with a constant speed (no matter how strong the collision with the player is).

I want to recreate something like this after the collision:
https://www.youtube.com/watch?v=zsdPYFPTdw0

I wrote this code:

{
private Rigidbody2D rb;
private Vector2 lastVelocity;

private ConstantForce2D cf;

private Vector2 direction;
private Vector2 surfaceNormal;
[HideInInspector]
public float speed = 5;

[HideInInspector]
public float setTime = 5;

[HideInInspector]
public float smooth = 6;
private bool timeEnded = false;

private void Awake()
{
rb = GetComponent<Rigidbody2D>();
cf = GetComponent<ConstantForce2D>();
}

private void Update()
{
Debug.Log(rb.velocity.magnitude);

if (timeEnded)
rb.velocity = Vector2.Lerp(rb.velocity, Vector2.zero, smooth * Time.deltaTime);
}

private void FixedUpdate()
{
lastVelocity = rb.velocity;
}

private void OnCollisionEnter2D(Collision2D collision)
{
// QUANDO VIENE COLPITO
if (collision.collider.tag == "Player")
{
surfaceNormal = collision.contacts.normal;
direction = surfaceNormal.normalized;

//cf.force = direction * speed;
rb.AddForce(cf.force = direction * speed * Time.fixedDeltaTime);

StartCoroutine(StopBall());
}

// QUANDO COLPISCE IL MURO
if (collision.collider.tag == "Wall")
{
Vector2 surfaceNormal = collision.contacts.normal;
rb.velocity = Vector2.Reflect(lastVelocity, surfaceNormal);
}
}

IEnumerator StopBall()
{
yield return new WaitForSeconds(setTime);

timeEnded = true;
}
}


I still don't understand why the speed doesn't remain constant, why sometimes it's zero and why it depends on the force with which I hit it.

• Why specifically "using AddForce"? Forces are good for accelerating an object over a duration. If you want it to keep a constant velocity, then just setting the velocity directly could be a simpler route to that goal. – DMGregory Jul 30 '19 at 11:54
• Does it increase or decrease? Plus I don't think you should define the speed in the Update() method, just set it to 4 when you introduce it at the beginning of the script, like "private float speed = 4f;". If the speed decreases, perhaps it is because there is some drag with the surfaces? Be sure to check your physics parameters! – FSic Aug 2 '19 at 11:26

## 1 Answer

If the floor is smooth i.e. there is no drag from the surface, just use AddForce setting the ForceMode to Impulse, something like this:

    void FixedUpdate()
{
rb.AddForce(dirX, dirY, dirZ, ForceMode.Impulse);
}


It is important that you use Impulse as force mode, since otherwise the force is continuously applied on your rigidbody, therefore constantly increasing the acceleration; impulse will apply it once and then, if there is no drag, the rigidbody will keep moving with the same velocity. To stop after a set time, well there are multiple ways. One could be that as soon as you hit the ball you start a Coroutine that will set the rigidbody velocity to zero, for instance:

private IEnumerator StopBall() { yield return new WaitForSeconds(setTime); rb.velocity = Vector3.zero; }

and you call this in your script by using StartCoroutine(StopBall()); from your update method. Hope it helps!