示例#1
0
    public float distance;  //距离起点的长度

    public PBCircleNode(PBCircle _circle, Vector3 _position, Vector3 _tangent, float _angle)
    {
        circle   = _circle;
        position = _position;
        tangent  = _tangent;
        angle    = _angle;
    }
示例#2
0
 public PBCircleNode(PBCircleNode node)
 {
     circle   = node.circle;
     position = node.position;
     tangent  = node.tangent;
     angle    = node.angle;
 }
    private void CreateTrack()
    {
        if (splineTrack == null)
        {
            EditorUtility.DisplayDialog(null, "请把该窗口关闭,重新选择履带!", "OK");
            return;
        }

        if (circleObjects.Count == 0)
        {
            EditorUtility.DisplayDialog(null, "请选择圆!!!", "OK");
            return;
        }
        if (curveType == PBCircleCurveType.OneCircle && circleObjects.Count > 1)
        {
            EditorUtility.DisplayDialog(null, "单圆履带只能选择一个圆!!!", "OK");
            return;
        }
        if (curveType == PBCircleCurveType.Line && circleObjects.Count < 2)
        {
            EditorUtility.DisplayDialog(null, "排排站履带要选择至少两个圆!!!", "OK");
            return;
        }
        if (curveType == PBCircleCurveType.Enclosed && circleObjects.Count < 3)
        {
            EditorUtility.DisplayDialog(null, "包围圈履带要选择至少三个圆!!!", "OK");
            return;
        }

        Vector3 normal = circleObjects[0].transform.forward;

        for (int i = 1; i < circleObjects.Count; i++)
        {
            if (circleObjects[i].transform.forward != normal)
            {
                EditorUtility.DisplayDialog(null, "所有的圆必须要在同一个平面,forward方向保持一致!!!", "OK");
                return;
            }
        }

        PBCircle[] circles = new PBCircle[circleObjects.Count];
        for (int i = 0; i < circles.Length; i++)
        {
            float radius = 1f;
            if (circleObjects[i].name.Contains("40"))
            {
                radius = Gear40Radius;
            }
            else if (circleObjects[i].name.Contains("80"))
            {
                radius = Gear80Radius;
            }

            circles[i] = new PBCircle(circleObjects[i].transform, radius);
        }
        splineTrack.SetCircles(circles, curveType);
        EditorUtility.SetDirty(splineTrack);
    }
