- Home /
Smoothly moving a rectTransform by script
So I'm building an interface right now and I have a number panel that I want to move around. And it sort of works. I've been using a coroutine to do this, but I'm facing the problem that it either just snaps to the target, or just moves minimally (depending on where I put the yield return null;
.
In the following case it snaps:
IEnumerator MovePanelToPosition(int activeNumber)
{
while (Mathf.Abs(rectTransform.anchorMax.x - (startAnchorMax.x - (xChange * (activeNumber)).x)) > 0.02f)
{
//Debug.Log(Mathf.Abs(rectTransform.anchorMax.x - (xChange * savedNumber).x));
rectTransform.anchorMax -= xChange / 100 * movementfactor;
rectTransform.anchorMin -= xChange / 100 * movementfactor;
}
yield return null;
}
In the other case it just ends the coroutine after doing the while once (I think).
IEnumerator MovePanelToPosition(int activeNumber)
{
while (Mathf.Abs(rectTransform.anchorMax.x - (startAnchorMax.x - (xChange * (activeNumber)).x)) > 0.02f)
{
//Debug.Log(Mathf.Abs(rectTransform.anchorMax.x - (xChange * savedNumber).x));
rectTransform.anchorMax -= xChange / 100 * movementfactor;
rectTransform.anchorMin -= xChange / 100 * movementfactor;
yield return null;
}
yield return null;
}
I really just want it to move smoothly to the target location without needing to use animations. This works easy enough for normal transforms, so I'm not sure what's the issue with the rectTransform / what I'm doing wrong.
Answer by Vega4Life · Dec 06, 2018 at 09:45 PM
Try something like this:
IEnumerator MovePanelToPosition(int activeNumber)
{
while (Mathf.Abs(rectTransform.anchorMax.x - (startAnchorMax.x - (xChange * (activeNumber)).x)) > 0.02f)
{
//Debug.Log(Mathf.Abs(rectTransform.anchorMax.x - (xChange * savedNumber).x));
rectTransform.anchorMax -= xChange / 100 * movementfactor;
rectTransform.anchorMin -= xChange / 100 * movementfactor;
// TRY THIS LINE, wait for a frame //
// Waiting a frame should give it enough time to not look instant
// If the movement isn't fast enough, possible add a speed variable and multiply it to the movementFactor
yield return new WaitForEndOfFrame();
}
}
Thank you very much. This works.
Any idea why the original ones didn't? They worked well enough for moving gameObjects around.
The first one is just a loop without any delay in there, thus it just snaps. It exits the loop hits the yield and exits the coroutine.
The second one kind of works because yield return null... in a way acts like WaitForEndOfFrame(). Yield return null resumes on the next frame after the Update() call, but WaitForEndOfFrame will resume on the current frame after all the things render. Also, in your case, you already had a yield in the coroutine, so you didn't need the last on. You only need multiple yields if you plan on another delay later in the coroutine.
To me, if movement is something I am messing with, I think it's best to stick with WaitForEndOfFrame(). It literally resumes at the end of frame, after rendering, etc. You get some smooth movement that way.
Be sure to cache your yield instruction
IEnumerator $$anonymous$$ovePanelToPosition(int activeNumber)
{
var yieldInstruction = new WaitForEndOfFrame();
//...
Indeed. Though, you would cache it outside of the coroutine, so all other coroutines could use it. You wouldn't see much of an improvement, unless there were quite a few coroutines. I wouldn't cache it for just one.