182 lines
6.1 KiB
C#
182 lines
6.1 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
public class SorghumFieldController : MonoBehaviour
|
||
{
|
||
// 原有字段保持不变
|
||
public MeshRenderer fieldArea;
|
||
public bool randomRotate = false;
|
||
public float rowDistance = 1;
|
||
public float strainDistance = 1;
|
||
public float diseasedRate = 0;
|
||
|
||
// 新增动态渲染相关字段
|
||
[Header("Dynamic Rendering")]
|
||
public int chunksPerAxis = 10; // 每轴区块数量
|
||
private Dictionary<Vector2Int, List<GameObject>> chunkMap = new Dictionary<Vector2Int, List<GameObject>>();
|
||
private float chunkSize;
|
||
private Bounds fieldBounds;
|
||
|
||
public void InitSorghum(float rowDistance, float strainDistance, float diseasedRate, bool randomRotate = false)
|
||
{
|
||
GameObject sorghumPrefab = Resources.Load<GameObject>("Prefabs/高粱预制体");
|
||
if (sorghumPrefab == null || fieldArea == null)
|
||
{
|
||
Debug.LogError("预制体或农田区域未分配!");
|
||
return;
|
||
}
|
||
|
||
BoxCollider fieldCollider = fieldArea.GetComponent<BoxCollider>();
|
||
if (fieldCollider == null)
|
||
{
|
||
Debug.LogError("农田区域缺少BoxCollider组件");
|
||
return;
|
||
}
|
||
|
||
// 初始化农田参数
|
||
fieldBounds = fieldCollider.bounds;
|
||
chunkSize = Mathf.Max(fieldBounds.size.x, fieldBounds.size.z) / chunksPerAxis;
|
||
|
||
// 预生成所有高粱并分配到区块
|
||
GenerateSorghumGrid(sorghumPrefab, rowDistance, strainDistance);
|
||
ProcessDiseasedPlants(diseasedRate, randomRotate);
|
||
|
||
// 初始隐藏所有高粱
|
||
SetAllChunksVisibility(false);
|
||
}
|
||
|
||
void GenerateSorghumGrid(GameObject prefab, float rowDist, float strainDist)
|
||
{
|
||
for (float x = fieldBounds.min.x; x <= fieldBounds.max.x; x += rowDist)
|
||
{
|
||
for (float z = fieldBounds.min.z; z <= fieldBounds.max.z; z += strainDist)
|
||
{
|
||
Vector3 spawnPos = new Vector3(x, fieldBounds.min.y, z);
|
||
GameObject obj = Instantiate(prefab, spawnPos, Quaternion.identity, fieldArea.transform);
|
||
|
||
|
||
AddToChunk(obj);
|
||
}
|
||
}
|
||
}
|
||
|
||
void AddToChunk(GameObject sorghum)
|
||
{
|
||
Vector2Int chunkCoord = new Vector2Int(
|
||
Mathf.FloorToInt((sorghum.transform.position.x - fieldBounds.min.x) / chunkSize),
|
||
Mathf.FloorToInt((sorghum.transform.position.z - fieldBounds.min.z) / chunkSize)
|
||
);
|
||
|
||
if (!chunkMap.ContainsKey(chunkCoord))
|
||
{
|
||
chunkMap[chunkCoord] = new List<GameObject>();
|
||
}
|
||
chunkMap[chunkCoord].Add(sorghum);
|
||
}
|
||
|
||
void ProcessDiseasedPlants(float diseasedRate, bool randomRotate)
|
||
{
|
||
SorghumController[] sorghumControllers = FindObjectsOfType<SorghumController>();
|
||
int DisCount = (int)(sorghumControllers.Length * diseasedRate);
|
||
for (int i = 0; i < DisCount; i++)
|
||
{
|
||
int iter = (int)(sorghumControllers.Length * UnityEngine.Random.value);
|
||
if (iter >= sorghumControllers.Length) iter = sorghumControllers.Length - 1;
|
||
if (iter < 0) iter = 0;
|
||
sorghumControllers[iter].Init(SorghumState.Diseased, randomRotate);
|
||
sorghumControllers[iter] = sorghumControllers[sorghumControllers.Length - 1];
|
||
SorghumController[] newArry = new SorghumController[sorghumControllers.Length - 1];
|
||
Array.Copy(sorghumControllers, newArry, sorghumControllers.Length - 1);
|
||
}
|
||
|
||
foreach (var item in sorghumControllers)
|
||
{
|
||
item.Init(SorghumState.Healthy, randomRotate);
|
||
SetRenderersEnabled(false, item.gameObject);
|
||
//item.gameObject.GetComponentInChildren<Renderer>().enabled = false; // 初始隐藏
|
||
}
|
||
}
|
||
|
||
void SetAllChunksVisibility(bool visible)
|
||
{
|
||
foreach (var chunk in chunkMap.Values)
|
||
{
|
||
foreach (GameObject plant in chunk)
|
||
{
|
||
SetRenderersEnabled(visible, plant);
|
||
}
|
||
}
|
||
}
|
||
|
||
void Start()
|
||
{
|
||
InitSorghum(rowDistance, strainDistance, diseasedRate, randomRotate);
|
||
StartCoroutine(VisibilityUpdateRoutine());
|
||
}
|
||
|
||
IEnumerator VisibilityUpdateRoutine()
|
||
{
|
||
WaitForSeconds wait = new WaitForSeconds(0.1f); // 每0.1秒更新一次
|
||
Plane[] frustumPlanes = new Plane[6];
|
||
Camera mainCam = Camera.main;
|
||
|
||
while (true)
|
||
{
|
||
if (mainCam != null)
|
||
{
|
||
frustumPlanes = GeometryUtility.CalculateFrustumPlanes(mainCam);
|
||
|
||
foreach (var chunk in chunkMap)
|
||
{
|
||
Bounds chunkBounds = CalculateChunkBounds(chunk.Key);
|
||
bool shouldVisible = GeometryUtility.TestPlanesAABB(frustumPlanes, chunkBounds);
|
||
SetChunkVisibility(chunk.Key, shouldVisible);
|
||
}
|
||
}
|
||
yield return wait;
|
||
}
|
||
}
|
||
|
||
Bounds CalculateChunkBounds(Vector2Int coord)
|
||
{
|
||
Vector3 min = new Vector3(
|
||
fieldBounds.min.x + coord.x * chunkSize,
|
||
fieldBounds.min.y,
|
||
fieldBounds.min.z + coord.y * chunkSize
|
||
);
|
||
|
||
return new Bounds(
|
||
min + new Vector3(chunkSize / 2, 0, chunkSize / 2),
|
||
new Vector3(chunkSize, fieldBounds.size.y, chunkSize)
|
||
);
|
||
}
|
||
|
||
void SetChunkVisibility(Vector2Int coord, bool visible)
|
||
{
|
||
if (chunkMap.TryGetValue(coord, out List<GameObject> plants))
|
||
{
|
||
foreach (GameObject plant in plants)
|
||
{
|
||
SetRenderersEnabled(visible, plant);
|
||
//plant.GetComponentInChildren<Renderer>().enabled = visible;
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SetRenderersEnabled(bool enabled, GameObject go)
|
||
{
|
||
GameObject obj = go;
|
||
if (obj == null) obj = this.gameObject;
|
||
Renderer[] renderers = go.GetComponentsInChildren<Renderer>();
|
||
foreach (Renderer r in renderers)
|
||
{
|
||
r.enabled = enabled;
|
||
}
|
||
|
||
LODGroup lg = go.GetComponent<LODGroup>();
|
||
Debug.Log("LOD组数:" + lg.GetLODs().Length);
|
||
//Renderer[] rd = lg.GetLODs();
|
||
}
|
||
} |