How to ping pong precisely between two points

Hi,
I’m building an obstacle that will be used inside a tunnel. It’s basically a set of objects that will move towards the center of the tunnel, and then move back out towards it’s circumference and repeat indefinitely.

I’m trying to use MathF.PingPong to achieve this and whilst it looks like it works there is variation in the open/closed positions. This will cause a problem as when the ‘gate’ is supposed to be open, there’s a chance it might still be protruding into the tunnel.

If you look at the difference in the size of the inner hole at 3 secs and 21 secs, you can see how much variance is occuring.

Ultimately I want them staggered like a ripple so my code is setup for that, but i’ve simplified it for the purposes of posting here. This is attached to a empty game object and starts the movement (will be used to stagger the start of each pillar):

public class PillarController : MonoBehaviour
{
    [SerializeField] private List<GameObject> Pillars = new List<GameObject>();

    void Start()
    {
        StartCoroutine(StaggeredStart());
    }

    IEnumerator StaggeredStart()
    {
        foreach (var pillar in Pillars)
        {
            var pillarMovement = pillar.GetComponent<PillarMovement>();
            pillarMovement.StartPingPonging();
        }

        yield return null;
    }

}

This is on the PillarContainer objects, which are empty GameObjects that have the pillars (capsules) as children:

public class PillarMovement : MonoBehaviour
{

    private bool canPingPong = false;
    [SerializeField] private  float length;
    [SerializeField] private float sloMoMultiplier;

    public void StartPingPonging()
    {
        canPingPong = true;
    }

    void Update()
    {
        if (canPingPong)
        {
            DoPingPong();
        }
    }

    private void DoPingPong()
    {
        var lPos = transform.localPosition;
        var upMovement = (Mathf.PingPong(Time.time, length) - length / 2) / sloMoMultiplier;
        transform.Translate(new Vector3(0,upMovement,0),Space.Self);
    }
}

Is it possible to get the capsules to start and stop at precise locations, with the caveat that floats aren’t ever going to exactly match my start and end values? Seems like the variance is larger than what would be caused by tiny decimal differences.

Repro package attached.

Thanks
Mick

8122196–1052822–ImprecisePingPong.unitypackage (15.4 KB)

It’s safest to avoid relying on cyclic, accumulating values unless they’re integers (which obviously they can’t be here) due to the possibility of rounding errors building up.

Here I would either:

  • Replace the script with an Animator and trigger/enable a parameter to set it going, or
  • Use Mathf.Sin((Time.time * speed) + offset) * movementHeight to calculate the position rather than the velocity each frame.
3 Likes

Thanks. I went for the simple animator approach and it worked perfectly. Believe it or not i’m about two weeks from releasing a game and it goes to show that I often try to solve issues programmatically when i’d be better off using the available tools in Unity: