Unity3D实现模型体积拖拽变化
实现模型拖拽体积改变功能算法:
public Transform crossLeft; public Transform cro***ight; public Transform arrowUp; public Transform arrowDown; //模型结构子对象 public Transform legLeftUp; public Transform legRightUp; public Transform legLeftDown; public Transform legRightDown; public Transform arrow; /// /// 传动带模型MeshFilter /// public MeshFilter conveyorMeshFilter; /// /// 传送带边沿护栏模型MeshFilter /// public MeshFilter guardBarMeshFilter; public BoxCollider boxCollider; //Mesh保存 private Dictionary conveyorMeshLeftVertices; private Dictionary conveyorMeshRightVertices; private Dictionary conveyorMeshUpVertices; private Dictionary conveyorMeshDownVertices; private Dictionary guardBarMeshLeftVertices; private Dictionary guardBarMeshRightVertices; private Dictionary guardBarMeshUpVertices; private Dictionary guardBarMeshDownVertices; //交互所用变量 private float firstDistanceToOtherCross; private Vector3 nowInputMousePosition; float endDistance; private Transform otherCross; private Vector3 otherCrossScreenPostion; private Vector3 lastInputMousePoistion;
核心方法:
//初始化
void Init()
{
conveyorMeshLeftVertices = FiltrateVertices(conveyorMeshFilter.mesh, VecticeDir.Left);
conveyorMeshRightVertices = FiltrateVertices(conveyorMeshFilter.mesh, VecticeDir.Right);
conveyorMeshUpVertices = FiltrateVertices(conveyorMeshFilter.mesh, VecticeDir.Up);
conveyorMeshDownVertices = FiltrateVertices(conveyorMeshFilter.mesh, VecticeDir.Down);
guardBarMeshLeftVertices = FiltrateVertices(guardBarMeshFilter.mesh, VecticeDir.Left);
guardBarMeshRightVertices = FiltrateVertices(guardBarMeshFilter.mesh, VecticeDir.Right);
guardBarMeshUpVertices = FiltrateVertices(guardBarMeshFilter.mesh, VecticeDir.Up);
guardBarMeshDownVertices = FiltrateVertices(guardBarMeshFilter.mesh, VecticeDir.Down);
//length = 1;
//heigth = 1;
boxCollider = gameObject.GetComponent();
if (name.Contains("left"))
{
otherCross = converyEntityMediator.converyEntityView.cro***ight;
isLeft = true;
}
else
{
otherCross = converyEntityMediator.converyEntityView.crossLeft;
isLeft = false;
}
}
///
/// 筛选顶点,分成左右两堆
///
/// 顶点方向
Dictionary FiltrateVertices(Mesh mesh, VecticeDir dir)
{
Dictionary result = new Dictionary();
for (int i = 0; i < mesh.vertices.Length; i++)
{
switch (dir)
{
case VecticeDir.Left:
if (mesh.vertices[i].z > 0)
{
result.Add(i, mesh.vertices[i]);
}
break;
case VecticeDir.Up:
if (mesh.vertices[i].x > 0)
{
result.Add(i, mesh.vertices[i]);
}
break;
case VecticeDir.Right:
if (mesh.vertices[i].z < 0)
{
result.Add(i, mesh.vertices[i]);
}
break;
case VecticeDir.Down:
if (mesh.vertices[i].x < 0)
{
result.Add(i, mesh.vertices[i]);
}
break;
}
}
return result;
}
//宽度
public void ChangeWidth(float width,Vector3 dir, bool isUp)
{
List conveyorMeshVertices = new List(conveyorMeshFilter.mesh.vertices);
List guardBarMeshVertices = new List(guardBarMeshFilter.mesh.vertices);
float halfWidth = width / 2;
transform.position += halfWidth * (transform.rotation * dir).normalized;
//this.length += length;
//改变板和边栏的长度
foreach (KeyValuePair item in conveyorMeshUpVertices)
{
conveyorMeshVertices[item.Key] += Vector3.right * halfWidth;
}
foreach (KeyValuePair item in conveyorMeshDownVertices)
{
conveyorMeshVertices[item.Key] -= Vector3.right * halfWidth;
}
foreach (KeyValuePair item in guardBarMeshUpVertices)
{
guardBarMeshVertices[item.Key] += Vector3.right * halfWidth;
}
foreach (KeyValuePair item in guardBarMeshDownVertices)
{
guardBarMeshVertices[item.Key] -= Vector3.right * halfWidth;
}
if (isUp)
{
//设置子物体的位置
legLeftUp.localPosition += halfWidth * dir;
legRightUp.localPosition += halfWidth * dir;
legLeftDown.localPosition -= halfWidth * dir;
legRightDown.localPosition -= halfWidth * dir;
arrowUp.localPosition += halfWidth * dir;
arrowDown.localPosition -= halfWidth * dir;
}
else
{
//设置子物体的位置
legLeftUp.localPosition -= halfWidth * dir;
legRightUp.localPosition -= halfWidth * dir;
legLeftDown.localPosition += halfWidth * dir;
legRightDown.localPosition += halfWidth * dir;
arrowUp.localPosition -= halfWidth * dir;
arrowDown.localPosition += halfWidth * dir;
}
float arrowScale = Mathf.Clamp(((ConveyorEntity)entity).conveyorProperty.Width * 2f, 0.2f, 1);
arrow.localScale = new Vector3(arrowScale, 1, arrowScale);
conveyorMeshFilter.mesh.SetVertices(conveyorMeshVertices);
guardBarMeshFilter.mesh.SetVertices(guardBarMeshVertices);
//设置collider
boxCollider.size += Vector3.right * width;
}
/// 改变传送带长度
///
/// 传送带长度
/// 是否选择的左边移动
public void ChangeLength(float length, Vector3 dir,bool isChoiceLeft = false)
{
List conveyorMeshVertices = new List(conveyorMeshFilter.mesh.vertices);
List guardBarMeshVertices = new List(guardBarMeshFilter.mesh.vertices);
float halfLength = length / 2;
transform.position += halfLength *( transform.rotation * dir).normalized;
//改变板和边栏的长度
foreach (KeyValuePair item in conveyorMeshLeftVertices)
{
conveyorMeshVertices[item.Key] += Vector3.forward * halfLength;
}
foreach (KeyValuePair item in guardBarMeshLeftVertices)
{
guardBarMeshVertices[item.Key] += Vector3.forward * halfLength;
}
foreach (KeyValuePair item in conveyorMeshRightVertices)
{
conveyorMeshVertices[item.Key] -= Vector3.forward * halfLength;
}
foreach (KeyValuePair item in guardBarMeshRightVertices)
{
guardBarMeshVertices[item.Key] -= Vector3.forward * halfLength;
}
if (isChoiceLeft)
{
//设置子物体的位置
legLeftUp.localPosition += halfLength * dir;
legRightUp.localPosition -= halfLength * dir;
legLeftDown.localPosition += halfLength * dir;
legRightDown.localPosition -= halfLength * dir;
crossLeft.localPosition += halfLength * dir;
cro***ight.localPosition -= halfLength * dir;
}
else
{
//设置子物体的位置
legLeftUp.localPosition -= halfLength * dir;
legRightUp.localPosition += halfLength * dir;
legLeftDown.localPosition -= halfLength * dir;
legRightDown.localPosition += halfLength * dir;
crossLeft.localPosition -= halfLength * dir;
cro***ight.localPosition += halfLength * dir;
}
//float arrowScale = Mathf.Clamp(((ConveyorEntity)entity).conveyorProperty.Length * 2f, 0.2f, 1);
//arrow.localScale = new Vector3(arrowScale, 1, arrowScale);
conveyorMeshFilter.mesh.SetVertices(conveyorMeshVertices);
guardBarMeshFilter.mesh.SetVertices(guardBarMeshVertices);
//设置collider
boxCollider.size += Vector3.forward * length;
ChangeBounds(100);//拉伸mesh会导致原bound不在摄像机视角下,造成传送带不渲染 (Frustum Culling)
}
private void ChangeBounds(float boundLength)
{
Vector3 bound = new Vector3(boundLength, boundLength, boundLength);
conveyorMeshFilter.mesh.bounds = new Bounds(transform.position, bound);
guardBarMeshFilter.mesh.bounds = new Bounds(transform.position, bound);
}
交互输入:
private void OnMouseDown()
{
endAddDistance = 0;
otherArrowScreenPostion = Camera.main.WorldToScreenPoint(otherArrow.position);
lastInputMousePoistion = Input.mousePosition;
lastDistanceToOtherCross = Vector2.Distance(otherArrowScreenPostion, lastInputMousePoistion);
}
private void OnMouseDrag()
{
nowInputMousePosition = Input.mousePosition;
float distance = Vector2.Distance(nowInputMousePosition, lastInputMousePoistion) * 0.1f;
float otherDistaceToNowInputMousePosition = Vector2.Distance(otherArrowScreenPostion, nowInputMousePosition);
//减少宽度
if (lastDistanceToOtherCross > otherDistaceToNowInputMousePosition)
{
endAddDistance -= distance;
ChangeWidth(-distance, (transform.localPosition - otherArrow.localPosition).normalized, isUp);
}
//增加宽带
else if (lastDistanceToOtherCross < otherDistaceToNowInputMousePosition)
{
endAddDistance += distance;
ChangeWidth(distance, (transform.localPosition - otherArrow.localPosition).normalized, isUp);
}
if (otherDistaceToNowInputMousePosition otherDistaceToNowInputMousePosition)
{
if (Vector3.Distance(transform.localPosition, otherCross.localPosition) Vector3.Distance(transform.localPosition, otherCross.localPosition))
{
return;
}
endDistance -= distance;
converyEntityMediator.ChangeLength(-distance, (transform.localPosition - otherCross.localPosition).normalized, isLeft);
}
//增加长度
else if (firstDistanceToOtherCross < otherDistaceToNowInputMousePosition)
{
endDistance += distance;
converyEntityMediator.ChangeLength(distance, (transform.localPosition - otherCross.localPosition).normalized, isLeft);
}
lastInputMousePoistion = Input.mousePosition;
lastDistanceToOtherCross = Vector2.Distance(otherArrowScreenPostion, lastInputMousePoistion);
}
private void OnMouseUp()
{
if (endAddDistance != 0)
{
ChangeWidth(-endAddDistance, (transform.localPosition - otherArrow.localPosition).normalized, isUp);
ChangeLength(-endDistance, (transform.localPosition - otherCross.localPosition).normalized, isLeft);
}
}
