How to bounce one object correctly?

My object is an arrow.

Arrow should bounce off the walls.

After the collision, the object (sprite) must rotate in the direction of movement.

My problem is that sometimes the arrow instead of bouncing, for example, to the left - it bounces to the right, which makes it look very strange.

Does anyone know how to solve this problem?

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

public class TestFollow : 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;

		// 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>();


		}
	public void Update ()
	{

		rb.velocity = currSpeed;
		
		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;

			}
		}
	}


		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"))
						Debug.Log ("hit");
					{

						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;
		}

}

Here is the video

https://gfycat.com/SoupyPointlessAmericanindianhorse

First of all, your script always rotates the arrow 90 degrees counterclockwise(at least i think that counterclockwise is the positive direction). That means that the bounce only works as intended when the left side of the arrow hits the wall. When the right side hits first, it rotates the arrow so that it faces the wall, instead of away from it, which makes it rotate 90 degrees again.


Luckily for you, unity has some great built-in tools for bouncing objects (and physical simulations in general). If you are moving your arrow by adding a force or setting a velocity, you can use a “Physics material 2D” to do all the simulation for you.


Here’s a possible solution that you can use. Assuming that you want your arrow to move at a constant speed, you should first of all set the velocity of the arrow to a constant value each update like this:

void Update () {
    gameobject.getComponent<Rigidbody2D>().velocity = moveSpeed;
}

This piece of code is run just before each frame, and should be placed just after your Start() method instead of your OnCollisionEnter2D. Now you just have to add a “Physics material 2D” material to your arrow. To create one of these materials, right-click in the asset folder that you want it, and select it under the “create” menu as shown below:



Now you should have a new material. Select the material, and set the bounciness to whatever you want (0 means no bounce at all, 1 means all force is preserved). I think you want to set it to 1. Also, you should probably set the friction to 0.


124935-untitled2.png


Now it’s time to add this material to your arrow. Select your arrow in the inspector, and look at its Rigidbody2D. There you should see a field called “Material” with a little button on the side. Click on the button, and select your newly created material from the menu that just popped up…


(i would add another image here, but i am only allowed two images in each answer. Too bad)


EDIT:
You also have to add a 2D collider component to your arrow. You do that by selecting your gameobject, going the the inspector and pressing the “Add component” beneath all the gameobjects components button. Then search for “2d collider” and add the collider that fits your gameobject best. In this case i would recommend the “2d polygon collider”. It creates a collider that approximates the sprite of the gameobject.

And Voilà, now your arrow should bounce perfectly off all other colliders (At this point I’m assuming that your wall has a collider component attached).