How to bounce the bullet?

I have bullet.

My script allows me to:

  1. Move the ball around the screen with a mouse

  2. After pressing the left mouse button, hold the bullet, change the sprite and choose the rotation (place where it will fire)

  3. After pressing the right mouse button, shoot it.

My problem?
The bullet after shooting doesn’t bounce off the walls and doesn’t rotate (face) in the moving direction.

My script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewFollow : MonoBehaviour {

        public Sprite sprite1; // Drag your first sprite here
        public Sprite sprite2;
        public float moveSpeed = 10f;
        bool mouseClicked = false;
        private SpriteRenderer spriteRenderer;
        bool rightClicked = false;
        private bool canClick = true;
        public float speed;
        public Rigidbody2D rb;

        // Use this for initialization

    void Start ()
    {

        spriteRenderer = GetComponent<SpriteRenderer>(); // we are accessing the SpriteRenderer that is attached to the Gameobject
        if (spriteRenderer.sprite == null) // if the sprite on spriteRenderer is null then
            spriteRenderer.sprite = sprite1; // set the sprite to sprite1

        rb = GetComponent<Rigidbody2D>();

    }

    Coroutine changeSpriteRoutine;
    WaitForSeconds wfs = new WaitForSeconds(0.05f);

    void OnCollisionEnter2D (Collision2D whatHitMe)
    {
        GameObject g = whatHitMe.gameObject;
        if (g.CompareTag("Background") || g.CompareTag("Enemy"))
        {
            if(changeSpriteRoutine == null)
                changeSpriteRoutine = StartCoroutine(ChangeTheDamnSprite());
            {

                if (g.CompareTag("Background") || g.CompareTag("Enemy"))
            {

                    float angle = Mathf.Atan2(rb.velocity.y, rb.velocity .x) * Mathf.Rad2Deg;
                    rb.rotation = angle - 90;


        }
    }
        }
    }

    IEnumerator ChangeTheDamnSprite() {
        spriteRenderer.sprite = sprite2;
        yield return wfs;
        spriteRenderer.sprite = sprite1;
        changeSpriteRoutine = null;
    }

    public void Update ()
    {

        transform.position = Vector2.Lerp (transform.position, Camera.main.ScreenToWorldPoint (Input.mousePosition), moveSpeed);

        Vector3 difference = Camera.main.ScreenToWorldPoint (Input.mousePosition) - transform.position;
        difference.Normalize ();

        {
            if (canClick)
            {
                if (Input.GetMouseButtonDown (0)) {
                    Debug.Log ("Left Mouse Button was pressed");
                    moveSpeed = 0f;
                    if (spriteRenderer.sprite == sprite1) { // if the spriteRenderer sprite = sprite1 then change to sprite2
                        spriteRenderer.sprite = sprite2;

                    }
                    mouseClicked = true; //register that the mouse has been clicked and the sprite is changed to sprite2
                    rightClicked = false;              
                    canClick = false;
                }
            }

        if (mouseClicked) {        //checks if sprite has already been changed
            Vector3 mousePos = Input.mousePosition;        //gets the current mouse position on screen
            int currentCase = 0;
            //following does a case-check on the position of your mouse with respect to the sprite:
            if (Camera.main.transform.position.x - (Screen.width/2) + mousePos.x < transform.position.x) {      
                if (Camera.main.transform.position.x - (Screen.height/2)+mousePos.y < transform.position.y) {
                    currentCase = 2;
                } else {
                    currentCase = 3;
                }
            } else {
                if (Camera.main.transform.position.x - (Screen.height/2)+mousePos.y < transform.position.y) {
                    currentCase = 1;
                } else {
                    currentCase = 0;
                }
            }
            //create a new rotation:
            transform.rotation = Quaternion.Euler (0, 0, 90 * currentCase);
        }
            {

                if (Input.GetMouseButton(1)) {
                    Debug.Log ("Pressed secondary button.");
                    rightClicked = true;
                    mouseClicked = false;

                }
                if(rightClicked)


                    transform.position += (transform.right + transform.up).normalized *  speed * Time.deltaTime;

            }
        }
    }
}

Could anyone fix my script? I am a bit desperate because I am improving it for weeks and I can not achieve anything.

The whole situation can be seen in the video:

https://gfycat.com/pl/gifs/detail/BothTerrificElephantbeetle

PS: My bullet call is called “Pill”.

What you need to look at is Vector2.Reflect - Unity - Scripting API: Vector2.Reflect.

The basic premise is that when the bullet collides with the wall, it reflects it.

I can’t check it right now as I don’t have time to open unity and play around but I did find this answer that may help - c# - Unity - how to use Vector2.Reflect() - Stack Overflow

void OnCollisionEnter(Collision collision)
{
    Vector2D inDirection = GetComponent<RigidBody2D>().velocity;
    Vector2D inNormal = collision.contacts[0].normal;
    Vector2D newVelocity = Vector2D.Reflect(inDirection, inNormal);
}

Ok. I changed the script a bit.

