Search Unity

Ignore Default Gravity In Pipeline

Discussion in 'Physics' started by KOemxe, Aug 20, 2018.

  1. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Hi Everyone!

    Forgive me if there is already another post addressing something like this, but I haven't found it yet. I'm trying to get my object to ignore the default gravity field and move between the walls of the pipe in the attached image.

    The effect I'm trying to achieve is to allow my player (cube) to exit with a different rotation/spin when leaving the pipe as it falls back toward the ground.

    I've seen an attractor script for planetary bodies elsewhere, but I'm not sure those apply to this scenario or not. Obviously, I'm planning on using a mesh collidor for my pipeline in the image (I created this in Blender) and the faces are inverted.

    If I need to create a script for this, where would I start? Which object would I apply this script to and in which way?
     

    Attached Files:

  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
    You have few ways of doing it.
    But I describe 2.
    1, Switch on/off gravity on RigidBody itself.
    2. Use own gravity script, to control gravity acting on objects. You can have then even planetary effect.
     
  3. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Hi @Antypodish , thanks for your reply! I wanted to ask, would this allow my cube to turn upside down as it moves left and right in the pipe structure?
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
    If you switch off gravity on Rigid Body, and apply forces at the cube, pointing toward cross section center of the pipe, then should not be issue. Your force vector would be ( center of pipe position - cube position ) multiply by actual force ( gravity ). So you can technically even jump upside down. ;)
     
  5. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Hi @Antypodish ,

    I think I may know what you're getting at! Just thought I'd ask though - not sure how I'd calculate the center of my pipe FBX model, but here's the current code I'm playing around with:

    Code (CSharp):
    1. private void OnCollisionEnter(Collision collision)
    2.     {
    3.         //collision.gameObject.GetComponent<Rigidbody>().transform.up = Vector3.zero;
    4.         //player.gameObject.GetComponent<Rigidbody>().useGravity = false;
    5.         myNormal = transform.up;
    6.         playerRB = collision.gameObject.GetComponent<Rigidbody>();
    7.         gravity = 0;
    8.         //playerRB.isKinematic = true;
    9.         //player.gameObject.GetComponent<Rigidbody>().AddRelativeForce()
    10.     }
    11.  
    12.     private void FixedUpdate()
    13.     {
    14.         if (gravity == 0)
    15.         {
    16.             myNormal = transform.up;
    17.             playerRB.AddForce(-10 * playerRB.mass * myNormal);
    18.         }
    19.     }
    20.  
    21.     private void OnCollisionExit(Collision collision)
    22.     {
    23.         //player.gameObject.GetComponent<Rigidbody>().useGravity = true;
    24.         gravity = 1;
    25.         playerRB.isKinematic = false;
    26.     }
    I have the player rigidbody declared as a global variable earlier, along with the gravity flag, etc. Probably not the best way to do it but I'm lazy :p - outside of that, what would you do differently about the functions I'm using above?
     
  6. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
    Ah just looked at your image again. you walking inside pipe, not outside of the pipe?
    If inside, then vector need push away from center.

    Other than that
    - You know where is the pipe. You can either cache gameObject, ray cast, or detect on collision.
    - You know orientation of the pipe, or pipes
    - You know length (scale). Most likely forward z axis.
    - You know position of player / cube
    - What you need, is a distance from cross section center.
    - Therefore, what you need, is project calculated distance vector from center of pipe object, to pipe forward vector.

    Something like that (for pushing outised) (untested may not work directly), but you get an idea.
    Code (CSharp):
    1. Vector3 vectorFromPipeCenter = cubePosition - pipeCenter ;
    2. Vector forwardPipeVector = pipeRotation * Vector3.forward ;
    3. // or
    4. Vector forwardPipeVector = pipeTransform.forward ;
    5. // And finally
    6. Vector project2Center = Vector3.Project ( vectorFromPipeCenter, forwardPipeVector ) ;
    7. float radiusFromCrossectionCenter = project2Center.magniude ;
     
    Last edited: Aug 24, 2018
  7. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Hi @Antypodish ,

    Yes. I do want the cube to be walking INSIDE the pipe. :)

    On that note, should I pass the pipe in as a global parameter in the class this method belongs to? Or can I call on the pipe to get the center of it in the function itself?

    Code (CSharp):
    1. private void OnCollisionEnter(Collision collision)
    2.     {
    3.         //collision.gameObject.GetComponent<Rigidbody>().transform.up = Vector3.zero;
    4.         //player.gameObject.GetComponent<Rigidbody>().useGravity = false;
    5.         myNormal = transform.up;
    6.         playerRB = collision.gameObject.GetComponent<Rigidbody>();
    7.        
    8.         gravity = 0;
    9.         //playerRB.isKinematic = true;
    10.         //player.gameObject.GetComponent<Rigidbody>().AddRelativeForce()
    11.     }
     
  8. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
    Preferably store data in scripts, where you going use it. If you can, avoid global parameters.
    Make a script with class holding pipe methods and properties. And then instantiate this class, in the script you are going to use. This script should hold references to pipe, or pipes. Probably as a list, or dictionary.
     
  9. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Hi @Antypodish !

    So, I tried to apply what you said, though not necessarily doing all the things I should do like avoid using global parameters. :p

    Can you tell what I'm doing below exactly? I've had no success with getting the cube to stick to the walls of the pipe yet instead of falling down.

    Code (CSharp):
    1. private void FixedUpdate()
    2.     {
    3.         if (gravity == 0)
    4.         {
    5.             myNormal = transform.up;
    6.             //playerRB.AddForce(-10 * playerRB.mass * myNormal);
    7.             vectorFromPipeCenter = playerRB.position - attractRB.position;
    8.             forwardPipeVector = attractRB.rotation.z * Vector3.forward;
    9.             // or
    10.             //Vector forwardPipeVector = pipeTransform.forward;
    11.             // And finally
    12.             project2Center = Vector3.Project(forwardPipeVector, forwardPipeVector);
    13.             float radiusFromCrossectionCenter = project2Center.magnitude;
    14.             playerRB.AddForce(project2Center);
    15.         }
    16.     }
     
  10. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
    If you falling down, means your normal gravity is still active.

    What script tries to do, is to find a vector, facing toward center of pipe, oriented in its forward direction. To get vector to center, along its axis, you need project vectors, to find perpendicular vector to pipe axis.



    Vector Projection
    https://en.wikipedia.org/wiki/Vector_projection

    I hope you are not color blind, as I used colors here, for better picturing :p

    Simply you are looking for a2, which is project2Center, which is calculated by Vector3.Project ( vectorFromPipeCenter, forwardPipeVector); Where a1 = forwardPipeVector and a = vectorFromPipeCenter. Now I just realized, I made slight mistake. Since I accidentally put into Vector3.Project twice forwardPipeVector, instead vectorFromPipeCenter and forwardPipeVector.
    So now you project a onto a1 to get a2.
    now suitable is to get normalized a2 vector, so you normalizing it. which means values of vector are between -1 and 1.
    With that, you should have artificial gravity direction, which you can apply to AddForce.
    And second mistake I made.

    Code (CSharp):
    1. Vector3 pipeGravityPull = project2Center.normalized * Mathf.Pow ( radiusFromCrossectionCenter * someOptionalForceFactor ), 2 ) ; // pipe pull force = distance from pipe center to power 2
    2. playerRB.AddForce ( pipeGravityPull ) ;
    just on side note,
    forwardPipeVector = attractRB.rotation.z * Vector3.forward; // getting forward vector of the pipe axis.
    is the same as
    attractRB.transform.forward ;

    If all that makes sense ;)

    Code (CSharp):
    1. private void FixedUpdate()
    2.     {
    3.         if (gravity == 0)
    4.         {
    5.             myNormal = transform.up;
    6.             //playerRB.AddForce(-10 * playerRB.mass * myNormal);
    7.             vectorFromPipeCenter = playerRB.position - attractRB.position;
    8.             forwardPipeVector = attractRB.rotation.z * Vector3.forward;
    9.             // or
    10.             //Vector forwardPipeVector = pipeTransform.forward;
    11.             // And finally
    12.             project2Center = Vector3.Project(forwardPipeVector, vectorFromPipeCenter);
    13.             float radiusFromCrossectionCenter = project2Center.magnitude;
    14.            
    15.             // pipe pull force = distance from pipe center to power 2
    16.             Vector3 pipeGravityPull = project2Center.normalized * Mathf.Pow ( radiusFromCrossectionCenter * someOptionalForceFactor ), 2 ) ;
    17.             playerRB.AddForce ( pipeGravityPull ) ;
    18.         }
    19.     }
    Something like that, if haven't made more mistakes. :p
     
    Last edited: Aug 24, 2018
  11. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Actually, I wonder if I'm also doing it wrong since I'm trying to trigger this movement when the player cube COLLIDES with the pipe, like so:

    Code (CSharp):
    1. private void OnCollisionEnter(Collision collision)
    2.     {
    3.         //collision.gameObject.GetComponent<Rigidbody>().transform.up = Vector3.zero;
    4.         //player.gameObject.GetComponent<Rigidbody>().useGravity = false;
    5.         myNormal = transform.up;
    6.         playerRB = collision.gameObject.GetComponent<Rigidbody>();
    7.        
    8.         gravity = 0;
    9.         //playerRB.isKinematic = true;
    10.         //player.gameObject.GetComponent<Rigidbody>().AddRelativeForce()
    11.     }
    Maybe it's better to do something different? Not sure. What do you think?
     
  12. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Also, should I be making only the player a rigid body and the pipe not a rigid body? Or does that even matter?
     
  13. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
    Player must be, if you want apply Add gravity. However pipe not.
     
  14. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Well I turned the player's gravity back on. However movement still seems to be the same. Here's my overall code, in case you wonder. Again, I know you said don't use global variables (which makes sense) but I'm just playing around :)

    "gravity" is just a flag to figure if I should allow gravity to run its normal course or start to attract the RigidBody towards the pipe center.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class FauxGravity : MonoBehaviour {
    6.  
    7.     public Transform attractor;
    8.     public Transform player;
    9.     Rigidbody attractRB;
    10.     Rigidbody playerRB;
    11.     Vector3 myNormal;
    12.     Vector3 vectorFromPipeCenter;
    13.     Vector3 forwardPipeVector;
    14.     Vector3 project2Center;
    15.     int gravity = 1;
    16.  
    17.     // Use this for initialization
    18.     void Start () {
    19.         attractRB = attractor.GetComponent<Rigidbody>();
    20.     }
    21.    
    22.     // Update is called once per frame
    23.     void Update () {
    24.        
    25.     }
    26.  
    27.     private void OnCollisionEnter(Collision collision)
    28.     {
    29.         //collision.gameObject.GetComponent<Rigidbody>().transform.up = Vector3.zero;
    30.         //player.gameObject.GetComponent<Rigidbody>().useGravity = false;
    31.         myNormal = transform.up;
    32.         playerRB = collision.gameObject.GetComponent<Rigidbody>();
    33.        
    34.         gravity = 0;
    35.         //playerRB.isKinematic = true;
    36.         //player.gameObject.GetComponent<Rigidbody>().AddRelativeForce()
    37.     }
    38.  
    39.     private void FixedUpdate()
    40.     {
    41.         if (gravity == 0)
    42.         {
    43.             Debug.Log("Gravity is 0.");
    44.             myNormal = transform.up;
    45.             //playerRB.AddForce(-10 * playerRB.mass * myNormal);
    46.             vectorFromPipeCenter = playerRB.position - attractRB.position;
    47.             //vectorFromPipeCenter = attractRB.position - playerRB.position;
    48.             forwardPipeVector = attractRB.rotation.z * Vector3.forward;
    49.             // or
    50.             //Vector forwardPipeVector = pipeTransform.forward;
    51.             // And finally
    52.             project2Center = Vector3.Project(forwardPipeVector, forwardPipeVector);
    53.             float radiusFromCrossectionCenter = project2Center.magnitude;
    54.             // pipe pull force = distance from pipe center to power 2
    55.             Vector3 pipeGravityPull = project2Center.normalized * Mathf.Pow ( (radiusFromCrossectionCenter * 1 ), 2 ) ;
    56.             playerRB.AddForce ( pipeGravityPull ) ;
    57.         }
    58.     }
    59.  
    60.     private void OnCollisionExit(Collision collision)
    61.     {
    62.         Debug.Log("Gravity is 1 again.");
    63.         //player.gameObject.GetComponent<Rigidbody>().useGravity = true;
    64.         gravity = 1;
    65.         playerRB.isKinematic = false;
    66.     }
    67.  
    68.     void gravityAttract(Collider colliderObject)
    69.     {
    70.         var rb = colliderObject.GetComponent<Rigidbody>();
    71.         rb.AddForce(Vector3.down * 30, ForceMode.Force);
    72.         rb.AddForce(Vector3.up * 30, ForceMode.Force);
    73.     }
    74. }
     
  15. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
  16. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Physics.gravity is not an int value? Or are you saying just turn off gravity altogether from all objects?

    I've tried turning gravity off on the player but it doesn't seem too helpful. Think it would help if you saw other files too?
     
  17. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
    is float. But the point is, if you 0 that, then you would be sure, not the normal gravity is pulling down. If still failing down, means something else is acting on object. And yes, switching gravity in the game object does switches it off/on. Is just to check/test.
     
  18. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    So I just figured out part of the problem, it seems that I need to alter my PlayerMovement script so that it moves along the pipe wall when the collision is detected. But I don't know how my player will detect that! Here's my player collision script:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class PlayerCollison : MonoBehaviour {
    4.  
    5.     public PlayerMovement movement;
    6.  
    7.  
    8.     void OnCollisionEnter(Collision collisionInfo)
    9.     {
    10.         if (collisionInfo.collider.tag == "Obstacle")
    11.         {
    12.             Debug.Log("We hit a freaking obstacle.");
    13.             Debug.Log("Player has collided with: " + collisionInfo.collider.name);
    14.             movement.enabled = false;
    15.             FindObjectOfType<GameManagement>().EndGame();
    16.         }
    17.         else
    18.         {
    19.             Debug.Log("Player has collided with: " + collisionInfo.collider.name);
    20.         }
    21.        
    22.     }
    23. }
    It seems it only detects the objects with the "Obstacle" tag, even though my else block is OUTSIDE that check.

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. public class PlayerMovement : MonoBehaviour {
    5.  
    6.     public Rigidbody rb;
    7.  
    8.     public float forwardForce = 2000f;
    9.     public float sidewaysForce = 500f;
    10.     public Boolean fauxGravity = false;
    11.  
    12.     // Use this for initialization
    13.     void Start () {
    14.        
    15.     }
    16.    
    17.     // Update is called once per frame use fixed update for Unity Fizzix
    18.     void FixedUpdate () {
    19.         //add forward force
    20.         rb.AddForce(0, 0, forwardForce * Time.deltaTime);
    21.        
    22.         if (Input.GetKey(KeyCode.RightArrow) && !fauxGravity)
    23.         {
    24.             rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
    25.         }
    26.        
    27.         if (Input.GetKey(KeyCode.LeftArrow) && !fauxGravity)
    28.         {
    29.             rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
    30.         }
    31.  
    32.         if (rb.position.y <-1f)
    33.         {
    34.             FindObjectOfType<GameManagement>().EndGame();
    35.         }
    36.     }
    37.  
    38.     //void OnCollisionEnter(Collision collision)
    39.     //{
    40.     //    //collision.gameObject.GetComponent<Rigidbody>().transform.up = Vector3.zero;
    41.     //    //player.gameObject.GetComponent<Rigidbody>().useGravity = false;
    42.     //    System.Console.WriteLine("Player has collided with: " + collision.collider.name);
    43.     //    if(collision.gameObject.name == "PipeBasic 1")
    44.     //    {
    45.     //        System.Console.WriteLine("Player Collided with Pipe");
    46.     //        fauxGravity = true;
    47.     //    }
    48.     //    //playerRB.isKinematic = true;
    49.     //    //player.gameObject.GetComponent<Rigidbody>().AddRelativeForce()
    50.     //}
    51. }
    52.  
    Above is my PlayerMovement script. I like to think I can change the gravity flag in either of those scripts so that player movement is confined to the pipe walls... can my pipe be marked kinematic for this to work???
     
  19. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
    Yes, shouldn't be a problem. As long you have working collision detection, to trigger gravity.

    Can you put another debug log, just outside, or after if else loop? Just to see, if collisionInfo.collider.name is detected for else condition. My thought is, maybe OnCollisionEnter is not triggered, when tag is different than Obstacle?
     
  20. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Hey @Antypodish, can't say that will help.

    But maybe I can email you my project so you can see what I have and what I need to change?
     
  21. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
    Sorry, but I got already two project opened at once, all the time. So they keep me occupied by much ;)

    You can always strip project (make copy) to leave just asset folder, Then simply zip it, or so. And attach it here, as just small file, if suitable.

    Try different collision detection. Just do some basics test. Like different tags. Or names, or objects. Maybe you missed something.
     
  22. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    I wonder if Raycasts would help? I've been reading a little about these online...
     
  23. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    OK, so I made SOME kind of progress - but the trouble is updating the player's normal... seems that when I try to normalize the force affecting the player, the player just slows down and then freezes in place.

    Code (CSharp):
    1. private void FixedUpdate()
    2.     {
    3.         if (gravity == 0)
    4.         {
    5.             //Debug.Log("Gravity is 0.");
    6.            
    7.             //playerRB.AddForce(-10 * playerRB.mass * myNormal);
    8.             vectorFromPipeCenter = attractRB.position - playerRB.position;
    9.             vectorFromPipeCenter.Normalize();
    10.             Debug.Log("Player distrance from pipe center: " + vectorFromPipeCenter);
    11.             //vectorFromPipeCenter = attractRB.position - playerRB.position;
    12.             forwardPipeVector = attractRB.rotation.z * Vector3.forward;
    13.             Debug.Log("Player forward vector? " + forwardPipeVector);
    14.             // or
    15.             //Vector forwardPipeVector = pipeTransform.forward;
    16.             // And finally
    17.             project2Center = Vector3.Project(vectorFromPipeCenter, playerRB.angularVelocity);
    18.             float radiusFromCrossectionCenter = project2Center.magnitude;
    19.             // pipe pull force = distance from pipe center to power 2
    20.             pipeGravityPull = project2Center.normalized * Mathf.Pow ( (radiusFromCrossectionCenter * 1 ), 2 ) ;
    21.             playerRB.useGravity = false;
    22.             Debug.Log("Adding force from FG");
    23.             playerRB.AddForce (pipeGravityPull.x, pipeGravityPull.y, 0) ;
    24.         }
    25.         if (gravity == 1)
    26.         {
    27.             //playerRB.useGravity = true;
    28.         }
    29.     }
     
  24. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
    vectorFromPipeCenter.Normalize() is more like direction rather distance.
    (just for info) The actual distance (see line 10 and 18), if you actually need it, is vectorFromPipeCenter.magnitude
    Just for extra note, try not over use this method, calling 100s times per frame, as it uses sqrt.

    In line 17 you have
    Code (CSharp):
    1. project2Center = Vector3.Project(vectorFromPipeCenter, playerRB.angularVelocity);
    with
    Code (CSharp):
    1. playerRB.angularVelocity
    Is this what you suppose to have?
    Are you sure is this right?
     
  25. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Hi @Antypodish ,

    So, in light of what you said, what would you suggest with my player movement script? It seems I have to make my player movement script work in tandem with that method I provided earlier from my FauxGravity script.

    Code (CSharp):
    1. void FixedUpdate () {
    2.         distanceFromPipeCenter.Normalize();
    3.         //add forward force
    4.         rb.AddForce(0, 0, forwardForce * Time.deltaTime);
    5.        
    6.         if (Input.GetKey(KeyCode.RightArrow) && !fauxGravity)
    7.         {
    8.             rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
    9.         }
    10.        
    11.         if (Input.GetKey(KeyCode.LeftArrow) && !fauxGravity)
    12.         {
    13.             rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
    14.         }
    15.         if (Input.GetKey(KeyCode.RightArrow) && fauxGravity)
    16.         {
    17.             //Debug.Log("Right pressed");
    18.             rb.AddForce(sidewaysForce * pipePull.x*Time.deltaTime, sidewaysForce * pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
    19.             Debug.Log(rb.angularVelocity);
    20.             rb.rotation = Quaternion.FromToRotation(transform.up, distanceFromPipeCenter) * transform.rotation;
    21.         }
    22.         if (Input.GetKey(KeyCode.RightArrow) && fauxGravity)
    23.         {
    24.             //Debug.Log("Left pressed");
    25.             rb.AddForce(-sidewaysForce * pipePull.x * Time.deltaTime, sidewaysForce * pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
    26.             Debug.Log(rb.angularVelocity);
    27.             float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * sidewaysForce;
    28.             Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, transform.up);
    29.             //align with surface normal
    30.             transform.rotation = Quaternion.FromToRotation(transform.up, distanceFromPipeCenter) * transform.rotation;
    31.             //apply heading rotation
    32.             transform.rotation = headingDelta * transform.rotation;
    33.         }
    34.         if (rb.position.y <-1f)
    35.         {
    36.             FindObjectOfType<GameManagement>().EndGame();
    37.         }
    38.     }
     
  26. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
    Are these two separate scripts, running in game? Or you have replaced the previous one with the current, what you have just shown.?

    Just curious. Can you explain, what made you think, using playerRB.angularVelocity in first place?
     
  27. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Hi there,

    These are two separate scripts.

    One controls the movement of the player. The other was the one we tried to work on together, which applied the false gravity to the surface normal.

    angularVelocity was what I thought could be used to translate the rotation of the player, but that could me understanding Unity physics incorrectly, and especially physics in general.
     
  28. KOemxe

    KOemxe

    Joined:
    May 1, 2018
    Posts:
    35
    Hi @Antypodish !

    So, I worked through this with another dev friend of mine a couple of nights ago. We figured out that your algorithm was definitely right - the problem is that when my player moves left or right, it is ONLY moving along the horizontal axis. That being said, I've run into ANOTHER issue too - taking note of the forward vector of my pipe model ALWAYS returns zero.

    I've already revised the algorithm to not only follow what you had written, but include ADDITIONAL logic so that activation of the false gravity doesn't depend on whether the cube collides with the pipe wall, but rather is inside the collidor itself, if that makes sense. Can you take a look at the two scripts below and let me know what you suggest?

    Player movement script:
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. public class PlayerMovement : MonoBehaviour {
    5.  
    6.     public Rigidbody rb;
    7.  
    8.     public float forwardForce = 2000f;
    9.     public float sidewaysForce = 500f;
    10.     public Boolean fauxGravity = false;
    11.     public Vector3 distanceFromPipeCenter = new Vector3(0, 0, 0);
    12.     public Vector3 pipePull = new Vector3(0,0,0);
    13.  
    14.     // Use this for initialization
    15.     void Start () {
    16.        
    17.     }
    18.    
    19.     // Update is called once per frame use fixed update for Unity Fizzix
    20.     void FixedUpdate () {
    21.         distanceFromPipeCenter.Normalize();
    22.         //add forward force
    23.         rb.AddForce(0, 0, forwardForce * Time.deltaTime);
    24.  
    25.         if (Input.GetKey(KeyCode.RightArrow) && !fauxGravity)
    26.         {
    27.             rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
    28.         }
    29.  
    30.         if (Input.GetKey(KeyCode.LeftArrow) && !fauxGravity)
    31.         {
    32.             rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
    33.         }
    34.         if (Input.GetKey(KeyCode.RightArrow) && fauxGravity)
    35.         {
    36.             //Debug.Log("Right pressed");
    37.             rb.AddForce(sidewaysForce * -pipePull.x * Time.deltaTime, sidewaysForce * pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
    38.             Debug.Log(rb.angularVelocity);
    39.             //float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * sidewaysForce;
    40.             //Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, transform.up);
    41.             //align with surface normal
    42.             //transform.rotation = Quaternion.FromToRotation(transform.up, distanceFromPipeCenter) * transform.rotation;
    43.             //apply heading rotation
    44.             //transform.rotation = headingDelta * transform.rotation;
    45.         }
    46.         if (Input.GetKey(KeyCode.LeftArrow) && fauxGravity)
    47.         {
    48.             //Debug.Log("Left pressed");
    49.             rb.AddForce(-sidewaysForce * -pipePull.x * Time.deltaTime, sidewaysForce * pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
    50.             Debug.Log(rb.angularVelocity);
    51.             //float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * sidewaysForce;
    52.             //Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, transform.up);
    53.             //align with surface normal
    54.             //transform.rotation = Quaternion.FromToRotation(transform.up, distanceFromPipeCenter) * transform.rotation;
    55.             //apply heading rotation
    56.             //transform.rotation = headingDelta * transform.rotation;
    57.         }
    58.         //if (fauxGravity)
    59.         //{
    60.         //    rb.useGravity = false;
    61.         //    float distForward = Mathf.Infinity;
    62.         //    RaycastHit hitForward;
    63.            
    64.         //    if (Physics.SphereCast(transform.position, 0.25f, -transform.up + transform.forward, out hitForward, 5))
    65.         //    {
    66.         //        distForward = hitForward.distance;
    67.         //    }
    68.         //    float distDown = Mathf.Infinity;
    69.         //    RaycastHit hitDown;
    70.         //    if (Physics.SphereCast(transform.position, 0.25f, -transform.up, out hitDown, 5))
    71.         //    {
    72.         //        distDown = hitDown.distance;
    73.         //    }
    74.         //    float distBack = Mathf.Infinity;
    75.         //    RaycastHit hitBack;
    76.         //    if (Physics.SphereCast(transform.position, 0.25f, -transform.up + -transform.forward, out hitBack, 5))
    77.         //    {
    78.         //        distBack = hitBack.distance;
    79.         //    }
    80.  
    81.         //    if (distForward < distDown && distForward < distBack)
    82.         //    {
    83.         //        transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitForward.normal), hitForward.normal), Time.deltaTime * 5.0f);
    84.         //    }
    85.         //    else if (distDown < distForward && distDown < distBack)
    86.         //    {
    87.         //        transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitDown.normal), hitDown.normal), Time.deltaTime * 5.0f);
    88.         //    }
    89.         //    else if (distBack < distForward && distBack < distDown)
    90.         //    {
    91.         //        transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitBack.normal), hitBack.normal), Time.deltaTime * 5.0f);
    92.         //    }
    93.  
    94.         //    GetComponent<Rigidbody>().AddForce(-transform.up * Time.deltaTime * 10);
    95.         //}
    96.         if (rb.position.y <-1f)
    97.         {
    98.             FindObjectOfType<GameManagement>().EndGame();
    99.         }
    100.     }
    101.  
    102.     //void OnCollisionEnter(Collision collision)
    103.     //{
    104.     //    //collision.gameObject.GetComponent<Rigidbody>().transform.up = Vector3.zero;
    105.     //    //player.gameObject.GetComponent<Rigidbody>().useGravity = false;
    106.     //    System.Console.WriteLine("Player has collided with: " + collision.collider.name);
    107.     //    if(collision.gameObject.name == "PipeBasic 1")
    108.     //    {
    109.     //        System.Console.WriteLine("Player Collided with Pipe");
    110.     //        fauxGravity = true;
    111.     //    }
    112.     //    //playerRB.isKinematic = true;
    113.     //    //player.gameObject.GetComponent<Rigidbody>().AddRelativeForce()
    114.     //}
    115. }
    FauxGravity script:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class FauxGravity : MonoBehaviour {
    6.  
    7.     public Transform attractor;
    8.     public Transform player;
    9.     public Transform collider;
    10.     Rigidbody attractRB;
    11.     Rigidbody playerRB;
    12.     Vector3 myNormal;
    13.     public Vector3 vectorFromPipeCenter;
    14.     public Vector3 forwardPipeVector;
    15.     Vector3 project2Center;
    16.     public Vector3 pipeGravityPull;
    17.     int gravity = 1;
    18.  
    19.     // Use this for initialization
    20.     void Start () {
    21.         attractRB = attractor.GetComponent<Rigidbody>();
    22.         playerRB = player.GetComponent<Rigidbody>();
    23.         //Physics.gravity.magnitude = 0;
    24.     }
    25.    
    26.     // Update is called once per frame
    27.     void Update () {
    28.        
    29.     }
    30.  
    31.     private void OnCollisionEnter(Collision collision)
    32.     {
    33.         //collision.gameObject.GetComponent<Rigidbody>().transform.up = Vector3.zero;
    34.         //player.gameObject.GetComponent<Rigidbody>().useGravity = false;
    35.         myNormal = playerRB.transform.up;
    36.         //playerRB = collision.gameObject.GetComponent<Rigidbody>();
    37.        
    38.         gravity = 0;
    39.         //playerRB.isKinematic = true;
    40.         //player.gameObject.GetComponent<Rigidbody>().AddRelativeForce()
    41.     }
    42.  
    43.     private void FixedUpdate()
    44.     {
    45.         if (gravity == 0)
    46.         {
    47.             //Debug.Log("Gravity is 0.");
    48.            
    49.             //playerRB.AddForce(-10 * playerRB.mass * myNormal);
    50.             vectorFromPipeCenter = playerRB.position - attractRB.position;
    51.             //vectorFromPipeCenter.Normalize();
    52.             Debug.Log("Player distrance from pipe center: " + vectorFromPipeCenter.magnitude);
    53.             //vectorFromPipeCenter = attractRB.position - playerRB.position;
    54.             Debug.Log("attractRB forward is " + playerRB.rotation.z);
    55.             forwardPipeVector = player.forward.magnitude * Vector3.forward;
    56.             Debug.Log("Player forward vector? " + forwardPipeVector);
    57.             // or
    58.             //Vector forwardPipeVector = pipeTransform.forward;
    59.             // And finally
    60.             project2Center = Vector3.Project(forwardPipeVector, vectorFromPipeCenter);
    61.             float radiusFromCrossectionCenter = project2Center.magnitude;
    62.             Debug.Log("Normal is: " + Quaternion.AngleAxis(90, forwardPipeVector));
    63.             // pipe pull force = distance from pipe center to power 2
    64.             pipeGravityPull = Quaternion.AngleAxis(90, forwardPipeVector) * project2Center.normalized * Mathf.Pow ( (radiusFromCrossectionCenter * 1 ), 2 );
    65.             Debug.Log("Pipe gravity vector? " + pipeGravityPull);
    66.             playerRB.useGravity = true;
    67.             Debug.DrawLine(pipeGravityPull, pipeGravityPull);
    68.             Debug.Log("Adding force from FG");
    69.             playerRB.AddForce(pipeGravityPull);
    70.         }
    71.         if (gravity == 1)
    72.         {
    73.             //playerRB.useGravity = true;
    74.         }
    75.     }
    76.  
    77.     private void OnCollisionExit(Collision collision)
    78.     {
    79.         //Debug.Log("Gravity is 1 again.");
    80.         //player.gameObject.GetComponent<Rigidbody>().useGravity = true;
    81.         gravity = 1;
    82.         //playerRB.useGravity = true;
    83.         playerRB.isKinematic = false;
    84.         //playerRB.AddForce(10, 20, 0);
    85.     }
    86.  
    87.     void gravityAttract(Collider colliderObject)
    88.     {
    89.         var rb = colliderObject.GetComponent<Rigidbody>();
    90.         rb.AddForce(Vector3.down * 30, ForceMode.Force);
    91.         rb.AddForce(Vector3.up * 30, ForceMode.Force);
    92.     }
    93. }
    I more than appreciate the help you've provided so far!
     
    Antypodish likes this.
  29. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,775
    Briefly looking at, looks ok.
    I mean, if it works with further improvements that cool to hear.
    I presume, you are done on that part for now?

    Now you should play with it for some time. and when you sure all works, clean up the scrips. You can always keep draft version copies somewhere.

    Ideally would be, if you at some point adapt classes FauxGravity and PlayerMovement to be without MonoBehaviour.
    But don't worry abut it for now. If you don't have many active scripts all over the place, that should be fine.

    Btw, if you ever use KeyUp or KeyDown, means pressed and released, then keep in mind, to put them in update, rather than FixedUpdate. Otherwise, you may miss key evenets.

    Good luck.