示例#4
0
    public void GetBottomMidSample(out Vector3 position, out Vector3 tangent, out Vector3 emit, out float distance)
    {
        //单圆
        if (curveType == PBCircleCurveType.OneCircle)
        {
            PBCircleNode node = nodes.First.Value;
            Vector3      r    = -node.circle.up.normalized;
            position = node.circle.center + r * node.circle.radius;
            tangent  = -node.tangent;
            emit     = r;
            distance = 0.5f * nodes.Last.Value.distance;

            return;
        }

        PBCircleNode node1;
        PBCircleNode node2;

        if (curveType == PBCircleCurveType.Line)
        {
            int half  = (nodes.Count - 1) / 2;
            int index = half + half / 2;
            node1 = nodes.ElementAt(index - 1);
            node2 = nodes.ElementAt(index);
        }
        else
        {
            int half = (nodes.Count - 1) / 2;
            node1 = nodes.ElementAt(half - 1);
            node2 = nodes.ElementAt(half);
        }

        if (node1.ConnectLine(node2))
        {
            position = Vector3.Lerp(node1.position, node2.position, 0.5f);
            tangent  = node1.tangent;
            emit     = (node1.position - node1.circle.center).normalized;
            distance = 0.5f * (node1.distance + node2.distance);
        }
        else
        {
            PBCircle circle = node1.circle;
            float    angle  = node1.angle + 0.5f * node1.deltaAngle(node2);
            Vector3  r      = Quaternion.AngleAxis(angle, circle.forward) * circle.up;
            r.Normalize();
            position = circle.center + r * circle.radius;
            tangent  = Quaternion.AngleAxis(angle, circle.forward) * (-circle.right);
            emit     = r;
            distance = 0.5f * (node1.distance + node2.distance);
        }
    }
    private static PBCircleNode[] CalculateTangentLines(PBCircle c1, PBCircle c2)
    {
        Vector3 o1o2          = c2.center - c1.center;
        float   o1o2_distance = o1o2.magnitude;

        o1o2.Normalize();

        float angle;// 90-圆心连线与公切线的夹角

        if (Mathf.Approximately(c1.radius, c2.radius))
        {
            angle = 90;
        }
        else
        {
            float r1 = Mathf.Max(c1.radius, c2.radius);
            float r2 = Mathf.Min(c1.radius, c2.radius);

            float x = o1o2_distance * r1 / (r1 - r2);
            angle = Mathf.Acos(r1 / x) * Mathf.Rad2Deg;

            if (c1.radius < c2.radius)
            {
                angle = 180 - angle;
            }
        }

        Vector3[] Rs = new[]
        {
            Quaternion.AngleAxis(angle, c1.forward) * o1o2,
            Quaternion.AngleAxis(angle, -c1.forward) * o1o2,
        };

        PBCircleNode[] nodes = new PBCircleNode[4];

        for (int i = 0; i < Rs.Length; i++)
        {
            PBCircleNode n1, n2; //第 i 条公切线的c1、c2上的点

            Vector3 r       = Rs[i];
            Vector3 p       = c1.center + r * c1.radius;
            Vector3 tangent = Quaternion.AngleAxis(90, c1.forward) * r;
            n1 = new PBCircleNode(c1, p, tangent, GetAngle(c1, r));
            p  = c2.center + r * c2.radius;
            n2 = new PBCircleNode(c2, p, tangent, GetAngle(c2, r));

            nodes[i * 2]     = n1;
            nodes[i * 2 + 1] = n2;
        }
        return(nodes);
    }
