Search Unity

2D kinematic body that bounces off other surfaces, or dynamic body without acceleration?

Discussion in 'Physics' started by whitesmoque, May 9, 2019.

  1. whitesmoque

    whitesmoque

    Joined:
    Apr 30, 2019
    Posts:
    19
    TL;DR
    How do I make a ball that has no acceleration from outside forces, but can also handle collisions well enough to not pass through walls?

    I ran into a simple problem the other day, but the more I try to figure it out, the more it seems like there is no simple solution... I am currently making an atari break out clone, and I want to make a ball that bounces off of walls and also other rigid bodies that happen to be in the scene, such as creatures and people. The ball was a rigid body, I removed the gravity, and I added a material with no friction and a bounciness of 1. the ball did just fine and kept up a constant speed, but when it collided with other objects that were moving in the scene it slowed down... Eventually it slowed and slowed until the game was not playable.

    I made a thread about this in the 2D forum. A man of the name RockyWallbanger came along and told me that it was not possible to do such a thing with a dynamic body.
    He gave me this script that i attached to my ball;

    Code (CSharp):
    1. [RequireComponent(typeof(Rigidbody2D))]
    2. public class ConstantVelocity : MonoBehaviour
    3. {
    4.     //These are just to give the rigidbody an initial velocity
    5.     private float randomX;
    6.     private float randomY;
    7.  
    8.     private Rigidbody2D rb;
    9.  
    10.     private void Awake()
    11.     {
    12.         //Randomize the initial velocity
    13.         randomX = Random.Range(1f, 5f);
    14.         randomY = Random.Range(1f, 5f);
    15.  
    16.         //Get a reference to our Rigidbody2D component, set it's body type to Kinematic    
    17.         //UseFullKinematicContacts means this will still register collisions with the Physics2D system
    18.         rb = GetComponent<Rigidbody2D>();
    19.         rb.isKinematic = true;
    20.         rb.useFullKinematicContacts = true;
    21.  
    22.         //Set the initial velocity of the Rigidbody
    23.         rb.velocity = new Vector2(randomX, randomY);
    24.     }
    25.  
    26.     private void OnCollisionEnter2D(Collision2D collision)
    27.     {
    28.         //When we register a collision, we're going to get the first point of collision
    29.         //Then we just reflect our rigidbody about the contact normal, maintaining velocity
    30.         ContactPoint2D hit = collision.GetContact(0);
    31.         rb.velocity = Vector2.Reflect(rb.velocity, hit.normal);
    32.     }
    33.  
    34.     private void FixedUpdate()
    35.     {
    36.         //Logging the velocity magnitude will show us the speed not changing
    37.         //Note, you may see tiny tiny changes due to floating point precision
    38.         Debug.Log(rb.velocity.magnitude.ToString());
    39.     }
    40. }
    [/QUOTE]

    This worked. The problem of the ball slowing down was solved... However, here comes my new problem, and the reason I am taking this to the physics forum. Because I am out of ideas, and I do not really think anyone wants to read the big long thread to solve a problem that arose, due to a solution, especially since its physics based in the 2D forum. (if you do, here is a link to it.)

    Since I attached that script to the ball it bounces off of any collider it runs into, however when it hits corners, or where two colliders intersect and It hits two colliders at the same time it cannot register them both, and picks one of the colliders to register, and ignores the other such that it passes through that one.

    I tried setting the fixed timeset to .01 and that helped it to register corners better, but still when it hits multiple colliders at the exact same time, it ignores all but one...

    I am just not sure what to do It seems like such a simple thing; "make ball go and bounce off of things while remaining that speed." but I have been absolutely pulling my hair out over this issue. Any input you have I would appreciate.

    PS sorry if I make any rookie mistakes, I'm kindof new to unity, and i'm new to this forum, so let me know if I did something wrong or maybe broke some sort of rule about making too many threads about the same problem, if so, I am so sorry :eek:
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    I think it is possible with a dynamic body, by storing the initial velocity and enforcing that after a collision:

    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ConstantVelocity : MonoBehaviour {
    6.  
    7.     public float speed = 500.0f;
    8.     public Vector2 direction = Vector2.right;
    9.     float wantedVelocity;
    10.     Rigidbody2D rb;
    11.    
    12.     IEnumerator Start () {
    13.         rb = GetComponent<Rigidbody2D>();
    14.         rb.AddForce (direction.normalized * speed);
    15.         yield return new WaitForFixedUpdate();
    16.         wantedVelocity = rb.velocity.magnitude;
    17.     }
    18.    
    19.     void OnCollisionExit2D () {
    20.         if (rb.velocity.magnitude != wantedVelocity) {
    21.             var dir = rb.velocity.normalized;
    22.             rb.velocity = Vector2.zero;
    23.             rb.AddForce (dir * speed);
    24.         }
    25.     }
    26. }
    --Eric
     
  3. whitesmoque

    whitesmoque

    Joined:
    Apr 30, 2019
    Posts:
    19
    Ok, I tried out your script... Here is a video of what happened. The ball hit the wall and then stopped.
     
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    With such a tiny space you probably have a very low velocity. This is what I get.

    --Eric
     
  5. whitesmoque

    whitesmoque

    Joined:
    Apr 30, 2019
    Posts:
    19
    That looks like exactly what I have been wanting, however, its not giving me the same thing o_O... This is what I got, I noticed turning off rotation and gravity seems to fugger things up.

    Well atleast now I know there is hope.
     

    Attached Files:

  6. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    I did turn off gravity; freezing rotation has no effect either. Physics has problems with very big or small numbers, in case that might be an issue.

    --Eric
     
  7. whitesmoque

    whitesmoque

    Joined:
    Apr 30, 2019
    Posts:
    19
    Allright Eric, i'm starting to pull my hair out over this. I made a whole new project, I did turn off gravity, and I remade exactly what you had, with nothing except for the script you gave me. The walls have nothing except box colliders. when I hit play the ball shoots over to the right and stays there. here is a screenshot of just about everything, I don't really know, maybe my unity is out of date. As far as size goes, I do not know how that could be the problem, any insight you have would surely help though. Thanks.
     

    Attached Files:

  8. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Needs a physics material with 0 friction, 1 bounciness. At least that's what I used.

    --Eric
     
  9. whitesmoque

    whitesmoque

    Joined:
    Apr 30, 2019
    Posts:
    19
    holy cow! I think It actually is working! give me a day to re-implement everything, And I will get back with you, and we can call this case closed. But you have no Idea how much crap i sifted through and how much rearranging I had to do. Thanks!:D
     
  10. whitesmoque

    whitesmoque

    Joined:
    Apr 30, 2019
    Posts:
    19
    Ok, check this out. It moves continuously no matter what unless the velocity hits zero, and when that happens it dies.
     
  11. whitesmoque

    whitesmoque

    Joined:
    Apr 30, 2019
    Posts:
    19
    This is bothersome... This was the reason I had issues in the first place... You see, the only thing about my game that makes it not just another block breaking game, is the fact that upon destruction the blocks, the block instantiates a little creature that does it's own thing. The initial problem I had was that after the ball would hit these falling creatures at a certain position, the ball would stagger almost like it hit a bucket of jello, and slowly the velocity would decrease until no movement at all.. Here this problem is occurring again, with one difference, when it hits a normal block, it goes back to normal speed. So how in the world do I make it so that this object does not slow down the ball?

    I am attaching the script of the object that slowed down the ball.
    Code (CSharp):
    1.  
    2. public class [B]SluggoBehaviorScript [/B]: MonoBehaviour {
    3.  
    4.  
    5.  
    6. [SerializeField] private int [B]hurtID[/B];
    7.  
    8. [SerializeField] public GameObject [B]hurt[/B];
    9.  
    10. public BounceUI [B]ThebounceUI[/B];
    11.  
    12.  
    13.  
    14.     // Use this for initialization
    15.  
    16.     void Start () {
    17.  
    18.         ThebounceUI = GameObject.Find("Canvas").GetComponent<BounceUI>();
    19.  
    20.     }
    21.  
    22.    
    23.  
    24.     // Update is called once per frame
    25.  
    26.     void Update () {
    27.  
    28.        
    29.  
    30.     }
    31.  
    32.     void OnCollisionEnter2D(Collision2D other)
    33.  
    34.     {
    35.  
    36.         Debug.Log(other.gameObject.tag);
    37.  
    38.         if (other.gameObject.tag == "BallTag")
    39.  
    40.         {
    41.  
    42.             if (hurtID == 0)
    43.  
    44.             {
    45.  
    46.             Destroy(gameObject);
    47.  
    48.             Instantiate(hurt, transform.position , Quaternion.identity);
    49.  
    50.             }
    51.  
    52.             else if (hurtID == 1)
    53.  
    54.             {
    55.  
    56.                 Destroy(gameObject);
    57.  
    58.                 ThebounceUI.GuiltyOfMurder();
    59.  
    60.    
    61.  
    62.             }
    63.  
    64.         }
    65.  
    66.  
    67. }
    68.  
    69.  
    70.  
     
  12. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Yeah, I'd expect that; anything times Vector2.zero is Vector2.zero. You'd have to make a specific check for that, though I have no idea what a logical action would be, since realistically once you force something to stop, it's going to stay stopped. ;) As for the other thing, I'd assume it's creating a situation where the velocity is changed in a way that's not detected in OnCollisionExit2D, in which case you'd have to check in other functions (e.g OnCollisionEnter2D), possibly FixedUpdate if necessary.

    --Eric