93 lines
3.5 KiB
C#
93 lines
3.5 KiB
C#
using UnityEngine;
|
|
using KinematicCharacterController;
|
|
|
|
namespace Code.Gameplay.Character.Controller.Abilities
|
|
{
|
|
/*
|
|
* Механика наклона персонажа при контакте со стеной
|
|
* Управляет визуальным наклоном модели в зависимости от высоты подъёма по стене
|
|
*/
|
|
public class WallLeanMechanic
|
|
{
|
|
private readonly float _maxLeanAngle;
|
|
private readonly float _leanSharpness;
|
|
private readonly float _heightScale;
|
|
|
|
private Transform _characterTransform;
|
|
private Vector3 _lastWallNormal;
|
|
private float _lastWallContactHeight;
|
|
private float _leanFactor;
|
|
private float _leanSign;
|
|
private Vector3 _leanDirection;
|
|
|
|
public WallLeanMechanic(float maxLeanAngle, float leanSharpness, float heightScale)
|
|
{
|
|
_maxLeanAngle = maxLeanAngle;
|
|
_leanSharpness = leanSharpness;
|
|
_heightScale = heightScale;
|
|
}
|
|
|
|
// Назначаем трансформ визуальной модели один раз
|
|
public void SetCharacterTransform(Transform transform)
|
|
{
|
|
_characterTransform = transform;
|
|
}
|
|
|
|
// Вызывается из OnMovementHit
|
|
public void OnWallContact(KinematicCharacterMotor motor, Vector3 wallNormal, float contactHeight)
|
|
{
|
|
_lastWallNormal = wallNormal;
|
|
_lastWallContactHeight = contactHeight;
|
|
|
|
_leanDirection = -_lastWallNormal;
|
|
_leanDirection = Vector3.ProjectOnPlane(_leanDirection, motor.CharacterUp).normalized;
|
|
|
|
_leanSign = Mathf.Sign(_lastWallNormal.x != 0
|
|
? Vector3.Dot(_leanDirection, motor.CharacterForward * _lastWallNormal.z)
|
|
: Vector3.Dot(_leanDirection, motor.CharacterForward * _lastWallNormal.z));
|
|
|
|
Debug.Log("CharacterUp: " + motor.CharacterUp);
|
|
Debug.Log("CharacterForward: " + motor.CharacterForward);
|
|
Debug.Log("CharacterRight: " + motor.CharacterRight);
|
|
Debug.Log(_leanSign);
|
|
}
|
|
|
|
// Обновление каждый кадр
|
|
public void UpdateLean(KinematicCharacterMotor motor, float deltaTime)
|
|
{
|
|
if (!_characterTransform) return;
|
|
|
|
var isGrounded = motor.GroundingStatus.IsStableOnGround;
|
|
|
|
if (!isGrounded)
|
|
{
|
|
var heightDelta = motor.TransientPosition.y - _lastWallContactHeight;
|
|
var targetLeanFactor = Mathf.Clamp01(heightDelta * _heightScale);
|
|
_leanFactor = Mathf.Lerp(_leanFactor, targetLeanFactor, 1f - Mathf.Exp(-_leanSharpness * deltaTime));
|
|
}
|
|
else
|
|
{
|
|
_leanFactor = Mathf.Lerp(_leanFactor, 0f, 1f - Mathf.Exp(-_leanSharpness * deltaTime));
|
|
}
|
|
|
|
ApplyLeanRotation(motor);
|
|
}
|
|
|
|
private void ApplyLeanRotation(KinematicCharacterMotor motor)
|
|
{
|
|
if (_leanFactor <= 0.01f)
|
|
{
|
|
_characterTransform.localRotation = Quaternion.identity;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
if (_leanDirection.sqrMagnitude < 0.01f) return;
|
|
|
|
var leanAngle = _leanSign * _leanFactor * _maxLeanAngle;
|
|
var leanRotation = Quaternion.AngleAxis(leanAngle, Vector3.Cross(motor.CharacterUp, _leanDirection));
|
|
_characterTransform.localRotation = leanRotation;
|
|
}
|
|
}
|
|
} |