Stretch Sprite to match mouse position

Hello,

Just wondering how to make this kind of behaviour possible:


The circle represents an object to rotate around, the line represents the sprite I want to stretch and the arrow represents the cursor.

I already have the sprite rotating toward the cursor with this code:

   // ROTATING THE SPELL AIM AROUND THE PLAYER
    private Vector3 mousePos;
    private Transform target;
    private Vector3 objPos;
    private float angle;

    public void Update()
    {
        if (target == null)
            return;

        mousePos = Input.mousePosition;
        mousePos.z = 1.551f;

        objPos = Camera.main.WorldToScreenPoint(target.position);

        mousePos.x = mousePos.x - objPos.x;
        mousePos.y = mousePos.y - objPos.y;

        angle = Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg;

        target.rotation = Quaternion.Euler(new Vector3(0, 0, angle-90f));

        if (spell.resizable)
        {
            mousePos = Input.mousePosition;
            mousePos.z = 0f;

            float scale = Mathf.Abs(Vector2.Distance(mousePos, this.transform.position));

            Debug.Log(scale/500f);

            target.GetComponent<SpriteRenderer>().size = new Vector2(target.GetComponent<SpriteRenderer>().size.x, scale/500f);
        }
    }

Note: the -90f on the final angle rotation is because it was 90 degrees out and I wasn’t sure why, if anyone knows feel free to comment on that too.

The second part (after it checks if the spell is resizable) is the troublesome part that I can’t figure out. The current behaviour is non-uniform and does not scale linearly with distance.

How can I go about this more successfully?

Thanks.

One approach might be two sprites: one is the circle, the other is a line, and you will:

  • position the line so that one end starts at the perimeter of the circle closest to the mouse (put the line sprite pivot at one end of the line)
  • rotate the line so it aims at the mouse
  • scale the line (in only one axis, its long axis) so that it reaches precisely to the mouse position.

Another approach would be to make the circle a sprite and do the line with a line renderer.

And another heavier approach would be to do your own geometry creation on the fly… that’s a lot heavier lift, but would give you the most precise control over outcomes.

My current way is using the Sliced Draw Mode on the Sprite Renderer to make the line longer without squashing per say.
It kind of works, to an extent. But not how I want it.
Heres a gif of it currently.

https://gyazo.com/0a09de7da285f380b414bc092fffd506

As you can see the extension is not uniform.
And at the end of the GIF you can see that it does not extend, instead retracts.

I want to stay away from Line Renderers as I want to achieve a specific look, and using two sprites I feel would be more complicated than using just one.

EDIT:

I managed to figure this out.
Here’s the code I used;

        if (spell.resizable)
        {
            mousePos = Input.mousePosition;

            mousePos = Camera.main.ScreenToWorldPoint(mousePos);
            mousePos.z = 0f;

            float distance = Mathf.Abs(Vector2.Distance(mousePos, this.transform.position));

            float scale = 0.7f + (distance / 0.5f) * 0.8f;

            target.GetComponent<SpriteRenderer>().size = new Vector2(target.GetComponent<SpriteRenderer>().size.x, scale);
        }

The issue was that I didn’t convert the mouse position to a world point.

The 0.7f is an offset value because it wasn’t exactly central.
The 0.5f is because each “meter” in my game is 0.5 units in Unity
and the 0.8f is the size that I need to extend the sprite by for each “meter”.

Thanks for the help.

1 Like