diff --git a/Assets/Scripts/MiniGame/HuoShan/Emo/LakeLineDrawer.cs b/Assets/Scripts/MiniGame/HuoShan/Emo/LakeLineDrawer.cs index 13cc7229e..422a7eefc 100644 --- a/Assets/Scripts/MiniGame/HuoShan/Emo/LakeLineDrawer.cs +++ b/Assets/Scripts/MiniGame/HuoShan/Emo/LakeLineDrawer.cs @@ -117,33 +117,130 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer } [System.Serializable] - public class TargetPoint + public abstract class GridObject { - public string name = "未命名目标"; // 目标的名字 - public Vector2 gridPosition; // 网格位置(0到pointCount-1) - public TargetType type; - public Color color = Color.white; - [HideInInspector] - public float visibility = 0f; // 可见度 - [HideInInspector] - public float scale = 1f; // 当前大小 - [HideInInspector] - public float lastTriggerTime = -1f; // 最后一次被触发的时间 - [HideInInspector] - public bool isFound = false; // 是否已被找到 + public Vector2 gridPosition; + public float visibility = 0f; + public float lastRippleTime = -1f; + public float riseProgress = 0f; + public float colorFadeProgress = 0f; + public float lastTextTime = -1f; + public string displayText; + public Color color; + public bool isFound = false; + public float scale = 1f; + + protected static float OBSTACLE_VISIBILITY_FADE_SPEED = 0.5f; + protected static float OBSTACLE_RISE_SPEED = 2f; + protected static float OBSTACLE_COLOR_FADE_SPEED = 3f; + protected static float TARGET_FADE_IN_SPEED = 2f; + protected static float TARGET_MAX_SCALE = 1.5f; + protected static float TARGET_SCALE_SPEED = 2f; + + public virtual void OnRippleHit(float currentTime) + { + lastRippleTime = currentTime; + if (visibility <= 0f) + { + visibility = 0.2f; + riseProgress = 0f; + colorFadeProgress = 0f; + } + else if (visibility < 1f) + { + riseProgress = Mathf.Max(riseProgress, visibility); + } + } + + public virtual void UpdateVisibility(float currentTime) + { + if (lastRippleTime <= 0f) + { + visibility = 0f; + riseProgress = 0f; + colorFadeProgress = 0f; + return; + } + + if (currentTime - lastRippleTime > 6f) + { + visibility = Mathf.Max(0f, visibility - Time.deltaTime * OBSTACLE_VISIBILITY_FADE_SPEED); + riseProgress = Mathf.Max(0f, riseProgress - Time.deltaTime * OBSTACLE_RISE_SPEED); + } + else if (visibility > 0f) + { + visibility = Mathf.Min(1f, visibility + Time.deltaTime * OBSTACLE_VISIBILITY_FADE_SPEED); + riseProgress = Mathf.Min(1f, riseProgress + Time.deltaTime * OBSTACLE_RISE_SPEED); + } + + if (visibility > 0f) + { + colorFadeProgress = Mathf.Min(1f, colorFadeProgress + Time.deltaTime * OBSTACLE_COLOR_FADE_SPEED); + } + else + { + colorFadeProgress = 0f; + } + } } - public enum TargetType + [System.Serializable] + public class TargetPoint : GridObject { - Sphere, - Cube, - Torus + public string name = "未命名目标"; + public TargetType type; + + public override void OnRippleHit(float currentTime) + { + if (lastRippleTime <= 0) + { + lastRippleTime = currentTime; + isFound = true; + visibility = 0.2f; + } + } + + public override void UpdateVisibility(float currentTime) + { + if (lastRippleTime > 0) + { + visibility = Mathf.Min(1f, visibility + Time.deltaTime * TARGET_FADE_IN_SPEED); + float targetScale = 1f + (TARGET_MAX_SCALE - 1f) * Mathf.Sin(currentTime * TARGET_SCALE_SPEED); + scale = Mathf.Lerp(scale, targetScale, Time.deltaTime * TARGET_SCALE_SPEED); + } + else + { + visibility = 0f; + scale = 1f; + } + } + } + + [System.Serializable] + public class Obstacle : GridObject + { + public Obstacle() + { + displayText = "障碍"; + color = Color.white; + } } private struct Ripple { public Vector2 position; public float startTime; + public bool isValid; + + public static Ripple Create(Vector2 pos, float time) + { + return new Ripple + { + position = pos, + startTime = time, + isValid = true + }; + } } private struct RippleResult @@ -155,18 +252,6 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer public float shapeDistortion; } - [System.Serializable] - public class Obstacle - { - public Vector2 gridPosition; // 网格位置(0到pointCount-1) - public string displayText = "障碍"; // 碰撞时显示的文字 - [HideInInspector]public float visibility = 0f; // 可见度 - [HideInInspector]public float lastRippleTime = -1f; // 最后一次被涟漪影响的时间 - [HideInInspector]public float riseProgress = 0f; // 升起进度(0-1) - [HideInInspector]public float colorFadeProgress = 0f; // 颜色淡入进度(0-1) - [HideInInspector]public float lastTextTime = -1f; // 最后一次生成文字的时间 - } - private struct CollisionEffect { public Vector2 position; @@ -182,8 +267,50 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer private const float RIPPLE_TIME_FACTOR = 0.5f; private const float RIPPLE_EASE_FACTOR = 0.5f; + // 性能优化相关常量 + private const int MAX_RIPPLE_COUNT = 20; + private const int MAX_COLLISION_EFFECT_COUNT = 10; + private const int MAX_FLOATING_TEXT_COUNT = 15; + private const float CACHE_UPDATE_INTERVAL = 0.1f; + private const int NOISE_LAYERS = 3; + private const float MIN_DISTANCE_BETWEEN_OBSTACLES = 2f; + + // 缓存相关 + private float lastCacheUpdateTime; + private Vector3[] cachedPoints; + private bool[] cachedValidPoints; + private float[] cachedHeights; + private Color[] cachedColors; + private Dictionary heightCache; + private float lastHeightCacheUpdateTime; + + // 对象池 + private Queue textObjectPool; + private Queue collisionEffectPool; + private Queue ripplePool; + + private void InitializePools() + { + textObjectPool = new Queue(); + collisionEffectPool = new Queue(); + ripplePool = new Queue(); + heightCache = new Dictionary(); + + // 预创建对象 + for (int i = 0; i < MAX_FLOATING_TEXT_COUNT; i++) + { + if (textPrefab != null) + { + var obj = Instantiate(textPrefab, worldSpaceCanvas.transform); + obj.SetActive(false); + textObjectPool.Enqueue(obj); + } + } + } + private void Start() { + InitializePools(); // 添加按钮点击事件监听 if (upButton != null) upButton.onClick.AddListener(MoveUp); if (downButton != null) downButton.onClick.AddListener(MoveDown); @@ -293,17 +420,52 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer if (rightButton != null) rightButton.onClick.RemoveListener(MoveRight); // 清除所有按钮 - ClearTargetButtons(); + if (targetButtons != null) + { + foreach (var button in targetButtons.Values) + { + if (button != null) + { + button.onClick.RemoveAllListeners(); + Destroy(button.gameObject); + } + } + targetButtons.Clear(); + } // 清除所有漂浮文字 - foreach (var text in floatingTexts) + if (floatingTexts != null) { - if (text.textComponent != null) + foreach (var text in floatingTexts) { - Destroy(text.textComponent.gameObject); + if (text != null && text.textComponent != null) + { + Destroy(text.textComponent.gameObject); + } + } + floatingTexts.Clear(); + } + + // 清理对象池 + if (textObjectPool != null) + { + while (textObjectPool.Count > 0) + { + var obj = textObjectPool.Dequeue(); + if (obj != null) + { + Destroy(obj); + } } } - floatingTexts.Clear(); + + // 清理其他集合 + if (ripples != null) ripples.Clear(); + if (targetTriggerRipples != null) targetTriggerRipples.Clear(); + if (collisionEffects != null) collisionEffects.Clear(); + if (obstacles != null) obstacles.Clear(); + if (targetPoints != null) targetPoints.Clear(); + if (heightCache != null) heightCache.Clear(); } private void MoveUp() @@ -357,29 +519,23 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer private void Update() { - // 如果是播放状态,则更新时间;否则设为0 - time = Application.isPlaying ? Time.time * timeScale : 0f; + float currentTime = Application.isPlaying ? Time.time * timeScale : 0f; + time = currentTime; + + if (currentTime - lastCacheUpdateTime >= CACHE_UPDATE_INTERVAL) + { + UpdateCache(); + lastCacheUpdateTime = currentTime; + } HandleMouseInput(); HandleUIInput(); CleanExpiredRipples(); CleanExpiredCollisionEffects(); - UpdateObstacleVisibility(); - UpdateTargetVisibility(); + UpdateGridObjects(obstacles); + UpdateGridObjects(targetPoints); CleanExpiredTargetTriggerRipples(); - UpdateFloatingTexts(); // 添加更新文字效果 - - // 检查所有涟漪的碰撞 - if (Application.isPlaying) - { - float currentTime = Time.time; - foreach (var ripple in ripples) - { - float elapsed = currentTime - ripple.startTime; - float spread = elapsed * rippleSpreadSpeed; - CheckRippleCollisions(ripple.position, spread, currentTime); - } - } + UpdateFloatingTexts(); } private void HandleMouseInput() @@ -391,29 +547,41 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer if (Physics.Raycast(ray, out RaycastHit hit)) { Vector3 hitPos = hit.point; - - ripples.Add(new Ripple - { - position = new Vector2(hitPos.x, hitPos.z), - startTime = Time.time - }); + ripples.Add(Ripple.Create(new Vector2(hitPos.x, hitPos.z), Time.time)); } } } private void CleanExpiredRipples() { - ripples.RemoveAll(r => Time.time - r.startTime > rippleDuration); + float currentTime = Time.time; + for (int i = ripples.Count - 1; i >= 0; i--) + { + if (currentTime - ripples[i].startTime > rippleDuration) + { + ripplePool.Enqueue(ripples[i]); + ripples.RemoveAt(i); + } + } } private void CleanExpiredCollisionEffects() { - collisionEffects.RemoveAll(e => Time.time - e.startTime > collisionEffectDuration); + float currentTime = Time.time; + for (int i = collisionEffects.Count - 1; i >= 0; i--) + { + if (currentTime - collisionEffects[i].startTime > collisionEffectDuration) + { + collisionEffectPool.Enqueue(collisionEffects[i]); + collisionEffects.RemoveAt(i); + } + } } private void CleanExpiredTargetTriggerRipples() { - targetTriggerRipples.RemoveAll(r => Time.time - r.startTime > targetTriggerDuration); + float currentTime = Time.time; + targetTriggerRipples.RemoveAll(r => currentTime - r.startTime > targetTriggerDuration); } // 计算涟漪对某个点的影响,返回该点的偏移量和亮度提升 @@ -451,7 +619,7 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer ref float rippleOffset, ref float brightness, ref Color targetColor, ref float maxTargetInfluence, ref float shapeDistortion, bool isTargetTrigger = false) { - if (ripple == null) return; + if (!ripple.isValid) return; // 计算基础参数 float elapsed = currentTime - ripple.startTime; @@ -509,76 +677,95 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer float step = fieldSize / (pointCount - 1); float halfField = fieldSize * 0.5f; - // 检查障碍物碰撞 - foreach (var obstacle in obstacles) + // 检查所有网格对象 + CheckGridObjectCollisions(obstacles, ripplePos, spread, currentTime, step, halfField, true); + CheckGridObjectCollisions(targetPoints, ripplePos, spread, currentTime, step, halfField, false); + } + + private void CheckGridObjectCollisions(List objects, Vector2 ripplePos, float spread, float currentTime, + float step, float halfField, bool isObstacle) where T : GridObject + { + foreach (var obj in objects) { - float x = -halfField + obstacle.gridPosition.x * step + fieldOffset.x; - float z = -halfField + obstacle.gridPosition.y * step + fieldOffset.y; + float x = -halfField + obj.gridPosition.x * step + fieldOffset.x; + float z = -halfField + obj.gridPosition.y * step + fieldOffset.y; Vector2 worldPos = new Vector2(x, z); float dist = Vector2.Distance(ripplePos, worldPos); - if (dist <= rippleMaxRadius && Mathf.Abs(dist - spread) < obstacleWidth * 0.5f) + float checkRadius = isObstacle ? obstacleWidth * 0.5f : 0.5f; + + if (dist <= rippleMaxRadius && Mathf.Abs(dist - spread) < checkRadius) { - obstacle.lastRippleTime = currentTime; - - if (obstacle.visibility <= 0f) + if (isObstacle) { - obstacle.visibility = 0.2f; - obstacle.riseProgress = 0f; - obstacle.colorFadeProgress = 0f; + obj.OnRippleHit(currentTime); + AddCollisionEffect(worldPos, currentTime); + + if (currentTime - obj.lastTextTime > 2f) + { + Vector3 textPosition = new Vector3(x, GetCachedHeight(x - fieldOffset.x, z - fieldOffset.y) + obstacleHeight * 0.5f, z); + CreateFloatingText(textPosition, obj.displayText, obj.color); + obj.lastTextTime = currentTime; + } } - else if (obstacle.visibility < 1f) + else if (obj.lastRippleTime < currentTime - targetTriggerDuration) { - obstacle.riseProgress = Mathf.Max(obstacle.riseProgress, obstacle.visibility); - } + obj.OnRippleHit(currentTime); + AddTargetTriggerRipple(worldPos, currentTime); + + if (targetButtons.ContainsKey(obj as TargetPoint)) + { + targetButtons[obj as TargetPoint].gameObject.SetActive(true); + } - collisionEffects.Add(new CollisionEffect - { - position = worldPos, - startTime = currentTime - }); - - // 检查是否可以生成新的文字(冷却时间为2秒) - if (currentTime - obstacle.lastTextTime > 2f) - { - Vector3 textPosition = new Vector3(x, GetHeight(x - fieldOffset.x, z - fieldOffset.y, time) + obstacleHeight * 0.5f, z); - CreateFloatingText(textPosition, obstacle.displayText, obstacleColor); - obstacle.lastTextTime = currentTime; + Vector3 textPosition = new Vector3(x, GetCachedHeight(x - fieldOffset.x, z - fieldOffset.y) + targetHeightOffset, z); + CreateFloatingText(textPosition, obj.displayText, obj.color); } } } + } - // 检查目标碰撞 - foreach (var target in targetPoints) + private void AddCollisionEffect(Vector2 position, float currentTime) + { + if (collisionEffectPool.Count > 0) { - float x = -halfField + target.gridPosition.x * step + fieldOffset.x; - float z = -halfField + target.gridPosition.y * step + fieldOffset.y; - Vector2 worldPos = new Vector2(x, z); - - float dist = Vector2.Distance(ripplePos, worldPos); - if (dist <= rippleMaxRadius && Mathf.Abs(dist - spread) < 0.5f && target.lastTriggerTime < currentTime - targetTriggerDuration) + var effect = collisionEffectPool.Dequeue(); + effect.position = position; + effect.startTime = currentTime; + collisionEffects.Add(effect); + } + else + { + collisionEffects.Add(new CollisionEffect { - // 确保目标点之前没有被触发过 - if (target.lastTriggerTime <= 0) - { - target.lastTriggerTime = currentTime; - target.isFound = true; - target.visibility = 0.2f; // 初始可见度 - targetTriggerRipples.Add(new Ripple - { - position = worldPos, - startTime = currentTime - }); + position = position, + startTime = currentTime + }); + } + } - if (targetButtons.ContainsKey(target)) - { - targetButtons[target].gameObject.SetActive(true); - } + private void AddTargetTriggerRipple(Vector2 position, float currentTime) + { + if (ripplePool.Count > 0) + { + var newRipple = ripplePool.Dequeue(); + newRipple.position = position; + newRipple.startTime = currentTime; + newRipple.isValid = true; + targetTriggerRipples.Add(newRipple); + } + else + { + targetTriggerRipples.Add(Ripple.Create(position, currentTime)); + } + } - Vector3 textPosition = new Vector3(x, GetHeight(x - fieldOffset.x, z - fieldOffset.y, time) + targetHeightOffset, z); - CreateFloatingText(textPosition, target.name, target.color); - } - } + private void UpdateGridObjects(List objects) where T : GridObject + { + float currentTime = Time.time; + foreach (var obj in objects) + { + obj.UpdateVisibility(currentTime); } } @@ -729,59 +916,6 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer Draw.Line(current, next, lineWidth * (1f - heightT * 0.5f), lineColor); } - private void DrawEdgeLines(float halfField, float halfVisible) - { - // 绘制湖面边缘的向下线条(无扰动) - float step = fieldSize / (pointCount - 1); - float halfEdgeLineLength = edgeLineLength * 0.5f; // 设置边缘线长度 - - // 1. 绘制 X 轴的边缘线(左边和右边) - for (float z = -halfField; z <= halfField; z += step) - { - float worldZ = z + fieldOffset.y; - float x = halfField + fieldOffset.x; // 右边 - DrawEdgeLine(x, worldZ, halfVisible); - x = -halfField + fieldOffset.x; // 左边 - DrawEdgeLine(x, worldZ, halfVisible); - } - - // 2. 绘制 Z 轴的边缘线(上边和下边) - for (float x = -halfField; x <= halfField; x += step) - { - float worldX = x + fieldOffset.x; - float z = halfField + fieldOffset.y; // 上边 - DrawEdgeLine(worldX, z, halfVisible); - z = -halfField + fieldOffset.y; // 下边 - DrawEdgeLine(worldX, z, halfVisible); - } - } - - private void DrawEdgeLine(float x, float z, float halfVisible) - { - // 检查点是否在可视区域内 - if (Mathf.Abs(x) > halfVisible || Mathf.Abs(z) > halfVisible) - { - return; - } - - // 计算湖面高度作为起始点的Y坐标 - float startY = GetHeight(x - fieldOffset.x, z - fieldOffset.y, time); // 获取湖面高度 - - // 设置边缘线的起始点 - Vector3 start = new Vector3(x, startY, z); - - // 设置边缘线的终止点,向下延伸一定的长度 - Vector3 end = new Vector3(x, startY - edgeLineLength, z); // 向下延伸的线条 - - // 设置颜色,基于高度 - float heightT = Mathf.InverseLerp(-waveHeight, waveHeight, startY); - Color lineColor = Color.Lerp(edgeDarkColor, edgeLightColor, heightT); - lineColor.a *= 0.8f; // 设置透明度 - - // 绘制边缘线 - Draw.Line(start, end, lineWidth * 0.5f, lineColor); - } - // 绘制目标点 private void DrawTargetPoints() { @@ -964,146 +1098,63 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer } } - private void UpdateObstacleVisibility() - { - float currentTime = Application.isPlaying ? Time.time : 0f; - foreach (var obstacle in obstacles) - { - // 在编辑器中,如果没有被涟漪影响过,保持可见 - if (!Application.isPlaying) - { - // obstacle.visibility = 1f; - // obstacle.riseProgress = 1f; - // obstacle.colorFadeProgress = 1f; - continue; - } - - // 在游戏模式下,如果从未被涟漪影响过,保持不可见 - if (obstacle.lastRippleTime <= 0f) - { - obstacle.visibility = 0f; - obstacle.riseProgress = 0f; - obstacle.colorFadeProgress = 0f; - continue; - } - - // 如果超过6秒没有被涟漪影响,开始逐渐消失 - if (currentTime - obstacle.lastRippleTime > 6f) - { - float fadeSpeed = Time.deltaTime; - obstacle.visibility = Mathf.Max(0f, obstacle.visibility - fadeSpeed); - // 同时降低升起高度 - obstacle.riseProgress = Mathf.Max(0f, obstacle.riseProgress - fadeSpeed); - } - else if (obstacle.visibility > 0f) - { - // 如果正在显现,继续增加可见度 - obstacle.visibility = Mathf.Min(1f, obstacle.visibility + Time.deltaTime * 0.5f); - // 同时增加升起高度 - obstacle.riseProgress = Mathf.Min(1f, obstacle.riseProgress + Time.deltaTime * 2f); - } - - // 更新颜色淡入进度 - if (obstacle.visibility > 0f) - { - obstacle.colorFadeProgress = Mathf.Min(1f, obstacle.colorFadeProgress + Time.deltaTime * 3f); - } - else - { - obstacle.colorFadeProgress = 0f; - } - } - } - - private void UpdateTargetVisibility() - { - float currentTime = Time.time; - foreach (var target in targetPoints) - { - // 如果目标已经被触发过 - if (target.lastTriggerTime > 0) - { - // 更新可见度 - target.visibility = Mathf.Min(1f, target.visibility + Time.deltaTime * targetFadeInSpeed); - - // 更新大小 - float targetScale = 1f + (targetMaxScale - 1f) * Mathf.Sin(currentTime * targetScaleSpeed); - target.scale = Mathf.Lerp(target.scale, targetScale, Time.deltaTime * targetScaleSpeed); - } - else - { - // 如果从未被触发过,确保保持不可见 - target.visibility = 0f; - target.scale = 1f; - } - } - } - private void GenerateRandomObstacles() { obstacles.Clear(); float step = fieldSize / (pointCount - 1); float halfField = fieldSize * 0.5f; - // 为每个目标生成周围的障碍物 foreach (var target in targetPoints) { - // 计算目标的世界坐标 float targetX = -halfField + target.gridPosition.x * step; float targetZ = -halfField + target.gridPosition.y * step; Vector2 targetWorldPos = new Vector2(targetX, targetZ); - // 计算这个目标周围应该生成的障碍物数量 int obstacleCount = Mathf.CeilToInt(maxObstacleCount / targetPoints.Count); for (int i = 0; i < obstacleCount; i++) { - // 生成随机角度和距离 float angle = Random.Range(0f, 360f) * Mathf.Deg2Rad; float distance = Random.Range(minDistanceToTarget, maxDistanceToTarget); - // 计算障碍物的世界坐标 float obstacleX = targetX + Mathf.Cos(angle) * distance; float obstacleZ = targetZ + Mathf.Sin(angle) * distance; - // 转换为网格坐标 int gridX = Mathf.RoundToInt((obstacleX + halfField) / step); int gridZ = Mathf.RoundToInt((obstacleZ + halfField) / step); - // 确保坐标在有效范围内 - if (gridX >= 0 && gridX < pointCount && gridZ >= 0 && gridZ < pointCount) + if (IsValidObstaclePosition(gridX, gridZ)) { - // 检查是否与现有障碍物重叠 - bool isOverlapping = false; - foreach (var existingObstacle in obstacles) + obstacles.Add(new Obstacle { - float dist = Vector2.Distance( - new Vector2(gridX, gridZ), - existingObstacle.gridPosition - ); - if (dist < 2f) // 最小间距 - { - isOverlapping = true; - break; - } - } - - if (!isOverlapping) - { - obstacles.Add(new Obstacle - { - gridPosition = new Vector2(gridX, gridZ), - visibility = 0f, - lastRippleTime = -1f, - riseProgress = 0f, - colorFadeProgress = 0f - }); - } + gridPosition = new Vector2(gridX, gridZ), + visibility = 0f, + lastRippleTime = -1f, + riseProgress = 0f, + colorFadeProgress = 0f + }); } } } } + private bool IsValidObstaclePosition(int gridX, int gridZ) + { + if (gridX < 0 || gridX >= pointCount || gridZ < 0 || gridZ >= pointCount) + return false; + + foreach (var existingObstacle in obstacles) + { + float dist = Vector2.Distance( + new Vector2(gridX, gridZ), + existingObstacle.gridPosition + ); + if (dist < MIN_DISTANCE_BETWEEN_OBSTACLES) + return false; + } + return true; + } + private void OnDrawGizmos() { if (!Application.isPlaying) @@ -1144,7 +1195,7 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer if (elapsed >= textLifeTime) { - Destroy(text.textComponent.gameObject); + RecycleFloatingText(text); floatingTexts.RemoveAt(i); continue; } @@ -1189,14 +1240,22 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer { if (textPrefab == null || worldSpaceCanvas == null) return; - GameObject textObj = Instantiate(textPrefab, worldSpaceCanvas.transform); + GameObject textObj; + if (textObjectPool.Count > 0) + { + textObj = textObjectPool.Dequeue(); + textObj.SetActive(true); + } + else + { + textObj = Instantiate(textPrefab, worldSpaceCanvas.transform); + } + TextMeshProUGUI tmp = textObj.GetComponent(); if (tmp != null) { tmp.text = text; - tmp.color = new Color(color.r, color.g, color.b, 0f); // 初始透明 - - // 设置世界空间位置 + tmp.color = new Color(color.r, color.g, color.b, 0f); textObj.transform.position = position; floatingTexts.Add(new FloatingText @@ -1208,4 +1267,138 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer }); } } + + private void RecycleFloatingText(FloatingText text) + { + if (text.textComponent != null) + { + text.textComponent.gameObject.SetActive(false); + textObjectPool.Enqueue(text.textComponent.gameObject); + } + } + + private void UpdateCache() + { + if (cachedPoints == null || cachedPoints.Length != pointCount * pointCount) + { + cachedPoints = new Vector3[pointCount * pointCount]; + cachedValidPoints = new bool[pointCount * pointCount]; + cachedHeights = new float[pointCount * pointCount]; + cachedColors = new Color[pointCount * pointCount]; + } + + float step = fieldSize / (pointCount - 1); + float halfField = fieldSize * 0.5f; + float halfVisible = visibleAreaSize * 0.5f; + + for (int i = 0; i < pointCount; i++) + { + for (int j = 0; j < pointCount; j++) + { + int index = i * pointCount + j; + float x = -halfField + j * step + fieldOffset.x; + float z = -halfField + i * step + fieldOffset.y; + + cachedValidPoints[index] = Mathf.Abs(x) <= halfVisible && Mathf.Abs(z) <= halfVisible; + if (cachedValidPoints[index]) + { + cachedHeights[index] = GetHeight(x, z, time); + cachedPoints[index] = new Vector3(x, cachedHeights[index], z); + cachedColors[index] = CalculatePointColor(x, z, cachedHeights[index]); + } + } + } + } + + private Color CalculatePointColor(float x, float z, float height) + { + float heightT = Mathf.InverseLerp(-waveHeight, waveHeight, height); + RippleResult ripple = GetRippleEffect(x, z, Time.time); + float brightness = Mathf.Clamp01(1f + ripple.brightnessBoost); + + Color baseColor = Color.Lerp(lakeDarkColor, lakeLightColor, heightT); + baseColor *= brightness; + + if (ripple.targetInfluence > 0) + { + baseColor = Color.Lerp(baseColor, ripple.targetColor, ripple.targetInfluence); + } + + return baseColor; + } + + private void UpdateHeightCache() + { + if (Time.time - lastHeightCacheUpdateTime < CACHE_UPDATE_INTERVAL) + return; + + heightCache.Clear(); + float step = fieldSize / (pointCount - 1); + float halfField = fieldSize * 0.5f; + + for (int i = 0; i < pointCount; i++) + { + for (int j = 0; j < pointCount; j++) + { + float x = -halfField + j * step; + float z = -halfField + i * step; + Vector2 pos = new Vector2(x, z); + heightCache[pos] = GetHeight(x, z, time); + } + } + + lastHeightCacheUpdateTime = Time.time; + } + + private float GetCachedHeight(float x, float z) + { + Vector2 pos = new Vector2(x, z); + if (heightCache.TryGetValue(pos, out float height)) + { + return height; + } + return GetHeight(x, z, time); + } + + private void DrawEdgeLines(float halfField, float halfVisible) + { + float step = fieldSize / (pointCount - 1); + float halfEdgeLineLength = edgeLineLength * 0.5f; + + // 绘制 X 轴的边缘线 + for (float z = -halfField; z <= halfField; z += step) + { + float worldZ = z + fieldOffset.y; + float x = halfField + fieldOffset.x; + DrawEdgeLine(x, worldZ, halfVisible); + x = -halfField + fieldOffset.x; + DrawEdgeLine(x, worldZ, halfVisible); + } + + // 绘制 Z 轴的边缘线 + for (float x = -halfField; x <= halfField; x += step) + { + float worldX = x + fieldOffset.x; + float z = halfField + fieldOffset.y; + DrawEdgeLine(worldX, z, halfVisible); + z = -halfField + fieldOffset.y; + DrawEdgeLine(worldX, z, halfVisible); + } + } + + private void DrawEdgeLine(float x, float z, float halfVisible) + { + if (Mathf.Abs(x) > halfVisible || Mathf.Abs(z) > halfVisible) + return; + + float startY = GetHeight(x - fieldOffset.x, z - fieldOffset.y, time); + Vector3 start = new Vector3(x, startY, z); + Vector3 end = new Vector3(x, startY - edgeLineLength, z); + + float heightT = Mathf.InverseLerp(-waveHeight, waveHeight, startY); + Color lineColor = Color.Lerp(edgeDarkColor, edgeLightColor, heightT); + lineColor.a *= 0.8f; + + Draw.Line(start, end, lineWidth * 0.5f, lineColor); + } }