737 lines
28 KiB
C#
737 lines
28 KiB
C#
using UnityEngine;
|
||
using Shapes;
|
||
using System.Collections.Generic;
|
||
using UnityEngine.UI;
|
||
|
||
[ExecuteAlways]
|
||
public class LakeLineDrawer : ImmediateModeShapeDrawer
|
||
{
|
||
[Header("场设置")]
|
||
public float fieldSize = 80f;
|
||
public Vector2 fieldOffset = Vector2.zero;
|
||
public int pointCount = 80;
|
||
public float pointSize = 0.1f;
|
||
public float lineWidth = 0.03f;
|
||
|
||
[Header("颜色设置")]
|
||
public Color lakeDarkColor = new Color(0f, 0.5f, 1f); // 湖面低处颜色
|
||
public Color lakeLightColor = new Color(0.5f, 1f, 1f, 0.3f); // 湖面高处颜色
|
||
public Color edgeDarkColor = new Color(0f, 0.5f, 1f); // 边缘低处颜色
|
||
public Color edgeLightColor = new Color(0.5f, 1f, 1f, 0.3f); // 边缘高处颜色
|
||
public float edgeLineLength = 1f; // 边缘线的长度
|
||
|
||
[Header("UI控制")]
|
||
public Button upButton;
|
||
public Button downButton;
|
||
public Button leftButton;
|
||
public Button rightButton;
|
||
public float moveStep = 1f; // 每次移动的步长
|
||
|
||
[Header("目标点设置")]
|
||
public List<TargetPoint> targetPoints = new List<TargetPoint>();
|
||
public float targetSize = 0.5f;
|
||
public float rotationSpeed = 30f; // 旋转速度(度/秒)
|
||
public float floatAmplitude = 0.2f; // 起伏幅度
|
||
public float floatFrequency = 2f; // 起伏频率
|
||
public float targetLineWidth = 0.02f; // 目标点线框的宽度
|
||
public float targetHeightOffset = 0.5f; // 目标点距离湖面的高度偏移
|
||
public Color targetFillColor = Color.red; // 目标点实体颜色
|
||
public Color targetWireColor = Color.white; // 目标点线框颜色
|
||
public float wireScale = 1.05f; // 线框相对于实体的大小比例
|
||
|
||
[Header("可视区域")]
|
||
public float visibleAreaSize = 20f;
|
||
|
||
// 波动参数,用于生成波动效果
|
||
public float noiseScale = 0.3f;
|
||
public float waveHeight = 1.5f;
|
||
public float waveSpeed = 1f;
|
||
public float timeScale = 1f;
|
||
[Header("涟漪参数")]
|
||
public float rippleStrength = 2f; // 恢复原来的强度
|
||
public float rippleDuration = 0.8f; // 适中的持续时间
|
||
public float rippleSpreadSpeed = 4f; // 适中的传播速度
|
||
public float rippleSharpness = 4f; // 适中的锐度
|
||
public float rippleMaxRadius = 3f; // 新增:涟漪最大半径
|
||
|
||
[Header("障碍物设置")]
|
||
public List<Obstacle> obstacles = new List<Obstacle>();
|
||
public float obstacleHeight = 2f; // 障碍物高度
|
||
public float obstacleWidth = 0.5f; // 障碍物宽度
|
||
public Color obstacleColor = Color.white; // 障碍物颜色
|
||
public float collisionEffectDuration = 0.5f; // 碰撞效果持续时间
|
||
public float collisionEffectSize = 1f; // 碰撞效果大小
|
||
public Color collisionEffectColor = Color.white; // 碰撞效果颜色
|
||
public int collisionEffectRingCount = 3; // 涟漪环的数量
|
||
public int collisionEffectDashCount = 12; // 每个环的虚线数量
|
||
|
||
private Vector3[] points;
|
||
// 存储每个点是否在可视区域内的标记
|
||
private bool[] validPoints;
|
||
private float time;
|
||
private List<Ripple> ripples = new List<Ripple>();
|
||
|
||
[System.Serializable]
|
||
public class TargetPoint
|
||
{
|
||
public Vector2 gridPosition; // 网格位置(0到pointCount-1)
|
||
public TargetType type;
|
||
public Color color = Color.white;
|
||
}
|
||
|
||
public enum TargetType
|
||
{
|
||
Sphere,
|
||
Cube,
|
||
Torus
|
||
}
|
||
|
||
private struct Ripple
|
||
{
|
||
public Vector2 position;
|
||
public float startTime;
|
||
}
|
||
|
||
private struct RippleResult
|
||
{
|
||
public float heightOffset;
|
||
public float brightnessBoost;
|
||
}
|
||
|
||
[System.Serializable]
|
||
public class Obstacle
|
||
{
|
||
public Vector2 gridPosition; // 网格位置(0到pointCount-1)
|
||
[HideInInspector]public float visibility = 0f; // 可见度(0-1)
|
||
[HideInInspector]public float lastRippleTime = -1f; // 最后一次被涟漪影响的时间
|
||
[HideInInspector]public float riseProgress = 0f; // 升起进度(0-1)
|
||
[HideInInspector]public float colorFadeProgress = 0f; // 颜色淡入进度(0-1)
|
||
}
|
||
|
||
private struct CollisionEffect
|
||
{
|
||
public Vector2 position;
|
||
public Vector2 direction; // 撞击方向
|
||
public float startTime;
|
||
}
|
||
|
||
private List<CollisionEffect> collisionEffects = new List<CollisionEffect>();
|
||
|
||
private void Start()
|
||
{
|
||
// 添加按钮点击事件监听
|
||
if (upButton != null) upButton.onClick.AddListener(MoveUp);
|
||
if (downButton != null) downButton.onClick.AddListener(MoveDown);
|
||
if (leftButton != null) leftButton.onClick.AddListener(MoveLeft);
|
||
if (rightButton != null) rightButton.onClick.AddListener(MoveRight);
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
// 移除按钮点击事件监听
|
||
if (upButton != null) upButton.onClick.RemoveListener(MoveUp);
|
||
if (downButton != null) downButton.onClick.RemoveListener(MoveDown);
|
||
if (leftButton != null) leftButton.onClick.RemoveListener(MoveLeft);
|
||
if (rightButton != null) rightButton.onClick.RemoveListener(MoveRight);
|
||
}
|
||
|
||
private void MoveUp()
|
||
{
|
||
float halfVisible = visibleAreaSize * 0.5f;
|
||
float maxOffset = fieldSize * 0.5f - halfVisible * 0.6f; // 允许超出20%
|
||
if (fieldOffset.y < maxOffset)
|
||
{
|
||
fieldOffset.y += moveStep;
|
||
fieldOffset.y = Mathf.Clamp(fieldOffset.y, -maxOffset, maxOffset);
|
||
}
|
||
}
|
||
|
||
private void MoveDown()
|
||
{
|
||
float halfVisible = visibleAreaSize * 0.5f;
|
||
float maxOffset = fieldSize * 0.5f - halfVisible * 0.8f; // 允许超出20%
|
||
if (fieldOffset.y > -maxOffset)
|
||
{
|
||
fieldOffset.y -= moveStep;
|
||
fieldOffset.y = Mathf.Clamp(fieldOffset.y, -maxOffset, maxOffset);
|
||
}
|
||
}
|
||
|
||
private void MoveLeft()
|
||
{
|
||
float halfVisible = visibleAreaSize * 0.5f;
|
||
float maxOffset = fieldSize * 0.5f - halfVisible * 0.8f; // 允许超出20%
|
||
if (fieldOffset.x > -maxOffset)
|
||
{
|
||
fieldOffset.x -= moveStep;
|
||
fieldOffset.x = Mathf.Clamp(fieldOffset.x, -maxOffset, maxOffset);
|
||
}
|
||
}
|
||
|
||
private void MoveRight()
|
||
{
|
||
float halfVisible = visibleAreaSize * 0.5f;
|
||
float maxOffset = fieldSize * 0.5f - halfVisible * 0.8f; // 允许超出20%
|
||
if (fieldOffset.x < maxOffset)
|
||
{
|
||
fieldOffset.x += moveStep;
|
||
fieldOffset.x = Mathf.Clamp(fieldOffset.x, -maxOffset, maxOffset);
|
||
}
|
||
}
|
||
|
||
private void HandleUIInput()
|
||
{
|
||
// 由于现在使用按钮事件,这个方法可以留空或删除
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
// 如果是播放状态,则更新时间;否则设为0
|
||
time = Application.isPlaying ? Time.time * timeScale : 0f;
|
||
|
||
HandleMouseInput();
|
||
HandleUIInput();
|
||
CleanExpiredRipples();
|
||
CleanExpiredCollisionEffects();
|
||
UpdateObstacleVisibility();
|
||
}
|
||
|
||
private void HandleMouseInput()
|
||
{
|
||
if (Application.isPlaying && Input.GetMouseButtonDown(0))
|
||
{
|
||
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
||
|
||
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
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
private void CleanExpiredRipples()
|
||
{
|
||
ripples.RemoveAll(r => Time.time - r.startTime > rippleDuration);
|
||
}
|
||
|
||
private void CleanExpiredCollisionEffects()
|
||
{
|
||
collisionEffects.RemoveAll(e => Time.time - e.startTime > collisionEffectDuration);
|
||
}
|
||
|
||
// 计算涟漪对某个点的影响,返回该点的偏移量和亮度提升
|
||
private RippleResult GetRippleEffect(float x, float z, float currentTime)
|
||
{
|
||
float rippleOffset = 0f;
|
||
float brightness = 0f;
|
||
|
||
// 遍历所有涟漪,计算它们对当前点的影响
|
||
foreach (var ripple in ripples)
|
||
{
|
||
// 计算涟漪已经存在的时间
|
||
float elapsed = currentTime - ripple.startTime;
|
||
float spread = elapsed * rippleSpreadSpeed; // 涟漪扩展的距离
|
||
float dist = Vector2.Distance(new Vector2(x, z), ripple.position); // 当前点与涟漪中心的距离
|
||
|
||
// 如果距离超过最大半径,跳过这个涟漪的影响
|
||
if (dist > rippleMaxRadius)
|
||
continue;
|
||
|
||
// 计算涟漪的时间影响,t表示涟漪的衰减程度
|
||
float t = Mathf.Clamp01(elapsed / rippleDuration);
|
||
float ease = Mathf.Sin(t * Mathf.PI); // 使用正弦函数使衰减效果平滑
|
||
|
||
// 计算涟漪对当前点的高度影响
|
||
float spike = Mathf.Exp(-Mathf.Pow(dist - spread, 2f) * rippleSharpness);
|
||
rippleOffset += spike * rippleStrength * ease;
|
||
|
||
// 计算涟漪对当前点的亮度提升
|
||
float bright = Mathf.Exp(-Mathf.Pow((dist - spread) * 0.5f, 2f));
|
||
brightness += bright * ease;
|
||
|
||
// 检查涟漪是否与障碍物碰撞
|
||
CheckObstacleCollision(ripple.position, spread, currentTime);
|
||
}
|
||
|
||
return new RippleResult
|
||
{
|
||
heightOffset = rippleOffset,
|
||
brightnessBoost = brightness
|
||
};
|
||
}
|
||
|
||
private void CheckObstacleCollision(Vector2 ripplePos, float spread, float currentTime)
|
||
{
|
||
float step = fieldSize / (pointCount - 1);
|
||
float halfField = fieldSize * 0.5f;
|
||
foreach (var obstacle in obstacles)
|
||
{
|
||
// 将网格位置转换为世界坐标
|
||
float x = -halfField + obstacle.gridPosition.x * step + fieldOffset.x;
|
||
float z = -halfField + obstacle.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)
|
||
{
|
||
obstacle.lastRippleTime = currentTime;
|
||
|
||
if (obstacle.visibility <= 0f)
|
||
{
|
||
obstacle.visibility = 0.2f;
|
||
obstacle.riseProgress = 0f;
|
||
obstacle.colorFadeProgress = 0f;
|
||
}
|
||
else if (obstacle.visibility < 1f)
|
||
{
|
||
obstacle.riseProgress = Mathf.Max(obstacle.riseProgress, obstacle.visibility);
|
||
}
|
||
|
||
// 计算撞击方向(从涟漪中心指向障碍物)
|
||
Vector2 hitDirection = (worldPos - ripplePos).normalized;
|
||
|
||
collisionEffects.Add(new CollisionEffect
|
||
{
|
||
position = worldPos,
|
||
direction = hitDirection,
|
||
startTime = currentTime
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
// 计算某个点的基础高度,基于噪声函数模拟波浪
|
||
private float GetHeight(float x, float z, float currentTime)
|
||
{
|
||
float noise = 0;
|
||
float amp = 1f;
|
||
float freq = 1f;
|
||
|
||
// 生成多个频率的噪声,模拟更复杂的波动
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
// 基于当前时间和位置生成噪声值
|
||
float nx = x * freq * noiseScale;
|
||
float nz = z * freq * noiseScale;
|
||
float nt = currentTime * waveSpeed * freq;
|
||
noise += Mathf.PerlinNoise(nx + nt, nz + nt) * amp; // 累加噪声
|
||
amp *= 0.5f; // 每次衰减幅度
|
||
freq *= 2f; // 每次增加频率
|
||
}
|
||
|
||
return noise * waveHeight;
|
||
}
|
||
|
||
// 绘制湖面
|
||
public override void DrawShapes(Camera cam)
|
||
{
|
||
using (Draw.Command(cam))
|
||
{
|
||
Draw.ResetAllDrawStates();
|
||
Draw.LineGeometry = LineGeometry.Volumetric3D;
|
||
Draw.Thickness = lineWidth;
|
||
|
||
float step = fieldSize / (pointCount - 1);
|
||
float halfField = fieldSize * 0.5f;
|
||
float halfVisible = visibleAreaSize * 0.5f;
|
||
|
||
if (points == null || points.Length != pointCount * pointCount)
|
||
points = new Vector3[pointCount * pointCount];
|
||
if (validPoints == null || validPoints.Length != pointCount * pointCount)
|
||
validPoints = new bool[pointCount * pointCount];
|
||
|
||
CalculatePointPositions(step, halfField, halfVisible);
|
||
DrawPointsAndLines(step, halfField, halfVisible);
|
||
DrawEdgeLines(halfField, halfVisible);
|
||
DrawTargetPoints();
|
||
DrawObstacles(); // 绘制障碍物
|
||
DrawCollisionEffects(); // 绘制碰撞效果
|
||
}
|
||
}
|
||
|
||
// 计算每个点的位置和涟漪效果
|
||
private void CalculatePointPositions(float step, float halfField, float halfVisible)
|
||
{
|
||
// 遍历每个点,计算其位置和涟漪影响
|
||
for (int i = 0; i < pointCount; i++)
|
||
{
|
||
for (int j = 0; j < pointCount; j++)
|
||
{
|
||
// 计算当前点的位置(x,z)
|
||
float x = -halfField + j * step + fieldOffset.x;
|
||
float z = -halfField + i * step + fieldOffset.y;
|
||
|
||
// 判断该点是否在可视区域内
|
||
bool inside = Mathf.Abs(x) <= halfVisible && Mathf.Abs(z) <= halfVisible;
|
||
int index = i * pointCount + j; // 计算当前点的索引
|
||
validPoints[index] = inside; // 设置该点是否有效
|
||
|
||
if (!inside)
|
||
continue;
|
||
|
||
// 获取基础波浪高度,并计算涟漪影响
|
||
float baseHeight = GetHeight(x, z, time);
|
||
RippleResult ripple = GetRippleEffect(x, z, Time.time);
|
||
float finalY = baseHeight + ripple.heightOffset;
|
||
|
||
// 创建点的坐标
|
||
Vector3 pos = new Vector3(x, finalY, z);
|
||
points[index] = pos; // 存储计算得到的点
|
||
|
||
// 计算亮度:基于高度,越高越亮
|
||
float heightT = Mathf.InverseLerp(-waveHeight, waveHeight, finalY);
|
||
float brightness = Mathf.Clamp01(1f + ripple.brightnessBoost); // 计算亮度,防止超出范围
|
||
Color baseColor = Color.Lerp(lakeDarkColor, lakeLightColor, heightT);
|
||
baseColor *= brightness;
|
||
|
||
// 绘制当前点
|
||
Draw.Sphere(pos, pointSize * (1f - heightT * 0.5f), baseColor);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 绘制点与点之间的连线
|
||
private void DrawPointsAndLines(float step, float halfField, float halfVisible)
|
||
{
|
||
for (int i = 0; i < pointCount; i++)
|
||
{
|
||
for (int j = 0; j < pointCount; j++)
|
||
{
|
||
int index = i * pointCount + j;
|
||
if (!validPoints[index])
|
||
continue;
|
||
|
||
Vector3 current = points[index];
|
||
|
||
if (j < pointCount - 1 && validPoints[index + 1])
|
||
{
|
||
Vector3 next = points[index + 1];
|
||
DrawLineBetweenPoints(current, next, halfField, halfVisible);
|
||
}
|
||
|
||
// 绘制与下边点的连线
|
||
if (i < pointCount - 1 && validPoints[index + pointCount])
|
||
{
|
||
Vector3 next = points[index + pointCount];
|
||
DrawLineBetweenPoints(current, next, halfField, halfVisible);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 绘制两点之间的连线,加入深度和颜色的渐变
|
||
private void DrawLineBetweenPoints(Vector3 current, Vector3 next, float halfField, float halfVisible)
|
||
{
|
||
// 计算连线的平均高度
|
||
float avgY = (current.y + next.y) * 0.5f;
|
||
float heightT = Mathf.InverseLerp(-waveHeight, waveHeight, avgY);
|
||
|
||
// 计算连线的颜色,依赖于高度
|
||
Color lineColor = Color.Lerp(lakeDarkColor, lakeLightColor, heightT);
|
||
lineColor.a *= 0.8f; // 设置透明度
|
||
|
||
// 绘制连线
|
||
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()
|
||
{
|
||
float step = fieldSize / (pointCount - 1);
|
||
float halfField = fieldSize * 0.5f;
|
||
float halfVisible = visibleAreaSize * 0.5f;
|
||
|
||
foreach (var target in targetPoints)
|
||
{
|
||
// 将网格位置转换为世界坐标
|
||
float x = -halfField + target.gridPosition.x * step + fieldOffset.x;
|
||
float z = -halfField + target.gridPosition.y * step + fieldOffset.y;
|
||
|
||
// 检查是否在可视区域内
|
||
if (Mathf.Abs(x) > halfVisible || Mathf.Abs(z) > halfVisible)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 获取该点的高度
|
||
float height = GetHeight(x, z, time);
|
||
|
||
// 添加额外的起伏效果和高度偏移
|
||
float floatOffset = Mathf.Sin(time * floatFrequency) * floatAmplitude;
|
||
Vector3 position = new Vector3(x, height + floatOffset + targetHeightOffset, z);
|
||
|
||
// 计算旋转
|
||
float rotation = time * rotationSpeed;
|
||
Quaternion rot = Quaternion.Euler(0, rotation, 0);
|
||
|
||
// 绘制外层立方体线框
|
||
DrawWireCube(position, rot, targetSize * wireScale, targetWireColor);
|
||
|
||
// 根据类型绘制内部形状
|
||
switch (target.type)
|
||
{
|
||
case TargetType.Sphere:
|
||
Draw.Sphere(position, targetSize * 0.8f, targetFillColor);
|
||
break;
|
||
case TargetType.Cube:
|
||
Draw.Cube(position, rot, targetSize * 0.8f, targetFillColor);
|
||
break;
|
||
case TargetType.Torus:
|
||
Draw.Torus(position, rot, targetSize * 0.8f, targetSize * 0.3f, targetFillColor);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
private void DrawWireCube(Vector3 position, Quaternion rotation, float size, Color color)
|
||
{
|
||
Vector3[] vertices = new Vector3[]
|
||
{
|
||
new Vector3(-size, -size, -size),
|
||
new Vector3(size, -size, -size),
|
||
new Vector3(size, size, -size),
|
||
new Vector3(-size, size, -size),
|
||
new Vector3(-size, -size, size),
|
||
new Vector3(size, -size, size),
|
||
new Vector3(size, size, size),
|
||
new Vector3(-size, size, size)
|
||
};
|
||
|
||
// 应用旋转
|
||
for (int i = 0; i < vertices.Length; i++)
|
||
{
|
||
vertices[i] = rotation * vertices[i] + position;
|
||
}
|
||
|
||
// 绘制边
|
||
int[] edges = new int[]
|
||
{
|
||
0,1, 1,2, 2,3, 3,0, // 底面
|
||
4,5, 5,6, 6,7, 7,4, // 顶面
|
||
0,4, 1,5, 2,6, 3,7 // 连接线
|
||
};
|
||
|
||
for (int i = 0; i < edges.Length; i += 2)
|
||
{
|
||
Draw.Line(vertices[edges[i]], vertices[edges[i+1]], targetLineWidth, color);
|
||
}
|
||
}
|
||
|
||
private void DrawObstacles()
|
||
{
|
||
float step = fieldSize / (pointCount - 1);
|
||
float halfField = fieldSize * 0.5f;
|
||
float halfVisible = visibleAreaSize * 0.5f;
|
||
|
||
foreach (var obstacle in obstacles)
|
||
{
|
||
// 在编辑器中始终显示
|
||
if (Application.isPlaying && obstacle.visibility <= 0f)
|
||
continue;
|
||
|
||
// 将网格位置转换为世界坐标
|
||
float x = -halfField + obstacle.gridPosition.x * step + fieldOffset.x;
|
||
float z = -halfField + obstacle.gridPosition.y * step + fieldOffset.y;
|
||
|
||
// 检查是否在可视区域内
|
||
if (Mathf.Abs(x) > halfVisible || Mathf.Abs(z) > halfVisible)
|
||
continue;
|
||
|
||
// 获取该点的高度
|
||
float height = GetHeight(x, z, time);
|
||
|
||
// 计算颜色和升起效果
|
||
Color currentColor = obstacleColor;
|
||
if (Application.isPlaying)
|
||
{
|
||
currentColor.a *= obstacle.visibility * obstacle.colorFadeProgress;
|
||
}
|
||
float riseHeight = obstacleHeight * (Application.isPlaying ? obstacle.riseProgress : 1f);
|
||
|
||
// 绘制障碍物
|
||
Vector3 basePos = new Vector3(x, height, z);
|
||
float halfWidth = obstacleWidth * 0.5f;
|
||
|
||
// 绘制底部
|
||
Draw.Line(basePos + new Vector3(-halfWidth, 0, -halfWidth), basePos + new Vector3(halfWidth, 0, -halfWidth), lineWidth, currentColor);
|
||
Draw.Line(basePos + new Vector3(halfWidth, 0, -halfWidth), basePos + new Vector3(halfWidth, 0, halfWidth), lineWidth, currentColor);
|
||
Draw.Line(basePos + new Vector3(halfWidth, 0, halfWidth), basePos + new Vector3(-halfWidth, 0, halfWidth), lineWidth, currentColor);
|
||
Draw.Line(basePos + new Vector3(-halfWidth, 0, halfWidth), basePos + new Vector3(-halfWidth, 0, -halfWidth), lineWidth, currentColor);
|
||
|
||
// 绘制顶部(考虑升起效果)
|
||
Vector3 topPos = basePos + Vector3.up * riseHeight;
|
||
Draw.Line(topPos + new Vector3(-halfWidth, 0, -halfWidth), topPos + new Vector3(halfWidth, 0, -halfWidth), lineWidth, currentColor);
|
||
Draw.Line(topPos + new Vector3(halfWidth, 0, -halfWidth), topPos + new Vector3(halfWidth, 0, halfWidth), lineWidth, currentColor);
|
||
Draw.Line(topPos + new Vector3(halfWidth, 0, halfWidth), topPos + new Vector3(-halfWidth, 0, halfWidth), lineWidth, currentColor);
|
||
Draw.Line(topPos + new Vector3(-halfWidth, 0, halfWidth), topPos + new Vector3(-halfWidth, 0, -halfWidth), lineWidth, currentColor);
|
||
|
||
// 绘制连接线
|
||
Draw.Line(basePos + new Vector3(-halfWidth, 0, -halfWidth), topPos + new Vector3(-halfWidth, 0, -halfWidth), lineWidth, currentColor);
|
||
Draw.Line(basePos + new Vector3(halfWidth, 0, -halfWidth), topPos + new Vector3(halfWidth, 0, -halfWidth), lineWidth, currentColor);
|
||
Draw.Line(basePos + new Vector3(halfWidth, 0, halfWidth), topPos + new Vector3(halfWidth, 0, halfWidth), lineWidth, currentColor);
|
||
Draw.Line(basePos + new Vector3(-halfWidth, 0, halfWidth), topPos + new Vector3(-halfWidth, 0, halfWidth), lineWidth, currentColor);
|
||
}
|
||
}
|
||
|
||
private void DrawCollisionEffects()
|
||
{
|
||
foreach (var effect in collisionEffects)
|
||
{
|
||
float elapsed = Time.time - effect.startTime;
|
||
float t = elapsed / collisionEffectDuration;
|
||
|
||
float scale = Mathf.Lerp(0f, collisionEffectSize, t);
|
||
float alpha = Mathf.Lerp(1f, 0f, t);
|
||
Color effectColor = collisionEffectColor;
|
||
effectColor.a *= alpha;
|
||
|
||
// 使用效果位置的世界坐标
|
||
Vector3 effectPos = new Vector3(effect.position.x,
|
||
GetHeight(effect.position.x, effect.position.y, time),
|
||
effect.position.y);
|
||
|
||
// 设置虚线样式
|
||
Draw.UseDashes = true;
|
||
Draw.DashStyle = DashStyle.RelativeDashes(DashType.Basic, 0.5f, 0.5f, DashSnapping.Tiling, 0f, 0f);
|
||
|
||
// 绘制同心圆涟漪,但根据撞击方向调整形状
|
||
for (int i = 0; i < collisionEffectRingCount; i++)
|
||
{
|
||
float ringScale = scale * (i + 1) / collisionEffectRingCount;
|
||
float ringAlpha = alpha * (1f - (float)i / collisionEffectRingCount);
|
||
Color ringColor = effectColor;
|
||
ringColor.a *= ringAlpha;
|
||
|
||
// 计算椭圆的长轴和短轴
|
||
float majorAxis = ringScale;
|
||
float minorAxis = ringScale * 0.7f; // 短轴略短,形成椭圆
|
||
|
||
// 计算旋转角度(使长轴与撞击方向对齐)
|
||
float angle = Mathf.Atan2(effect.direction.y, effect.direction.x) * Mathf.Rad2Deg;
|
||
Quaternion rotation = Quaternion.Euler(0, angle, 0);
|
||
|
||
// 绘制椭圆环
|
||
int segments = 32;
|
||
Vector3 prevPoint = Vector3.zero;
|
||
for (int j = 0; j <= segments; j++)
|
||
{
|
||
float angle2 = (float)j / segments * Mathf.PI * 2;
|
||
float x = Mathf.Cos(angle2) * majorAxis;
|
||
float z = Mathf.Sin(angle2) * minorAxis;
|
||
Vector3 point = rotation * new Vector3(x, 0, z) + effectPos;
|
||
|
||
if (j > 0)
|
||
{
|
||
Draw.Line(prevPoint, point, lineWidth * (1f - t), ringColor);
|
||
}
|
||
prevPoint = point;
|
||
}
|
||
}
|
||
|
||
// 恢复默认样式
|
||
Draw.UseDashes = false;
|
||
}
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
// 如果超过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;
|
||
}
|
||
}
|
||
}
|
||
}
|