1

I've created a platform with unity where you can stretch it out with touch by using Sprite Shape Controller. The ideas is that upon touch you can drag this platform and curve it and follow your mouse like so: enter image description here

I've got it working pretty much besides 1 problem:

I wish to roll a rigid body 2D on it, a simple ball. Problem arises when I stretch it down fast and let it go to it's original position, the ball is going through it and falling down. The expected behavior is that it should shoot it up based on how much I've dragged keeping the momentum going. Here's an AnchorDragger script I wrote that is responsible for the dragging behavior:

using UnityEngine;
using UnityEngine.U2D;

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

    public float speed = 0.4f;

    public SpriteShapeController spriteShapeController;
    private Spline spline;
    private bool released = false;
    private int inseretedPointIndex = INVALLID_INSERTED_POINT_INDEX;
    private Vector3 originalPos;
    private Vector3 dropPos;
    private Ray originalToDropRay;
    private float distanceToOriginalPos;

    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 (!released && inseretedPointIndex != INVALLID_INSERTED_POINT_INDEX)
        {
            spline = spriteShapeController.spline;
            Ray r = Camera.main.ScreenPointToRay(Input.mousePosition);
            Plane p = new Plane(Vector3.forward, spriteShapeController.spline.GetPosition(0));
            float d;
            p.Raycast(r, out d);
            Vector3 pos = r.GetPoint(d);
            spline.SetPosition(inseretedPointIndex, pos);
            spriteShapeController.BakeCollider();
        }
        if (released)
        {
            Vector3 pos;
            if (distanceToOriginalPos - speed >= 0)
            {
                pos = originalToDropRay.GetPoint(distanceToOriginalPos - speed);
                spline.SetPosition(inseretedPointIndex, pos);
                distanceToOriginalPos -= speed;
            }
            else
            {
                pos = originalToDropRay.GetPoint(0);
                spline.SetPosition(inseretedPointIndex, pos);
                distanceToOriginalPos = 0;
            }
            if (pos == originalPos)
            {
                released = false;
                spline.RemovePointAt(inseretedPointIndex);
                inseretedPointIndex = INVALLID_INSERTED_POINT_INDEX;
            }
        }
    }

    void OnMouseDown()
    {
        released = false;
        Debug.Log("Mouse Down Position:" + Input.mousePosition);
        //Vector3 mouseDownPos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 1.0f));
        Ray r = Camera.main.ScreenPointToRay(Input.mousePosition);
        Plane p = new Plane(Vector3.forward, spriteShapeController.spline.GetPosition(0));
        float d;
        p.Raycast(r, out d);
        Vector3 mouseDownPos = r.GetPoint(d);
        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;
                if ((-currentPointPos.x * mouseDownPos.y + currentPointPos.y * mouseDownPos.x) < 0)
                {
                    closestPointIndex = i + 1;
                } else
                {
                    closestPointIndex = i;
                }
            }
        }
        spline.InsertPointAt(closestPointIndex, mouseDownPos);
        spline.SetTangentMode(closestPointIndex, ShapeTangentMode.Continuous);
        inseretedPointIndex = closestPointIndex;
        originalPos = mouseDownPos;
        Debug.Log("Inserted point index: " + inseretedPointIndex);
    }

    void OnMouseUp()
    {
        Debug.Log("Mouse Up");
        spline = spriteShapeController.spline;
        released = true;
        dropPos = spline.GetPosition(inseretedPointIndex);
        Vector3 heading = dropPos - originalPos;
        distanceToOriginalPos = heading.magnitude;
        Vector3 direction = heading / distanceToOriginalPos;
        originalToDropRay = new Ray(originalPos, direction);
        //spline.RemovePointAt(inseretedPointIndex);
        //inseretedPointIndex = INVALLID_INSERTED_POINT_INDEX;
    }
}

Here's a gif showing the problem: https://gfycat.com/badzanychimneyswift

Jorayen
  • 1,737
  • 2
  • 21
  • 52
  • Necromancer reporting in: You have to change the Y value+ the offset of the center of the ball to match the Y value of the node near the ball. The ball basically needs to know that its touching the ground. – TehTris Oct 06 '22 at 01:16

0 Answers0