Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Ignore force from certain rigidbodies

Discussion in 'Physics' started by Leniaal, Nov 23, 2017.

  1. Leniaal

    Leniaal

    Joined:
    Nov 7, 2012
    Posts:
    119
    Hello,

    I have a problem regarding force between rigidbodies, and how to discard force from certain rigidbodies.

    Say for example we have two players; p1 and p2(mass of 70).
    We also have a cube(mass of 150).

    If p1 walks into the cube, I don't want p1 to apply force to the cube. I just want it to collide and stop moving. I don't want players to be able push each other away, so again, just colliding.. no force.

    Now this could be solved with for example making the rigidbody of the cube kinematic.

    But say, the cube is falling down and the player collides with it. I don't want it to just freeze in the air like time has stopped, in my case I want it to act like the player is simply a collider without force. Maybe it even pushes the player, but never the other way around.For me it would seem like quite a common issue, especially with the two players colliding but no application of force between the two.

    Another option is to set the velocity of the object hit to 0 when the player collides with it. But say for example a car hits p1 and he flies into p2, I don't want p1 to stop. Can somebody help me understand how to achieve this?
     
  2. tyomklz

    tyomklz

    Joined:
    Jul 31, 2015
    Posts:
    48
    Can't you just increase the cube's mass drastically? Another thing that I have in mind is getting cube's properties (velocity and angular velocity) in FixedUpdate() then all the collision happen after that (players affecting the cube) then in Update() or LateUpdate() you return cube's initial properties from FixedUpdate() and you're done. I'm not sure if it'll work, just an idea.

    You can check Unity's execution orders here: https://docs.unity3d.com/Manual/ExecutionOrder.html
     
    Last edited: Nov 24, 2017
  3. Leniaal

    Leniaal

    Joined:
    Nov 7, 2012
    Posts:
    119
    The problem with simply increasing mass is that other objects that aren't players(For example a car) won't be applying realistic force. Plus that doesn't solve my player walking into player problem. Your other solution sounds a bit messy, but perhaps a possibility. I might play around with it a bit. Thanks for your suggestions!
     
  4. tyomklz

    tyomklz

    Joined:
    Jul 31, 2015
    Posts:
    48
    I've tested my idea, it works, but may be improved for sure:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class DontMove : MonoBehaviour
    4. {
    5.     new Rigidbody rigidbody;
    6.     public Vector3 position, velocity, angularVelocity;
    7.     public bool isColliding;
    8.  
    9.     void Awake()
    10.     {
    11.         rigidbody = GetComponent<Rigidbody>();
    12.     }
    13.  
    14.     void FixedUpdate()
    15.     {
    16.         if (!isColliding)
    17.         {
    18.             position = rigidbody.position;
    19.             velocity = rigidbody.velocity;
    20.             angularVelocity = rigidbody.angularVelocity;
    21.         }
    22.     }
    23.  
    24.     void LateUpdate()
    25.     {
    26.         if (isColliding)
    27.         {
    28.             rigidbody.position = position;
    29.             rigidbody.velocity = velocity;
    30.             rigidbody.angularVelocity = angularVelocity;
    31.         }
    32.     }
    33.  
    34.     void OnCollisionEnter(Collision collision)
    35.     {
    36.         if (collision.collider.tag == "Player")
    37.             isColliding = true;
    38.     }
    39.  
    40.     void OnCollisionExit(Collision collision)
    41.     {
    42.         if (collision.collider.tag == "Player")
    43.             isColliding = false;
    44.     }
    45. }

    Here's a preview of the script functionality (1st disabled script, 2nd enabled script):



    Please, let us know if you've been able to achieve a better result, so others could learn from it and resolve the similar problem in their games :)
     
    Last edited: Nov 24, 2017
    spiglebach and Leniaal like this.
  5. Leniaal

    Leniaal

    Joined:
    Nov 7, 2012
    Posts:
    119
    Nice, but there are some problems with it. I added the rotation of the rigidbody, so that it doesn't rotate when the corners of the object are hit.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PlayerCollideDetection : MonoBehaviour
    6. {
    7.  
    8.     new Rigidbody rigidbody;
    9.     public Vector3 position, velocity, angularVelocity;
    10.     public Quaternion rotation;
    11.     public bool isColliding;
    12.  
    13.     void Awake()
    14.     {
    15.         rigidbody = GetComponent<Rigidbody>();
    16.     }
    17.  
    18.     void FixedUpdate()
    19.     {
    20.         if (!isColliding)
    21.         {
    22.             position = rigidbody.position;
    23.             rotation = rigidbody.rotation;
    24.             velocity = rigidbody.velocity;
    25.             angularVelocity = rigidbody.angularVelocity;
    26.         }
    27.     }
    28.  
    29.     void LateUpdate()
    30.     {
    31.         if (isColliding)
    32.         {
    33.             rigidbody.position = position;
    34.             rigidbody.rotation = rotation;
    35.             rigidbody.velocity = velocity;
    36.             rigidbody.angularVelocity = angularVelocity;
    37.         }
    38.     }
    39.  
    40.     void OnCollisionEnter(Collision collision)
    41.     {
    42.         if (collision.collider.tag == "Player")
    43.             isColliding = true;
    44.     }
    45.  
    46.     void OnCollisionExit(Collision collision)
    47.     {
    48.         if (collision.collider.tag == "Player")
    49.             isColliding = false;
    50.     }
    51. }
    52.  
    Now I tested it with a player (mass 70) and cube (mass 150).

    As you can see, the object that is not supposed to move wobbles briefly. You can see the same behavior in your own gif. However I believe this can be fixed.

    Another issue is the example with the car. In this image you can see a player already colliding with the cube. Now imagine the capsule moving is a car (mass 1500).


    The solution is still possible, though you'd have to check on all kinds of objects which is quite annoying.

    I guess what surprises me is that there is no way to ignore force from certain objects. Just like you can ignore collision based on layers. Additional suggestions are still very much welcome, but I suppose I'll explore this solution some more. Thanks a lot for thinking with me tyomklz.
     
  6. tyomklz

    tyomklz

    Joined:
    Jul 31, 2015
    Posts:
    48
    True. Welp, we tried, you're welcome and good luck with solving that :)

    You might want to bring Unity team's attention to this case, since you're not the first and by far not last person who's looking for this (I googled). It would be a really nice additional physics feature to have. We already have collision ignore, why not add forces ignore, right? :)
     
  7. Leniaal

    Leniaal

    Joined:
    Nov 7, 2012
    Posts:
    119
  8. tyomklz

    tyomklz

    Joined:
    Jul 31, 2015
    Posts:
    48
    Cool. Done.
     
  9. Grizmu

    Grizmu

    Joined:
    Aug 27, 2013
    Posts:
    131
    If you need a kinematic rigidbody behaviour on collisions between two non-kinematic rigidbodies, you can do so by simulating the collision yourself using triggers or raycasts.
    This way if anything else collides with the object that the player touches, the collision acts like if the player is not even there.

    I've included an example project for you. There you have a player and cube objects, which are all non-kinematic rigidbodies, but the cube objects are acting like a kinematic rigidbody to the player.

    The basic collision script for the player can look like this:
    Code (CSharp):
    1.     Vector3 dir;
    2.     Vector3 newVelocity;
    3.     float dist;
    4.     float deadZone = 0.5f;
    5.  
    6.     public void OnTriggerStay(Collider col) {
    7.         if(Physics.ComputePenetration(entityCollider, body.position, transform.rotation, col, col.gameObject.transform.position, col.gameObject.transform.rotation, out dir, out dist)) { //1
    8.             newVelocity = Vector3.ProjectOnPlane(body.velocity, dir); //2
    9.             newVelocity += dir * (dist + deadZone); //3
    10.             body.velocity = newVelocity;
    11.         }
    12.     }
    The included code makes it so the player is unable to move inside any collider triggering the OnTriggerStay method. You could also add additional velocity/force computations if you want the player to inherit the velocity of the object it collides with.

    How does it work?
    1. ComputePenetration function returns true if two colliders overlap each other, the
    direction and the distance of the overlap.
    2. Then we cast the player's velocity to the plane of the overlap direction, making the collider the player touches act like a wall, into which player is trying to walk to, but slides on.
    3. Finally we correct the overlap so the player just touches the collider.
     

    Attached Files:

    mrdatsun likes this.
  10. tyomklz

    tyomklz

    Joined:
    Jul 31, 2015
    Posts:
    48
    What you ended up doing, Leniaal?
     
  11. Leniaal

    Leniaal

    Joined:
    Nov 7, 2012
    Posts:
    119
    Unfortunately I haven't been able to work on it anymore. I'm picking it up again, and hopefully this weekend I can come to a final conclusion. I have just looked at @Griz his example project. First of all, thanks for your interest and suggestion. It works quite nice I have to say. Though I see some problems with it.

    It kind of feels like there's tar on the object you are colliding with. And you have to apply force to get loose.


    And when I went to take a shower with the cubes, I noticed that they go through the player from time to time.



    Actually all the time, lol.

    But worst of all, in my case. We don't use apply force but
    Code (CSharp):
    1. this.transform.position = this.transform.position + this.velocity;
    to move our character. And so the code doesn't really do anything In my own project.

    Now as I was creating this post, I forgot that I actually worked on something last week and that I haven't really tested it. I just tested it a bit, and it seems to work quite well. The "car" in this example can be anything that IS allowed to move the object, and the player is not. The script goes on the object.


    Code (CSharp):
    1. void OnCollisionEnter(Collision collision)
    2.     {
    3.         Debug.Log(rigidbody.velocity.magnitude);
    4.         if (collision.collider.tag == "Player")
    5.         {
    6.             playersColliding += 1;
    7.             if (rigidbody.velocity.magnitude < 0.3 && !overRuling)
    8.                 rigidbody.constraints = RigidbodyConstraints.FreezeAll;
    9.         }
    10.         if (collision.collider.tag == "Car")
    11.         {
    12.             overRuling = true;
    13.             rigidbody.constraints = RigidbodyConstraints.None;
    14.         }
    15.     }
    16.  
    17.     void OnCollisionExit(Collision collision)
    18.     {
    19.         if (collision.collider.tag == "Player")
    20.         {
    21.             playersColliding -= 1;
    22.             Debug.Log(playersColliding);
    23.             if (playersColliding == 0)
    24.                 rigidbody.constraints = RigidbodyConstraints.None;
    25.         }
    26.         if (collision.collider.tag == "Car")
    27.         {
    28.             if (playersColliding > 0 && carsColliding == 0)
    29.             {
    30.                 overRuling = false;
    31.                 rigidbody.constraints = RigidbodyConstraints.FreezeAll;
    32.             }
    33.         }
    34.     }
    I'll let you know if it really works in all scenarios sometime soon.
     
  12. tyomklz

    tyomklz

    Joined:
    Jul 31, 2015
    Posts:
    48
    Yeah, I was about to suggest freezing constraints last time, but got distracted and never did, sorry.
     
  13. Bonfyre_

    Bonfyre_

    Joined:
    Mar 14, 2021
    Posts:
    2
    I'm reviving this thread as I have still not found an elegant way to solve this problem. Anyone know if this has been improved since?
     
    Dannyboy271 likes this.
  14. Dannyboy271

    Dannyboy271

    Joined:
    Aug 3, 2020
    Posts:
    1
    I know it's been a while, but something I thought of is creating a pseudo child object with a collider that copies the parent objects position/rotation via script, and then allow the pseudo child to bear the brunt of the collisions while the parent is just chillin like a villain cause it's not a real parent and is unaffected by the child's treatment.

    Kinda like bad parenting in real life.
     
    MarcoZVincenzi and ReieJeia like this.