• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Tofa · Sep 30, 2014 at 03:18 PM · physicsrigidbodyvelocityaddforce

Why does writing to rigidbody.velocity after AddForce stop my rigidbody moving?

I've not spotted t$$anonymous$$s issue documented, so hoping someone can help out.

My aim:

  1. Add input force 'correctly' to my rigidbody (via AddForce)

  2. Adjust the rigidbody velocity to stop it going too fast (e.g. by capping the max)

[as an aside, I know for #2, adjusting the rigidbody velocity directly isn't recommended, but I still see it mentioned in Unity Answers and forums and it is even in some Unity demo scripts, I tried to only use it for limiting max velocity]

I didn't even get as far as step #2 though - what I discovered was: After I use AddForce, then making any change to the rigidbody velocity, even just doing a get/set, seems to cancel out any movement made with AddForce.

Any idea what I'm doing wrong? Have I missed somet$$anonymous$$ng obvious? I'll paste my code below, you can repro by adding a cube and assigning t$$anonymous$$s script to it. See the line marked #THEPROBLEM for whereabouts the issue occurs.

 using UnityEngine;
 using System.Collections;
 
 [RequireComponent(typeof(Rigidbody))]
 public class TestMover : MonoBehaviour {
 
     private Transform cameraTransform;
     
     void Start ()
     {
         cameraTransform = Camera.main.transform;
     }
     
     
     public float charMoveInputForceXZ = 25f;
             
     void moveCharacter (Vector3 inputVector)
     {
         rigidbody.AddForce(inputVector * charMoveInputForceXZ * Time.deltaTime , ForceMode.VelocityChange);
 
 
         // #THEPROBLEM
         // The below should have no effect, yet...
         // * If commented out, the rigidbody can be moved
         // * If compiled in, the rigidbody cannot be moved
         // * If compiled in and placed prior to the AddForce line, the rigidbody can be moved
         Vector3 v;
         
         v = rigidbody.velocity;
         
         rigidbody.velocity = v;
     }
     
 
     void FixedUpdate ()
     {
         Vector3 cameraForward;
         Vector3 moveInput = Vector3.zero;
 
 
         float h = Input.GetAxis("Horizontal");
         float v = Input.GetAxis("Vertical");
         
         if (cameraTransform != null)
         {
             // calculate camera relative direction to move:
             cameraForward = Vector3.Scale (cameraTransform.forward, new Vector3(1,0,1)).normalized;
             moveInput = v * cameraForward + h * cameraTransform.right;    
         }
         
         if (moveInput.magnitude > 1)
         {
             moveInput.Normalize();
         }
             
         moveCharacter(moveInput);
     }
 }




Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by Owen-Reynolds · Sep 30, 2014 at 04:37 PM

In your case, easiest way is probably to not use AddForce. Change line 19 to rigidbody.velocity+=inputVector...

AddForce is merely a front-end to a direct velocity change. The four versions do/don't divide by mass and multiply by deltaTime. Your first line "should" omit time.deltaTime and instead use ForceMode.Acceleration (w$$anonymous$$ch applies T.dT for you.)

The "never use velocity directly" advice is really just a warning to people starting out with programming and physics systems. Try to explain what Time.deltaTime does to a non-mathy person, and you find yourself saying "know what -- forget I mentioned it. Use AddForce."

I use direct velocity changes for everyt$$anonymous$$ng, in dozens of ways including a velocity limit, and never had a problem like that. But then I never use AddForce, so don't use them together.

For fun, I'd print velocity after each line (print each x,y,z by itself, otherwise it's cut off to the tenths place.) It's gotta be some crazy bug elsewhere, or a compiler glitch.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Tofa · Sep 30, 2014 at 05:06 PM 0
Share

Ah, right, that makes a lot of sense, thanks!

I did wonder why the docs warned people off of changing velocity and then the samples proceeded to do just that! :-)

Hearing you say:

I use direct velocity changes for everything, in dozens of ways including a velocity limit

is exactly the kind of info I needed - I'll stick to modifying velocity from now on!

[Relating to "For fun..."... It's the writeback on line 31 that triggers the issue, I'd hazard a guess that the internals of the setter for rigidbody.velocity is doing something more than just setting it]

avatar image
1

Answer by Kiwasi · Sep 30, 2014 at 07:39 PM

Its worth noting that t$$anonymous$$s is not a bug. There is a reason the docs say not to set velocity every frame, and that is because it overrides the physics engine velocity calculations.

To explain further AddForce does not actually change the velocity of the RigidBody. AddForce queues a force to the physics engine to be applied during the next physics update step. The physics update happens after FixedUpdate. During the physics update all queued forces are applied, and the RigidBody is assigned the new velocity. Then the RigidBody is moved. Direct changes to velocity are applied after the forces are calculated. T$$anonymous$$s is by design, otherwise direct velocity changes would be overridden by the physics engine.

In terms of your script that means v is reading the velocity before the force is applied. In your case 0. Then the physics update is applied, w$$anonymous$$ch applies your force. Then you set the velocity back to v, w$$anonymous$$ch is zero.

Note: I'm not 100% certain that velocity changes are applied after forces by PhysX. But t$$anonymous$$s does seem to be the most logical cause to your problem. The other possibility is that your force simply isn't large enough. If I get bored enough I might run a few tests to confirm.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
1

Answer by Chris the Horribly Named · Jan 21, 2015 at 08:57 AM

I was intrigued by BoredMormon's post, so I did a quick test in 4.6.1 to confirm/explore when AddForce indeed happens.

