Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Local gravity inside collider

Discussion in 'Physics' started by Berzohr, Dec 1, 2014.

  1. Berzohr

    Berzohr

    Joined:
    Jul 17, 2014
    Posts:
    9
    Hi people!
    I have a problem, i will make a platform with a local gravity (oriented to local object), when if the character goes inside, get the local gravity, but if don't go it take the game gravity.

    For simplify my idea i make a draft:


    Any idea to how make this?
    Thank you =)
     
    Last edited: Dec 1, 2014
  2. cl9-2

    cl9-2

    Joined:
    May 31, 2013
    Posts:
    417
    One possibility is adding a box collider trigger containing the plartform, then depending on the type Trigger event, enabling or disabling the object's ConstantForce component.
     
  3. Berzohr

    Berzohr

    Joined:
    Jul 17, 2014
    Posts:
    9
    I have update the URL of draft :)
    Thanks cl.9 to yours tips, i try immediately.
     
  4. Berzohr

    Berzohr

    Joined:
    Jul 17, 2014
    Posts:
    9
    -.- i update again the draft... Sorry....
     

    Attached Files:

  5. MatthewW

    MatthewW

    Joined:
    Nov 30, 2006
    Posts:
    1,356
    Triggers are definitely the way to go here.

    OnTriggerStay will fire on a Trigger once every physics update for every object inside the trigger.

    You probably want to define gravity locally to the trigger object, so you can easily position them in your level and have them work. Depending on your game, you might not want to affect all rigidbodies, either (maybe just the player or something).

    Code would roughly look like this, placed on your trigger:

    Code (csharp):
    1.  
    2. public Vector3 gravityForce = new Vector3(0f, -9.8f, 0f)
    3.  
    4. function OnTriggerStay (other : Collider)
    5. {
    6.     if (other.attachedRigidbody /* || some other check here too! */)
    7.     {
    8.         other.attachedRigidbody.AddForce(transform.TransformDirection(gravityForce), ForceMode.Acceleration);
    9.     }
    10. }
    11.  
     
  6. Berzohr

    Berzohr

    Joined:
    Jul 17, 2014
    Posts:
    9
    Thanks Matthew, the code for Trigger work, but now i have a double gravity inside (one of game and one force inside the trigger). Specially when the platform are on top (inverse) the player have the zero gravity (game push down and collider push up).

    I need disability the game gravity, only if player are in the trigger collider.
     
  7. MatthewW

    MatthewW

    Joined:
    Nov 30, 2006
    Posts:
    1,356
    You can toggle rigidbody.useGravity: http://docs.unity3d.com/ScriptReference/Rigidbody-useGravity.html

    Maybe by setting it true and false in OnTriggerEnter/OnTriggerExit. This can get weird if you have overlapping triggers, though. (You might enter a new trigger and then exit another trigger after, and still be inside the new trigger). It's the easiest solution, and will apply to all rigidbodies equally, but requires your gravity zone things be spaced pretty far apart.

    A more robust solution would be to keep gravity disabled permanently and have your character always apply its gravity forces. The downside here is that you'd need to add a script to every object that you want affected by the zones. (Or could do it programmatically somewhere).

    This more robust solution would look like:

    The execution order page is here: http://docs.unity3d.com/Manual/ExecutionOrder.html

    and the physics timestamp is:

    Screenshot 2014-12-02 11.19.04.png

    Relative to the actual physics simulation, OnTriggerStay is actually before FixedUpdate.

    I'd recommend your character have some kind of ManualGravity script, with a simple Vector3 gravity parameter exposed. That script's FixedUpdate would look like:

    Code (csharp):
    1.  
    2.  
    3. // apply whatever we had stored this frame
    4. rigidbody.AddForce(gravity, ForceMode.Acceleration);
    5.  
    6. // default gravity value here
    7. gravity = new Vector3(0f, -9.8f, 0f);
    8.  
    Note that the default gravity is set *after* it's applied. Before the next time FixedUpdate could run, other scripts and events would be able to modify the gravity. Your OnTriggerStay in the gravity zones would just do:

    Code (csharp):
    1.  
    2. public Vector3 gravityForce = new Vector3(0f, -9.8f, 0f)
    3.  
    4. function OnTriggerStay (other : Collider)
    5. {
    6.     var manualGravity = other.GetComponent<ManualGravity>();
    7.  
    8.     if (manualGravity)
    9.     {
    10.        manualGravity.gravity = transform.TransformDirection(gravityForce);
    11.     }
    12. }
    13.  
    Note that you could complicate this even further by doing a List<Vector3> gravityForces, or something, and then each zone would add to that list. This would let you have overlapping zones that behave like they do in the super simple solution above. (You'd just apply a normal gravity force if that list was empty).

    Hope this helps!

    P.S. Ignoring the more advanced solution there, if you're going to never overlap gravity zones just do the OnTriggerEnter/OnTriggerExit toggle of rigidbody.useGravity! I just included the other example here as a more robust way to handle overlapping triggers.
     
  8. Berzohr

    Berzohr

    Joined:
    Jul 17, 2014
    Posts:
    9
    Dear Mattew,
    i try your solution but i wrong something, when the character are in the trigger zone there isn't a gravity force (gravity 0).

    I make this CSharp Scripts. The first is the component of Character with rigidbody:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class ManualGravity : MonoBehaviour {
    5.  
    6.     void FixUpdate () {
    7.         // apply whatever we had stored this frame
    8.         rigidbody.AddForce(gravity, ForceMode.Acceleration);
    9.     }
    10.  
    11.     // default gravity value here
    12.     public Vector3 gravity = new Vector3(0f, -9.8f, 0f);
    13. }
    14.  
    and the second is for collider with Is trigger checked:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class TrackGravity : MonoBehaviour {
    5.  
    6.     void OnTriggerEnter (Collider other){
    7.         other.attachedRigidbody.useGravity = false;
    8.  
    9.     }
    10.  
    11.     void OnTriggerExit (Collider other){
    12.         other.attachedRigidbody.useGravity = true;
    13.     }
    14.  
    15.     public Vector3 gravityForce = new Vector3 (0f, -9.8f, 0f);
    16.      
    17.     void OnTriggerStay (Collider other){
    18.         var manualGravity = other.GetComponent<ManualGravity>();
    19.         if (manualGravity){
    20.             manualGravity.gravity = transform.TransformDirection(gravityForce);
    21.         }
    22.     }
    23. }
    24.  
    What i wrong?
    Thank you for the support :)
     
  9. MatthewW

    MatthewW

    Joined:
    Nov 30, 2006
    Posts:
    1,356
    FixUpdate should be FixedUpdate?

    When in doubt, add a Debug.Log("some piece of information") call or something a block of code to make sure it's firing (that message will show up in the console window).
     
    metaldc4life likes this.