使用Unity原生LineRenderer+Edge Collider2D实现在2D场景中画线并带碰撞体。
我们先来看看效果
实现思路,当鼠标点击的时候开始在当前位置实例化LineRenderer对象,然后移动的过程中记录移动的点并赋值给LineRenderer中的 Positions属性动态修改LineRenderer的形状和长度。碰撞器方面使用Edge Collider 2D 通过类似方式,记录点并赋值给碰撞器的Points。
OK看完了大概原理还是来看看具体的代码吧。
using UnityEngine; using System.Collections; using System.Collections.Generic; using System; public class DrawLineScripts : MonoBehaviour { //得到带有LineRender物体对象 [Tooltip("The GameObject of LineObject")] public GameObject lineRenderer; //定义一个公共类来存储初始化成成的物体对象 [Tooltip("The number of instantiate LineObject")] public int preFabLineCount = 6; //初始化LineRenderer 物体对象的集合 [HideInInspector] public List<GameObject> lineList; //存储鼠标移动过的点 [HideInInspector] public List<Vector2> linePos; //移动点索引 private int idx = 0; //全局线段对象变量 private GameObject gameObj; void Awake() { //激活阶段生成固定数量的物体对象 for (int i = 0; i < preFabLineCount; i++) { GameObject go = Instantiate(lineRenderer, new Vector3(0f, 0f, 0f), Quaternion.identity); //将生成的对象隐藏,当需要使用的时候修改位置并显示出来。 go.SetActive(false); //设置实例化出来物体的父级对象 go.transform.SetParent(gameObject.transform); //将对象添加到全局列表中 lineList.Add(go); } } // Update is called once per frame void Update() { if(Input.GetMouseButtonDown(0)) //鼠标左键点击的时候 { gameObj = GetLineRenderer(); //得到鼠标移动的坐标并将屏幕坐标转换为世界坐标 Vector3 ve3 = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Input.mousePosition.z)); //得到对象身上的LineRenderer组件 LineRenderer lineRenderer = gameObj.GetComponent<LineRenderer>(); //设置LineRenderer组件的起始位置 lineRenderer.SetPosition(idx, new Vector3(ve3.x,ve3.y,0f)); //设置LineRenderer的宽度 lineRenderer.startWidth = 0.4f; //将二维坐标存到数组中 Vector2 v2 = new Vector2(ve3.x, ve3.y); linePos.Add(v2); } else if(Input.GetMouseButton(0)) //鼠标左键移动或者静止的时候 { ++idx; //设置LineRenderer位置的索引每移动一次增加一次 LineRenderer lineRenderer = gameObj.GetComponent<LineRenderer>(); Vector3 ve3 = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Input.mousePosition.z)); lineRenderer.positionCount = idx + 1; lineRenderer.SetPosition(idx, new Vector3(ve3.x, ve3.y, 0f)); Vector2 v2 = new Vector2(ve3.x, ve3.y); linePos.Add(v2); } else if(Input.GetMouseButtonUp(0)) //鼠标左键抬起的时候 { Vector3 ve3 = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Input.mousePosition.z)); EdgeCollider2D edge = gameObj.GetComponent<EdgeCollider2D>(); //得到物体身上的EdgeCollider2D组件 edge.points = linePos.ToArray(); //将存起来的二维向量点赋值到碰撞器实现碰撞器初始化 linePos.Clear(); //清除点集合方便下次点击记录 idx = 0; //索引归零 } } /// <summary> /// 获取LineRenderer对象,如果对象集合中有未激活对象则取出未激活对象并激活,否则生成新对象 /// </summary> /// <returns></returns> private GameObject GetLineRenderer() { for (int i = 0; i < lineList.Count; i++) { if (lineList[i].activeInHierarchy == false) { lineList[i].SetActive(true); lineList[i].transform.position = new Vector3(0f, 0f, 0f); return lineList[i]; } } GameObject go = Instantiate(lineRenderer,new Vector3(0f,0f,0f),Quaternion.identity); go.transform.SetParent(gameObject.transform); lineList.Add(go); return go; } }
代码里面有详细的注释,大部分讲清了实现原理,我们看一下Inspector面板。
LineRenderer对象面板
这里讲一下这个实现存在的问题,这个实现是基于2D场景的,如果要实现3D场景,只要修改其中的屏幕坐标转换成世界坐标的方法,然后LineRenderer设置点的时候直接使用三维向量坐标即可,但是在3D场景中Edge Collider 2D便不能使用了。具体使用什么碰撞器以后再研究。