Search Unity

Character controller script: physics or not?

Discussion in 'Scripting' started by alph, Aug 10, 2010.

  1. alph

    alph

    Joined:
    Jul 20, 2010
    Posts:
    89
    In a game you can choose to make your character affected by the physics or not, both as I understand has ups and downs.

    The 2D tutorial has a character that is not affected by the physics engine, but I have seen others that have scripts that are.

    Problem with a character being affected by physics is that there are lots of tiny movements/rotations that makes the movement very "unstable". And the movement of the character are less customable.

    Problem with a character not being affected by physics is that all the interaction with the other gameobjects needs special scripts to "simulate" that the character is affecting them "with no mass".

    I'm looking for some more opinions about this before I make a final decision about it in my game. Any first hand experience with this problems are very welcome!
     
  2. AngryAnt

    AngryAnt

    Keyboard Operator

    Joined:
    Oct 25, 2005
    Posts:
    3,045
    I usually make my character controllers physics based. What I do is I calculate the desired velocity, factor in the existing velocity and then apply it via ForceMode.VelocityChange.

    An example of getting a desired velocity (untested):
    Code (csharp):
    1. Vector3 targetVelocity = ((transform.forward * Input.GetAxis ("Vertical") + transform.right * Input.GetAxis ("Horizontal")) / 2.0f) * m_Acceleration;
    After factoring in the current velocity, I clamp to max speed and apply it via AddForce and ForceMode.VelocityChange.
     
  3. alph

    alph

    Joined:
    Jul 20, 2010
    Posts:
    89
    Coming from a Unity team member, that surely makes me think it's the right way to go.

    I changed my script (I was just using rigidbody.velocity.y instead of ForceMode.VelocityChange, but it seemed to do just the same) to what you said, but I'm experiencing some artifacts that is essential for me to fix.

    When i just move my character left/right it kind of "vibrates", meaning I can see that the rotation in all the axis are changing very slightly. In a 2D game, this cannot happen. So I set the rotation to 0 each frame, but that seems like a strange way to solve it.

    Also when im jumping (using ForceMode.VelocityChange = Vector3(0,jumpSpeed,0);) it really messes up the rotation and movement of the character (which again i cannot have because Im making a 2D game)

    Any thoughts on how to solve this?
     
  4. AngryAnt

    AngryAnt

    Keyboard Operator

    Joined:
    Oct 25, 2005
    Posts:
    3,045
    Hard to guess at where your stutter is coming from. Maybe an idea would to do a minimum clamping of your desired velocity as well - only applying the change if it's more than N unites.

    Also make sure that your rigidbody has freezeRotation enabled.
     
  5. alph

    alph

    Joined:
    Jul 20, 2010
    Posts:
    89
    I didn't have freezeRotation checked, that took care of the problems I've encountered so far!

    Thanks a lot for your help Angry Ant :)
     
  6. alph

    alph

    Joined:
    Jul 20, 2010
    Posts:
    89
    Oups, I had some weird errors that made it work first though it shouldn't, and after cleaning up my code, now it doesn't work at all.

    Basically I use what i got from you:

    Code (csharp):
    1. Vector3 targetVelocity = transform.right * Input.GetAxis ("Horizontal");
    2. ForceMode.VelocityChange = targetVelocity;
    I know this is bad code, and I get the error: Assets/Scripts/Player.js(31,16): UCE0001: ';' expected. Insert a semicolon at the end.

    And I really dont understand how you use Vector3 in this case.

    What I want to do is something as simple as move my character along the x-axis when i press left/right arrow buttons.

    Greatful for another hint! :)
     
  7. AngryAnt

    AngryAnt

    Keyboard Operator

    Joined:
    Oct 25, 2005
    Posts:
    3,045
    ForceMode is an enum used to specify how forces are added to rigidbodies. Forces are always added to rigidbodies using the AddForce method, so finding the docs entries on those two items should give you what you need.
     
  8. alph

    alph

    Joined:
    Jul 20, 2010
    Posts:
    89
    OK, I already read those docs, but because of lack of examples it's very hard to understand.

    I found some example code here though:

    http://www.unifycommunity.com/wiki/index.php?title=RigidbodyFPSWalker

    From that doc I was able to get it working with this:

    Code (csharp):
    1. var targetVelocity = new Vector3(Input.GetAxis("Horizontal"), 0, 0);
    2. targetVelocity *= forwardSpeed;
    3. var velocity = rigidbody.velocity;
    4. var velocityChange = (targetVelocity - velocity);
    5. velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
    6. velocityChange.z = 0;
    7. velocityChange.y = 0;
    8. rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
    9.  
    I guess it's working, but right now I'm not gonna say I understand this or how I should include the bit of code you supplied earlier.
     
  9. zoultrex

    zoultrex

    Joined:
    Mar 11, 2010
    Posts:
    63
    Heres a way that also works based on the code above but also with rotation based on where the character is facing, for example attach a mouseLook script to it so you can move where it will look(rotate).
    Code (csharp):
    1.     Vector3 moveDirection;
    2.     private float inputX;
    3.     private float inputY;
    4.     public float speed = 10f;
    5.     public float MaxSpeed = 30f;
    6.  
    7.     void FixedUpdate()
    8.     {
    9.         inputX = Input.GetAxis("Horizontal");
    10.         inputY = Input.GetAxis("Vertical");
    11.  
    12.         moveDirection = new Vector3(inputX, 0, inputY);
    13.         moveDirection = transform.TransformDirection(moveDirection) * speed;
    14.         var velocity = rigidbody.velocity;
    15.         var velocityChange = (moveDirection - velocity);
    16.         velocityChange.x = Mathf.Clamp(velocityChange.x, -MaxSpeed, MaxSpeed);
    17.         velocityChange.z = Mathf.Clamp(velocityChange.z, -MaxSpeed, MaxSpeed);
    18.         rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
    19.  
    20.     }