My script now:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewFollow : MonoBehaviour {

        public Sprite sprite1; // Drag your first sprite here
        public Sprite sprite2;
        public float moveSpeed = 10f;
        bool mouseClicked = false;
        private SpriteRenderer spriteRenderer;
        bool rightClicked = false;
        private bool canClick = true;
        public float speed;
        public Rigidbody2D rb;
    float constantSpeed = 10f;
    // stored in fixed update, to be used in OnCollisionEnter (which may have an altered value).
    Vector2 currSpeed;

        // Use this for initialization

    void Start ()
    {

        spriteRenderer = GetComponent<SpriteRenderer>(); // we are accessing the SpriteRenderer that is attached to the Gameobject
        if (spriteRenderer.sprite == null) // if the sprite on spriteRenderer is null then
            spriteRenderer.sprite = sprite1; // set the sprite to sprite1

        rb = GetComponent<Rigidbody2D>();

    }

    Coroutine changeSpriteRoutine;
    WaitForSeconds wfs = new WaitForSeconds(0.05f);

    void OnCollisionEnter2D (Collision2D whatHitMe)
    {
        GameObject g = whatHitMe.gameObject;
        if (g.CompareTag("Background") || g.CompareTag("Enemy"))
        {
            if(changeSpriteRoutine == null)
                changeSpriteRoutine = StartCoroutine(ChangeTheDamnSprite());
            {

                if (g.CompareTag("Background") || g.CompareTag("Enemy"))
                {

                    rb.velocity = Vector2.Reflect(currSpeed, whatHitMe.contacts[0].normal);
                    rb.rotation +=90;

        }
    }
        }
    }

    IEnumerator ChangeTheDamnSprite() {
        spriteRenderer.sprite = sprite2;
        yield return wfs;
        spriteRenderer.sprite = sprite1;
        changeSpriteRoutine = null;
    }

    public void Update ()
    {

        transform.position = Vector2.Lerp (transform.position, Camera.main.ScreenToWorldPoint (Input.mousePosition), moveSpeed);

        Vector3 difference = Camera.main.ScreenToWorldPoint (Input.mousePosition) - transform.position;
        difference.Normalize ();

        currSpeed = rb.velocity = constantSpeed * (rb.velocity.normalized);

        {
            if (canClick)
            {
                if (Input.GetMouseButtonDown (0)) {
                    Debug.Log ("Left Mouse Button was pressed");
                    moveSpeed = 0f;
                    if (spriteRenderer.sprite == sprite1) { // if the spriteRenderer sprite = sprite1 then change to sprite2
                        spriteRenderer.sprite = sprite2;

                    }
                    mouseClicked = true; //register that the mouse has been clicked and the sprite is changed to sprite2
                    rightClicked = false;              
                    canClick = false;
                }
            }

        if (mouseClicked) {        //checks if sprite has already been changed
            Vector3 mousePos = Input.mousePosition;        //gets the current mouse position on screen
            int currentCase = 0;
            //following does a case-check on the position of your mouse with respect to the sprite:
            if (Camera.main.transform.position.x - (Screen.width/2) + mousePos.x < transform.position.x) {      
                if (Camera.main.transform.position.x - (Screen.height/2)+mousePos.y < transform.position.y) {
                    currentCase = 2;
                } else {
                    currentCase = 3;
                }
            } else {
                if (Camera.main.transform.position.x - (Screen.height/2)+mousePos.y < transform.position.y) {
                    currentCase = 1;
                } else {
                    currentCase = 0;
                }
            }
            //create a new rotation:
            transform.rotation = Quaternion.Euler (0, 0, 90 * currentCase);
        }
            {

                if (Input.GetMouseButton(1)) {
                    Debug.Log ("Pressed secondary button.");
                    rightClicked = true;
                    mouseClicked = false;

                }
                if(rightClicked)


                    transform.position += (transform.right + transform.up).normalized *  speed * Time.deltaTime;

            }
        }
    }
}

I prepared a few code versions and in the best option(this code above), it looked like this:

https://gfycat.com/pl/gifs/detail/EarnestDeliriousHarrierhawk

Does anyone know how to make the bullet bounce normally? :slight_smile:

What do you mean normally, what happens now and what do you want to happen?

Try formatting your code a bit better, that will make it much easier to read.

Thanks for your answer.

If you watched the video (to which I posted the link) you should understand what happens now ( what is wrong). :wink:

The ball after a moment of reflection is like “suspended”.

It is not easy to write, that’s why I put a video.:face_with_spiral_eyes:

Sorry, only watched the beginning.

I’d really start by cleaning up your code, remove any unnecessary brackets and fix your indentation. Then add some debugging, put a debug log in your OnCollisionEnter to see when you reflect and when you dont. You can even use OnCollisionStay to determine when you keep colliding with the edges.

Thanks for good words :wink:
I know that my problem lies in this line:

rb.velocity = Vector2.Reflect(currSpeed, whatHitMe.contacts[0].normal);
                    rb.rotation +=90;

My gameObject (bullet) should rotate 90 degrees in the direction of movement after each hit.

I had a similar problem with another script and the situation was the same.

Unfortunately, that script has long been deleted and I don’t know how I solved that problem.:frowning:

