0
\$\begingroup\$

I wish to create a game object where you can start dragging it by touching somewhere on the line of its collision and to create these "dynamic shapes" by stretching the sprites and readjusting the sprite look and collision according to the drag point.

Adding an illustration for clearance: enter image description here

Started playing with Sprite Shape Renderer to create these curved sprite tiles but I need to be able to create dynamic ones using the mouse cursor and adjust all collisions.

I've tried to add an AnchorDragger script to the Sprite Shape Renderer object:

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

public class AnchorDragger : MonoBehaviour
{
    const int INVALLID_INSERTED_POINT_INDEX = -1;

    public SpriteShapeController spriteShapeController;
    private Spline spline;
    private int inseretedPointIndex = INVALLID_INSERTED_POINT_INDEX;

    void Start()
    {
        spline = spriteShapeController.spline;
        int pointCount = spline.GetPointCount();
        for (var i = 0; i < pointCount; i++)
        {
            Vector3 currentPointPos = spline.GetPosition(i);
            Debug.Log("Point " + i + " position: " + currentPointPos);
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (inseretedPointIndex != INVALLID_INSERTED_POINT_INDEX)
        {
            spline = spriteShapeController.spline;
            spline.SetPosition(inseretedPointIndex, Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 1.0f)));
            // Debug.Log("Setting position to: " + Camera.main.ScreenToWorldPoint(Input.mousePosition));
        }
    }

    void OnMouseDown()
    {
        Debug.Log("Mouse Down Position:" + Input.mousePosition);
        Vector3 mouseDownPos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 1.0f));
        Debug.Log("World Position: " + mouseDownPos);
        spline = spriteShapeController.spline;
        int pointCount = spline.GetPointCount();
        int closestPointIndex = int.MaxValue;
        float minDistance = int.MaxValue;
        for (var i = 0; i < pointCount; i++)
        {
            Vector3 currentPointPos = spline.GetPosition(i);
            float distance = Vector3.Distance(currentPointPos, mouseDownPos);
            if (distance < minDistance)
            {
                minDistance = distance;
                closestPointIndex = i;
            }
        }
        spline.InsertPointAt(closestPointIndex, mouseDownPos);
        spline.SetTangentMode(closestPointIndex, ShapeTangentMode.Continuous);
        inseretedPointIndex = closestPointIndex;
        Debug.Log("Inserted point index: " + inseretedPointIndex);
    }

    void OnMouseUp()
    {
        Debug.Log("Mouse Up");
        spline = spriteShapeController.spline;
        spline.RemovePointAt(inseretedPointIndex);
        inseretedPointIndex = INVALLID_INSERTED_POINT_INDEX;
    }
}

Basically tried to figure the closest point on the spline where I've clicked and then inserting a new point and setting its position on Update to where the mouse is and delete the point on mouse up.
Right now I'm having a problem where the drag position is not correct for some reason.
Where I clicked, where the new point position is set: enter image description here

Even when I tried to play with where I click and where I take my mouse to while dragging, not sure why, could use help!

Also I'm not sure how I would update the EdgeCollider2D? I know I can get it in the Update method using:

EdgeCollider2D edgeCollider = gameObject.GetComponent<EdgeCollider2D>();

But how would I actually update it correctly to fit the new sprite?

\$\endgroup\$
  • \$\begingroup\$ not sure how you are validating the insert point but note how I figured mine in below and also my new point index is spline.GetPointCount()-1 \$\endgroup\$ – Justin Markwell Oct 18 at 16:09
0
\$\begingroup\$

You need to rebake the collider to force the update. wrote this last December but should help you get the position correct.

        var insertPoint = Input.mousePosition;
        insertPoint.z = 10.0f;
        insertPoint = Camera.main.ScreenToWorldPoint(insertPoint);
        var m = Mathf.Abs((insertPoint - lastPosition).magnitude);
        if (Input.GetMouseButton(0) && m > minimumDistance)
        {
            var spriteShapeController = gameObject.GetComponent<SpriteShapeController>();
            var spline = spriteShapeController.spline;

            spline.InsertPointAt(spline.GetPointCount(), insertPoint);
            var newPointIndex = spline.GetPointCount() - 1;
            spline.SetTangentMode(newPointIndex, ShapeTangentMode.Continuous);
            spline.SetHeight(newPointIndex, 1.0f);
            lastPosition = insertPoint;
            spriteShapeController.BakeCollider();
        }

here is a gif of it working dynamically enter image description here

\$\endgroup\$
  • \$\begingroup\$ So I've added a call to BakeCollider inside the Update method but the collider is still not updating. Also what about the point being positioned wrong as shown in my picture? Now sure what I'm doing wrong to cause it \$\endgroup\$ – Jorayen Oct 18 at 9:56
  • \$\begingroup\$ Ok, I need to set Update Collider in the Sprite Shape Controller to true otherwise it won't update. (Still having problems with where I drag the sprite since it doesn't point to the mouse location like in the pic) \$\endgroup\$ – Jorayen Oct 18 at 12:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.