Search Unity

Converting a rigidbody2D script to be compatible for a normal rigidbody

Discussion in 'Scripting' started by darryldonohoe, Nov 16, 2015.

  1. darryldonohoe

    darryldonohoe

    Joined:
    Jan 10, 2012
    Posts:
    55
    Hey,

    Recently i asked a question on Unity Answers, and was helped alot by ijdau! However!
    The script was made for a Rigidbody2D, and the game i am currently working on is being build in a 3D environment thus using a normal Rigidbody.

    I have never used a Rigidbody2D before, so i don't know how to "convert"(if that is possible) this script to be compatible with a normal Rigidbody.

    The controller is made for a Top Down game, where up is always up doesn't matter which direction the player is currently facing in.

    This will be used for a vehicle sort of controller, so when the player is turning his/her joystick. It is slowly (or fast, depending on the turn speed) turning towards the angle of the joystick.

    Here is an image of what i mean:




    Like i said, the script provided by ijdau, does this great, but is made for a Rigidbody2D.

    Here is the script:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class TestPlayer : MonoBehaviour
    5. {  
    6.     private Rigidbody2D rb;
    7.     private float hInput = 0.0f;
    8.     private float vInput = 0.0f;
    9.    
    10.     public float speed = 200.0f;
    11.     public float turnRate = 3.0f;
    12.    
    13.     Quaternion targetRotation;
    14.    
    15.     void Start()
    16.     {
    17.         rb =  GetComponent<Rigidbody2D>();
    18.         targetRotation = Quaternion.identity;
    19.     }
    20.    
    21.     void Update()
    22.     {
    23.         hInput = Input.GetAxis("Horizontal");
    24.         vInput = Input.GetAxis("Vertical");
    25.     }
    26.    
    27.     void FixedUpdate()
    28.     {
    29.         Vector3 move = new Vector3(hInput, vInput, 0);
    30.        
    31.         if(move.x != 0.0f || move.y != 0.0f)
    32.         {
    33.             targetRotation = Quaternion.LookRotation(Vector3.forward, move);
    34.             transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, turnRate);
    35.             rb.AddRelativeForce(Vector3.up * speed * Time.fixedDeltaTime);
    36.         }
    37.  
    38.         // Get a left or right 90 degrees angle based on the rigidbody current rotation velocity
    39.         float steeringRightAngle;
    40.  
    41.         if(rb.angularVelocity > 0)
    42.         {
    43.             steeringRightAngle = -90;
    44.         } else {
    45.             steeringRightAngle = 90;
    46.         }
    47.         // Find a Vector2 that is 90 degrees relative to the local forward direction (2D top down)
    48.         Vector2 rightAngleFromForward = Quaternion.AngleAxis(steeringRightAngle, Vector3.forward) * Vector2.up;
    49.  
    50.         // Calculate the 'drift' sideways velocity from comparing rigidbody forward movement and the right angle to this.
    51.         float driftForce = Vector2.Dot(rb.velocity, rb.GetRelativeVector(rightAngleFromForward.normalized));
    52.  
    53.         // Calculate an opposite force to the drift and apply this to generate sideways traction (aka tyre grip)
    54.         Vector2 relativeForce = (rightAngleFromForward.normalized * -1.0f) * (driftForce * 10.0f);
    55.  
    56.         rb.AddForce(rb.GetRelativeVector(relativeForce));
    57.     }
    58. }
    Do you guys have any idea on how to tackle this? Any help would be appreciated!

    And just in case, here is the link to the "Answer-thread":
    http://answers.unity3d.com/questions/1095197/top-down-carvehicle-movement.html#answer-1095277

    Cheers,
    Darryl
     
  2. martinmr

    martinmr

    Joined:
    Mar 25, 2015
    Posts:
    325
    As far as i know there is no big difference, i think, that with rigidbody2D some calculations are excluded which you don't need in 2D space. but for just changing from 2D to normal rigidbody :

    - Remove Rigidbody2D from your gameobejct and add a normal Rigidbody.
    - In code change GetComponent<Rigidbody2D>(); ot GetComponent<Rigidbody>();

    rest should work fine because both rigidbodies using same funcitons.
    maybe you will have to change Y and Z values in your code. because 2D -> 3D


    if the rest of code works as you need i had to test but unfortunately haven'T time for that atm, maybe someone else knows ? :D

    p.s.: For a 2D game i still would use normal Rigidbody and Normal Collider (there are also both with a 2D version) but for mysterious circumstances the normal rb and col are more perfomant than their 2D versions
     
  3. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    You will probably want to tick off some of the lock rotation/position settings on the Rigidbody, but yeah, for the most part it should be just removing the '2D' from everything.
     
  4. darryldonohoe

    darryldonohoe

    Joined:
    Jan 10, 2012
    Posts:
    55
    Hey guy's,
    Thanks for the replies. But i already tried doing this, it just gave me an error concerning the GetRelativeVector. And from what i have seen. I don't think that there is a equivalent version of this for a normal rigidbody.

    Or am i missing something?


    Cheers,
    Darryl
     
  5. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    True, Rigidbody doesn't have that.... but honestly, I don't know why Rigidbody2D has it, as you certainly don't need it. Transform.TransformDirection should do the same thing.
     
  6. darryldonohoe

    darryldonohoe

    Joined:
    Jan 10, 2012
    Posts:
    55
    Hey sorry for the late reply, anyway i checked it out. I came up with this.
    So far it is moving, but very buggy.

    Up is up, down is up, left is left but with an increased speed?!? and right is right but also with an increased speed.
    Also, once you let go of the joystick the model starts rotating.

    I tried converting it first, but then it gave me errors or it wouldnt even move. So right now i am pretty happy that the script at least does something.

    Anyway here is what i came up with:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class TankController : MonoBehaviour
    5. {
    6.     private Rigidbody rb;
    7.     private float hInput = 0.0f;
    8.     private float vInput = 0.0f;
    9.    
    10.     public float speed = 200.0f;
    11.     public float turnRate = 3.0f;
    12.    
    13.     Quaternion targetRotation;
    14.  
    15.     private Transform myTransform;
    16.     private Vector3 curDirection;        //maybe useful for something?
    17.  
    18.  
    19.     void Start()
    20.     {
    21.         rb =  GetComponent<Rigidbody>();
    22.         targetRotation = Quaternion.identity;
    23.  
    24.         myTransform = transform;
    25.     }
    26.    
    27.     void Update()
    28.     {
    29.         hInput = Input.GetAxis("Horizontal");
    30.         vInput = Input.GetAxis("Vertical");
    31.     }
    32.    
    33.     void FixedUpdate()
    34.     {
    35.         Vector3 move = new Vector3(hInput, vInput, 0);
    36.  
    37.         curDirection = myTransform.TransformDirection (myTransform.forward);
    38.  
    39.  
    40.         if(move.x != 0.0f || move.y != 0.0f)
    41.         {
    42.             targetRotation = Quaternion.LookRotation(Vector3.forward, move);
    43.             transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, turnRate);
    44.             rb.AddForce(Vector3.up * speed * Time.fixedDeltaTime);
    45.         }
    46.        
    47.         // Get a left or right 90 degrees angle based on the rigidbody current rotation velocity
    48.         float steeringRightAngle;
    49.  
    50.  
    51.  
    52.         if(rb.angularVelocity.magnitude > 0)
    53.         {
    54.             steeringRightAngle = -90;
    55.         }
    56.         else
    57.         {
    58.             steeringRightAngle = 90;
    59.         }
    60.  
    61.         // Find a Vector2 that is 90 degrees relative to the local forward direction (2D top down)
    62.         Vector3 rightAngleFromForward = Quaternion.AngleAxis(steeringRightAngle, Vector3.forward) * Vector3.up;
    63.        
    64.         // Calculate the 'drift' sideways velocity from comparing rigidbody forward movement and the right angle to this.
    65.         //float driftForce = Vector2.Dot(rb.velocity, rb.GetRelativeVector(rightAngleFromForward.normalized));
    66.  
    67.         float driftForce = Vector2.Dot(rb.velocity, transform.TransformDirection(rightAngleFromForward));
    68.        
    69.         // Calculate an opposite force to the drift and apply this to generate sideways traction (aka tyre grip)
    70.         Vector3 relativeForce = (rightAngleFromForward.normalized * -1.0f) * (driftForce * 10.0f);
    71.        
    72.         rb.AddForce(relativeForce);
    73.     }
    74. }
    Do you have any idea how to fix these issues?

    Also i wanted to say, its not that i am new to scripting(been scripting for a while now), its just that i hate doing controllers!
    I am not good at controllers, a while ago i made a working dungeon generator capable of generating hundreds of room within 3 seconds.(which i am pretty proud of). But controllers are a whole other level. I find them to be the most difficult.


    Cheers,
    Darryl
     
  7. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    I would try normalizing the result of your Vector2.Dot operation. The scale of the input vectors does affect the scale of the output vectors.
     
  8. darryldonohoe

    darryldonohoe

    Joined:
    Jan 10, 2012
    Posts:
    55
    Thanks man!
    I got the script working now, or at least half working.
    The movement is there, the controller can also turn correctly. However i can only make it fully work once i use the X & Y axis.

    But i want to use the X & Z axis, if i change the move Vector to:

    Code (CSharp):
    1. Vector3 move = new Vector3(hInput, 0, vInput);
    And change this line:

    Code (CSharp):
    1. rb.AddRelativeForce(Vector3.up * speed * Time.fixedDeltaTime);
    To:

    Code (CSharp):
    1. rb.AddRelativeForce(Vector3.forward * speed * Time.fixedDeltaTime);
    Then the controller can only move forward and thats it. Also the rotation is only rotating on the Z axis.
    So you get a vehicle thats only moving forward and nothing else, but once you start pressing left or right its doing a side wheelie but still moving forward.

    Here is the script, i put some comments besides the lines that i think i need to change.
    (note, the script is now set up for the X & Y axis)

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class TankController : MonoBehaviour
    5. {
    6.     private Rigidbody rb;
    7.     private float hInput = 0.0f;
    8.     private float vInput = 0.0f;
    9.    
    10.     public float speed = 200.0f;
    11.     public float turnRate = 3.0f;
    12.    
    13.     Quaternion targetRotation;
    14.  
    15.     private Transform myTransform;
    16.  
    17.  
    18.     void Start()
    19.     {
    20.         rb =  GetComponent<Rigidbody>();
    21.         targetRotation = Quaternion.identity;
    22.  
    23.         myTransform = transform;
    24.     }
    25.  
    26.  
    27.     void Update()
    28.     {
    29.         hInput = Input.GetAxis("Horizontal");
    30.         vInput = Input.GetAxis("Vertical");
    31.     }
    32.  
    33.  
    34.     void FixedUpdate()
    35.     {
    36.         Vector3 move = new Vector3(hInput, vInput, 0);
    37.  
    38.         if(move.x != 0.0f || move.y != 0.0f)    //move.x is probably fine, but move.y needs to be changed!
    39.         {
    40.             targetRotation = Quaternion.LookRotation(Vector3.forward, move);    //I guess i need to change something in here!
    41.             myTransform.rotation = Quaternion.RotateTowards(myTransform.rotation, targetRotation, turnRate);
    42.             rb.AddRelativeForce(Vector3.up * speed * Time.fixedDeltaTime);        //And also need to change something in here! (probably the Vector3.up)
    43.         }
    44.        
    45.         // Get a left or right 90 degrees angle based on the rigidbody current rotation velocity
    46.         float steeringRightAngle;
    47.  
    48.         if(rb.angularVelocity.magnitude > 0)
    49.         {
    50.             steeringRightAngle = -90;
    51.         }
    52.         else
    53.         {
    54.             steeringRightAngle = 90;
    55.         }
    56.  
    57.         // Find a Vector2 that is 90 degrees relative to the local forward direction (2D top down)
    58.         Vector3 rightAngleFromForward = Quaternion.AngleAxis(steeringRightAngle, Vector3.forward) * Vector2.up;
    59.  
    60.         float driftForce = Vector2.Dot(rb.velocity, myTransform.TransformDirection(rightAngleFromForward.normalized));
    61.        
    62.         // Calculate an opposite force to the drift and apply this to generate sideways traction (aka tyre grip)
    63.         Vector2 relativeForce = (rightAngleFromForward.normalized * -1.0f) * (driftForce * 10.0f);
    64.        
    65.         rb.AddForce(myTransform.TransformDirection(relativeForce));
    66.     }
    67. }
    Any advice would be appreciated!

    Cheers,
    Darryl
     
  9. martinmr

    martinmr

    Joined:
    Mar 25, 2015
    Posts:
    325
    Hm I would do something like tihs for moving my car. Pseudocode:

    Code (CSharp):
    1. private Quaternion newRotation;
    2. private accelerate = true;
    3. void Update() {
    4.    if(leftpushed) {
    5.        newRotation.eulerAngles = new Vector3(0, transform.eulerAngles.y + rotationAccuracy, 0); //instead of 0 maybe transforms euler x z
    6.    } else if (rightPushed) {
    7.       ... //same for right
    8.    }
    9.  
    10.    if(button/axis for acceleration pushed) {
    11.       accelerate = true;
    12.    } else {
    13.       accelerate = false;
    14.    }
    15.  
    16.    if (transform.rotation != newRotation) {
    17.       float step = speed * 20f * Time.deltaTime;                                                
    18.       transform.rotation = Quaternion.RotateTowards(transform.rotation, newRotation, step);
    19.    }  
    20. }
    21.  
    22. void FixedUpdate() {
    23.    rb.AddForce(transform.forward * speed);
    24. }
    25.  
    something like that.
    usefull here, the transform.forward .up .down etc calls, forward gives you the local position of your transform in world space. so you car will only move forward in the direction it's looking.

    you are using Vector.forward this will give you the worldposition maybe therefore it's moving in the wrong direction.
    in my case a woudl change the rotation ind car is only moving in his own (local) forward Vector
     
  10. darryldonohoe

    darryldonohoe

    Joined:
    Jan 10, 2012
    Posts:
    55
    Hey Martinmr, thanks for the pseudocode, i tried it. And as far as i am aware. It is working!

    I redid the script. I also added the CrossPlatformInput behavour.
    It's even working with a Joystick(turning towards the angle the joystick is currently pointing at, with the appropriate turnRate)

    So this is great! Thanks again for the help!

    Also for anyone that is interested, this is the code i ended up with;

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityStandardAssets.CrossPlatformInput;
    4.  
    5. public class TestPlayer : MonoBehaviour
    6. {
    7.     private Rigidbody rb;
    8.     public float hInput = 0.0f;
    9.     public float vInput = 0.0f;
    10.  
    11.     public float speed = 200.0f;
    12.     public float turnRate = 3.0f;
    13.  
    14.     Quaternion targetRotation;
    15.  
    16.     private Transform myTransform;
    17.  
    18.  
    19.     void Start()
    20.     {
    21.         rb = GetComponent<Rigidbody>();
    22.         targetRotation = Quaternion.identity;
    23.  
    24.         myTransform = transform;
    25.     }
    26.  
    27.  
    28.     void Update()
    29.     {
    30.         hInput = CrossPlatformInputManager.GetAxis("Horizontal");
    31.         vInput = CrossPlatformInputManager.GetAxis("Vertical");
    32.     }
    33.  
    34.  
    35.     void FixedUpdate()
    36.     {
    37.         Rotation(hInput, vInput);
    38.         Movement(hInput, vInput);
    39.     }
    40.  
    41.     void Rotation(float horizontal, float vertical)
    42.     {
    43.         float angle = Mathf.Atan2(hInput, vInput) * Mathf.Rad2Deg;
    44.         float step = turnRate * Time.deltaTime;
    45.  
    46.         if (horizontal != 0 || vertical != 0)
    47.         {
    48.             targetRotation.eulerAngles = new Vector3(0, angle, 0);
    49.  
    50.             myTransform.rotation = Quaternion.RotateTowards(myTransform.rotation, targetRotation, step);
    51.         }
    52.     }
    53.  
    54.     void Movement(float horizontal, float vertical)
    55.     {
    56.         if(horizontal != 0.0f || vertical != 0.0f)
    57.         {
    58.             rb.AddForce(myTransform.forward * speed * Time.deltaTime);
    59.         }
    60.     }
    61. }
    Cheers,
    Darryl