- Home /
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
Answer by Aske_Johansen · Sep 21, 2018 at 02:18 AM
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.
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).
Thanks for the answer, but unfortunately it does not work :( However, I appreciate the comprehensive answer
Actually, now that you mention it, i forgot something. Your arrow has to have a 2d collider attached for it to work (There are many different kinds). You can add one in the inspector by pressing the "Add Component" and searching for "2d collider". You probably want the polygon collider.
Hi. Thanks for the answer. $$anonymous$$y object has two colliders. The first one has also added psychic materials 2d with 0-0
I had to do it because otherwise the arrow did not bounce off the wall but was stuck in it (the arrow collider entered the wall collider)
Here you can read about it: http://johnstejskal.com/wp/setting-up-your-characters-2d-colliders-in-unity/ It's something similar :)
Your answer
Follow this Question
Related Questions
Reflecting Objects off of Boundaries/Walls 2 Answers
Making a pong-like game, and want the ball to reflect according to where on the paddle it hits 1 Answer
How can I get gameObject's all script components? 1 Answer
Balls bounce off wall in different ways 1 Answer
2D pong, bouncer - ball movement, friction, bounciness, speed [screenshot] 2 Answers