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\$
2
  • \$\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
    Commented Jul 30, 2019 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
    Commented Aug 2, 2019 at 11:26

1 Answer 1

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

You must log in to answer this question.

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