Maybe you know another way how to rotate (my bullet) 90 degrees in the direction of moving after each bounce from the wall?

PS: I’m sorry for English, I’m still learning :wink:

Can you verify that that line is executed when it sticks?

Add a debug log there and see if it happens when you think it does, and not too often.

Hi.

I made a smaller circle collider that I had added to the face (in video YELLOW part) of the bullet and now it is not stuck, but the bullet falls out of the screen.

I added Debu.Log to check and it detects everything - every hit and rotation.

The same situation is when I exchange circle collider 2d for polygon collider 2d.

That’s how it looks now:

https://gfycat.com/pl/gifs/detail/BadMiserlyFowl
 rb.rotation +=90;

Whats this for ?
If you get wrong normal direction for what ever reason multiply it with -1.0f.
Also consider reading the description of functions witch say you should use GetContacts instead of of contacts.

ContactPoint2D[] myContact = new ContactPoint2D[1];
    void OnCollisionEnter2D (Collision2D collider)
    {
        collider.GetContacts(myContact);
        //do stuff with myContact[0].normal;
        //or if the behavior is mirrored with (myContact[0].normal * -1.0f)
    }

I use it to rotate (gameObject - sprite called “Pill”) 90 degrees in the direction of movement after each hit.

I guess that’s what you try to do.

    float speed = 0.1f;
    Vector2 direction = new Vector3(0.7f,0.7f);
    ContactPoint2D[] myContact = new ContactPoint2D[1];


    void OnCollisionEnter2D (Collision2D collider)
    {
        collider.GetContacts(myContact);
        direction = Vector2.Reflect(direction, myContact[0].normal);
        this.transform.rotation = Quaternion.LookRotation(new Vector3(direction.x,direction.y,0.0f));
    }


    public void Update ()
    {
        this.transform.position += new Vector3(direction.x,direction.y,0.0f) * speed;
    }

This works with rigid body set to kinematic.

1 Like

Thanks for this script, but I will look for another option.
Sending rigidbody 2d to kinematic, will cause that the bullet won’t bounce off the walls and I will have to make many changes in the script.

In addition, the script has disabled bouncing with 90 degrees in the direction of movement after each hit.

However, thank you for the script, maybe someday I will use it :slight_smile:

Actually the script lets the bullet bounce off walls it collides with.

I also still do not get why you want to use + 90 degrees if your bullet is moving at a wall with a direction of 315 you will rotate it to 405 degree. Or when it fly’s straight up at 0 degree and you rotate it +90 degrees it will fly parallel with the wall at 90 degree…


Also if for what ever reason you want 90 degree bounce don’t use Vector2.Reflect instead go with cousins and sinus.

Because without rb.rotation +=90; there is no bullet rotation moment.

The impact is detected, but there is no rotation.

That’s how it looks then:

https://gfycat.com/pl/gifs/detail/FlakyPinkAmphiuma

Also, with your corrections, I can’t choose a place where I shoot.

As you can see on the video, after pressing the left mouse button, I can choose four directions:
1)up right
2)down right
3)down left
4)up left

When I add your script, the ball flies only in the up right direction.

Only cause it looks more wrong without +90 it wont make +90 the right way to do it also it always moves top right cause the direction is set to 0.7,0.7… (cos and sin of 45°)

Also the script is there to show you how to implement a bouncing object not to replace your whole code…

Ok, I think I know what’s wrong but I do not know how to solve it.

If I add to the rb.rotation “+” the bullet is reflected only in the right side (which causes stuck or fall out when it should bounce left).

Analogous situation with a “-”, but this time bullet reflected only left.

However without “+” or “-” bullet doesn’t bounce at all.

please check the below code, apply it to bullet which should have rigidbody with gravity 0 and a circle collider 2d

public float speed;

private void Update()
{
transform.Translate(Vector2.up * Time.deltaTime * speed);
}

private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.gameObject.tag == “wall”)
{
ContactPoint2D point = collision.contacts[0];
Vector2 newDir = Vector2.zero;
Vector2 curDire = this.transform.TransformDirection(Vector2.up);

newDir = Vector2.Reflect(curDire, point.normal);
transform.rotation = Quaternion.FromToRotation(Vector2.up, newDir);
}
}

Is that a solution or a problem??? :eyes:

Maybe no one needs it . But here are my two solutions. I wanted to use collider as trigger only.

It is with Raycast and working fine.

    private void OnTriggerEnter2D(Collider2D collision)
    {

        if (//collided with player)
        {
           //do damage and destroy
        }
        else if(collision && collision.gameObject != _sender.gameObject)
        {
            Physics2D.queriesStartInColliders = false;
            RaycastHit2D hit = Physics2D.Raycast(_rigidBody.position, _rigidBody.velocity);
             if (hit)
             {
                    Vector2 inDirection = _rigidBody.velocity;
                    Vector2 inNormal = hit.normal;
                    Vector2 newVelocity = Vector2.Reflect(inDirection, inNormal);
                    _rigidBody.velocity = newVelocity.normalized * _speed;
             }
            Physics2D.queriesStartInColliders = _cachedQueryStartInColliders;
        }
    }

Ref: