This commit is contained in:
2025-05-08 19:08:31 +08:00
parent 552955f3d4
commit e461982627
4 changed files with 1756 additions and 235 deletions
@@ -21,9 +21,11 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
public float edgeLineLength = 1f; // 边缘线的长度
[Header("UI控制")]
public Slider xOffsetSlider;
public Slider zOffsetSlider;
public float maxOffset = 20f;
public Button upButton;
public Button downButton;
public Button leftButton;
public Button rightButton;
public float moveStep = 1f; // 每次移动的步长
[Header("目标点设置")]
public List<TargetPoint> targetPoints = new List<TargetPoint>();
@@ -52,6 +54,17 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
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;
@@ -85,6 +98,92 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
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
@@ -93,20 +192,10 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
HandleMouseInput();
HandleUIInput();
CleanExpiredRipples();
CleanExpiredCollisionEffects();
UpdateObstacleVisibility();
}
private void HandleUIInput()
{
if (xOffsetSlider != null && zOffsetSlider != null)
{
fieldOffset = new Vector2(
xOffsetSlider.value * maxOffset,
zOffsetSlider.value * maxOffset
);
}
}
// 处理鼠标点击,触发新的涟漪
private void HandleMouseInput()
{
if (Application.isPlaying && Input.GetMouseButtonDown(0))
@@ -131,6 +220,11 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
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)
{
@@ -160,15 +254,58 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
// 计算涟漪对当前点的亮度提升
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 // 亮度提升
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)
{
@@ -212,7 +349,9 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
CalculatePointPositions(step, halfField, halfVisible);
DrawPointsAndLines(step, halfField, halfVisible);
DrawEdgeLines(halfField, halfVisible);
DrawTargetPoints(); // 添加目标点的绘制
DrawTargetPoints();
DrawObstacles(); // 绘制障碍物
DrawCollisionEffects(); // 绘制碰撞效果
}
}
@@ -301,6 +440,33 @@ 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)
{
// 检查点是否在可视区域内
@@ -310,7 +476,7 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
}
// 计算湖面高度作为起始点的Y坐标
float startY = GetHeight(x, z, time); // 获取湖面高度
float startY = GetHeight(x - fieldOffset.x, z - fieldOffset.y, time); // 获取湖面高度
// 设置边缘线的起始点
Vector3 start = new Vector3(x, startY, z);
@@ -327,40 +493,6 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
Draw.Line(start, end, lineWidth * 0.5f, lineColor);
}
private void DrawEdgeLines(float halfField, float halfVisible)
{
// 绘制湖面边缘的向下线条(无扰动)
float step = fieldSize / (pointCount - 1);
float halfEdgeLineLength = edgeLineLength * 0.5f; // 设置边缘线长度
// 只在field边界处绘制线条,且仅当边界在可视区域内时绘制
// 1. 绘制 X 轴的边缘线(左边和右边)
for (float z = -halfField; z <= halfField; z += step)
{
// 检查边界点是否在可视区域内
if (Mathf.Abs(z) <= halfVisible)
{
float x = halfField; // 右边
DrawEdgeLine(x, z, halfVisible);
x = -halfField; // 左边
DrawEdgeLine(x, z, halfVisible);
}
}
// 2. 绘制 Z 轴的边缘线(上边和下边)
for (float x = -halfField; x <= halfField; x += step)
{
// 检查边界点是否在可视区域内
if (Mathf.Abs(x) <= halfVisible)
{
float z = halfField; // 上边
DrawEdgeLine(x, z, halfVisible);
z = -halfField; // 下边
DrawEdgeLine(x, z, halfVisible);
}
}
}
// 绘制目标点
private void DrawTargetPoints()
{
@@ -443,4 +575,162 @@ public class LakeLineDrawer : ImmediateModeShapeDrawer
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;
}
}
}
}
@@ -2,28 +2,28 @@ using UnityEngine;
using UnityEngine.UI;
using Shapes;
public class LakeUIController : MonoBehaviour
{
[SerializeField] private LakeLineDrawer lakeDrawer;
public Slider xOffsetSlider;
public Slider zOffsetSlider;
// public class LakeUIController : MonoBehaviour
// {
// [SerializeField] private LakeLineDrawer lakeDrawer;
// public Slider xOffsetSlider;
// public Slider zOffsetSlider;
private void Start()
{
// 设置滑动条的初始值
if (xOffsetSlider != null && zOffsetSlider != null)
{
xOffsetSlider.minValue = -1f;
xOffsetSlider.maxValue = 1f;
xOffsetSlider.value = 0f;
// private void Start()
// {
// // 设置滑动条的初始值
// if (xOffsetSlider != null && zOffsetSlider != null)
// {
// xOffsetSlider.minValue = -1f;
// xOffsetSlider.maxValue = 1f;
// xOffsetSlider.value = 0f;
zOffsetSlider.minValue = -1f;
zOffsetSlider.maxValue = 1f;
zOffsetSlider.value = 0f;
// zOffsetSlider.minValue = -1f;
// zOffsetSlider.maxValue = 1f;
// zOffsetSlider.value = 0f;
// 将滑动条引用传递给LakeLineDrawer
lakeDrawer.xOffsetSlider = xOffsetSlider;
lakeDrawer.zOffsetSlider = zOffsetSlider;
}
}
}
// // 将滑动条引用传递给LakeLineDrawer
// lakeDrawer.xOffsetSlider = xOffsetSlider;
// lakeDrawer.zOffsetSlider = zOffsetSlider;
// }
// }
// }