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 as42 · Jul 02, 2014 at 05:35 AM · lerpasyncanimatethreadstween

Asynchronously and smoothly move a 2D player character?

Let's say I have a 2D rpg game (think Pokemon or old Zelda).

I want to hit "up" and have the player character smoothly walk one block up (say a block is 32 pixels, or some noticeable distance, and characters always move in units of blocks... basically Pokemon, like I said).

On beginner's instinct I wanted to do this:

 void Update() {
     if(Input.GetKeyDown(KeyCode.upArrow) {
         Vector2 newPos= //blah blah blah Mr Freeman
         transform.position = Vector2.Lerp(oldPos, newPos, Time.deltaTime);
     }
 }

But obviously the problem arises that Lerp must happen continuously to appear like smooth motion, and since it is enclosed within that if statement, that will definitely not be the case, meaning the object will jump across the screen.

The obviously (and obviously bad) "solution" would be a while loop:

     // Update is called once per frame
     void Update () {
         moveCharacter();
     }
 
 
     void moveCharacter() {
         if(Input.GetKeyDown (right)) {
             Vector2 to = //blah blah blah
             while(Vector2.Distance(transform.position, to) > 3) {
                 transform.position = Vector2.Lerp (transform.position, to, Time.deltaTime);
             }
         }
     }


But this raises some questions. First, it seems like Time.deltaTime doesn't change within the same iteration of Update()? That is to say, Update() was called once, which then called moveCharacter(), which started the while loop. But since we're still in just the first iteration of Update(), does Time.deltaTime remain accurate, so that Time.deltaTime in the beginning of a long Update() call will be different than Time.deltaTime by the end?

Also, I'm curious as to what thread this while loop sits on. If I have a lengthy while loop (never a good idea) and it's in a script associated with this player GameObject, if it starts looping forever, what will it block? Will the whole game freeze as this while loop performs? Or is threading done intelligently?

In the end, my question is "How can I perform this translation smoothly over time without blocking other execution and without doing something needlessly complex." Hopefully I get answers to all those other questions I asked along the way, too...

Thanks for listening.

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
0
Best Answer

Answer by Lazdude17 · Jul 02, 2014 at 06:14 AM

 private float currentX; //Current x position
 private float currentY; //Current y position
 private Vector2 playerPos; //Player Position
 private float stepTargetX; //Destination after key press
 private float stepTargetY; //Destination after key press
 
 void Update()
 {
     if(Input.GetKeyDown(Up) && playerY == stepTargetY) //Can only move after previous move is finished
     {
         stepTargetY = playerY + 32 //or whatever number you want
     }
     
     if(playerY < stepTargetY)
     {
         Mathf.Lerp(playerY, stepTargetY, //Whatever time you want * Time.deltaTime)
     }
     //Repeat for other directions
 
     playerPos = new Vector2(playerX, playerY);
     transform.position = playerPos;
 
 }

Hope it helps get you started. Idk about answering the rest of those haha but I think this should work. If not let me know.

Comment
Add comment · Show 4 · 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 as42 · Jul 02, 2014 at 11:20 PM 0
Share

Thanks, will give it a shot!

avatar image as42 · Jul 03, 2014 at 12:15 AM 0
Share

I ended up doing everything from your suggestion, except I simplified it a bit by removing the lerp. The reason for this is it turns out I don't want acceleration and deceleration with the movement, just constant speeds. So simply transfor$$anonymous$$g the position directly did the job.

Just wondering, how do I figure out the dimensions of my screen? Not pixels, but whatever unit of density Unity uses? It seems to be far denser than pixels, since lerping a character was specific down to many decimals...

avatar image Lazdude17 · Jul 03, 2014 at 12:30 AM 0
Share

Well when you import a sprite you have the option to set the pixels to units conversion. If you left it at 100 then 100 px X 100 px is One Unity Unit. So if you have a 16X16 character then your Unit would be about 6.25 characters across. So I think you could find out the size you want through that...I believe this to be accurate haha may want to ask a smarter person.

avatar image The2ndQuest · May 16, 2018 at 05:44 AM 0
Share

Hey, hope you don't $$anonymous$$d me hopping in here, but this question/thread is pretty much what I'm trying to do for a simple movement test but the above code doesn't seem to work and similar questions on here aren't trying to achieve the same effect as this thread.

So, basically, I'm just trying to increment the x or y position by 0.7 (which would move the character to the next tile) and while i can get an instant "snap" to work easily enough, getting the character sprite to visually transition to that position is the problem I've been having for the past few hours.

The code above seems to be the right idea for what I'm trying to do, but it results in zero character movement. Now, some of the variables were undeclared or mislabeled in the example ("currentX vs "playerX", for instance); or "playerX" & "playerY" never being defined), so I'm wondering if my attempts to correct those somehow screwed something else up?

Here's the code I have so far, for just the "up" and "right" keys (so both x and y values can be modified- i'll just duplicate the other two once i get these working).

     private float playerX; //Current x position
     private float playerY; //Current y position
     private Vector2 playerPos; //Player Position
     private float stepTargetX; //Destination after key press
     private float stepTargetY; //Destination after key press
 
     void Start()
     {
         playerX= transform.position.x; 
         playerY= transform.position.y; 
 
     }
 
     void Update()
     {
 
         if(Input.Get$$anonymous$$eyDown("up") && playerY == stepTargetY) //Can only move after previous move is finished
         {
             stepTargetY = playerY + 0.7f; //or whatever number you want
         }
 
         if(playerY < stepTargetY)
         {
             $$anonymous$$athf.Lerp (playerY, stepTargetY, 0.5f * Time.deltaTime);
         }
 
         if(Input.Get$$anonymous$$eyDown("right") && playerX == stepTargetX) //Can only move after previous move is finished
         {
             stepTargetX = playerX + 0.7f; //or whatever number you want
         }
 
         if(playerX < stepTargetX)
         {
             $$anonymous$$athf.Lerp (playerX, stepTargetX, 0.5f * Time.deltaTime);
         }
 
                         //Repeat for other directions
 
         playerPos = new Vector2(playerX, playerY);
         transform.position = playerPos;
 
     }
avatar image
0

Answer by Loius · Jul 02, 2014 at 06:11 AM

Unity runs in a single thread - Updates and other Unity special functions are called sequentially and they can block.

Normal functions are not threaded and cause blocking behaviour (your code blocks execution, moves the character gradually from a to b over one frame, then resumes).

Coroutines run when they can (similar timing to Update, but I'm not sure what order Update, coroutines, and LateUpdate are called in), but are still part of the main program and will block while they're executing. You use yield return {value} to pause execution of a coroutine, and you must always use StartCoroutine to begin a coroutine (if your coroutines seem to be silently failing, you probably forgot to StartCoroutine them)

yield return null - wait one frame

yield return new WaitForSeconds(float) - wait for some number of seconds

yield return StartCoroutine(Function()) - wait for a subroutine to complete before continuing

 void Update() {
   if ( Input.GetKeyDown(KeyCode.UpArrow) ) {
     StartCoroutine(Move(Vector3.up));
   }
 }
 
 bool isMoving = false;
 float speed = 2f;
 
 IEnumerator Move(Vector3 offsetFromCurrent) {
   if ( isMoving ) yield break; // exit function
   isMoving = true;
   Vector3 from = transform.position;
   Vector3 to = from + offsetFromCurrent;
   for ( float t = 0f; t < 1f; t += Time.deltaTime * speed ) {
     transform.position = Vector3.Lerp(from,to,t);
     yield return null;
   }
   transform.position = to;
   isMoving = false;
 }

Actual threads run in parallel as expected, but it's important to note that their access to Unity objects (Transform, etc) is very limited (you generally need to create a separate class, unrelated to Unity, which your Unity-linked class can communicate with).

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

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

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

Animate fanning cards almost works! 1 Answer

How to animate a UI Button without using Mecanim? (For example, by using DOTween instead) 1 Answer

Change a gameObject property at runtime from another thread 0 Answers

Thread in Jar verify it in Unity 1 Answer

Easy transition between multiple views? 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