Compare version 1:

    void FixedUpdate()
     {
         print("Enter FixedUpdate. rigidbody v: " + t$$anonymous$$s.rigidbody.velocity);
         t$$anonymous$$s.rigidbody.velocity += Vector3.forward;
         print("Exit FixedUpdate. rigidbody v: " + t$$anonymous$$s.rigidbody.velocity);
     }

to version 2:

    void FixedUpdate()
     {
         print("Enter FixedUpdate. rigidbody v: " + t$$anonymous$$s.rigidbody.velocity);
         t$$anonymous$$s.rigidbody.AddForce(Vector3.forward, ForceMode.VelocityChange);
         print("Exit FixedUpdate. rigidbody v: " + t$$anonymous$$s.rigidbody.velocity);
     }

With Version 1 you get what you might expect, namely if you update rigidbody.velocity, the change is visible right away, just as with a "normal variable":

 Enter FixedUpdate. rigidbody v: (0.0, 0.0, 0.0)
 Exit FixedUpdate. rigidbody v: (0.0, 0.0, 1.0)
 Enter FixedUpdate. rigidbody v: (0.0, 0.0, 1.0)
 Exit FixedUpdate. rigidbody v: (0.0, 0.0, 2.0)
 Enter FixedUpdate. rigidbody v: (0.0, 0.0, 2.0)
 Exit FixedUpdate. rigidbody v: (0.0, 0.0, 3.0)
 Enter FixedUpdate. rigidbody v: (0.0, 0.0, 3.0)
 Exit FixedUpdate. rigidbody v: (0.0, 0.0, 4.0)

With Version 2, in contrast, we see don't see the rigidbody's velocity being increased until we get to the next FixedUpdate:

 Enter FixedUpdate. rigidbody v: (0.0, 0.0, 0.0)
 Exit FixedUpdate. rigidbody v: (0.0, 0.0, 0.0)
 Enter FixedUpdate. rigidbody v: (0.0, 0.0, 1.0)
 Exit FixedUpdate. rigidbody v: (0.0, 0.0, 1.0)
 Enter FixedUpdate. rigidbody v: (0.0, 0.0, 2.0)
 Exit FixedUpdate. rigidbody v: (0.0, 0.0, 2.0)
 Enter FixedUpdate. rigidbody v: (0.0, 0.0, 3.0)
 Exit FixedUpdate. rigidbody v: (0.0, 0.0, 3.0)
 Enter FixedUpdate. rigidbody v: (0.0, 0.0, 4.0)
 Exit FixedUpdate. rigidbody v: (0.0, 0.0, 4.0)

So AddForce is indeed being delayed until after FixedUpdate

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Tofa · Jan 21, 2015 at 10:04 AM 0
Share

Thanks! Yes, since my original post, I've kept with AddForce.

Just to add something I tried which helped: For cases when you need to access the 'latest' velocity during the FixedUpdate you can just setup something to cache it, i.e. you just write to your cache and it sums up what you are adding, so reading back gives you what you'd expect. Then at the end of the FixedUpdate you actually send the total cached velocity out via AddForce, and at the start of FixedUpdate you can reset your internal cache to be the rigidbody velocity again.

avatar image
0

Answer by Ferb · Sep 30, 2014 at 05:30 PM

My guess would be that there's a bug in w$$anonymous$$ch the AddForce is updating the velocity, but the old velocity is still being stored in the physics engine for certain reasons, getting rigidbody.velocity is getting the old value before you changed it, and setting it is setting the value that had been updated.

As for why you shouldn't alter velocity, it's basically because it messes with physics. You could do it if you're really really careful, but all the checks you're going to have to make to avoid unintended consequences will be awkward.

Take t$$anonymous$$s instance for example - using force to move a character, but changing velocity to cap the speed. The trouble is that t$$anonymous$$s may also cap the speed not only when the player is trying to move, but when a fast object is pus$$anonymous$$ng the player. And if the players velocity is capped in that instance, you may have an irresistible force pus$$anonymous$$ng an immovable (or immovable past a certain speed) object, w$$anonymous$$ch will cause big problems, such as the two objects starting to overlap. A better solution to cap the player movement speed would be to just check the current movement speed first, and reduce the amount of force applied accordingly. Here is the code I use in my 2D-platformer so that the user can't make the player run faster than 3 units per second. (The commands will be slightly different for 3D-rigidbodies.)

     tempvel = rigidbody2D.velocity;
     tempvel.x = 3f * hInput;
     rigidbody2D.AddForce(0.1f * (tempvel - rigidbody2D.velocity),ForceMode2D.Impulse);

(The multiplication by 0.1 is so that the character slowly accelerates rather than immediately running at the requested speed.) All movement here is by added force rather than setting the velocity, but the speed the user can move the player is still capped, but the character can move at greater speeds if moved by other forces in the level.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Owen-Reynolds · Sep 30, 2014 at 08:15 PM 0
Share

Your example doesn't necessarily have a max speed of three. AddForce will gladly move the player faster and faster and faster, like a rocket on a spaceship. If you think about it, it Adds Force, which increases the speed.

The only reason velocity is capped is because of friction (rigidbody drag, and frictionMaterials.) Eventually the Added force and friction exactly cancel, and you get a max speed. But if you tweak drag, the max changes. Or if you want to change the max to 4 ... the math isn't obvious. Or if you want to increase accel, but not max speed.

Normally, the exact speed won't matter, as long as it looks good, and you can do it by eye. If you need an exact max speed, adding if(rigidbody.velocity.magnitude lessThan 3) before the push mostly works.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

7 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Countering AddForce by Modifying velocity 3 Answers

How can I convert velocity/direction to Force? 3 Answers

AddForce vs Velocity issues with Rigidbody2D 2 Answers

Is there a formula I can use to calculate force needed to achieve a certain velocity? 2 Answers

Throwing knife doesn't throw correctly 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges