Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using ZongCaiGongZuoMian;
public class CoalWall : MonoBehaviour
{
[SerializeField]
Material mat;
float zjInternal;//支架间隔
float zjHeightMax;
Transform trWheel01;//第一个滚筒
Transform trWheel02;//第二个滚筒
Transform[] gbTrans;//刮板机组
float vertInternal;//点间隔
float vertInternalSqrt;
[SerializeField]
float wheelRadius = 1f;//滚筒半径
public float radiusOfWheel { get { return wheelRadius; } }
float wheelRadiusSqrt;
[SerializeField]
float distGBToWall = 1;
Vector3 curPos01;
Vector3 curPos02;
List<Vector3> listPos01 = new List<Vector3>();
List<Vector3> listPos02 = new List<Vector3>();
Mesh mesh;
int wVertCount;
int hVertCount;
float wSize;
float hSize;
int countWRadius;
int countHRadius;
Transform trCoalWall;
IEnumerator Start()
{
zjInternal = ZongCaiManager.instance.zjInternal;
zjHeightMax = 3;
//
yield return new WaitUntil(delegate { return ZongCaiManager.instance.caiMeiJi; });
trWheel01 = ZongCaiManager.instance.caiMeiJi.coalWallPointLeft;
trWheel02 = ZongCaiManager.instance.caiMeiJi.coalWallPointRight;
//curPos随便赋值一下,最好远离煤壁实际位置,这样在更新的时候直接发现位置有区别,就开始计算了。
curPos01 = Vector3.left * 100;
curPos02 = Vector3.left * 100;
listPos01.Add(curPos01);
listPos02.Add(curPos02);
wheelRadiusSqrt = wheelRadius * wheelRadius;
//
yield return new WaitUntil(delegate { return ZongCaiManager.instance.gbTrans.Length > 0; });
gbTrans = ZongCaiManager.instance.gbTrans;
vertInternal = zjInternal * 0.12f;
vertInternalSqrt = vertInternal * vertInternal;
//
Create(zjInternal * (gbTrans.Length + 1), zjHeightMax, vertInternal);
}
public void Create(float width, float height, float unitSize)
{
GameObject objCoalWall = new GameObject("CoalWall");
trCoalWall = objCoalWall.transform;
trCoalWall.SetParent(transform);
trCoalWall.position = gbTrans[0].position + Vector3.forward * distGBToWall;
int wCount = Mathf.CeilToInt(width / unitSize);
int hCount = Mathf.CeilToInt(height / unitSize);
wVertCount = wCount + 1;
hVertCount = hCount + 1;
wSize = width / wCount;
hSize = height / hCount;
countWRadius = (int)(wheelRadius / wSize) + 1;
countHRadius = (int)(wheelRadius / hSize) + 1;
Vector3[] vs = new Vector3[wVertCount * hVertCount];
for (int i = 0; i < wVertCount; i++)
{
for (int j = 0; j < hVertCount; j++)
{
vs[i * hVertCount + j] = new Vector3(i * wSize, j * hSize, 0);
}
}
int[] ts = new int[wCount * hCount * 6];
int k = 0;
for (int i = 0; i < wCount; i++)
{
for (int j = 0; j < hCount; j++)
{
ts[k + 0] = i * hVertCount + j;
ts[k + 1] = ts[k + 0] + 1;
ts[k + 2] = (i + 1) * hVertCount + j;
ts[k + 3] = ts[k + 1];
ts[k + 4] = ts[k + 2] + 1;
ts[k + 5] = ts[k + 2];
k += 6;
}
}
Vector2[] uvs = new Vector2[vs.Length];
for (int i = 0; i < uvs.Length; i++)
{
uvs[i] = vs[i] * 0.2f;
}
mesh = new Mesh();
mesh.vertices = vs;
mesh.triangles = ts;
mesh.RecalculateNormals();
mesh.uv = uvs;
MeshFilter filter = objCoalWall.AddComponent<MeshFilter>();
filter.mesh = mesh;
MeshRenderer render = objCoalWall.AddComponent<MeshRenderer>();
render.material = mat;
}
void Update()
{
UpdateListPos();
UpdateMeshByLastPos();
UpdateByGuaBan();
}
int listMaxCount = 16;
void UpdateListPos()
{
if (!trCoalWall) return;
if (!trWheel01) return;
if (!trWheel02) return;
//
Vector3 pos = trCoalWall.InverseTransformPoint(trWheel01.position);
if ((pos - listPos01[listPos01.Count - 1]).sqrMagnitude > vertInternalSqrt)
{
listPos01.Add(pos);
while (listPos01.Count > listMaxCount)
{
listPos01.RemoveAt(0);
}
}
pos = trCoalWall.InverseTransformPoint(trWheel02.position);
if ((pos - listPos02[listPos02.Count - 1]).sqrMagnitude > vertInternalSqrt)
{
listPos02.Add(pos);
while (listPos02.Count > listMaxCount)
{
listPos02.RemoveAt(0);
}
}
}
UnityAction<Transform> onCutLeft;
public void AddActCutLeft(UnityAction<Transform> act) { onCutLeft -= act; onCutLeft += act; }
public void RemoveActCutLeft(UnityAction<Transform> act) { onCutLeft -= act; }
UnityAction<Transform> onCutRight;
public void AddActCutRight(UnityAction<Transform> act) { onCutRight -= act; onCutRight += act; }
public void RemoveActCutRight(UnityAction<Transform> act) { onCutRight -= act; }
void UpdateMeshByLastPos()
{
if (!mesh) return;
//
bool changed01 = false;
bool changed02 = false;
if (!Mathf.Approximately((curPos01 - listPos01[listPos01.Count - 1]).sqrMagnitude, 0))
{
changed01 = true;
curPos01 = listPos01[listPos01.Count - 1];
}
if (!Mathf.Approximately((curPos02 - listPos02[listPos02.Count - 1]).sqrMagnitude, 0))
{
changed02 = true;
curPos02 = listPos02[listPos02.Count - 1];
}
if (changed01 || changed02)
{
Vector3[] vs = mesh.vertices;
if (changed01)
{
UpdateVerticeByWheel(vs, trWheel01, curPos01, onCutLeft);
}
if (changed02)
{
UpdateVerticeByWheel(vs, trWheel02, curPos02, onCutRight);
}
mesh.vertices = vs;
mesh.RecalculateNormals();
}
}
void UpdateVerticeByWheel(Vector3[] vertices, Transform trWheel, Vector3 curPos, UnityAction<Transform> act)
{
Vector3 posToWall = trCoalWall.InverseTransformPoint(trWheel.position);
//
int iW = Mathf.RoundToInt(posToWall.x / wSize);
int iWMin = Mathf.Clamp(iW - countWRadius, 0, wVertCount);
int iWMax = Mathf.Clamp(iW + countWRadius, 0, wVertCount);
//
int iH = Mathf.RoundToInt(posToWall.y / hSize);
int iHMin = Mathf.Clamp(iH - countHRadius, 0, hVertCount);
int iHMax = Mathf.Clamp(iH + countHRadius, 0, hVertCount);
for (int i = iWMin; i < iWMax; i++)
{
for (int j = iHMin; j < iHMax; j++)
{
int index = i * hVertCount + j;
Vector2 v2 = vertices[index] - curPos;
if (v2.sqrMagnitude > wheelRadiusSqrt) continue;
if (vertices[index].z < curPos.z) vertices[index].z = curPos.z;
act?.Invoke(trWheel01);
}
}
}
float timeUpdateByGuaBan = -100;
void UpdateByGuaBan()
{
if (!mesh) return;
if (Time.time - timeUpdateByGuaBan < 5) return;
timeUpdateByGuaBan = Time.time;
Vector3[] vs = mesh.vertices;
Vector3[] colPs = new Vector3[gbTrans.Length];
for (int i = 0; i < gbTrans.Length; i++)
{
colPs[i] = trCoalWall.InverseTransformPoint(gbTrans[i].position);
colPs[i].z += distGBToWall;
}
int indexGB = 0;
for (int i = 0; i < wVertCount; i++)
{
int indexW = i * hVertCount;
Vector3 v = vs[indexW];
while (v.x > colPs[indexGB].x)
{
if (indexGB >= colPs.Length - 1) break;
indexGB++;
}
for (int j = 0; j < hVertCount; j++)
{
vs[indexW + j].z = colPs[indexGB].z;
}
}
//
float xMin = float.MaxValue;
float xMax = float.MinValue;
float yMin = float.MaxValue;
float yMax = float.MinValue;
foreach (Vector3 pos in listPos01)
{
if (xMin > pos.x) xMin = pos.x;
if (xMax < pos.x) xMax = pos.x;
if (yMin > pos.y) yMin = pos.y;
if (yMax < pos.y) yMax = pos.y;
}
foreach (Vector3 pos in listPos02)
{
if (xMin > pos.x) xMin = pos.x;
if (xMax < pos.x) xMax = pos.x;
if (yMin > pos.y) yMin = pos.y;
if (yMax < pos.y) yMax = pos.y;
}
int iWMin = Mathf.Clamp(Mathf.RoundToInt(xMin / wSize) - countWRadius, 0, wVertCount);
int iWMax = Mathf.Clamp(Mathf.RoundToInt(xMax / wSize) + countWRadius, 0, wVertCount);
int iHMin = Mathf.Clamp(Mathf.RoundToInt(yMin / hSize) - countHRadius, 0, hVertCount);
int iHMax = Mathf.Clamp(Mathf.RoundToInt(yMax / hSize) + countHRadius, 0, hVertCount);
for (int i = iWMin; i < iWMax; i++)
{
for (int j = iHMin; j < iHMax; j++)
{
int index = i * hVertCount + j;
foreach (Vector3 pos in listPos01)
{
Vector2 v2 = vs[index] - pos;
if (v2.sqrMagnitude > wheelRadiusSqrt) continue;
if (vs[index].z < pos.z) vs[index].z = pos.z;
}
foreach (Vector3 pos in listPos02)
{
Vector2 v2 = vs[index] - pos;
if (v2.sqrMagnitude > wheelRadiusSqrt) continue;
if (vs[index].z < pos.z) vs[index].z = pos.z;
}
}
}
//
mesh.vertices = vs;
mesh.RecalculateNormals();
}
}