Я ненавижу наклоны (не прорвёмся)
This commit is contained in:
1 parent
d10d2cdca6
commit
766609489d
7 files changed
+97
-1463
No files matched your search
+43
-131
@@ -1,147 +1,59 @@
|
||||
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;
|
||||
|
||||
private Vector3 _lastWallContactPoint;
|
||||
private bool _isLeaningOnWall;
|
||||
private const float WallProximityThreshold = 0.6f;
|
||||
private Transform _model;
|
||||
|
||||
public WallLeanMechanic(float maxLeanAngle, float leanSharpness, float heightScale)
|
||||
public void SetModel(Transform model) => _model = model;
|
||||
|
||||
public void Update(bool isWallRunning, Vector3 wallNormal, Vector3 characterForward)
|
||||
{
|
||||
_maxLeanAngle = maxLeanAngle;
|
||||
_leanSharpness = leanSharpness;
|
||||
_heightScale = heightScale;
|
||||
}
|
||||
|
||||
// Назначаем трансформ визуальной модели один раз
|
||||
public void SetCharacterTransform(Transform transform)
|
||||
{
|
||||
_characterTransform = transform;
|
||||
}
|
||||
|
||||
// Вызывается из OnMovementHit
|
||||
public void OnWallContact(KinematicCharacterMotor motor, Vector3 wallNormal, float contactHeight)
|
||||
{
|
||||
// Только если это действительно стена (не пол/потолок)
|
||||
var dotWithUp = Vector3.Dot(wallNormal, motor.CharacterUp);
|
||||
if (Mathf.Abs(dotWithUp) > 0.7f) // ~45°, можно настроить
|
||||
return;
|
||||
|
||||
_lastWallNormal = wallNormal;
|
||||
_lastWallContactHeight = contactHeight;
|
||||
_lastWallContactPoint = motor.TransientPosition;
|
||||
|
||||
// Пересчитываем направление наклона
|
||||
_leanDirection = -_lastWallNormal;
|
||||
_leanDirection = Vector3.ProjectOnPlane(_leanDirection, motor.CharacterUp).normalized;
|
||||
|
||||
_leanSign = 1;
|
||||
|
||||
// what the fuck
|
||||
if (_leanDirection.x != 0)
|
||||
if (_model == null)
|
||||
{
|
||||
switch (_leanDirection.x)
|
||||
{
|
||||
case -1 or 1 when motor.CharacterRight.x > 0.1f:
|
||||
_leanSign = -1;
|
||||
break;
|
||||
case -1 or 1 when Mathf.Abs(motor.CharacterRight.x) < 0.1f:
|
||||
_leanDirection = new Vector3(0, 0, -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (_leanDirection.z)
|
||||
{
|
||||
case 1 when Mathf.Abs(motor.CharacterRight.z) < 0.1f:
|
||||
_leanSign = -1;
|
||||
break;
|
||||
case -1 when motor.CharacterRight.z < -0.1f:
|
||||
case 1 when motor.CharacterRight.z > 0.1f:
|
||||
_leanDirection = new Vector3(-1, 0, 0);
|
||||
break;
|
||||
case -1 when motor.CharacterRight.z > 0.1f:
|
||||
case 1 when motor.CharacterRight.z < -0.1f:
|
||||
_leanDirection = new Vector3(1, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_isLeaningOnWall = true;
|
||||
}
|
||||
|
||||
// Обновление каждый кадр
|
||||
public void UpdateLean(KinematicCharacterMotor motor, float deltaTime)
|
||||
{
|
||||
if (!_characterTransform) return;
|
||||
|
||||
var currentPosition = motor.TransientPosition;
|
||||
|
||||
var isStillNearWall = false;
|
||||
if (_isLeaningOnWall && _lastWallNormal != Vector3.zero)
|
||||
{
|
||||
var toWall = currentPosition - _lastWallContactPoint;
|
||||
var distanceToWallPlane = Mathf.Abs(Vector3.Dot(toWall, _lastWallNormal));
|
||||
isStillNearWall = distanceToWallPlane <= WallProximityThreshold;
|
||||
}
|
||||
|
||||
if (_isLeaningOnWall)
|
||||
{
|
||||
var isBelowContactHeight = currentPosition.y < _lastWallContactHeight;
|
||||
|
||||
if (!isStillNearWall || isBelowContactHeight)
|
||||
{
|
||||
_isLeaningOnWall = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var heightDelta = currentPosition.y - _lastWallContactHeight;
|
||||
var targetLeanFactor = Mathf.Clamp01(heightDelta * _heightScale);
|
||||
_leanFactor = Mathf.Lerp(_leanFactor, targetLeanFactor, 1f - Mathf.Exp(-_leanSharpness * deltaTime));
|
||||
}
|
||||
}
|
||||
|
||||
if (!_isLeaningOnWall)
|
||||
{
|
||||
_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;
|
||||
_model.localRotation = Quaternion.identity;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_leanDirection.sqrMagnitude < 0.01f) return;
|
||||
if (!isWallRunning)
|
||||
{
|
||||
_model.localRotation = Quaternion.identity;
|
||||
return;
|
||||
}
|
||||
|
||||
var leanAngle = _leanSign * _leanFactor * _maxLeanAngle;
|
||||
var leanAxis = Vector3.Cross(motor.CharacterUp, _leanDirection);
|
||||
var leanRotation = Quaternion.AngleAxis(leanAngle, leanAxis);
|
||||
_characterTransform.localRotation = leanRotation;
|
||||
Vector3 n = new Vector3(wallNormal.x, 0f, wallNormal.z).normalized;
|
||||
if (n.sqrMagnitude < 0.001f) n = Vector3.forward;
|
||||
|
||||
Vector3 bodyRight = Vector3.Cross(Vector3.up, characterForward).normalized;
|
||||
float side = Vector3.Dot(n, bodyRight);
|
||||
float front = Vector3.Dot(n, characterForward);
|
||||
|
||||
Vector3 axis = Vector3.right;
|
||||
float angle = 0f;
|
||||
|
||||
if (side > 0.3f)
|
||||
{
|
||||
axis = Vector3.forward;
|
||||
angle = -25f;
|
||||
}
|
||||
else if (side < -0.3f)
|
||||
{
|
||||
axis = Vector3.forward;
|
||||
angle = 25f;
|
||||
}
|
||||
else if (front > 0.3f)
|
||||
{
|
||||
axis = Vector3.right;
|
||||
angle = -25f;
|
||||
}
|
||||
else if (front < -0.3f)
|
||||
{
|
||||
axis = Vector3.right;
|
||||
angle = 25f;
|
||||
}
|
||||
|
||||
_model.localRotation = Quaternion.AngleAxis(angle, axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-2
@@ -24,6 +24,9 @@ namespace Code.Gameplay.Character.Controller.Abilities
|
||||
|
||||
private float _surfaceAngleCos;
|
||||
private bool _canWallRun;
|
||||
public float WallContactHeight { get; private set; }
|
||||
|
||||
public Vector3 WallRunStartForward { get; private set; }
|
||||
|
||||
private KinematicCharacterMotor _motor;
|
||||
private CharacterInputHandler _inputHandler;
|
||||
@@ -80,12 +83,14 @@ namespace Code.Gameplay.Character.Controller.Abilities
|
||||
_wallRunTimer = 0f;
|
||||
_wallNormal = wallNormal.normalized;
|
||||
_wallContactPoint = contactPoint;
|
||||
WallContactHeight = contactPoint.y;
|
||||
|
||||
_wallTangentUp = Vector3.ProjectOnPlane(_motor.CharacterUp, _wallNormal).normalized;
|
||||
if (_wallTangentUp.sqrMagnitude < 0.01f) _wallTangentUp = Vector3.up;
|
||||
|
||||
_wallTangentRight = Vector3.Cross(_wallNormal, _wallTangentUp).normalized;
|
||||
|
||||
WallRunStartForward = _motor.CharacterForward;
|
||||
_motor.ForceUnground();
|
||||
}
|
||||
|
||||
@@ -220,8 +225,8 @@ namespace Code.Gameplay.Character.Controller.Abilities
|
||||
if (forwardInWallPlane.sqrMagnitude < 0.01f) forwardInWallPlane = _wallTangentRight;
|
||||
|
||||
Vector3 jumpDirection =
|
||||
forwardInWallPlane * 0.1f +
|
||||
wallAway * 0.5f +
|
||||
forwardInWallPlane * 0.2f +
|
||||
wallAway * 0.4f +
|
||||
wallUp * 0.4f;
|
||||
|
||||
jumpDirection = jumpDirection.normalized;
|
||||
|
||||
+9
-18
@@ -30,7 +30,7 @@ namespace Code.Gameplay.Character.Controller
|
||||
private SlideMechanic _slideMechanic;
|
||||
// private WallClimbMechanic _wallClimbMechanic;
|
||||
private WallRunningMechanic _wallRunningMechanic;
|
||||
//private WallLeanMechanic _wallLeanMechanic;
|
||||
private WallLeanMechanic _wallLeanMechanic;
|
||||
private GroundMovementSystem _groundMovement;
|
||||
private AirMovementSystem _airMovement;
|
||||
|
||||
@@ -72,11 +72,8 @@ namespace Code.Gameplay.Character.Controller
|
||||
_wallRunningMechanic.WallDetachImpulse = 7.0f;
|
||||
_wallRunningMechanic.WallContactAngleThreshold = 45.0f;
|
||||
|
||||
/*_wallLeanMechanic = new WallLeanMechanic(
|
||||
_characterConfig.maxWallLeanAngle,
|
||||
_characterConfig.wallLeanSharpness,
|
||||
_characterConfig.wallLeanHeightScale
|
||||
);*/
|
||||
_wallLeanMechanic = new WallLeanMechanic(
|
||||
);
|
||||
_groundMovement = new GroundMovementSystem(
|
||||
_characterConfig.maxStableMoveSpeed,
|
||||
_characterConfig.sprintMoveSpeed,
|
||||
@@ -89,7 +86,7 @@ namespace Code.Gameplay.Character.Controller
|
||||
motor.CharacterController = this; // Регистрация этого контроллера в движке
|
||||
_inputHandler.FirstPersonCameraRotation =
|
||||
motor.Transform.rotation; // Начальное вращение совпадает с персонажемс
|
||||
//_wallLeanMechanic.SetCharacterTransform(characterTransform);
|
||||
_wallLeanMechanic.SetModel(characterTransform);
|
||||
_wallRunningMechanic.Initialize(motor, _inputHandler);
|
||||
}
|
||||
|
||||
@@ -233,16 +230,15 @@ namespace Code.Gameplay.Character.Controller
|
||||
{
|
||||
_slideMechanic.EndSlide();
|
||||
}
|
||||
|
||||
// if (motor.GroundingStatus.IsStableOnGround)
|
||||
// {
|
||||
// _wallClimbMechanic.ResetWallClimbSession();
|
||||
// }
|
||||
}
|
||||
|
||||
public void AfterCharacterUpdate(float deltaTime)
|
||||
{
|
||||
//_wallLeanMechanic.UpdateLean(motor, deltaTime);
|
||||
_wallLeanMechanic.Update(
|
||||
_wallRunningMechanic.IsWallRunning,
|
||||
_wallRunningMechanic.GetWallNormal(),
|
||||
motor.CharacterForward
|
||||
);
|
||||
}
|
||||
|
||||
public bool IsColliderValidForCollisions(Collider coll)
|
||||
@@ -258,14 +254,9 @@ namespace Code.Gameplay.Character.Controller
|
||||
public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint,
|
||||
ref HitStabilityReport hitStabilityReport)
|
||||
{
|
||||
// Попытка начать Wall Run при ударе о поверхность
|
||||
if (_wallRunningMechanic.TryStartWallRun(hitNormal, hitPoint))
|
||||
{
|
||||
//_wallLeanMechanic.OnWallContact(motor, hitNormal, motor.TransientPosition.y);
|
||||
}
|
||||
|
||||
// if (_wallClimbMechanic.TryClimbWall(motor, hitNormal))
|
||||
// _wallLeanMechanic.OnWallContact(motor, hitNormal, motor.TransientPosition.y);
|
||||
}
|
||||
|
||||
public void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint,
|
||||
|
||||
Reference in new issue
Block a user