How to make an object spiral in toward another (moving) object using polar coordinates

Hello all,

I’m working on this game and one of the powers of this character is that he can they can shoot out this black hole like thing that sucks in nearby objects. The objects move in towards the hole in a spiraling motion (spiral inward) until they make it into the center of the hole.

I’m working on a script but I’m not too familiar with polar coordinates to make this work and when I try to implement this, the objects come towards the hole but as they get closer to the hole they slow down (I’m looking to have a constant speed) and if the hole moves, the object takes time to update and sometimes takes a large, strange, outwards orbit before correcting itself and spiraling back towards the hole. Here is some code:

    private float radius;
    [SerializeField] float radiusSpeed, theta, thetaSpeed;

    [SerializeField] private GameObject player;
    // Start is called before the first frame update
    void Start()
    {
        radius = GetDistance(player, this.gameObject);
        radiusSpeed = .05f;
        theta = 1f;
        thetaSpeed = .02f;
    }

    // Update is called once per frame
    void Update()
    {
        theta += Time.deltaTime * thetaSpeed;
        radius -= GetDistance(player, this.gameObject) * radiusSpeed * Time.deltaTime;

        transform.position = new Vector2(radius * Mathf.Cos(Mathf.Deg2Rad * theta), radius * Mathf.Sin(Mathf.Deg2Rad * theta));
    }

    private float GetDistance(GameObject a, GameObject b)
    {
        return Mathf.Abs(Vector2.Distance(a.transform.position, b.transform.position));
    }

The radius is acquired by getting the distance between the object and the target (hole) and the radiusSpeed is how fast the radius shrinks to create the spiral. The hole is referred to as player in this instance. I made a change to the game but haven’t reflected it in variable names yet.

I’m not 100% sure how my theta (angle) and the thetaSpeed are working, but what I thought this would do is grab theta which starts off as 1 which I assume is angle 1 and, multiplies it by how fast I want the angle to grow

Then, the new position of this object is the new value of the radius (which is the distance that updates every frame) multiplied by the sine and cosine (for x and y respectively) of the degrees but in radians.

I wrapped the Vector2.Distance call in a different function because I didn’t want to keep writing that out I’m not sure if the fact that I’m using Mathf.Abs has anything to do with it.

My assumptions for my sources of error are as follows:
As for the object slowing down as it gets closer to the hole, I’m assuming I need to normalize something
For the strange orbital pattern I’m assuming I’m not properly setting the objects to follow the hole but I’m not sure what I’m missing.

Math.Abs should be redundant since Vector2.Distance() always returns non-negative numbers.

I think the weird orbital thing is a feedback between the calculated radius and distance to player.

You might have better luck with the effect if you create the theta and radius parametrically off of a linearly increasing (or decreasing) time basis, all centered on the player’s position, sort of like that “super spirograph” game back in the day.

Try replace lines 17 and 18 above with this:

        // Time basis: t goes from 10 down to 0 and restarts at 10, again and again
        float t = 10 - ((Time.time * 2) % 10);

        float RateOfRange = 1;

        float RateOfSpin = 100;

        float theta = t * RateOfSpin;

        float radius = t * RateOfRange;

to see what I mean.

You can also get pretty cool effects like this just parenting objects to another invisible spinning object on the player, and gradually moving the outer objects towards the central spinning object, let Unity handle the transforms for you.

Or… just with Animations! :slight_smile:

@Kurt-Dekker Man you’re a genius!

Any source online where I can get an explanation on this?

The odd thing now though is that it doesn’t seem to follow the player :confused:

It’s just two parametric functions to relate a single steadily-increasing value to two values: radius and theta.

The stair-step jim-jammery on line 2 in my script is just modulo and negate… you can unwrap it step by step. It produces a down-sloping sawtooth wave.

Just add the player’s position to the calculated position before assigning it in your original line 20!

@Kurt-Dekker

Yeah I caught that like 10 minutes after I had asked lol. Thank you for the help!