Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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
0
Question by andreadoria · Sep 29, 2020 at 11:08 AM · animationinteractionvector3.lerp

How to "snap" the player into a position to perform an action

Hello. In my third person player project, my character need to perform interactions with some objects in the environment. What i have so far it's working. I can reach a certain distance from the object and start the interaction, but i can't properly "snap" my character into a "null object" that hold the position where i have to move in order to perform the action, right in front of the object.

If i do a very rude:

 public void MoveToPosition (Transform targetPos)
 {
       transform.position = targetPos.position;
 }

it work always. The character snaps right into place every time but it's very brutal and very ugly to watch. But if i try something more appropriate like this:

 public void moveTowardsPoint(Vector3 targetPos, Vector3 rotationDir, float moveSpeed, float rotationSpeed)
     {
         animator.SetBool("walking", true);
         transform.position = Vector3.MoveTowards(transform.position, targetPos, moveSpeed * Time.deltaTime);
         transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(rotationDir), Time.deltaTime * rotationSpeed);
     }

it never reach the exact center of the target position (the null object). It always stop much before, so the position is never the same, and i need to be in that exact point to perfom the animation correctly.

Here is a practical example of what i need.

https://www.youtube.com/watch?v=8OZsM5n4B2I

How do i solve this? I tried some ThirdPerson Character Controllers on the asset store that does something like this, but i don't want to customize a pre-made solution. I want to learn how to properly do stuff.

Somebody help?

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

2 Replies

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

Answer by SarperS · Sep 30, 2020 at 05:30 PM

Don't forget to disable any user input or operation that changes the transform.positionand transform.rotation values while the coroutine is running.

 private IEnumerator _snapToCoroutine;
 
 // Call this method, it makes sure you don't create multiple coroutines that fight for the current transform.position, only one instance of the coroutine runs
 public void SnapTo(Vector3 snapPosition, Quaternion snapRotation, float duration) {
     if(_snapToCoroutine != null) StopCoroutine(_snapToCoroutine);
     _snapToCoroutine = SnapToCoroutine(snapPosition, snapRotation, duration);
     StartCoroutine(_snapToCoroutine);
 }
 
 // Stops the running snap coroutine, only if a snap coroutine is running
 public void CancelSnap() {
     if(_snapToCoroutine != null) StopCoroutine(_snapToCoroutine);
 }
 
 private IEnumerator SnapToCoroutine(Vector3 snapPosition, Quaternion snapRotation, float duration) {
     // Store the start time and position, we require these for the linear interpolation
     float startTime = Time.time;
     Vector3 startPosition = transform.position;
     Quaternion startRotation = transform.rotation;
 
     // While the duration is not reached, move the position towards the snap position, increasing the value in equal steps for the given duration, every frame
     while(Time.time - startTime < duration) {
         // Gives us a value starting from 0 and ending in 1 as time progresses towards our duration, we will feed this 0-1 value into our linear interpolation
         float t = (Time.time - startTime) / duration;
 
         // This method performs faster than manually assigning transform.position and transform.rotation
         transform.SetPositionAndRotation(Vector3.Lerp(startPosition, snapPosition, t), Quaternion.Lerp(startRotation, snapRotation, t));
 
         yield return null;
     }
 
     // And finally snap to the desired position to eliminate any tiny floating point differences due to timing above
     transform.SetPositionAndRotation(snapPosition, snapRotation);
 }
Comment
Add comment · Show 6 · 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 andreadoria · Sep 30, 2020 at 06:00 PM 0
Share

Thank you very much! I'm going to try it, and from the comments, that's explain a lot why my position was always insufficient to reach the right center of the null.

avatar image SarperS andreadoria · Sep 30, 2020 at 06:03 PM 1
Share

You are welcome. Oh by the way, it seems I forgot to interpolate the rotation, the idea is the same though. Just store the starting rotation and then Quaternion.Lerp it towards the snapRotation (add this as another parameter) .

avatar image andreadoria SarperS · Oct 01, 2020 at 07:45 AM 0
Share

Thank you! It works as intended! That's exactly what i needed!

avatar image andreadoria · Oct 01, 2020 at 08:13 AM 0
Share

Hey @SarperS now it works also with the Rotation.

 public void SnapTo(Vector3 snapPosition, Quaternion snapRotation, float duration)
     {
         if (_snapToCoroutine != null) StopCoroutine(_snapToCoroutine);
         _snapToCoroutine = SnapToCoroutine(snapPosition, snapRotation, duration);
         StartCoroutine(_snapToCoroutine);
     }
 
     private IEnumerator SnapToCoroutine(Vector3 snapPosition, Quaternion snapRotation, float duration)
     {
         // Store the start time and position, we require these for the linear interpolation
         float startTime = Time.time;
         Vector3 startPosition = transform.position;
         Quaternion startRotation = transform.rotation;
 
         // While the duration is not reached, move the position towards the snap position, increasing the value in equal steps for the given duration, every frame
         while (Time.time - startTime < duration)
         {
             transform.position = Vector3.Lerp(startPosition, snapPosition, Time.time - startTime / duration);
             transform.rotation = Quaternion.Lerp(startRotation, snapRotation, Time.time - startTime / duration);
             yield return null;
         }
 
         // And finally snap to the desired position to eli$$anonymous$$ate any tiny floating point differences due to ti$$anonymous$$g above
         transform.position = snapPosition;
         transform.rotation = snapRotation;
     }

The only thing i notice is that if try to increase the speed of the snap (at 1.0f is very slow), it snaps immediately like before, like the Lerp isn't working. Even if try small increments like 1.1f or something like it, it snaps immediately. $$anonymous$$aybe because of the nature of Time.time? Should i try a different calculation in ti$$anonymous$$g?

avatar image SarperS andreadoria · Oct 01, 2020 at 08:38 AM 1
Share

Heh, this is what happens when you post not compiled and not tested code :) The problem was very simple, I forgot to add parentheses to the below line so division was happening before the required subtraction.

Time.time - startTime / duration should have been (Time.time - startTime) / duration

Anyways, I've updated the answer and cleaned up your code a little bit, and added new comments. Hope it helps improve your understanding. Take care.

http://answers.unity.com/answers/1776444/view.html

avatar image andreadoria SarperS · Oct 01, 2020 at 09:02 AM 0
Share

Thank you sir! This is exactly what i needed, and i learned something! Thank you!

avatar image
0

Answer by andreadoria · Oct 04, 2020 at 10:01 AM

I've found another solution that i think it's even more "elegant". It requires the DOTween library but i think it worth it. Same method as before with the coroutine but with DOTween you can give that "ease" curve to the movement that makes it a bit more nicer to look at.

 using DG.Tweening;

 public Ease ease; // Choose an ease curve from the inspector
 private IEnumerator _moveToPosCoroutine;
 
 // Call this method first, it makes sure you don't create multiple coroutines that fight for the current transform.position, only one instance of the coroutine runs
     public void MoveToPosition(Vector3 snapPosition, Quaternion snapRotation, float duration)
     {
         if (_moveToPosCoroutine != null) StopCoroutine(_moveToPosCoroutine);
         _moveToPosCoroutine = MoveToPositionCoroutine(pos01.transform.position, pos01.transform.rotation, duration);
         StartCoroutine(_moveToPosCoroutine);
     }
 
 // Stops the running snap coroutine, only if a snap coroutine is running
     public void CancelMoveToPos()
     {
         if (_moveToPosCoroutine != null) StopCoroutine(_moveToPosCoroutine);
     }
 
 private IEnumerator MoveToPositionCoroutine(Vector3 snapPosition, Quaternion snapRotation, float duration)
     {
         // Store the start time and position, we require these for the linear interpolation
         float startTime = Time.time;
 
         // While the duration is not reached, move the position towards the snap position, increasing the value in equal steps for the given duration, every frame
         while (Time.time - startTime < duration)
         {
             // Gives us a value starting from 0 and ending in 1 as time progresses towards our duration, we will feed this 0-1 value into our linear interpolation
             float t = (Time.time - startTime) / duration;
 
             // Transform position and rotation with DOTween library with ease curve.
             transform.DOMove(snapPosition, 0.05f, false).SetEase(ease);
             transform.DORotateQuaternion(snapRotation, 0.05f);
 
             yield return new WaitForSeconds(t);
         }
     }
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 SarperS · Oct 04, 2020 at 10:41 AM 0
Share

You don't need DOTween for that. You can achieve the same very easily like below:

First declare a public AnimationCurve you can play with in the inspector

public AnimationCurve SnapCurve;

Then change the line where we calculate the t as such so that it uses the curve while calculating it's value.

float t = SnapCurve.Evaluate((Time.time - startTime) / duration);

That's it, now you can apply any kind of easing or funky effect you can think of.

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

337 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 avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image 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

Animation the involves two game objects 1 Answer

Can the animation editor create local rotational data? 3 Answers

Adding animation clips via script 2 Answers

Syncing a Seperate Object's Position and Animation with a Playable Character 1 Answer

Animating a chest to open/close for unity 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