Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

Disabling physics pushing and demo scene

Discussion in '2D Experimental Preview' started by Xelnath, Jan 20, 2017.

  1. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    http://xelnath.com/xelnath/Assets.zip

    Create an empty 2d preview project. Replace the assets folder with the above.


    What happens:
    * Load SomeScene
    * Hit Play
    * Press "A"
    * Soldier travels *through* the other collider.

    What I want:

    * Open this scene, click on the Soldier (Player) and change the BodyType to "Dynamic".
    * Load SomeScene
    * Hit Play
    * Press "A"
    * Soldier travels up to and goes "clunk" against the brick and stops.

    Why cant I do it this way?

    What I really want is for this to happen when one soldiers pushes on another that is standing still, neither moves.

    However, when you select both objects and change to "Dynamic"
    ...
    * Load SomeScene
    * Hit Play
    * Press "A"
    * Soldier pushes the immobile one left.
     
  2. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    Kinematic
    DEMO_Bug_Kinematic.gif

    Dynamic (Soldier only)
    DEMO_Bug_Dynamic.gif

    Both Dynamic
    DEMO_Bug_DynamicBoth.gif
     
  3. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    @MelvMay I feel like this is as minimized + documented an example as I can make at the present. Let me know if there's some thing I can clarify.
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    Disabling the 'Skeleton Animation' stops the problem. Presumably it's modifying the transform of the collider which causes all existing contacts to be removed as the collider will be recreated. I'm not even sure how the collider is being created; persumably by all these scripts.

    I'm not an expert on these scripts but if it's doing this during fixed-update or update then you'll not see any contacts you can use. Having physics perform the col-de using a Dynamc body won't suffer from this because it's all done during the update, not after when your 'Skeleton Animation' script runs and causes the collider to be recreated.

    Anyway, this isn't really a simple set-up as it's using a pretty complex set of scripts to which I have no idea how it works.
     
  5. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    :|

    This is why I want to disable the ability for physics objects to modify each other's velocities. Then everything can be dynamic.
     
  6. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    So... what are my options? Do I just need to throw away unity's physics and collision detection? The only time I want info about if a collider is intersecting or touching another collider is after it's been moved.
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    Unity physics is not at fault here, it's the fault of the script constantly updating the Transform between the Collider2D and the Rigidbody2D it's attached to *every frame* during LateUpdate. If you do this, the collider is recreated which causes its contacts to be deleted and regenerated next fixed update. Colliders live in the local space of the Rigidbody2D so if you move the colliders and not the Rigidbody2D itself then they need to be recreated.

    Your movement scripts are based upon counting contacts, which there'll be NONE as you check them in fixed-update (and start the thing moving downwards) which is before the physics system runs. It then runs, following which the callbacks happen and you set the velocity to zero. Then the 'animation' scripts run in LateUpdate (potentially several times recreating the colliders) then eventually a fixed-update happens and you check for contacts (and start the thing moving downwards again) but there are none because your scripts causes the colliders to be recreated wiping any contacts then, again, the physics updates and regenerates the contacts and it goes on and on.

    If they are animating Transforms on GameObjects which have Colliders that are attached to a Rigidbody2D not on the same GameObject then you should add another Kinematic Rigidbody2D for that 'node'. This is what kinematics is about.

    Effectively what you have here is a kinematic rag-doll. When you do this, you should have a Kinematic Rigidbody2D at every animated position so that the Transform change updates the Rigidbody2D and not the Colliders attached to it. You typically nest Kinematic bodies like this. Moving a parent Kinematic body moves all the children with it.

    I did this on your project by adding a Kinematic Rigidbody2D onto the 'GameObject' under the 'Spine' game object. When I did this I saw contacts when overlapping stuff (I checked in the Info Rollout / Contacts).

    You cannot have a single Kinematic root body with colliders attached on chidlren GameObjects and animate their Transforms.

    There's nothing stopping your script from grabbing all Rigidbody2D children and simply checking them for contacts.
     
  8. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    Add a Kinematic Rigidbody2D to the 'GameObject' GO under the Spline Object then replace the 'body1.cs' script with the following I hacked together for you:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Body1 : MonoBehaviour {
    6.  
    7.     private Rigidbody2D[] mybodies;
    8.     private Rigidbody2D rootBody;
    9.  
    10.     public virtual void OnCollisionEnter2D(Collision2D coll)
    11.     {
    12.         rootBody.velocity = Vector2.zero;
    13.     }
    14.     public virtual void OnCollisionStay2D(Collision2D coll)
    15.     {
    16.         rootBody.velocity = Vector2.zero;
    17.     }
    18.     private Vector3 _lastVelocity;
    19.     private ContactPoint2D[] contacts = new ContactPoint2D[20];
    20.  
    21.     private void Start()
    22.     {
    23.         mybodies = GetComponentsInChildren<Rigidbody2D>();
    24.         rootBody = transform.root.GetComponent<Rigidbody2D> ();
    25.     }
    26.  
    27.     void FixedUpdate()
    28.     {
    29.           // Apply the final velocity
    30.         _lastVelocity = GetCurrentVelocity();
    31.  
    32.         rootBody.velocity = _lastVelocity;
    33.  
    34.         foreach (var b in mybodies)
    35.         {
    36.             int contactCount = b.GetContacts(contacts);
    37.             if ( contactCount > 0 )
    38.             {
    39.                 Debug.LogFormat("Contact count: {0}", contactCount);
    40.                 rootBody.velocity = Vector2.zero;
    41.                 break;
    42.             }
    43.         }
    44.     }
    45.  
    46.     public Vector3 GetCurrentVelocity()
    47.     {
    48.         var velocity = Vector3.down;
    49.         return velocity + Vector3.right * Input.GetAxis("Horizontal") * 5f;
    50.     }
    51. }
    52.  
    This works perfectly. It collides with the other box and the ground. By adding the Kinematic body you also stop the collider from being recreated so contacts are available to be checked.

    I would also recommend setting both Kinematic bodies to use Continuous collision detection to stop overlaps.

    Note that the above script is something I quickly modified; it makes various assumptions such as assuming the root has a Rigidbody2D. You can customise this part yourself.

    Hope this helps.
     
    Last edited: Jan 21, 2017
  9. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    Thank you. This was a very complex description and you systematically talked me through it.

    I appreciate you going into detail on it. I had no idea every non-trigger collider needed a rigidbody 2d attached to it - or what the purpose of Kinematic was.

    The impression I had from the tutorials was "use Kinematic when you want the physics system to be affected by it, but generally ignored by physics too."

    So now, I can change my game to auto-add a kinematic rigidbody 2d, and stop movement whenever there's a contact normal whose dot product is < 0 with the velocity. That will let objects move away from each other and not towards each other.
     
    Last edited: Jan 21, 2017
    MelvMay likes this.
  10. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    To be clear, this has nothing to do with triggers or non-triggers nor do you have to add a Rigidbody2D to every collider as some fixed rule. I've tried to explain it a few times above and granted it might be better with a picture (that I don't have)!

    I'll try to be clearer; Collider2D live in the space of the Rigidbody2D. For example, all the vertices of a BoxCollider2D are stored as a relative position from the Rigidbody2D. When you XY-position or Z-rotate the Rigidbody2D, the colliders attached to it do not require any attention so it's fast as it's only the Rigidbody2D that moves. However, if you adjust the collider offset or if the Collider2D lives on a child GameObject relative to the Rigidbody2D and you modify the Unity Transform inbetween the Rigidbody2D and Collider2D (the one on the Rigidbody2D is obviously fine to modify) then you've changed the relative position of the Collider2D with respect to the Rigidbody2D. Box2D is fairly immutable for stuff like this and such a change requires that the collider be destroyed and recreated so this is what we have to do.

    When you animate the Transform XY-position or Z-rotation on a GameObject that has a Rigidbody2D and a Collider2D, we know to ignore all the Collider2D on that GameObject and only adjust the Rigidbody2D because of the above. Likewise, if we had a GameObject that has a Rigidbody2D but the Collider2D is on a child GameObject and we animated the Transform XY-position or Z-rotation of the Transform on the parent Rigidbody2D we would still ignore the Collider2D on the child GameObject because they have not changed position/rotation relative to the attached Rigidbody2D. In this parent/child split, if we were to instead animate the Transform on the child GameObject (that contained the Collider2D only) then we're changing the relative position of the Collider2D with respect to its parent so it needs to be recreated in its new position.

    Recreating a collider involves destroying it then creating it. When you destroy a collider, Box2D immediately removes all its contacts. Those contacts will be recreated in its new position during the next physics update. We then have to match up the old deleted contacts with the new incoming ones so we don't end-up reporting new OnCollisionEnter2D or OnTriggerEnter2D which is a real PITA to do and has been the source of bugs in the past.

    When you have a rag-doll set-up where you typically have colliders in a hierarchy of GameObject, some of which you animate XY-position or Z-rotation then you need to have a Kinematic Rigidbody2D at those GameObject which you animate. You do not need to have a Rigidbody2D at every GameObject, just ones where you animate.

    Also, Kinematic Rigidbody2D automatically move relative to any parent Kinematic Rigidbody2D so modifying a root Rigidbody2D causes all children Rigidbody2D to move relative to it as you would expect in a normal Transform hierarchy; in this case it's also a Kinematic Rigidbody2D hierarchy as well but the difference being that there isn't a need to have a Rigidbody2D at every Transform position in that hierarchy, just the animate 'joint' positions.

    Finally, I'd like to add that amongst the plans this year is to investigate making major modifications to Box2D rather than living with its shortcomings. One of which is to remove/reduce the need to recreate a Collider2D if you transform it relative to its Rigidbody2D. The other is to either defer recreation of Collider2D and therefore the contacts and/or allow the contacts to be updated immediately, either by a global option or per-Collider2D/Rigidbody2D.

    That's it!

    Hope this explanation helps.
     
    Last edited: Jan 21, 2017
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    I wanted to add to this part as well; I see all the time, especially in docs where the docs guys/gals have 'simplified' the description for the sake of being concise at the loss of accuracy and I believe that in some cases, such as this, it adds long-term confusion or at least lack of real understanding which is, of course, not the users fault at all.

    All 2D components when added to the scene affect the physics system, full stop. A Static body may not be moved by the physics system but it affects it as it's considered when things overlap or touch it. A Kinematic body is the same except for the fact that like a Static body, forces do not move it. Forces include global gravity, user-applied forces or contact forces. They will move if you directly set their velocity but they'll keep moving unless you explicitly change the velocity. Dynamic bodies are obviously affected by forces.

    The only exception to this is when a Rigidbody2D has its Simulated property set to false. The body, its colliders, its joints (etc) are ignored by the physics system in this and only this case.

    Don't want you to feel like I'm jumping on you here, not at all, just my way of trying to clarify and I had some time on my hands to do so. Hope it all helps you. :)
     
    Last edited: Jan 21, 2017
  12. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Absolutely hate dumbing down docs with a passion. Gets right on my tits. There should be a

    Section that goes into maximum detail. For everything.
     
    MelvMay likes this.
  13. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    I couldn't agree more with this.

    Not trying to blame the docs guys/gals at all. It's very difficult to write good documentation that provides enough information for everyone in one place though. Also where to put it can be a challenge. Most of this kind of info should go into the manual and that's something I've got on my plate in 2017. Going to put a lot of work into the 2D physics manual. Heck, I almost wrote a book as a GDoc which I need to revamp into a 2D physics manual.
     
    Last edited: Jan 21, 2017
    hippocoder likes this.
  14. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Even programmer notes would help. Heck even stubs and comments. Something. It does not help that sometimes the terminology used in Unity doesn't quite reflect what it is actually doing at times.

    I get it, it's good business to be easily understood but IMHO you can have both. Whoever decided you couldn't is just wrong.
     
  15. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    I'm dedicated to getting a bunch of manual & docs work done early in 2017 hence it being in my top 5 things TODO and it's a big ol' list. ;)
     
    PGJ and hippocoder like this.
  16. piggybank1974

    piggybank1974

    Joined:
    Dec 15, 2015
    Posts:
    621
    I agree, mind you the programmers changed iskinematic to simulated, in 5.5 and it's still a stupid name, live or something to that nature, would of been better(as it confused the heck out of me until the docs played a part), mind you we have all done this from time to time I bet? :)
     
  17. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    This is not true. I am 'the programmers', I'm the dev for 2D physics here at Unity. Simulated has nothing whatsoever to do with a body being kinematic.

    The body-type defines the behaviour of the body and its colliders. Simulated simple turns on/off the physics system from simulated the body as the documentation states.
     
  18. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    I use simulated on/off to save processing and/or for pooling purposes.
     
  19. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    Yes, that's a pretty good use for it.
     
  20. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    I appreciate the clarity brought to bear here. The specific stepping not only through intended setup but also explanation for *how* you expected things to work was very helpful. I had no idea that you expected multiple rigidbodies on a character, let alone that *moving* colliders caused a refresh of the physics state.

    The details added to this thread has benefited multiple people here, so thank you for your patience and precision. I feel like I far more deeply understand what's going on.

    The way you helped diffuse the frustration, then step through how to achieve a beneficial result helped a lot here too - appreciate your maturity and attitude.
     
    MelvMay likes this.
  21. Pharan

    Pharan

    Joined:
    Oct 28, 2013
    Posts:
    102
    @MelvMay

    Thanks so much for the clarification!

    I was tasked to maintain the code for the third-party package/scripts Xelnath is using. (I didn't write it myself though so I'm not 100% clear on its original intent.)
    The part that counts contacts is not part of the package though.
    I'd like to able to set up some appropriate defaults and warnings so users can be guided about what things to do and what to avoid.
    The package already prevents users from using animated-and-weighted polygons as PolygonCollider2Ds, under the assumption that this also causes the collider to be recreated on the box2D side and yield unpredictable results and bad performance.

    Can you confirm or correct the following info? This might also be stuff to clarify in the docs.


    (1) A Collider2D without a Rigidbody2D is static; Like level geometry as a common example.
    Don't move it, ever. If you move its Transform or change its points, it needs to be regenerated in Box2D(?) Crazy expensive (?)



    (2) Unity Rigidbody2Ds map to box2D bodies? Unity Collider2Ds map to box2D fixtures?
    So a Collider2D with a Rigidbody2D both on the same GameObject forms "a whole rigidbody with a shape". This setup is "dynamic" by default.
    Changing the position and rotation is fine. Ideally, apply position and rotation via the Rigidbody2D class.
    What are the downsides to applying position, rotations on the Transform?
    Changing the scale is bad? Or is it fine, and only non-uniform/skewing scale is unpredictable?
    If applying things to the Transform is ok, is it ideally done in FixedUpdate? What happens if it's done in Update/LateUpdate?


    (ok to move)
    |- (don't move)
    |- (don't move)
    (3) A GameObject with a Rigidbody2D, and a bunch of child GameObjects with Collider2Ds on them, also forms a "one rigidbody object".
    The children's Collider2Ds belong to the parent Rigidbody2D; the Collider2Ds under those GameObjects together comprise the "shape" of that rigidbody.
    And by definition, the rigidbody can't have parts that move around. It's one, whole, rigid thing. And in box2D, it must move as a whole. Because it doesn't give individual transforms to each fixture on the box2D side, if you move one of the Transforms of the Collider2Ds, the collider (or the whole rigidbody?) needs to be recreated?

    (ok to move)
    |- (also ok to move)
    (4) If you have a GameObject with a Rigidbody2D and Collider2D, with a child GameObject also with a Rigidbody2D and Collider2D. This is essentially two separate box2D bodies, where the child automatically moves relative to the parent.
    This really only yields sane results if the child is locally fixed/kinematic/manually animated.
    Also, this "child" rigidbody will never communicate any collisions to the parent.

    (5) Recreation means the old collider (or whole rigidbody?) needs to be destroyed and a new one is created to take its place. You lose information on collisions/contacts when this happens.
    It's also bad for performance? How bad is bad? Like fine to do for a few things but don't do it for a lot of things?
    Or just don't do it because it violates how box2D works, and the cost is really in the interface between the C# side and the internal box2D side?

    (6) isKinematic means collisions don't affect that Rigidbody, but that body can affect other (dynamic) bodies.
    A kinematic rigidbody will move if you set its velocity manually.
    In the case of (4), collisions on the parent rigidbody will cause the kinematic child to move.

    Personally, I love the addition of .useFullKinematicContacts in 5.5!
    It's really nice for custom platformer physics/custom collision response.
    The .simulated property is useful too. And I'm excited for the new Contacts API in 5.6
     
    Last edited: Jan 23, 2017
  22. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    If by 'without a Rigidbody2D is static' you mean the Collider2D isn't attached to a Rigidbody2D then yes. If you mean a Rigidbody2D on the same GameObject then no, the statement isn't correct. As should be well known, a Collider2D attaches to a Rigidbody2D on the same GameObject or uses the nearest Rigidbody2D going up the Transform hierarchy.

    Try not to move static colliders. Stuff is only crazy expensive when you do it a lot!

    Rigidbody2D = b2Body; Collider2D = multiple b2Fixture + b2Shape (ignoring circle. box & edge colliders); Joint2D = b2Joint.
    When you add a Rigidbody(2D), you are asking that component to drive the Transform. Whether that's what you think or not, that's what you're asking Unity to do. If you set a body position/rotation directly then you immediately warp to that position; there's no interpolation available. If you set the body position/rotation then it'll update the Transform during the next physics update. If you set the Transform it'll update the transform and the body position/rotation immediately. Both will reset any interpolation being used. When you change a Transform is irrelevant to what it does.

    Changing any scale is bad because as I've said a lot above, Box2D does not provide any scaling of colliders (b2Shapes) therefore they need to be recreated. Box2D treats most collider stuff as immutable.

    Again, colliders attach to a rigidbody on the same GO or on a parent one. Changing a child collider transform causes only that collider to be recreated. Box2D allows fixture/shape to be removed and a new one added which is what we do. You do not have to remove all of them (other colliders attached to it).

    Yes, two separate b2Body. The child b2Body doesn't automatically move with the parent at all. It only happens when using a child body that is set to be Kinematic. This is a Unity thing, not a Box2D thing and happens specifically for hierarchical kinematic set-ups as this original post project was doing. Note that Box2D has no idea about Unity Transform or the hierarchy.

    Collisions/Triggers are only reported to the GO that contains the colliders/rigidbody that are involved.

    Just the colliders. It's work that you should avoid. Recreating some colliders are worse than others. A CircleCollider2D and BoxCollider2D always involve a single b2Fixture/b2Shape so they are relative fast. EdgeCollider2D scales with the number of edges although it's still pretty cheap. PolygonCollider2D costs can get high quickly as they allow not only a concave outline but also multiple paths defining interior holes. These paths are decomposed into multiple convex b2PolygonShape. This costs and the cost has nothing to do with C#.

    As I said above, when you destroy a fixture, all its contacts are removed.

    A kinematic body can have its linear and angular velocity set, yes. I don't believe this is supported in 3D physics though. Kinematic bodies that are children of other Kinematic bodies move with their parents as said above.

    I was trying to be brief above as it takes a lot of time to review and post, something I don't have a lot of right now, sorry!
     
    Last edited: Jan 23, 2017
  23. piggybank1974

    piggybank1974

    Joined:
    Dec 15, 2015
    Posts:
    621
    Just looking at an older unity project of Mine that got upgraded, So Simulated mean "I want this to be checked by physics"??

    I see Use Kinematic cont (Checkbox) that was Is Kinematic previously?? I've not started messing with it but Use Kinematic cont is only available on one of my Rigidbody2D objects and not others.
     
  24. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    Please don't hijack threads like this, it makes confusing topics even more confusing to follow.

    If you'd like to create a separate thread or start a conversation with me then I'd be happy to help, thanks.