Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • 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
6
Question by greel · Dec 15, 2011 at 09:40 PM · rigidbodyaddforcemovetargetmouse control

Stopping a rigidbody at target

Hi,

we're currently developing a dungeon siege style top down game where the player moves his character with mouse clicks. Since physics will have to take full effect on the character we decided to move the avatar by rotating its rigidbody towards the mouse and then use AddForce to move it along it's forward axis.

 void Move()
 {
     Vector3 dir = rigidbody.transform.forward * _fCurrentSpeed;    
     Vector3 v3TargetPos = new Vector3(v3MouseTarget.x, rigidbody.transform.position.y, v3MouseTarget.z);

     if(Vector3.Distance(rigidbody.transform.position, v3TargetPos) <= .5f )
     {    
         _fCurrentSpeed = 0f;
     }
     else
     {
         _fCurrentSpeed = fSpeed;
         transform.LookAt(v3TargetPos);
     }    
     rigidbody.AddForce(dir);

 }

The problem here is that the rigidbody will usually overshoot, turn around, walk back, and then stop. If i try to set the stop condition to transform.position == v3TargetPos the avatar will turn endlessly as the added force will always make it overshoot the target position.

Does anyone have an idea how to effectively stop the character once he's reached the target position? Alternate methods are also welcome :)

Thanks

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

1 Reply

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

Answer by aldonaletto · Dec 16, 2011 at 01:29 AM

Applying a force to reach some position is hard to control: the distance is a complicated function (integral) of force intensity, time and mass.

A simple solution is to just zero rigidbody.velocity when the target is reached, but this produces a very weird and unnatural result - the rigidbody just stops at the target position.

A better alternative is to use a feedback control algorithm, where the force is applied to reach a target velocity, and this velocity (clamped to some max value) is proportional to the distance to the target point - this way it will fall to zero when the target point is reached, stopping the rigidbody:

 public float toVel = 2.5f;
 public float maxVel = 15.0f;
 public float maxForce = 40.0f;
 public float gain = 5f;

 Rigidbody rbody;
 
 void Start(){
   rbody = GetComponent<Rigidbody>();
 }

 void FixedUpdate(){
   Vector3 dist = targetPos - transform.position;
   dist.y = 0; // ignore height differences
   // calc a target vel proportional to distance (clamped to maxVel)
   Vector3 tgtVel = Vector3.ClampMagnitude(toVel * dist, maxVel);
   // calculate the velocity error
   Vector3 error = tgtVel - rbody.velocity;
   // calc a force proportional to the error (clamped to maxForce)
   Vector3 force = Vector3.ClampMagnitude(gain * error, maxForce);
   rbody.AddForce(force);
 }

This controller makes the rigidbody go in the targetPos direction - just set targetPos to the desired position, and the rigidbody goes there. It doesn't rotate the rigidbody to the target direction, however - you may do it at Update.

The parameters maxVel, maxForce, toVel and gain adjust the controller characteristics, and may be tweaked to reach a stable and precise operation: maxVel is the max speed the rigidbody will reach when moving; maxForce limits the force applied to the rigidbody in order to avoid excessive acceleration (and instability); toVel converts the distance remaining to the target velocity - if too low, the rigidbody slows down early and takes a long time to stop; if too high, it may overshoot; the last parameter, gain, sets the feedback amount: if too low, the rigidbody stops before the target point; if too high, it may overshoot and oscillate (like your current algorithm).

Comment
Add comment · Show 13 · 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 greel · Dec 16, 2011 at 10:23 AM 0
Share

Thanks a lot!

I've implemented your approach and it works like a charm :) To further prevent the oscillation I've also added a distance check that will make the avatar simply look ahead of himself ins$$anonymous$$d of at the target position once he is close enough.

Very helpful. Thank you again :D

avatar image x70x · Oct 15, 2014 at 08:43 PM 0
Share

I'm using this basic functionality to create a sort of gravity gun for a first person game, but the objects I'm controlling seem to have a bit of a jittery movement when moving quickly. Is there something that is missing from this script that might improve the smoothness?

avatar image petey · Jan 07, 2017 at 03:04 AM 0
Share

Hiya @aldonaletto, I was messing around with this a bit and decided to make a little scene to test different values out quickly. Here's a webplayer link if anyone else wants to have a play. http://www.peterleary.com/ForumFiles/Attract/index.html

avatar image goutham12 · Mar 01, 2017 at 06:07 AM 0
Share

@aldonaletto iam doing a game(drone type). in that i have to stop the player at some target position. and one more condition it should not stop by calculating the distance. it should consider the mass of the object. apply force(up) also should consider mass after gets mass zero it should stop.

"theoretically if a object is going up and up and up their mass will reduse. how can we come to know here"

avatar image ijidau · Jan 03, 2018 at 11:56 PM 0
Share

@aldonaletto Thanks so much for your answer, this solved my problem. I'd like to understand it more though, where did you learn about this technique?

avatar image aldonaletto ijidau · Jan 05, 2018 at 03:12 AM 0
Share

This code implements a kind of Proportional Derivative Control, where the force applied is proportional to the distance to the target and also to its current velocity (velocity is the derivative of distance over time, hence the name Proportional Derivative). This algorithm first calculates the velocity needed proportionally to the current distance to the target position, then estimates the force necessary to reach the desired velocity - this way it automatically accelerates during most of the time and decelerates when getting near to the target.
I've kind of invented this algorithm based on previous experiences with real world servo controllers, but you can obtain more technical information from Wikipedia (PID controller)
NOTE: PID stands for Proportional Integral Derivative, and it's a little more complex than PD (Proportional Derivative). The Integral (I) term helps to zero the difference to the target due to friction in the real world, but in Unity we definitely don't need it - the simpler PD control does the job.

avatar image ijidau aldonaletto · Jan 05, 2018 at 04:21 AM 0
Share

Thanks for the explanation! I did end up finding some articles about PID Controllers, but had no idea what to search for initially. To experiment further, I've implemented this example with poor results (oscillation and crazyness).

I'll try to think through your PD approach more. It's very interesting and works a treat, I just have to sit down and write out the maths to properly wrap my head around it. $$anonymous$$aths does not come naturally to me.

From there I think your PD algorithm could be encapsulated into a class/library and then used across several applications.

Show more comments
Show more comments

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.

Follow this Question

Answers Answers and Comments

12 People are following this question.

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

Related Questions

How do you use add force to move a rigidbody to a transform.position? 1 Answer

How to make rigidbody.AddForce and controller.Move work together? 0 Answers

rigidbody addforce behaves different every time 2 Answers

rigidbody.AddForce(transform.forward * 5000) 1 Answer

Very simple water bouyancy script not working? 1 Answer


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