Растягиваемый движущийся спрайтовый сплайн с твердым телом 2D - PullRequest
1 голос
/ 18 октября 2019

Я создал единую платформу, где вы можете растянуть ее прикосновением, используя Sprite Shape Controller. Идея состоит в том, что при прикосновении вы можете перетащить эту платформу, изогнуть ее и следовать за своей мышью так: enter image description here

У меня это работает в значительной степени, кроме одной проблемы:

Я хочу накатить на него твердое тело 2D, простой шар. Проблема возникает, когда я быстро растягиваю его и возвращаю в исходное положение, мяч проходит через него и падает. Ожидаемое поведение состоит в том, что он должен поднять его, основываясь на том, сколько я потянул, чтобы сохранить импульс. Вот скрипт AnchorDragger, который я написал и который отвечает за поведение при перетаскивании:

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;
    }
}

Вот рисунок, показывающий проблему: https://gfycat.com/badzanychimneyswift

...