0
\$\begingroup\$

I've been trying to create a battle system for my game, and I've been trying to get a UI image to bounce back and forth inside another image, but for some reason, the UI image goes out of the other UI and bounces back, like so:

UI Bounce Glitch

Here's the script I add to the moving arrow image, in order to make it bounce:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class JumpSystem : MonoBehaviour
{
    private Vector2 startPosition;
    public int speed;

    // Start is called before the first frame update
    void Start()
    {
        startPosition = transform.position;
    }

    // Update is called once per frame
    void Update()
    {
        transform.position = new Vector2(startPosition.x + Mathf.Sin(Time.time * speed), transform.position.y);
    }
}

Is there any way I can prevent this incident from occurring? Please help me understand this and thank you in advance.

\$\endgroup\$
4
  • \$\begingroup\$ I don't see outer image's bounds in your calculations. \$\endgroup\$ Commented Mar 23, 2021 at 11:07
  • \$\begingroup\$ @ShadowsInRain The white arrow goes out of the gray box. \$\endgroup\$ Commented Mar 23, 2021 at 11:54
  • \$\begingroup\$ I'm pretty sure what @ShadowsInRain meant was we don't see any computationally reference to the image bounds. It doesn't look like you are scaling the displacement to the desired region. \$\endgroup\$
    – Pikalek
    Commented Mar 23, 2021 at 13:38
  • \$\begingroup\$ @Pikalek I see. That’s the thing. I don’t know exactly how to do that. \$\endgroup\$ Commented Mar 23, 2021 at 14:03

3 Answers 3

0
\$\begingroup\$

Try to put it in the Lateupdate(). or try to use mathf.lerp.

\$\endgroup\$
1
  • \$\begingroup\$ This answer is not very specific about what code should be written in LateUpdate or *how" one should use Mathf.Lerp to achieve this effect. \$\endgroup\$
    – DMGregory
    Commented Mar 24, 2021 at 11:38
0
\$\begingroup\$

Disclaimer: There's probably an off-the-self way to get this result from Unity with a built in lerp of some kind. That's a fine idea & it would probably be my first choice. This answer is meant to explain how to get the result manually.

Let's take the expression below apart, understand what it does & doesn't do, and then fix it:

startPosition.x + Mathf.Sin(Time.time * speed)

Starting from the inside & thinking about the math in general, Mathf.Sin(n) will return a value between -1 & 1 (inclusive).

By using Time.time instead of n you get something that will oscillate between -1 & 1 over time.

Multiplying Time.time by speed will scale the rate of oscillation. A speed of 2 will double the rate whereas a speed of 0.75 will make it one fourth slower.

Adding startPosition.x will displace the result. For instance, if startPosition.x has a value of 10.0, then the net result is an oscillation between 9.0 and 11.0.

Thus, the original expression alters the rate and midpoint of the oscillation.

Since you want to oscillate in a region of a particular size, you need to introduce math to scale the range the oscillation. Let's say you want to keep the animation within the bounds of 20 & 25. That requires a range of 5. But recall that sin goes from -1 to 1, so a scaling factor of 2.5 would change it to -2.5 to 2.5, which is a total range of 5 (part of our goal):

xMin = 20;
xMax = 25;
range = xMax - xMin;
scale = range/2.0;
x = scale * Mathf.Sin(Time.time * speed);

The last step is to move it to the desired location. One way to think about that is to recall that sin oscillates about a midpoint. If the target region is 20 to 25, then the target midpoint would be 22.5 and if we check the math, 22.5 ± 2.5 gives a result of 20 to 25. Note that the midpoint is actually the same as the starting bound plus half the range, which is the same thing as the scale. So the final expression would be something like this:

xMin = 20;
xMax = 25;
range = xMax - xMin;
scale = range/2.0;
xMid = mMin + scale;
x = xMid + scale * Mathf.Sin(Time.time * speed);

The code above could be simplified, however it has the benefit of being very explicit: you know what each part does making it easier to understand, modify & maintain. Adjust as necessary to fit your needs.

\$\endgroup\$
0
0
\$\begingroup\$

By using a RectTransform instead of a GameObject or Tranform type, I was able to access the anchorMin and anchorMax inside of the UI. Then, I simply created a private positionPercentage float and used Mathf.PingPong(), in order to get the back-and-forth movement I desired.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class JumpSystem : MonoBehaviour
{
    public float speed = 0.75f;
    private float positionPercentage; // float changed to allow back and forth movement
    public RectTransform imageTransform; // new type chosen

    void Update()
    {
        positionPercentage = Mathf.PingPong(speed * Time.time, 1); // determines the rate of UI movement

        // implement the positionPercentage movement
        imageTransform.anchorMin = new Vector2(positionPercentage, 0.5f);
        imageTransform.anchorMax = new Vector2(positionPercentage, 0.5f);
    }
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ You probably don't need positionPercentage to be a member variable, since you calculate it from scratch every frame. It can simply be a local temporary variable inside Update. \$\endgroup\$
    – DMGregory
    Commented Mar 24, 2021 at 1:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .