0
\$\begingroup\$

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[0].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[0].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.

\$\endgroup\$
  • \$\begingroup\$ 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. \$\endgroup\$ – DMGregory Jul 30 at 11:54
  • \$\begingroup\$ 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! \$\endgroup\$ – FSic Aug 2 at 11:26
1
\$\begingroup\$

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!

\$\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.