根据LineRenderer形状给物体添加PolygonCollider2D碰撞体

发表于2018-12-04
评论0 5.8k浏览

如图,在实时的绘制完成LineRenderer之后,会动态的添加PolygonCollider2D多边形碰撞体。读取LineRenderer的点位(一条折线),左右各便宜一定距离,形成一个闭合的线框,利用线框的点位修改PolygonCollider2D形状。


代码如下:
using System.Collections.Generic;
using UnityEngine;
public class LineCollider : MonoBehaviour
{
    //绘制过程中显示用LineRenderer
    [SerializeField] LineRenderer drawingLine;
    //带有碰撞体的LineRenderer, 要有PolygonCollider2D、LineRenderer组件, 
    [SerializeField] GameObject colliderLinePrefab;
    //灵敏度 
    [SerializeField] float minTouchDistance = 0.1f;
    Camera mainCamera;
    void Start()
    {
        mainCamera = Camera.main;
        //
        drawingLine.enabled = false;
        drawingLine.positionCount = 0;
    }
    Vector3 tmpTouchPos;
    bool tmpIsMouseDown;
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            tmpIsMouseDown = true;
            tmpTouchPos = mainCamera.ScreenToWorldPoint(Input.mousePosition);
            tmpTouchPos.z = 0;
            OnPressScreen(tmpTouchPos);
        }
        else if (Input.GetMouseButton(0) && tmpIsMouseDown)
        {
            tmpTouchPos = mainCamera.ScreenToWorldPoint(Input.mousePosition);
            tmpTouchPos.z = 0;
            OnTouchScreen(tmpTouchPos);
        }
        else if (Input.GetMouseButtonUp(0) && tmpIsMouseDown)
        {
            tmpTouchPos = mainCamera.ScreenToWorldPoint(Input.mousePosition);
            tmpTouchPos.z = 0;
            OnReleaseScreen(tmpTouchPos);
            tmpIsMouseDown = false;
        }
    }
    //鼠标点击
    Vector3 lastPos;
    List<Vector3> touchPosList = new List<Vector3>();
    public void OnPressScreen(Vector3 pressPos)
    {
        touchPosList.Clear();
        lastPos = pressPos;
        drawingLine.enabled = true;
        drawingLine.positionCount = 0;
    }
    //鼠标拖拽
    Vector3 tmpStartPoint;
    Vector3 tmpEndPoint;
    public void OnTouchScreen(Vector3 touchPos)
    {
        tmpStartPoint = lastPos;
        tmpEndPoint = touchPos;
        //显示绘制line
        if (Vector3.Distance(tmpStartPoint, tmpEndPoint) > minTouchDistance)
        {
            touchPosList.Add(lastPos);
            drawingLine.positionCount = touchPosList.Count;
            drawingLine.SetPosition(touchPosList.Count - 1, touchPosList[touchPosList.Count - 1]);
            lastPos = touchPos;
        }
    }
    //鼠标抬起
    public void OnReleaseScreen(Vector3 releasePos)
    {
        drawingLine.positionCount = 0;
        drawingLine.enabled = false;
        //绘制结束,生成碰撞line
        touchPosList.Add(releasePos);
        if (touchPosList.Count > 3)
            CreateColliderLine(touchPosList);
    }
    //生成碰撞line
    void CreateColliderLine(List<Vector3> pointList)
    {
        GameObject prefab = Instantiate(colliderLinePrefab, transform);
        LineRenderer lineRenderer = prefab.GetComponent<LineRenderer>();
        PolygonCollider2D polygonCollider = prefab.GetComponent<PolygonCollider2D>();
        lineRenderer.positionCount = pointList.Count;
        lineRenderer.SetPositions(pointList.ToArray());
        List<Vector2> colliderPath = GetColliderPath(pointList);
        polygonCollider.SetPath(0, colliderPath.ToArray());
    }
    //计算碰撞体轮廓
    float colliderWidth;
    List<Vector2> pointList2 = new List<Vector2>();
    List<Vector2> GetColliderPath(List<Vector3> pointList3)
    {
        //碰撞体宽度
        colliderWidth = drawingLine.startWidth;
        //Vector3转Vector2
        pointList2.Clear();
        for (int i = 0; i < pointList3.Count; i++)
        {
            pointList2.Add(pointList3[i]);
        }
        //碰撞体轮廓点位
        List<Vector2> edgePointList = new List<Vector2>();
        //以LineRenderer的点位为中心, 沿法线方向与法线反方向各偏移一定距离, 形成一个闭合且不交叉的折线
        for (int j = 1; j < pointList2.Count; j++)
        {
            //当前点指向前一点的向量
            Vector2 distanceVector = pointList2[j - 1] - pointList2[j];
            //法线向量
            Vector3 crossVector = Vector3.Cross(distanceVector, Vector3.forward);
            //标准化, 单位向量
            Vector2 offectVector = crossVector.normalized;
            //沿法线方向与法线反方向各偏移一定距离
            Vector2 up = pointList2[j - 1] + 0.5f * colliderWidth * offectVector;
            Vector2 down = pointList2[j - 1] - 0.5f * colliderWidth * offectVector;
            //分别加到List的首位和末尾, 保证List中的点位可以围成一个闭合且不交叉的折线
            edgePointList.Insert(0, down);
            edgePointList.Add(up);
            //加入最后一点
            if (j == pointList2.Count - 1)
            {
                up = pointList2[j] + 0.5f * colliderWidth * offectVector;
                down = pointList2[j] - 0.5f * colliderWidth * offectVector;
                edgePointList.Insert(0, down);
                edgePointList.Add(up);
            }
        }
        //返回点位
        return edgePointList;
    }
}

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签: