Random direction increases/decreases speed, can't use normalized property

Hello! I’m trying to make my game objects bounce off of walls after starting in random directions. Thanks to these forums I’ve pieced together some code that works really well, except that I can’t get the speed for each object to be consistent. When the X and Y direction of the object is too high or low, it changes the speed of the object, similar to the issue presented in this thread.

However, the solution in that thread doesn’t work here. When I use .normalized to make the speed the same, it nullifies my random direction! I can see in the Inspector that the random direction is still being set, it’s just making my Vector2 = (1,0) or (0,1) always, so my objects are bouncing around the screen in the exact same directions.

Is there an alternative to normalizing the direction that will allow me to keep the random directions as well as a constant speed?

Here is my code. When I take out the .normalized, it does do random directions, but then the balls bounce around at all different speeds.

I’m instantiating about 100 random balls as I test this out.

Any solutions/ideas are welcome!!

using UnityEngine;

public class BallMovement : MonoBehaviour
{
    public Rigidbody2D rb;
    public float ballSpeed = 1;

    public float dirX;
    public float dirY;

    public float posX;
    public float posY;
    public Vector2 ballPos;

    void Awake()
    {
        //Set random X and Y directions:
        dirX = Random.Range(-180, 180);
        dirY = Random.Range(-180, 180);
       
        //Set random position on the screen:
        posX = Random.Range(-10, 10);
        posY = Random.Range(-7, 7);

        //Place the ball at the random position:
        ballPos = new Vector2(posX, posY);
        gameObject.transform.position = ballPos;
    }

    void Update()
    {
        //Move in a random X and Y direction, normalized:
        transform.Translate(Vector2.right * new Vector2(dirX, 0).normalized * ballSpeed * Time.deltaTime);
        transform.Translate(Vector2.up * new Vector2(0, dirY).normalized * ballSpeed * Time.deltaTime);

    }

    void OnCollisionEnter2D(Collision2D coll)
    {


        if (coll.gameObject.tag == "XWall")
        {
            Debug.Log("Hit X");
            dirX *= -1;
        }

        if (coll.gameObject.tag == "YWall")
        {
            Debug.Log("Hit Y");
            dirY *= -1;
        }

        if (coll.gameObject.tag == "Ball")
        {
            Debug.Log("Hit Ball");
            Physics2D.IgnoreCollision(coll.gameObject.GetComponent<Collider2D>(), GetComponent<Collider2D>());
        }
    }
}

Hi!
Are you planning to use rigid bodies or simulating balls collision yourself through their transform ?

If you are planning to use rigid bodies, you can let it handle collision itself. Apply a force to the ball, and it should bounce on other colliders (you can decide which object will collide with which using layermasks and the collision matrix).

If you want to use transform, you can use circlecast (Unity - Scripting API: Physics2D.CircleCast). It’ll give you the normal, and then you can compute the bounce vector based on the normal and the ball direction.

Hope it helps.

1 Like

Thank you for your reply! I guess I need to decide which one I’m using and what are the benefits of each. I’ve actually made a few changes to the code since I posted this, going to explore a bit more and then update this with my findings…

Also that script reference article is suuuper helpful, thank you for sending this. I think it’s exactly the kind of thing that will work with my original code, which uses transform.

Alrighty, I think I found the solution! I did end up going with AddForce instead of Transform, and I like this solution much better. I was trying all sorts of things like clamping velocity, using Quaternions, etc.

The solution I found was much like you described above, simply using the rigidbody components. I also followed some of the cool random rotation script shown in this Pong how-to video to create my own ball movement script.

Here is the final code, works pretty much exactly how I want it to!

using UnityEngine;

public class BallMovement : MonoBehaviour
{
    public Rigidbody2D rb;
    public float ballSpeed;
    public float posX;
    public float posY;
    public Vector2 ballPos;
    void Awake()
    {
        ballSpeed = 50;
        rb = GetComponent<Rigidbody2D>();
      
        //Set random position on the screen:
        posX = Random.Range(-10f, 10f);
        posY = Random.Range(-7f, 7f);

        //Place the ball at the random position:
        ballPos = new Vector2(posX, posY);
        gameObject.transform.position = ballPos;
    }

    private void Start()
    {
        AddStartingForce();
    }

    private void AddStartingForce()
    {
        float dirX = Random.value < 0.5f ? Random.Range(-1.0f, -.2f) :
                                           Random.Range(.2f, 1f);
        float dirY = Random.value < 0.5f ? Random.Range(-1.0f, -.2f) :
                                           Random.Range(.2f, 1f);

        Vector2 ballDir = new Vector2(dirX, dirY);
        rb.AddForce(ballDir * ballSpeed);
    }


    private void OnEnable()
    {
        GameObject[] Balls = GameObject.FindGameObjectsWithTag("Ball");
        foreach (GameObject Ball in Balls)
        {
            Physics2D.IgnoreCollision(Ball.GetComponent<Collider2D>(), GetComponent<Collider2D>());
        }
    }
}