提交
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user