使用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便不能使用了。具体使用什么碰撞器以后再研究。