示例#6
0
    /// <summary>
    /// 通过距离起点的距离,获取线上的点的坐标、斜率、圆心到坐标的单位向量(垂直于斜率)
    /// </summary>
    public void GetSampleAtDistance(float distance, out Vector3 position, out Vector3 tangent, out Vector3 emit)
    {
        LinkedListNode <PBCircleNode> listNode = nodes.First;
        PBCircleNode startNode = null;
        PBCircleNode endNode   = null;

        while (listNode != null)
        {
            if (distance < listNode.Value.distance)
            {
                startNode = listNode.Previous.Value;
                endNode   = listNode.Value;
                break;
            }
            listNode = listNode.Next;
        }

        if (startNode == null)
        {
            throw new ArgumentException(string.Format("Distance must be less than curve length. Curve length: {0}, distance: {1}",
                                                      nodes.Last.Value.distance, distance));
        }

        float t = (distance - startNode.distance) / (endNode.distance - startNode.distance);

        if (startNode.ConnectLine(endNode))
        {
            //直线
            position = Vector3.Lerp(startNode.position, endNode.position, t);
            tangent  = startNode.tangent;
            emit     = (startNode.position - startNode.circle.center).normalized;
        }
        else
        {
            //圆弧
            PBCircle circle = startNode.circle;
            float    angle  = startNode.angle + t * startNode.deltaAngle(endNode);
            Vector3  r      = Quaternion.AngleAxis(angle, circle.forward) * circle.up;
            r.Normalize();
            position = circle.center + r * circle.radius;

            tangent = Quaternion.AngleAxis(angle, circle.forward) * (-circle.right);

            emit = r;
        }
    }
    private static float GetAngle(PBCircle circle, Vector3 dir)
    {
        float   dot   = Mathf.Clamp(Vector3.Dot(circle.up, dir), -1, 1);
        float   angle = Mathf.Acos(dot) * Mathf.Rad2Deg;
        Vector3 cross = Vector3.Cross(circle.up, dir);

        if (Vector3.Dot(cross, circle.forward) < 0)
        {
            angle = -angle;
        }
        if (angle < 0)
        {
            angle += 360;
        }

        return(angle);
    }
    protected override void LoadString(string data)
    {
        this.ShowWindow = false;

        string realData = data.Substring("track:".Length);

        string[] values = realData.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

        Spacing   = float.Parse(values[0]);
        CurveType = (PBCircleCurveType)int.Parse(values[1]);
        Deviation = values.Length >= 4 ? float.Parse(values[3]) : 0;

        values = values[2].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
        PBAnimNode[] blocks  = GameObject.FindObjectsOfType <PBAnimNode>();
        PBCircle[]   circles = new PBCircle[values.Length / 2];
        for (int i = 0; i < circles.Length; i++)
        {
            PBAnimNode block = blocks.FirstOrDefault(b => string.Equals(b.pbID, values[i * 2]));
            if (block == null)
            {
                Debug.LogError(">>>>>履带:找不到齿轮,pbID: " + values[i * 2]);
            }

            if (block.transform.localScale != Vector3.one)
            {
                Debug.LogError(">>>>>履带:齿轮gameobject的localscale不为1");
            }

            float radius = float.Parse(values[i * 2 + 1]);
#if BLOCK_EDITOR
            if (!Mathf.Approximately(block.transform.lossyScale.x, 1))
            {
                Debug.LogError(">>>>>搭建积木块不允许有缩放,请从根节点开始检查,并修正!");
            }
#else
            //app中在创建搭建前,可能会缩放根节点
            radius *= block.transform.lossyScale.x;
#endif
            PBCircle circle = new PBCircle(block.transform, radius);
            circles[i] = circle;
        }

        SetCircles(circles, CurveType);
    }
    private static LinkedList <PBCircleNode> BuildForOne(PBCircle[] circles)
    {
        LinkedList <PBCircleNode> nodes = new LinkedList <PBCircleNode>();
        PBCircle circle = circles[0];

        PBCircleNode node1 = new PBCircleNode(
            circle,
            circle.center + circle.up * circle.radius,
            -circle.right,
            0);

        nodes.AddFirst(node1);

        PBCircleNode node2 = new PBCircleNode(node1);

        node2.angle = 360;
        nodes.AddLast(node2);

        return(nodes);
    }
    private static LinkedList <PBCircleNode> BuildForEnclosed(PBCircle[] circles)
    {
        LinkedList <PBCircleNode> nodes = new LinkedList <PBCircleNode>();

        for (int i = 0; i < circles.Length; i++)
        {
            PBCircle       c1       = circles[i];
            PBCircle       c2       = i == circles.Length - 1 ? circles[0] : circles[i + 1];
            PBCircleNode[] subNodes = CalculateTangentLines(c1, c2);
            //只保留方向与圆心连线方向一致的
            //所以顺时针选择圆,就包围外圈,逆时针选择圆,就包围内圈
            nodes.AddLast(subNodes[2]);
            nodes.AddLast(subNodes[3]);
        }

        //最后一个要跟第一个相连,所以再拷贝第一个点到末尾
        nodes.AddLast(new PBCircleNode(nodes.First.Value));

        return(nodes);
    }
示例#11
0
    private void OnSceneGUI()
    {
        if (splineTrack.Curve == null || !splineTrack.Curve.IsBuilt)
        {
            return;
        }

        Color preColor = Handles.color;

        LinkedList <PBCircleNode>     nodes    = splineTrack.Curve.GetNodes();
        LinkedListNode <PBCircleNode> listNode = nodes.First.Next;
        PBCircleNode startNode;
        PBCircleNode endNode;

        while (listNode != null)
        {
            startNode     = listNode.Previous.Value;
            endNode       = listNode.Value;
            Handles.color = Color.green;
            if (startNode.ConnectLine(endNode))
            {
                Handles.DrawLine(startNode.position, endNode.position);
            }
            else
            {
                PBCircle circle = startNode.circle;
                Handles.DrawWireArc(circle.center, circle.forward, (startNode.position - circle.center).normalized, startNode.deltaAngle(endNode),
                                    circle.radius);
            }

            Handles.color = Color.blue;
            Handles.SphereCap(0, startNode.position, Quaternion.identity, 0.05f);
            listNode = listNode.Next;
        }

        Handles.color = preColor;
    }