Files
2026-02-21 16:45:37 +08:00

285 lines
8.4 KiB
C#

using System;
using System.Collections.Generic;
using UltimateWater.Internal;
using UnityEngine;
using UnityEngine.Serialization;
namespace UltimateWater
{
public class ComplexWavesEmitter : MonoBehaviour, IWavesParticleSystemPlugin
{
public enum WavesSource
{
CustomWaveFrequency = 0,
WindWavesSpectrum = 1,
Shoaling = 2,
Vehicle = 3
}
private class SpawnPoint
{
public readonly Vector2 Position;
public Vector2 Direction;
public readonly float Frequency;
public readonly float Amplitude;
public readonly float TimeInterval;
public float TimeLeft;
public SpawnPoint(Vector2 position, Vector2 direction, float frequency, float amplitude, float speed)
{
Position = position;
Direction = direction;
Frequency = frequency;
Amplitude = amplitude;
TimeInterval = (float)Math.PI * 2f / speed * UnityEngine.Random.Range(1f, 8f);
TimeLeft = UnityEngine.Random.Range(0f, TimeInterval);
}
}
[FormerlySerializedAs("wavesParticleSystem")]
[SerializeField]
private WaveParticleSystem _WavesParticleSystem;
[FormerlySerializedAs("wavesSource")]
[SerializeField]
private WavesSource _WavesSource;
[FormerlySerializedAs("wavelength")]
[SerializeField]
private float _Wavelength = 120f;
[FormerlySerializedAs("amplitude")]
[SerializeField]
private float _Amplitude = 0.6f;
[FormerlySerializedAs("emissionRate")]
[SerializeField]
private float _EmissionRate = 2f;
[FormerlySerializedAs("width")]
[SerializeField]
private int _Width = 8;
[FormerlySerializedAs("spectrumCoincidenceRange")]
[SerializeField]
[Range(0f, 180f)]
private float _SpectrumCoincidenceRange = 20f;
[FormerlySerializedAs("spectrumWavesCount")]
[SerializeField]
[Range(0f, 100f)]
private int _SpectrumWavesCount = 30;
[FormerlySerializedAs("span")]
[SerializeField]
[Tooltip("Affects both waves and emission area width.")]
private float _Span = 1000f;
[FormerlySerializedAs("waveShapeIrregularity")]
[SerializeField]
[Range(1f, 3.5f)]
private float _WaveShapeIrregularity = 2f;
[FormerlySerializedAs("lifetime")]
[SerializeField]
private float _Lifetime = 200f;
[FormerlySerializedAs("shoreWaves")]
[SerializeField]
private bool _ShoreWaves = true;
[FormerlySerializedAs("boundsSize")]
[SerializeField]
private Vector2 _BoundsSize = new Vector2(500f, 500f);
[FormerlySerializedAs("spawnDepth")]
[SerializeField]
[Range(3f, 80f)]
private float _SpawnDepth = 8f;
[FormerlySerializedAs("emissionFrequencyScale")]
[SerializeField]
[Range(0.01f, 2f)]
private float _EmissionFrequencyScale = 1f;
[FormerlySerializedAs("spawnPointsDensity")]
[SerializeField]
private float _SpawnPointsDensity = 1f;
private SpawnPoint[] _SpawnPoints;
private WindWaves _WindWaves;
private float _NextSpawnTime;
private float _TimeStep;
public void UpdateParticles(float time, float deltaTime)
{
if (!base.isActiveAndEnabled)
{
return;
}
switch (_WavesSource)
{
case WavesSource.CustomWaveFrequency:
if (time > _NextSpawnTime)
{
Vector3 position = base.transform.position;
Vector3 forward = base.transform.forward;
WaveParticle waveParticle = WaveParticle.Create(new Vector2(position.x, position.z), new Vector2(forward.x, forward.z).normalized, (float)Math.PI * 2f / _Wavelength, _Amplitude, _Lifetime, _ShoreWaves);
if (waveParticle != null)
{
_WavesParticleSystem.Spawn(waveParticle, _Width, _WaveShapeIrregularity);
waveParticle.Destroy();
waveParticle.AddToCache();
}
_NextSpawnTime += _TimeStep;
}
break;
case WavesSource.WindWavesSpectrum:
if (_SpawnPoints == null)
{
CreateSpectralWavesSpawnPoints();
}
UpdateSpawnPoints(deltaTime);
break;
case WavesSource.Shoaling:
if (_SpawnPoints == null)
{
CreateShoalingSpawnPoints();
}
UpdateSpawnPoints(deltaTime);
break;
}
}
private void Awake()
{
_WindWaves = _WavesParticleSystem.GetComponent<Water>().WindWaves;
OnValidate();
_WavesParticleSystem.RegisterPlugin(this);
}
private void OnEnable()
{
OnValidate();
_NextSpawnTime = Time.time + UnityEngine.Random.Range(0f, _TimeStep);
}
private void OnValidate()
{
_TimeStep = _Wavelength / _EmissionRate;
}
private void UpdateSpawnPoints(float deltaTime)
{
deltaTime *= _EmissionFrequencyScale;
for (int i = 0; i < _SpawnPoints.Length; i++)
{
SpawnPoint spawnPoint = _SpawnPoints[i];
spawnPoint.TimeLeft -= deltaTime;
if (spawnPoint.TimeLeft < 0f)
{
float num = (float)Math.PI * 2f / spawnPoint.Frequency;
float num2 = _Span * 0.3f / num;
int min = Mathf.Max(2, Mathf.RoundToInt(num2 * 0.7f));
int max = Mathf.Max(2, Mathf.RoundToInt(num2 * 1.429f));
spawnPoint.TimeLeft += spawnPoint.TimeInterval;
Vector2 position = spawnPoint.Position + new Vector2(spawnPoint.Direction.y, 0f - spawnPoint.Direction.x) * UnityEngine.Random.Range((0f - _Span) * 0.35f, _Span * 0.35f);
WaveParticle waveParticle = WaveParticle.Create(position, spawnPoint.Direction, spawnPoint.Frequency, spawnPoint.Amplitude, _Lifetime, _ShoreWaves);
if (waveParticle != null)
{
_WavesParticleSystem.Spawn(waveParticle, UnityEngine.Random.Range(min, max), _WaveShapeIrregularity);
waveParticle.Destroy();
waveParticle.AddToCache();
}
}
}
}
private void CreateShoalingSpawnPoints()
{
Bounds bounds = new Bounds(base.transform.position, new Vector3(_BoundsSize.x, 0f, _BoundsSize.y));
float x = bounds.min.x;
float z = bounds.min.z;
float x2 = bounds.max.x;
float z2 = bounds.max.z;
float num = Mathf.Sqrt(_SpawnPointsDensity);
float num2 = Mathf.Max(35f, bounds.size.x / 256f) / num;
float num3 = Mathf.Max(35f, bounds.size.z / 256f) / num;
bool[,] array = new bool[32, 32];
List<SpawnPoint> list = new List<SpawnPoint>();
GerstnerWave[] array2 = _WindWaves.SpectrumResolver.SelectShorelineWaves(50, 0f, 360f);
if (array2.Length == 0)
{
_SpawnPoints = new SpawnPoint[0];
return;
}
float num4 = _SpawnDepth * 0.85f;
float num5 = _SpawnDepth * 1.18f;
Vector2 vector = default(Vector2);
for (float num6 = z; num6 < z2; num6 += num3)
{
for (float num7 = x; num7 < x2; num7 += num2)
{
int num8 = Mathf.FloorToInt(32f * (num7 - x) / (x2 - x));
int num9 = Mathf.FloorToInt(32f * (num6 - z) / (z2 - z));
if (array[num8, num9])
{
continue;
}
float totalDepthAt = StaticWaterInteraction.GetTotalDepthAt(num7, num6);
if (!(totalDepthAt > num4) || !(totalDepthAt < num5) || !(UnityEngine.Random.value < 0.06f))
{
continue;
}
array[num8, num9] = true;
vector.x = StaticWaterInteraction.GetTotalDepthAt(num7 - 3f, num6) - StaticWaterInteraction.GetTotalDepthAt(num7 + 3f, num6);
vector.y = StaticWaterInteraction.GetTotalDepthAt(num7, num6 - 3f) - StaticWaterInteraction.GetTotalDepthAt(num7, num6 + 3f);
vector.Normalize();
GerstnerWave gerstnerWave = array2[0];
float num10 = Vector2.Dot(vector, array2[0].Direction);
for (int i = 1; i < array2.Length; i++)
{
float num11 = Vector2.Dot(vector, array2[i].Direction);
if (num11 > num10)
{
num10 = num11;
gerstnerWave = array2[i];
}
}
list.Add(new SpawnPoint(new Vector2(num7, num6), vector, gerstnerWave.Frequency, Mathf.Abs(gerstnerWave.Amplitude), gerstnerWave.Speed));
}
}
_SpawnPoints = list.ToArray();
}
private void CreateSpectralWavesSpawnPoints()
{
Vector3 normalized = base.transform.forward.normalized;
float num = Mathf.Atan2(normalized.x, normalized.z);
GerstnerWave[] array = _WindWaves.SpectrumResolver.SelectShorelineWaves(_SpectrumWavesCount, num * 57.29578f, _SpectrumCoincidenceRange);
_SpectrumWavesCount = array.Length;
Vector3 vector = new Vector3(base.transform.position.x + _Span * 0.5f, 0f, base.transform.position.z + _Span * 0.5f);
Vector2 vector2 = new Vector2(vector.x, vector.z);
List<SpawnPoint> list = new List<SpawnPoint>();
for (int i = 0; i < _SpectrumWavesCount; i++)
{
GerstnerWave gerstnerWave = array[i];
if (gerstnerWave.Amplitude != 0f)
{
Vector2 position = vector2 - gerstnerWave.Direction * _Span * 0.5f;
list.Add(new SpawnPoint(position, gerstnerWave.Direction, gerstnerWave.Frequency, Mathf.Abs(gerstnerWave.Amplitude), gerstnerWave.Speed));
}
}
_SpawnPoints = list.ToArray();
}
}
}