unity3d 绘制点绘制线 - CSDN
  • /// /// 脚本位置:Path身上 /// using UnityEngine; using System.Collections; using System.Collections.Generic; public class PathTrail : MonoBehaviour ... public bool ShowTrail = false;

    /// <summary>
    /// 脚本位置:Path身上
    /// </summary>
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    public class PathTrail : MonoBehaviour 
    {
        // 是否显示场景信息
        public bool ShowTrail = false;
    
        // 一个列表用于保存多条路径
        private GameObject[] Paths;
    
        // 一个字典用于保存多条路径点
        private Dictionary<GameObject, List<Transform>> PathNodes = new Dictionary<GameObject, List<Transform>>();
    
    
        void Awake()
        {
            BuildPath();
        }
    
    
        // 创建路径 - 可以在编辑状态下执行BuildPath
        [ContextMenu("BuildPath")]
        public void BuildPath()
        {
            PathNodes.Clear();
            // 找到path1和path2
            Paths = GameObject.FindGameObjectsWithTag("path");
            for (int i = 0; i <Paths.Length; i++)
            {	// 调用FindPathNode方法,查找path1中的所有路点
                PathNodes.Add(Paths[i], FindPathNode(Paths[i].transform));
            
            }
        }
    
    
        // 查找路点
        List<Transform> FindPathNode(Transform path)
        {
            int childCount = path.childCount;
            List<Transform> pathNode = new List<Transform>();
            Transform node;
    
            for (int i = 0; i < childCount; i++)
            {
                node = path.GetChild(i);
                node.name = path.name + "_Node" + i;
                pathNode.Add(node);
            }
            return pathNode;
        }
    
       
        // 绘制路径
        // 系统函数,自动调用
        void OnDrawGizmos()
        {
            if (!ShowTrail || Paths == null || Paths.Length == 0)
            {
    			return;
            }
                
    
            Gizmos.color = Color.black;
    		
            foreach (var pair in PathNodes)
            {            
    			// pair的返回值是KeyValuePair<GameObject, List<Transform>>键值对类型
    			// value指的就是list,count就是数组的长度,当路点数超过1个的时候才会画线
                if (pair.Value.Count <= 1)
                {
                    continue;
                }
    
                for (int i = 1; i < pair.Value.Count; i++)
                {	// 画线
                    Gizmos.DrawLine(pair.Value[i-1].position, pair.Value[i].position);
                }
            }
    
        }
    
    
    }
    


    展开全文
  • 1.动态添加(删除)路径,通过两个以上的路径绘制曲线,删除之后不影响其他点绘制曲线; 2.每个路径都可以被拖拽发生位移,可以通过锁定某个轴,使该轴不发生位移; 3.每个路径处有两个可调节点(首尾...

    近日,项目需求:前提:三维空间

    1.动态添加(删除)路径点,通过两个以上的路径点来绘制曲线,删除点之后不影响其他点绘制曲线;

    2.每个路径点都可以被拖拽发生位移,可以通过锁定某个轴,使该轴不发生位移;

    3.每个路径点处有两个可调节点(首尾只有一个调节点),可通过调节点来调节曲线切线(速度方向线)斜率,以达到平滑曲线;

    4.使该曲线形成路径,隐藏曲线,Player沿曲线完成自动寻路。

    先看效果,再贴代码。(使用贝塞尔曲线公式与LineRenderer绘制3D可调节曲线

    代码如下:两个脚本。

    1. DMDrawCurve.cs 挂载到任意对象即可

    该脚本实现绘制曲线,动态添加(删除)点,发生位移时更新绘制曲线,以及隐藏该曲线。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    namespace DM.Editor.View
    {
        [RequireComponent(typeof(LineRenderer))]
        public class DMDrawCurve : MonoBehaviour
        {
            public List<Transform> m_allPoints;
            private GameObject m_anchorPoint;
            private GameObject m_controlPoint;
            private GameObject m_pointParent;
            private LineRenderer m_lineRenderer;
            
            private int m_curveCount = 0;
            private int SEGMENT_COUNT = 60;//曲线取点个数(取点越多这个长度越趋向于精确)
    
            private static DMDrawCurve m_instance;
            public static DMDrawCurve Instance
            {
                get {
                    if (null == m_instance)
                        m_instance = new DMDrawCurve();
                    return m_instance;
                }
            }
            void Awake()
            {
                if (null == m_instance)
                    m_instance = this;
                SetLine();
                if (null == m_anchorPoint)
                    m_anchorPoint = Resources.Load("Prefabs/AnchorPoint") as GameObject;
                if (null == m_controlPoint)
                    m_controlPoint = Resources.Load("Prefabs/ControlPoint") as GameObject;
            }
            void SetLine()
            {
                if (null == m_lineRenderer)
                    m_lineRenderer = GetComponent<LineRenderer>();
                m_lineRenderer.material = Resources.Load("Materials/Line") as Material;
                m_lineRenderer.startColor = Color.red;
                m_lineRenderer.endColor = Color.green;
                m_lineRenderer.widthMultiplier = 0.2f;
            }
    
            public void Init(GameObject player)
            {//初始化一个基准点(Player)
                if (player == null) return;
                GameObject anchorPoint = LoadPoint(m_anchorPoint, player.transform.position);
                m_allPoints.Add(anchorPoint.transform);
            }      
            public void AddPoint(Vector3 anchorPointPos)
            {
                //初始化时m_allPoints添加了一个player
                if (m_allPoints.Count == 0) return;
                Transform lastPoint = m_allPoints[m_allPoints.Count - 1];
                GameObject controlPoint2 = LoadPoint(m_controlPoint, lastPoint.position+new Vector3(0,0,-1));   
                GameObject controlPoint = LoadPoint(m_controlPoint, anchorPointPos + new Vector3(0, 0, 1));
                GameObject anchorPoint = LoadPoint(m_anchorPoint, anchorPointPos);
    
                anchorPoint.GetComponent<CurvePointControl>().m_controlObject = controlPoint;
                lastPoint.GetComponent<CurvePointControl>().m_controlObject2 = controlPoint2;
    
                m_allPoints.Add(controlPoint2.transform);
                m_allPoints.Add(controlPoint.transform);
                m_allPoints.Add(anchorPoint.transform);
    
                DrawCurve();
            }
            public void DeletePoint(GameObject anchorPoint)
            {
                if (anchorPoint == null) return;
                CurvePointControl curvePoint = anchorPoint.GetComponent<CurvePointControl>();
                if (curvePoint && anchorPoint.tag.Equals("AnchorPoint"))
                {
                    if (curvePoint.m_controlObject)
                    {
                        m_allPoints.Remove(curvePoint.m_controlObject.transform);
                        Destroy(curvePoint.m_controlObject);
                    } 
                    if (curvePoint.m_controlObject2)
                    {
                        m_allPoints.Remove(curvePoint.m_controlObject2.transform);
                        Destroy(curvePoint.m_controlObject2);
                    }
                    if (m_allPoints.IndexOf(curvePoint.transform) == (m_allPoints.Count - 1))
                    {//先判断删除的是最后一个元素再移除
                        m_allPoints.Remove(curvePoint.transform);
                        Transform lastPoint = m_allPoints[m_allPoints.Count - 2];
                        GameObject lastPointCtrObject = lastPoint.GetComponent<CurvePointControl>().m_controlObject2;
                        if (lastPointCtrObject)
                        {
                            m_allPoints.Remove(lastPointCtrObject.transform);
                            Destroy(lastPointCtrObject);
                            lastPoint.GetComponent<CurvePointControl>().m_controlObject2 = null;
                        }
                    }
                    else
                    {
                        m_allPoints.Remove(curvePoint.transform);
                    }
                    Destroy(anchorPoint);
                    if(m_allPoints.Count == 1)
                    {
                        m_lineRenderer.positionCount = 0;
                    }
                }
    
                DrawCurve();
            }
            public void UpdateLine(GameObject anchorPoint, Vector3 offsetPos1, Vector3 offsetPos2)
            {
                if (anchorPoint == null) return;
                if (anchorPoint.tag.Equals("AnchorPoint"))
                {
                    CurvePointControl curvePoint = anchorPoint.GetComponent<CurvePointControl>();
                    if (curvePoint)
                    {
                        if (curvePoint.m_controlObject)
                            curvePoint.m_controlObject.transform.position = anchorPoint.transform.position + offsetPos1;
                        if (curvePoint.m_controlObject2)
                            curvePoint.m_controlObject2.transform.position = anchorPoint.transform.position + offsetPos2;
                    }
                }
                DrawCurve();
            }
            public List<Vector3> HiddenLine(bool isHidden=false)
            {
                m_pointParent.SetActive(isHidden);
                m_lineRenderer.enabled = isHidden;
                List<Vector3> pathPoints = new List<Vector3>();
                if(!isHidden)
                {
                    for(int i = 0; i < m_lineRenderer.positionCount; i++)
                    {
                        pathPoints.Add(m_lineRenderer.GetPosition(i));
                    }
                }
                return pathPoints;
            }
    
            private void DrawCurve()//画曲线
            {
                if (m_allPoints.Count < 4) return;
                m_curveCount = (int)m_allPoints.Count / 3;
                for (int j = 0; j < m_curveCount; j++)
                {
                    for (int i = 1; i <= SEGMENT_COUNT; i++)
                    {
                        float t = (float)i / (float)SEGMENT_COUNT;
                        int nodeIndex = j * 3;
                        Vector3 pixel = CalculateCubicBezierPoint(t, m_allPoints[nodeIndex].position, m_allPoints[nodeIndex + 1].position, m_allPoints[nodeIndex + 2].position, m_allPoints[nodeIndex + 3].position);
                        m_lineRenderer.positionCount = j * SEGMENT_COUNT + i;
                        m_lineRenderer.SetPosition((j * SEGMENT_COUNT) + (i - 1), pixel);
                    }
                }
            }
            private GameObject LoadPoint(GameObject pointPrefab,Vector3 pos)
            {
                if (pointPrefab == null)
                {
                    Debug.LogError("The Prefab is Null!");
                    return null;
                }
                if (null == m_pointParent)
                    m_pointParent = new GameObject("AllPoints");
                GameObject pointClone = Instantiate(pointPrefab);
                pointClone.name = pointClone.name.Replace("(Clone)", "");
                pointClone.transform.SetParent(m_pointParent.transform);
                pointClone.transform.position = pos;
    
                return pointClone;
            }
    
            //贝塞尔曲线公式:B(t)=P0*(1-t)^3 + 3*P1*t(1-t)^2 + 3*P2*t^2*(1-t) + P3*t^3 ,t属于[0,1].
            Vector3 CalculateCubicBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
            {
                float u = 1 - t;
                float tt = t * t;
                float uu = u * u;
                float uuu = uu * u;
                float ttt = tt * t;
    
                Vector3 p = uuu * p0;
                p += 3 * uu * t * p1;
                p += 3 * u * tt * p2;
                p += ttt * p3;
    
                return p;
            }
        }
    }

    2. CurvePointControl.cs (挂载到路径点与调节点上(两个预制体))

    该脚本实现每个路径点对应的两个调节点,以及绘制调节点与路径点之间的切线。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    
    namespace DM.Editor.View
    {
        public class CurvePointControl : MonoBehaviour
        {
            [Header("锁定X轴")]
            public bool m_isLockX = false;
            [Header("锁定Y轴")]
            public bool m_isLockY = true;
            [Header("锁定Z轴")]
            public bool m_isLockZ = false;
           
            [HideInInspector]
            public GameObject m_controlObject;
            [HideInInspector]
            public GameObject m_controlObject2;
    
    
            private Vector3 offsetPos1 = Vector3.zero;
            private Vector3 offsetPos2 = Vector3.zero;
            private LineRenderer lineRenderer;
            void Start()
            {
                if (gameObject.tag.Equals("AnchorPoint") && !lineRenderer)
                    lineRenderer = gameObject.AddComponent<LineRenderer>();
                if (lineRenderer)
                {
                    lineRenderer.sortingOrder = 1;
                    lineRenderer.material = new Material(Shader.Find("Particles/Alpha Blended"));
                    lineRenderer.startColor = lineRenderer.endColor = Color.yellow;
                    lineRenderer.widthMultiplier = 0.03f;
                    lineRenderer.positionCount = 0;
                }
            }
            void OnMouseDown()
            {
                if (!gameObject.tag.Equals("AnchorPoint")) return;
                OffsetPos();
            }
            public List<Vector3> OffsetPos()
            {
                List<Vector3> offsetPosList = new List<Vector3>();
                if (m_controlObject)
                    offsetPos1 = m_controlObject.transform.position - transform.position;
                if (m_controlObject2)
                    offsetPos2 = m_controlObject2.transform.position - transform.position;
                offsetPosList.Add(offsetPos1);
                offsetPosList.Add(offsetPos2);
    
    
                return offsetPosList;
            }
            void OnMouseDrag()
            {
                //if (gameObject.tag.Equals("AnchorPoint")) return;
                Vector3 pos0 = Camera.main.WorldToScreenPoint(transform.position);
                Vector3 mousePos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos0.z);
                Vector3 mousePosInWorld= Camera.main.ScreenToWorldPoint(mousePos);
                Vector3 thisPos = mousePosInWorld;
                if (m_isLockX)
                    thisPos.x = transform.position.x;
                if (m_isLockY)
                    thisPos.y = transform.position.y;
                if (m_isLockZ)
                    thisPos.z = transform.position.z;
                transform.position = thisPos;
                DMDrawCurve.Instance.UpdateLine(gameObject, offsetPos1, offsetPos2);   
            }      
            private void DrawControlLine()
            {
                if (!gameObject.tag.Equals("AnchorPoint") || (!m_controlObject && !m_controlObject2)) return;
                if (lineRenderer)
                {
                    lineRenderer.positionCount = (m_controlObject && m_controlObject2) ? 3 : 2;
                    if (m_controlObject && !m_controlObject2)
                    {
                        lineRenderer.SetPosition(0, m_controlObject.transform.position);
                        lineRenderer.SetPosition(1, transform.position);
                    }
                    if (m_controlObject2 && !m_controlObject)
                    {
                        lineRenderer.SetPosition(0, transform.position);
                        lineRenderer.SetPosition(1, m_controlObject2.transform.position);
                    }
                    if (m_controlObject && m_controlObject2)
                    {
                        lineRenderer.SetPosition(0, m_controlObject.transform.position);
                        lineRenderer.SetPosition(1, transform.position);
                        lineRenderer.SetPosition(2, m_controlObject2.transform.position);
                    }
                }
            }
            void Update()
            {
                DrawControlLine();
            }
        }
    }

    对应Inspector,如图

    3. Test.cs (任意挂载)

    该脚本实现Player自动寻路。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    namespace DM.Editor.View
    {
        public class Test : MonoBehaviour
        {
            public GameObject m_player;
            public List<Vector3> m_pathPoints;
            void Start()
            {
                DMDrawCurve.Instance.Init(m_player);
            }
    
            IEnumerator Move()
            {
                if (m_pathPoints.Count == 0) yield break;
                int item = 1;
                while (true)
                {
                    m_player.transform.LookAt(m_pathPoints[item]);
                    m_player.transform.position = Vector3.Lerp(m_pathPoints[item - 1], m_pathPoints[item], 1f);
                    item++;
                    if (item >= m_pathPoints.Count)
                    {
                        item = 1;
                        yield break;
                    }
                    yield return new WaitForEndOfFrame();
                }
            }
            void Update()
            {
                if (Input.GetKey(KeyCode.LeftControl) && (Input.GetMouseButtonUp(0) || Input.GetMouseButtonUp(1)))
                {
                    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                    RaycastHit hit;
                    if (Physics.Raycast(ray, out hit))
                    {
                        if (Input.GetMouseButtonUp(0) && hit.collider.tag.Equals("Terrain"))
                        {
                            Vector3 pointPos = new Vector3(hit.point.x, m_player.transform.position.y, hit.point.z);
                            DMDrawCurve.Instance.AddPoint(pointPos);
                        }
                        else if (Input.GetMouseButtonUp(1) && hit.collider.tag.Equals("AnchorPoint"))
                        {
                            DMDrawCurve.Instance.DeletePoint(hit.collider.gameObject);
                        }
                    }
                }
                if (Input.GetKeyUp(KeyCode.A))
                    m_pathPoints = DMDrawCurve.Instance.HiddenLine(false);
                else if (Input.GetKeyUp(KeyCode.Escape))
                {
                    DMDrawCurve.Instance.HiddenLine(true);
                    m_pathPoints.Clear();
                }
                if (Input.GetKeyUp(KeyCode.B))
                {
                    StartCoroutine(Move());
                }
            }
        }
    }

    注意:需要添加两个Tag值(Terrain,AnchorPoint),也可动态添加,一个给场景地面,一个给路径点(AnchorPoint),调节点不需要Tag。

    开发Demo以及.unitypackage的网盘链接在这里,需要的自行下载:

    链接:https://pan.baidu.com/s/1dwIOxcMB-Lhq_Tlxenb4fQ 密码:7g8y

    以上就是近日开发结果,如有不足,请批评指正。如有疑问,请留言,看到自然回复。

    如转载,请注明出处:https://mp.csdn.net/postedit

    展开全文
  • 动态添加(删除)路径,通过两个以上的路径绘制曲线,删除之后不影响其他点绘制曲线;2.每个路径都可以被拖拽发生位移,可以通过锁定某个轴,使该轴不发生位移;3.每个路径处有两个可调节点(首尾只有一...

    近日,项目需求:前提:三维空间

    1.动态添加(删除)路径点,通过两个以上的路径点来绘制曲线,删除点之后不影响其他点绘制曲线;

    2.每个路径点都可以被拖拽发生位移,可以通过锁定某个轴,使该轴不发生位移;

    3.每个路径点处有两个可调节点(首尾只有一个调节点),可通过调节点来调节曲线切线(速度方向线)斜率,以达到平滑曲线;

    4.使该曲线形成路径,隐藏曲线,Player沿曲线完成自动寻路。

    先看效果,再贴代码。(使用贝塞尔曲线公式与LineRenderer绘制3D可调节曲线


    代码如下:两个脚本。

    1. DMDrawCurve.cs 挂载到任意对象即可

    该脚本实现绘制曲线,动态添加(删除)点,发生位移时更新绘制曲线,以及隐藏该曲线。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    namespace DM.Editor.View
    {
        [RequireComponent(typeof(LineRenderer))]
        public class DMDrawCurve : MonoBehaviour
        {
            public List<Transform> m_allPoints;
            private GameObject m_anchorPoint;
            private GameObject m_controlPoint;
            private GameObject m_pointParent;
            private LineRenderer m_lineRenderer;
            
            private int m_curveCount = 0;
            private int SEGMENT_COUNT = 60;//曲线取点个数(取点越多这个长度越趋向于精确)
    
            private static DMDrawCurve m_instance;
            public static DMDrawCurve Instance
            {
                get {
                    if (null == m_instance)
                        m_instance = new DMDrawCurve();
                    return m_instance;
                }
            }
            void Awake()
            {
                if (null == m_instance)
                    m_instance = this;
                SetLine();
                if (null == m_anchorPoint)
                    m_anchorPoint = Resources.Load("Prefabs/AnchorPoint") as GameObject;
                if (null == m_controlPoint)
                    m_controlPoint = Resources.Load("Prefabs/ControlPoint") as GameObject;
            }
            void SetLine()
            {
                if (null == m_lineRenderer)
                    m_lineRenderer = GetComponent<LineRenderer>();
                m_lineRenderer.material = Resources.Load("Materials/Line") as Material;
                m_lineRenderer.startColor = Color.red;
                m_lineRenderer.endColor = Color.green;
                m_lineRenderer.widthMultiplier = 0.2f;
            }
    
            public void Init(GameObject player)
            {//初始化一个基准点(Player)
                if (player == null) return;
                GameObject anchorPoint = LoadPoint(m_anchorPoint, player.transform.position);
                m_allPoints.Add(anchorPoint.transform);
            }      
            public void AddPoint(Vector3 anchorPointPos)
            {
                //初始化时m_allPoints添加了一个player
                if (m_allPoints.Count == 0) return;
                Transform lastPoint = m_allPoints[m_allPoints.Count - 1];
                GameObject controlPoint2 = LoadPoint(m_controlPoint, lastPoint.position+new Vector3(0,0,-1));   
                GameObject controlPoint = LoadPoint(m_controlPoint, anchorPointPos + new Vector3(0, 0, 1));
                GameObject anchorPoint = LoadPoint(m_anchorPoint, anchorPointPos);
    
                anchorPoint.GetComponent<CurvePointControl>().m_controlObject = controlPoint;
                lastPoint.GetComponent<CurvePointControl>().m_controlObject2 = controlPoint2;
    
                m_allPoints.Add(controlPoint2.transform);
                m_allPoints.Add(controlPoint.transform);
                m_allPoints.Add(anchorPoint.transform);
    
                DrawCurve();
            }
            public void DeletePoint(GameObject anchorPoint)
            {
                if (anchorPoint == null) return;
                CurvePointControl curvePoint = anchorPoint.GetComponent<CurvePointControl>();
                if (curvePoint && anchorPoint.tag.Equals("AnchorPoint"))
                {
                    if (curvePoint.m_controlObject)
                    {
                        m_allPoints.Remove(curvePoint.m_controlObject.transform);
                        Destroy(curvePoint.m_controlObject);
                    } 
                    if (curvePoint.m_controlObject2)
                    {
                        m_allPoints.Remove(curvePoint.m_controlObject2.transform);
                        Destroy(curvePoint.m_controlObject2);
                    }
                    if (m_allPoints.IndexOf(curvePoint.transform) == (m_allPoints.Count - 1))
                    {//先判断删除的是最后一个元素再移除
                        m_allPoints.Remove(curvePoint.transform);
                        Transform lastPoint = m_allPoints[m_allPoints.Count - 2];
                        GameObject lastPointCtrObject = lastPoint.GetComponent<CurvePointControl>().m_controlObject2;
                        if (lastPointCtrObject)
                        {
                            m_allPoints.Remove(lastPointCtrObject.transform);
                            Destroy(lastPointCtrObject);
                            lastPoint.GetComponent<CurvePointControl>().m_controlObject2 = null;
                        }
                    }
                    else
                    {
                        m_allPoints.Remove(curvePoint.transform);
                    }
                    Destroy(anchorPoint);
                    if(m_allPoints.Count == 1)
                    {
                        m_lineRenderer.positionCount = 0;
                    }
                }
    
                DrawCurve();
            }
            public void UpdateLine(GameObject anchorPoint, Vector3 offsetPos1, Vector3 offsetPos2)
            {
                if (anchorPoint == null) return;
                if (anchorPoint.tag.Equals("AnchorPoint"))
                {
                    CurvePointControl curvePoint = anchorPoint.GetComponent<CurvePointControl>();
                    if (curvePoint)
                    {
                        if (curvePoint.m_controlObject)
                            curvePoint.m_controlObject.transform.position = anchorPoint.transform.position + offsetPos1;
                        if (curvePoint.m_controlObject2)
                            curvePoint.m_controlObject2.transform.position = anchorPoint.transform.position + offsetPos2;
                    }
                }
                DrawCurve();
            }
            public List<Vector3> HiddenLine(bool isHidden=false)
            {
                m_pointParent.SetActive(isHidden);
                m_lineRenderer.enabled = isHidden;
                List<Vector3> pathPoints = new List<Vector3>();
                if(!isHidden)
                {
                    for(int i = 0; i < m_lineRenderer.positionCount; i++)
                    {
                        pathPoints.Add(m_lineRenderer.GetPosition(i));
                    }
                }
                return pathPoints;
            }
    
            private void DrawCurve()//画曲线
            {
                if (m_allPoints.Count < 4) return;
                m_curveCount = (int)m_allPoints.Count / 3;
                for (int j = 0; j < m_curveCount; j++)
                {
                    for (int i = 1; i <= SEGMENT_COUNT; i++)
                    {
                        float t = (float)i / (float)SEGMENT_COUNT;
                        int nodeIndex = j * 3;
                        Vector3 pixel = CalculateCubicBezierPoint(t, m_allPoints[nodeIndex].position, m_allPoints[nodeIndex + 1].position, m_allPoints[nodeIndex + 2].position, m_allPoints[nodeIndex + 3].position);
                        m_lineRenderer.positionCount = j * SEGMENT_COUNT + i;
                        m_lineRenderer.SetPosition((j * SEGMENT_COUNT) + (i - 1), pixel);
                    }
                }
            }
            private GameObject LoadPoint(GameObject pointPrefab,Vector3 pos)
            {
                if (pointPrefab == null)
                {
                    Debug.LogError("The Prefab is Null!");
                    return null;
                }
                if (null == m_pointParent)
                    m_pointParent = new GameObject("AllPoints");
                GameObject pointClone = Instantiate(pointPrefab);
                pointClone.name = pointClone.name.Replace("(Clone)", "");
                pointClone.transform.SetParent(m_pointParent.transform);
                pointClone.transform.position = pos;
    
                return pointClone;
            }
    
            //贝塞尔曲线公式:B(t)=P0*(1-t)^3 + 3*P1*t(1-t)^2 + 3*P2*t^2*(1-t) + P3*t^3 ,t属于[0,1].
            Vector3 CalculateCubicBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
            {
                float u = 1 - t;
                float tt = t * t;
                float uu = u * u;
                float uuu = uu * u;
                float ttt = tt * t;
    
                Vector3 p = uuu * p0;
                p += 3 * uu * t * p1;
                p += 3 * u * tt * p2;
                p += ttt * p3;
    
                return p;
            }
        }
    }

    2. CurvePointControl.cs (挂载到路径点与调节点上(两个预制体))

    该脚本实现每个路径点对应的两个调节点,以及绘制调节点与路径点之间的切线。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    
    namespace DM.Editor.View
    {
        public class CurvePointControl : MonoBehaviour
        {
            [Header("锁定X轴")]
            public bool m_isLockX = false;
            [Header("锁定Y轴")]
            public bool m_isLockY = true;
            [Header("锁定Z轴")]
            public bool m_isLockZ = false;
           
            [HideInInspector]
            public GameObject m_controlObject;
            [HideInInspector]
            public GameObject m_controlObject2;
    
    
            private Vector3 offsetPos1 = Vector3.zero;
            private Vector3 offsetPos2 = Vector3.zero;
            private LineRenderer lineRenderer;
            void Start()
            {
                if (gameObject.tag.Equals("AnchorPoint") && !lineRenderer)
                    lineRenderer = gameObject.AddComponent<LineRenderer>();
                if (lineRenderer)
                {
                    lineRenderer.sortingOrder = 1;
                    lineRenderer.material = new Material(Shader.Find("Particles/Alpha Blended"));
                    lineRenderer.startColor = lineRenderer.endColor = Color.yellow;
                    lineRenderer.widthMultiplier = 0.03f;
                    lineRenderer.positionCount = 0;
                }
            }
            void OnMouseDown()
            {
                if (!gameObject.tag.Equals("AnchorPoint")) return;
                OffsetPos();
            }
            public List<Vector3> OffsetPos()
            {
                List<Vector3> offsetPosList = new List<Vector3>();
                if (m_controlObject)
                    offsetPos1 = m_controlObject.transform.position - transform.position;
                if (m_controlObject2)
                    offsetPos2 = m_controlObject2.transform.position - transform.position;
                offsetPosList.Add(offsetPos1);
                offsetPosList.Add(offsetPos2);
    
    
                return offsetPosList;
            }
            void OnMouseDrag()
            {
                //if (gameObject.tag.Equals("AnchorPoint")) return;
                Vector3 pos0 = Camera.main.WorldToScreenPoint(transform.position);
                Vector3 mousePos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos0.z);
                Vector3 mousePosInWorld= Camera.main.ScreenToWorldPoint(mousePos);
                Vector3 thisPos = mousePosInWorld;
                if (m_isLockX)
                    thisPos.x = transform.position.x;
                if (m_isLockY)
                    thisPos.y = transform.position.y;
                if (m_isLockZ)
                    thisPos.z = transform.position.z;
                transform.position = thisPos;
                DMDrawCurve.Instance.UpdateLine(gameObject, offsetPos1, offsetPos2);   
            }      
            private void DrawControlLine()
            {
                if (!gameObject.tag.Equals("AnchorPoint") || (!m_controlObject && !m_controlObject2)) return;
                if (lineRenderer)
                {
                    lineRenderer.positionCount = (m_controlObject && m_controlObject2) ? 3 : 2;
                    if (m_controlObject && !m_controlObject2)
                    {
                        lineRenderer.SetPosition(0, m_controlObject.transform.position);
                        lineRenderer.SetPosition(1, transform.position);
                    }
                    if (m_controlObject2 && !m_controlObject)
                    {
                        lineRenderer.SetPosition(0, transform.position);
                        lineRenderer.SetPosition(1, m_controlObject2.transform.position);
                    }
                    if (m_controlObject && m_controlObject2)
                    {
                        lineRenderer.SetPosition(0, m_controlObject.transform.position);
                        lineRenderer.SetPosition(1, transform.position);
                        lineRenderer.SetPosition(2, m_controlObject2.transform.position);
                    }
                }
            }
            void Update()
            {
                DrawControlLine();
            }
        }
    }

    对应Inspector,如图


    3. Test.cs (任意挂载)

    该脚本实现Player自动寻路。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    namespace DM.Editor.View
    {
        public class Test : MonoBehaviour
        {
            public GameObject m_player;
            public List<Vector3> m_pathPoints;
            void Start()
            {
                DMDrawCurve.Instance.Init(m_player);
            }
    
            IEnumerator Move()
            {
                if (m_pathPoints.Count == 0) yield break;
                int item = 1;
                while (true)
                {
                    m_player.transform.LookAt(m_pathPoints[item]);
                    m_player.transform.position = Vector3.Lerp(m_pathPoints[item - 1], m_pathPoints[item], 1f);
                    item++;
                    if (item >= m_pathPoints.Count)
                    {
                        item = 1;
                        yield break;
                    }
                    yield return new WaitForEndOfFrame();
                }
            }
            void Update()
            {
                if (Input.GetKey(KeyCode.LeftControl) && (Input.GetMouseButtonUp(0) || Input.GetMouseButtonUp(1)))
                {
                    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                    RaycastHit hit;
                    if (Physics.Raycast(ray, out hit))
                    {
                        if (Input.GetMouseButtonUp(0) && hit.collider.tag.Equals("Terrain"))
                        {
                            Vector3 pointPos = new Vector3(hit.point.x, m_player.transform.position.y, hit.point.z);
                            DMDrawCurve.Instance.AddPoint(pointPos);
                        }
                        else if (Input.GetMouseButtonUp(1) && hit.collider.tag.Equals("AnchorPoint"))
                        {
                            DMDrawCurve.Instance.DeletePoint(hit.collider.gameObject);
                        }
                    }
                }
                if (Input.GetKeyUp(KeyCode.A))
                    m_pathPoints = DMDrawCurve.Instance.HiddenLine(false);
                else if (Input.GetKeyUp(KeyCode.Escape))
                {
                    DMDrawCurve.Instance.HiddenLine(true);
                    m_pathPoints.Clear();
                }
                if (Input.GetKeyUp(KeyCode.B))
                {
                    StartCoroutine(Move());
                }
            }
        }
    }

    注意:需要添加两个Tag值(Terrain,AnchorPoint),也可动态添加,一个给场景地面,一个给路径点(AnchorPoint),调节点不需要Tag。

    开发测试Demo以及.unitypackage的网盘链接如下,需要的自行下载:

    链接:https://pan.baidu.com/s/1dwIOxcMB-Lhq_Tlxenb4fQ 密码:7g8y

    以上就是近日开发结果,如有不足,请批评指正。如有疑问,请留言,看到自然回复。

    如转载,请注明出处:IT_yanghui的博客

    展开全文
  • 贝塞尔曲线是一种绘制曲线的方法,它的原理很简单: 以二阶贝塞尔曲线为例 如图,在p0,p1之间移动着一个,我们先称之为a0,同样在p1,p2之间移动着一个,我们称之为a1。他们需要满足的条件是这样的,在移动中,...

    贝塞尔曲线是一种绘制曲线的方法,它的原理很简单:

    以二阶贝塞尔曲线为例


    如图,在p0,p1之间移动着一个点,我们先称之为a0,同样在p1,p2之间移动着一个点,我们称之为a1。他们需要满足的条件是这样的,在移动中,保证线段p0a0p0p1=p1a1p1p2=X

    ,这个比值X是从01逐渐变化的。

    然后我们连接a0,a1,在线段a0a1上有一点b0,我们同样保证a0b0a0a1=X;最后X01变化的过程就是如图所显示的样子。这就是贝塞尔曲线。简单吧!

    相对于更高阶的,原理一样,如果你有时间有耐心,函数很容易写出来的,这里只用二阶作为例子。

    二阶函数点的位置可以这样计算

    a0=p0+p1-p0*X

    a1=p1+p2-p1*X

    b0=a0+a1-a0*X

    这样我们根据p0p1p2的坐标就求出b0的坐标,b0的运动轨迹就是贝塞尔曲线。

    三个公式最后得出:

    b0=X*X*(p0+p2-2*p1)+2*X*(p1-p0)+p0

    知道原理,接下来我们用unity3d实现起来就容易了。

    代码如下:将脚本赋予一个空gameobject,并将新建的三个cube分别拖入对应空缺物体,运行游戏拖动物体就能看到贝塞尔曲线的变化。注意:这里只能在场景中拖动,不能在游戏视图中拖动,因为

    Debug.DrawLine方法是只能在场景中显示的。

    using UnityEngine;
    using System.Collections;
    
    public class draw : MonoBehaviour {
       public GameObject v0, v1, a0;
        LineRenderer lineRenderer;
        //Vector3 v0, v1;//顶点
        //Vector3 a0;
        float jianxi = 0.05f;//绘制的0-1的间隙 越小曲线越接近曲线,
    
        // Use this for initialization
        void Start ()
        {
          
        }
    	
    	// Update is called once per frame
    	void Update () {
            for(float i=0;i<1;i+=jianxi)
            {
                Debug.DrawLine(po(i, v0, v1, a0), po(i + jianxi, v0, v1, a0), Color.red);
                Debug.DrawLine(v0.transform.position,a0.transform.position, Color.green);
                Debug.DrawLine(a0.transform.position, v1.transform.position, Color.green);
            }
        }
           
        private Vector3 po(float t,GameObject v0, GameObject v1, GameObject a0)//根据当前时间t 返回路径  其中v0为起点 v1为终点 a为中间点 
        {
            Vector3 a;
            a.x = t * t * (v1.transform.position.x - 2 * a0.transform.position.x + v0.transform.position.x) + v0.transform.position.x + 2 * t * (a0.transform.position.x - v0.transform.position.x);//公式为B(t)=(1-t)^2*v0+2*t*(1-t)*a0+t*t*v1 其中v0为起点 v1为终点 a为中间点 
            a.y = t * t * (v1.transform.position.y - 2 * a0.transform.position.y + v0.transform.position.y) + v0.transform.position.y + 2 * t * (a0.transform.position.y - v0.transform.position.y);
            a.z = t * t * (v1.transform.position.z - 2 * a0.transform.position.z + v0.transform.position.z) + v0.transform.position.z + 2 * t * (a0.transform.position.z - v0.transform.position.z);
            return a;
        }
    }
    


    unity3d项目资源可以点击 这里 下载


    展开全文
  • 在前两篇中,我们使用了 Graphics(查看详情)以及 Line Renderer 方法绘制线条(查看详情),这次我们通过 GL 来绘制线条,这种方法与前两种方法相比,效率与性能上面差不多。原文链接:...
  • Unity3D使用GL绘制曲线

    2020-07-30 23:33:34
    Unity3D使用GL类绘制曲线,显示在坐标系中
  • 简介:新项目中需绘制可无限循环的2D多边形路面,于是写了个2D多边形生成器,包括Mesh绘制,添加阻挡及路面描边3个部分,代码如下
  • 为了平滑游戏对象在 Unity 中的行进路线,我们经常会在 Unity 中使用 ITweenPath 插件,但有时候我们或许只会使用到通过 ITweenPath 绘制出来的(比如把这些放到配置文件中),并不希望加载 ITweenPath...
  • 背景 由于要做Native2D的A* 算法寻路,所以必须进行Scene的网格划分,而进行了网格划分需要进行可视化的调试,需求就是这个逻辑。...2、Unity如何绘制网格 实现 1、Unity如何实现可视化调试 本文
  • 该资源,是Unity 3D路径跟随,可以选择闭合曲线和非闭合曲线,目标跟随时可以选择旋转跟随和非旋转跟随,曲线的绘制采用Hermite曲线。
  • 本项目基于Unity3d,可实现矢量图绘制,包括整个实体拖动,夹拖动编辑等。 现有功能主要为了完成某个项目,都是自主开发,效果还是不如传统CAD,功能也比较有限,毕竟unity3d是游戏引擎。 ...
  • 当再次看这篇文章时,还是觉得非常吃力,因为距离上一次转载的时间有点长了,上次是看懂了,但没有记录下来,所以这次看时还是需要费脑子才再次看懂了,所以这次我在后面详细的记录了下来,最好自己能够看懂原来...
  • Unity3D绘制一个平面图形可不容易,可别惯性思维觉得,嗯,这引擎3D的事情都能解决了,2D的不叫事情。其实除去布置UI,在Unity3D绘制一个2D平面图形是很蛋疼的一件事情。不然的话,也不会有大量的平面图形绘制...
  • 【前言】 图形化调试可以加速开发。 例如在战斗中,可能需要知道所有单位的仇恨值,如果这些信息全打log的话,很难有...Unity中图形化调试主要4种 Debug.Draw Gizmos.Draw Graphic.DrawMesh GL 只需在Scene窗口显示的
  • 今天我们学习一种简单的使用Unity Shader在屏幕上绘制几何图形的方法。其中包含了基本的(或者说是圆形)、直线(任意方向)和网格(横纵交错)的绘制方法。本文例程使用的是Unity5.4.1。
  • Unity 动态绘制曲线

    2020-06-24 17:30:43
    用shader绘制 动态sin曲线 源码在最下面
  • 绘制电线,分解出来就一下几个问题需解决: 曲线生成的问题 如何根据空间中两确定一条曲线 绘制的电线可以用鼠标点击 最终实现的效果如下: 现在我们来一一解决。 贝塞尔曲线 关于贝塞尔曲线的原理,讲解的文章很...
  • 为了平滑游戏对象在 Unity 中的行进路线,我们经常会在 Unity 中使用 ITweenPath 插件,但有时候我们或许只会使用到通过 ITweenPath 绘制出来的(比如把这些放到配置文件中),并不希望加载 ITweenPath 插件或者...
  • unity3d表格模拟绘制

    2012-10-31 17:57:31
    前段时间收到网友来信,该网友希望能够在Unity3d中实现表格的绘制并且能够动态地修改与获取表格中的信息。由于前段时间相对较忙,因此该问题一直未能解决,在这里先向该网友致歉,下面我将介绍一种使用TextField组件...
  • Unity绘制抛物线

    2018-03-06 10:16:26
    之前的文章请看这:Unity绘制抛物线代码上一篇文章只是简单地绘制了一个抛物线,但是无法随意移动或者旋转,最近因为做个项目可能会用到这个抛物线,所以我做了一些修改,现在抛物线可以跟随着起始移动、旋转,还...
1 2 3 4 5 ... 20
收藏数 11,075
精华内容 4,430
热门标签
关键字:

unity3d 绘制点绘制线