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; public SorghumPeriod sorghumPeriod = SorghumPeriod.Mature; // 新增动态渲染相关字段 [Header("Dynamic Rendering")] public int chunksPerAxis = 10; // 每轴区块数量 private Dictionary> chunkMap = new Dictionary>(); private float chunkSize; private Bounds fieldBounds; public void InitSorghum(float rowDistance, float strainDistance, float diseasedRate, bool randomRotate = false) { GameObject sorghumPrefab = Resources.Load("Prefabs/高粱预制体"); if (sorghumPrefab == null || fieldArea == null) { Debug.LogError("预制体或农田区域未分配!"); return; } BoxCollider fieldCollider = fieldArea.GetComponent(); 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, sorghumPeriod); // 初始隐藏所有高粱 SetAllChunksVisibility(true); } 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(); } chunkMap[chunkCoord].Add(sorghum); } void ProcessDiseasedPlants(float diseasedRate, bool randomRotate, SorghumPeriod period) { SorghumController[] sorghumControllers = FindObjectsOfType(); 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.Healthy, SorghumPeriod.Mature, 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, period, randomRotate); SetRenderersEnabled(false, item.gameObject); //item.gameObject.GetComponentInChildren().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 plants)) { foreach (GameObject plant in plants) { SetRenderersEnabled(visible, plant); //plant.GetComponentInChildren().enabled = visible; } } } private void SetRenderersEnabled(bool enabled, GameObject go) { GameObject obj = go; if (obj == null) obj = this.gameObject; Renderer[] renderers = go.GetComponentsInChildren(); foreach (Renderer r in renderers) { r.enabled = enabled; } //LODGroup lg = go.GetComponent(); //Debug.Log("LOD组数:" + lg.GetLODs().Length); //Renderer[] rd = lg.GetLODs(); } }