using System; using System.Collections.Generic; using UnityEngine; public class PlayerDiveSystem : MonoBehaviour { public event Action Surfaced; public event Action Dived; [Header("Настройки погружения")] [SerializeField] private Transform UpPoint; [SerializeField] private Transform DownPoint; [SerializeField] private float MaxSpeed = 5f; [SerializeField] private float SmoothTime = 0.5f; // Время разгона/торможения [SerializeField] private float SurfacedCooldown = 2f; // Cooldown на событие Surfaced private float currentHeightVelocity = 0f; private float totalHeight; [Header("Давление")] [SerializeField] private float DepthPercentToStartPressure = 0.4f; [SerializeField] private float PressureMultiplier = 0.2f; [SerializeField, Range(0,1)] private float PressurePercentToResetCooldown = 0.7f; [Header("Пузыри")] [SerializeField] List bubbleParticles; private bool forceMoveUp = false; private float lastSurfacedTime = -Mathf.Infinity; // Время последнего вызова Surfaced private bool wasUnderPressure = false; private bool wasMovingUp = false; private bool down = false; public float PressurePercent { get; private set; } public float DepthPercent => (UpPoint.position.y - transform.position.y) / totalHeight; public bool Dive { private get; set; } private void Awake() { totalHeight = UpPoint.position.y - DownPoint.position.y; foreach (var particle in bubbleParticles) particle.Stop(); } private void Update() { bool isMovingUp = !Dive && !forceMoveUp || forceMoveUp; bool isUnderPressure = DepthPercent > DepthPercentToStartPressure; ProcessPressure(); CheckAndTriggerSurfaced(isMovingUp, isUnderPressure); if (forceMoveUp) { MoveToHeight(UpPoint.position.y); // Достигли верха? Тогда выходим if (PressurePercent < PressurePercentToResetCooldown) { forceMoveUp = false; } return; } if (PressurePercent >= 1f) { forceMoveUp = true; return; } var targetHeight = Dive ? DownPoint.position.y : UpPoint.position.y; MoveToHeight(targetHeight); wasUnderPressure = isUnderPressure; wasMovingUp = isMovingUp; } private void CheckAndTriggerSurfaced(bool isMovingUp, bool isUnderPressure) { // Проверяем: движемся вверх, пересекаем границу давления, и прошло достаточно времени с последнего вызова bool crossingPressureBoundary = !isUnderPressure && wasUnderPressure; bool canTrigger = Time.time - lastSurfacedTime >= SurfacedCooldown; if (isMovingUp && crossingPressureBoundary && canTrigger) { TriggerSurfaced(); } } private void TriggerSurfaced() { down = false; Surfaced?.Invoke(); lastSurfacedTime = Time.time; } private void TriggerDived() { if (!down) { down = true; Dived?.Invoke(); } } private void ProcessPressure() { if (DepthPercent > DepthPercentToStartPressure) { AddPressure(); TriggerDived(); foreach(var bubble in bubbleParticles) { if(!bubble.isPlaying) bubble.Play(); } } else { ReducePressure(); } void AddPressure() { float pressureStrength = DepthPercent * PressureMultiplier; PressurePercent += pressureStrength * Time.deltaTime; PressurePercent = Mathf.Clamp01(PressurePercent); } void ReducePressure() { PressurePercent -= PressureMultiplier * Time.deltaTime; PressurePercent = Mathf.Clamp01(PressurePercent); foreach (var bubble in bubbleParticles) { if (bubble.isPlaying) bubble.Stop(); } } } private void MoveToHeight(float targetHeight) { float currentY = transform.position.y; float newY = Mathf.SmoothDamp( currentY, targetHeight, ref currentHeightVelocity, SmoothTime, MaxSpeed ); Vector3 newPosition = transform.position; newPosition.y = newY; transform.position = newPosition; float magnitude = UpPoint.position.y - DownPoint.position.y; float t = (transform.position.y - DownPoint.position.y) / magnitude; float minDensity = 0.0001f; // Минимальная плотность (на поверхности) float maxDensity = 0.01f; // Максимальная плотность (на дне) RenderSettings.fogDensity = Mathf.Lerp(maxDensity, minDensity, t); } }