This commit is contained in:
2025-05-09 12:48:59 +08:00
parent 53683ea8e4
commit 64b1251fe9
@@ -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<Vector2, float> heightCache;
private float lastHeightCacheUpdateTime;
// 对象池
private Queue<GameObject> textObjectPool;
private Queue<CollisionEffect> collisionEffectPool;
private Queue<Ripple> ripplePool;
private void InitializePools()
{
textObjectPool = new Queue<GameObject>();
collisionEffectPool = new Queue<CollisionEffect>();
ripplePool = new Queue<Ripple>();
heightCache = new Dictionary<Vector2, float>();
// 预创建对象
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<T>(List<T> 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<T>(List<T> 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<TextMeshProUGUI>();
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);
}
}