MoveTowards and Lerp not working on RectTransform?
Hello i am currently working on a menu, so we are talking GUI elements, where when you click on one folder the others move away, so there is room for the chosen folder to open. But i cannot find out how to smoothly move the folders around. I have tried using MoveTowards and Lerp, but it does not work. I have left my code both for Lerp and for MoveTowards so you can see. Note This code is run in a coroutine.
//if the folder is not open...
if (!isFolderOpen)
{
//Check every RectTransform in the children list...
foreach (RectTransform child in children)
{
//and check if it's x position is bigger then the currently clicked folder
if (child.anchoredPosition.x > rect.anchoredPosition.x)
{
newPos = new Vector2(child.anchoredPosition.x - distance, child.anchoredPosition.y);
while (child.anchoredPosition != newPos)
{
//child.anchoredPosition = Vector2.MoveTowards(child.anchoredPosition, newPos, 10 * Time.deltaTime);
//child.anchoredPosition = new Vector2(Mathf.Lerp(child.anchoredPosition.x, child.anchoredPosition.x - distance, 0.5f), child.anchoredPosition.y);
yield return null;
}
Update I can now make the folders move, but the movement is not stable. The first couple of times you open and close the folders everything looks great, but after a couple of clicks, the folders start shaking and suddenly move out instead of in. Here is the new code:
private IEnumerator MoveOut(RectTransform folder, bool left) //Moves the folders outwards away from the selected folder
{
//Creates a variable to store the new position of the folder
Vector3 newPosChild;
//should it move left?
if (left)
{
//then set the new position to it's current position minus distance
newPosChild = new Vector3(folder.localPosition.x - distance, folder.localPosition.y, folder.localPosition.z);
}
//or should it move to the right?
else
{
//then set the new position to it's current position plus distance
newPosChild = new Vector3(folder.localPosition.x + distance, folder.localPosition.y, folder.localPosition.z);
}
//As long as the folder is not in it's new position...
while (folder.localPosition != newPosChild)
{
//move it towards it's new position
folder.localPosition = Vector3.MoveTowards(folder.localPosition, newPosChild, movementSpeed * Time.deltaTime);
if (Vector3.Distance(folder.localPosition, newPosChild) < 10)
{
folder.localPosition = newPosChild;
}
yield return null;
}
}
private IEnumerator MoveBack(RectTransform folder)
{
StoreOriginalPosition childOriPos;
childOriPos = folder.gameObject.GetComponent<StoreOriginalPosition>();
while (folder.localPosition != childOriPos.originalPos)
{
//move it back to it's original position
folder.localPosition = Vector3.MoveTowards(folder.localPosition, childOriPos.originalPos, movementSpeed * Time.deltaTime);
if (Vector3.Distance(folder.localPosition, childOriPos.originalPos) < 10)
{
folder.localPosition = childOriPos.originalPos;
}
yield return null;
}
}
Your code is written in one function. This is means that your 'while' loop executes during one frame. Use class variable to save target position and do your cycle code in $$anonymous$$onoBehaviour.Update() function.
NEVER compare float values with operators '==' or '!='. Use 'UnityEngine.$$anonymous$$athf.Approximately()' for floats and compare distance for vectors.
Example:
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(RectTransform))]
public class $$anonymous$$ovingRectTransform : $$anonymous$$onoBehaviour
{
private const float EPSILON = 0.1f;
private const float LERP_SPEED = 0.3f;
private RectTransform _rectTrans;
private Vector2 _targetPosition;
void Start()
{
_rectTrans = GetComponent<RectTransform>();
_targetPosition = _rectTrans.anchoredPosition;
}
// Update is called once per frame
void Update()
{
Vector2 delta = _targetPosition - _rectTrans.anchoredPosition;
if (delta.sqr$$anonymous$$agnitude < EPSILON)
{
_rectTrans.anchoredPosition = _targetPosition;
//turn off Update() call
enabled = false;
}
else
{
_rectTrans.anchoredPosition = Vector2.Lerp(_rectTrans.anchoredPosition, _targetPosition, LERP_SPEED);
}
}
public void $$anonymous$$oveTo(Vector2 newPosition)
{
_targetPosition = newPosition;
//turn on Update() call
enabled = true;
}
}
I think you your case it's better to use tweener plugin. Like that: http://dotween.demigiant.com/
Read more about float comparsion: https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
Sorry i should have added that i run this code in a coroutine, with a yield return in the while, as i do not whish to run this in a update loop. I didn't add this in the post originally, sorry. I have updated the post now. The code posted is only a small snippet of the function.
Thank you, I did not know you should not compare floats in such a way, may i ask why not?
About float comparing. I've added a link in the end of my answer: https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
I think some values of a RectTransform are computed from others, based on various other settings. That extra complexity might be the real problem.
When you write "doesn't work" do you mean the values don't change at all?
float compare using ==/!= works with $$anonymous$$oveTowards, so that wouldn't be the problem ($$anonymous$$oveTowards flat-out copies the numbers when it gets close enough.) But it would be a problem with that use of Lerp.
With updated code it now moves, but it does not act in a stable manner :/ I will update the post with the new code.
Answer by ArturoSR · Sep 24, 2016 at 08:10 PM
@SilverShadowWolf Hello there.
OK, I check your code and there is one big mistake, if you want to move your UI (no matter which element it is), you need to manipulate the position not the anchor, see the next images:
Initial position
After move it
As you can see, the anchor does not have nothing to do about position, it's just for resizing/positioning reference relative to its parent (canvas or panel), to check this, just drag the UI Gizmo (press the button after scale in the tab tools to see it) after set any type of anchor to see what I mean, cheers.
Note: You can manipulate the position by scripting using this:
RectTransform transform;
transform.localPosition = new Vector3("New Pos in X", "New Pos in Y", 0);
I see, I was told multiple places on the internet you should use the anchoredposition, and not position, but I will try this thank you. But first I have a question, why does your Rect Transform look like it does? $$anonymous$$ine does not say pos X pos Y or width and height. Is this something you have renamed?
@$$anonymous$$oSR Have you ever try to move RectTransform from script? anchoredPosition is not an anchor. http://stackoverflow.com/questions/30100482/unity-ui-recttransform-position-does-not-make-sense-to-me
Yes they are most definitely different things, as you can move the object by changing the anchoredPosition. But for some reason i cannot seem to get it to work with my code, but localPosition does.
Your answer
Follow this Question
Related Questions
esc key oddity 2 Answers
What needs to be considered when moving from a Screen Space Overlay UI to a Screen Space Camera UI? 1 Answer
UI problems 0 Answers
Help with Time Crisis crosshair 0 Answers
OnGUI() problems in unity 5.6, worked with Unity 4. 0 Answers