diff --git a/Game/CourierOld/Assets/Code/Gameplay/Player/CharacterController.cs b/Game/CourierOld/Assets/Code/Gameplay/Player/CharacterController.cs index ef1135d..a1a2f3a 100644 --- a/Game/CourierOld/Assets/Code/Gameplay/Player/CharacterController.cs +++ b/Game/CourierOld/Assets/Code/Gameplay/Player/CharacterController.cs @@ -40,7 +40,9 @@ namespace Code.Gameplay.Player slideCooldown = 1.5f, // Время перезарядки слайда stableMovementSharpness = 15f, // Резкость изменения скорости движения (чем выше - тем резче) orientationSharpness = 10f, // Резкость изменения вращения персонажа (чем выше - тем резче) - jumpSpeed = 10f; // Скорость прыжка + jumpSpeed = 10f, // Скорость прыжка + wallClimbSpeedFactor = 0.8f, // Коэффициент преобразования горизонтальной скорости в вертикальную при залазании на стену + minWallClimbSpeed = 9f; // Минимальная горизонтальная скорость для начала залазания на стену [SerializeField] private Vector3 gravity = new(0, -30f, 0); // Вектор, отвечающий за применение гравитации @@ -65,6 +67,9 @@ namespace Code.Gameplay.Player private float _slideCooldownTimer; // Таймер перезарядки слайда private Vector3 _slideDirection; // Направление слайда private bool _slideRequested; // Флаг запроса слайда + + // Флаг для предотвращения повторного залазания на стену в один и тот же кадр + private bool _wallClimbAppliedThisFrame; // Инициализация контроллера private void Start() @@ -297,6 +302,9 @@ namespace Code.Gameplay.Player // Обновление скорости движения персонажа public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime) { + // Сбрасываем флаг залазания на стену в начале каждого кадра + _wallClimbAppliedThisFrame = false; + // Проверяем запрос слайда и запускаем его если можно if (_slideRequested && !_isSliding && motor.GroundingStatus.IsStableOnGround && _slideCooldownTimer <= 0f) { @@ -347,12 +355,12 @@ namespace Code.Gameplay.Player motor.ForceUnground(); } } - // Если персонаж не находится на земле else { // Применяем гравитацию currentVelocity += gravity * deltaTime; + // Отменяем прыжок (фикс проблемы с двойным прыжком после приземления) _jumpRequested = false; } @@ -393,6 +401,32 @@ namespace Code.Gameplay.Player public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) { + // Игнорируем, если уже залезли на стену в этом кадре или если слайд активен + if (_wallClimbAppliedThisFrame || _isSliding) return; + + // Проверяем, что это вертикальная или почти вертикальная поверхность (стена) + var dotWithUp = Vector3.Dot(hitNormal, motor.CharacterUp); + if (Mathf.Abs(dotWithUp) > 0.1f) return; // Не стена — это пол или потолок + + // Получаем текущую скорость персонажа + var currentVelocity = motor.Velocity; + + // Проекция скорости на направление к стене (отрицательная, если летим в стену) + var velocityIntoWall = Vector3.Dot(currentVelocity, -hitNormal); + + // Если движемся в стену с достаточной скоростью + if (velocityIntoWall > minWallClimbSpeed) + { + // Преобразуем часть горизонтальной скорости в вертикальную + var verticalBoost = velocityIntoWall * wallClimbSpeedFactor; + + // Добавляем вертикальный импульс через BaseVelocity + motor.BaseVelocity += motor.CharacterUp * verticalBoost; + + // Предотвращаем заземление и повторное применение в этом кадре + motor.ForceUnground(); + _wallClimbAppliedThisFrame = true; + } } // Обработка отчета о стабильности столкновения diff --git a/Game/CourierOld/Assets/Resources/Scenes/MovementDev.unity b/Game/CourierOld/Assets/Resources/Scenes/MovementDev.unity index b6d64a8..dc658f2 100644 --- a/Game/CourierOld/Assets/Resources/Scenes/MovementDev.unity +++ b/Game/CourierOld/Assets/Resources/Scenes/MovementDev.unity @@ -993,6 +993,8 @@ MonoBehaviour: stableMovementSharpness: 15 orientationSharpness: 10 jumpSpeed: 10 + wallClimbSpeedFactor: 0.8 + minWallClimbSpeed: 9 gravity: {x: 0, y: -30, z: 0} --- !u!1 &1959874989 GameObject: