using UdonSharp; using UnityEngine; using VRC.SDKBase; public class WaterSystem : UdonSharpBehaviour { [Header("--- Настройки синевы ---")] [SerializeField] private float offset = -0.4f; // Смещение синего экрана (глаза) [Header("--- Настройки плавания ---")] [SerializeField] private float swimSpeed = 2.5f; // Скорость всплытия вверх [SerializeField] private float shouldersOffset = 0.22f; // Высота плеч аватара private VRCPlayerApi localPlayer; private bool inWater = false; void Start() { // Инициализируем локального игрока при старте localPlayer = Networking.LocalPlayer; } public override void OnPlayerTriggerEnter(VRCPlayerApi player) { if (player != null && player.isLocal) { inWater = true; // Твоя оригинальная физика невесомости player.SetGravityStrength(0.01f); player.SetWalkSpeed(2f); // Замедление ходьбы в воде player.SetRunSpeed(2.5f); // Замедление бега в воде } } public override void OnPlayerTriggerExit(VRCPlayerApi player) { if (player != null && player.isLocal) { inWater = false; // Отключаем туман и сбрасываем плотность в 0 для суши RenderSettings.fog = false; RenderSettings.fogDensity = 0f; // Возвращаем стандартные настройки для суши player.SetGravityStrength(1.0f); player.SetWalkSpeed(4f); player.SetRunSpeed(4f); } } void Update() { if (inWater && localPlayer != null) { // Берем высоту глаз конкретного аватара в реальном времени float headY = localPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Head).position.y; // Твой оригинальный расчет уровня воды по позиции объекта float triggerTopY = transform.position.y + offset; // Расчет высоты плеч аватара float shouldersY = headY - shouldersOffset; // 1. Проверка синего экрана (по глазам) с плотностью на 1.0 if (headY < triggerTopY) { RenderSettings.fog = true; RenderSettings.fogDensity = 1.0f; // Выставляем плотность на однёрку } else { RenderSettings.fog = false; RenderSettings.fogDensity = 0f; // Убираем густоту над водой } // 2. Плавание вверх при зажатии кнопок bool isJumping = Input.GetButton("Jump"); // Работает на ПК (Пробел) // Фикс для телефонов: проверяем направление взгляда и движение вперед Vector3 lookDir = localPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Head).rotation * Vector3.forward; bool mobileSwimUp = (Input.GetAxisRaw("Vertical") > 0.1f) && (lookDir.y > 0.4f); if (isJumping || mobileSwimUp) { if (shouldersY < triggerTopY) // Если плечи под водой — плывем вверх { Vector3 vel = localPlayer.GetVelocity(); vel.y = swimSpeed; localPlayer.SetVelocity(vel); } } // 3. Блокиратор левитации (не пускает в воздух выше плеч) if (shouldersY >= triggerTopY) { Vector3 vel = localPlayer.GetVelocity(); if (vel.y > 0) { vel.y = 0; localPlayer.SetVelocity(vel); } } } } }