я ксиька :3

This commit is contained in:
MrTorex committed 2025-12-04 17:38:45 +03:00
1 parent b4de41894f
commit 4c16a63abd
1 file changed
+71 -110
@@ -7,14 +7,13 @@ namespace Code.Gameplay.Character.Controller.Abilities
{
public class WallRunningMechanic
{
public float MaxWallRunTime = 1.75f;
public float WallRunSpeed = 8.0f;
public float WallRunAcceleration = 25.0f;
public float WallRunGravityScale = 0.25f;
public float WallDetachImpulse = 7.0f;
public float WallContactAngleThreshold = 45.0f;
private readonly float _maxWallRunTime;
private readonly float _wallRunSpeed;
private readonly float _wallRunAcceleration;
private readonly float _wallRunGravityScale;
private readonly float _wallDetachImpulse;
private readonly float _wallContactAngleThreshold;
private bool _isWallRunning;
private float _wallRunTimer;
private Vector3 _wallNormal;
private Vector3 _wallTangentRight;
@@ -24,15 +23,12 @@ 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;
public bool IsWallRunning => _isWallRunning;
public bool IsWallRunning { get; private set; }
public WallRunningMechanic(
float maxWallRunTime,
float wallRunSpeed,
@@ -41,52 +37,44 @@ namespace Code.Gameplay.Character.Controller.Abilities
float wallDetachImpulse,
float wallContactAngleThreshold)
{
MaxWallRunTime = maxWallRunTime;
WallRunSpeed = wallRunSpeed;
WallRunAcceleration = wallRunAcceleration;
WallRunGravityScale = wallRunGravityScale;
WallDetachImpulse = wallDetachImpulse;
WallContactAngleThreshold = wallContactAngleThreshold;
_maxWallRunTime = maxWallRunTime;
_wallRunSpeed = wallRunSpeed;
_wallRunAcceleration = wallRunAcceleration;
_wallRunGravityScale = wallRunGravityScale;
_wallDetachImpulse = wallDetachImpulse;
_wallContactAngleThreshold = wallContactAngleThreshold;
}
public void Initialize(KinematicCharacterMotor motor, CharacterInputHandler inputHandler)
{
_motor = motor;
_inputHandler = inputHandler;
_surfaceAngleCos = Mathf.Cos(Mathf.Deg2Rad * WallContactAngleThreshold);
}
public void Reset()
{
_isWallRunning = false;
_wallRunTimer = 0f;
_wallNormal = Vector3.zero;
_surfaceAngleCos = Mathf.Cos(Mathf.Deg2Rad * _wallContactAngleThreshold);
}
public void Tick(float deltaTime)
{
if (_isWallRunning)
if (!IsWallRunning) return;
_wallRunTimer += deltaTime;
if (_wallRunTimer > _maxWallRunTime)
{
_wallRunTimer += deltaTime;
if (_wallRunTimer > MaxWallRunTime)
{
DetachFromWall(false);
}
DetachFromWall(false);
}
}
public bool TryStartWallRun(Vector3 hitNormal, Vector3 hitPoint)
{
if (_isWallRunning) return false;
if (IsWallRunning) return false;
float dotWithUp = Vector3.Dot(hitNormal, _motor.CharacterUp);
bool isWall = Mathf.Abs(dotWithUp) < _surfaceAngleCos;
var dotWithUp = Vector3.Dot(hitNormal, _motor.CharacterUp);
var isWall = Mathf.Abs(dotWithUp) < _surfaceAngleCos;
if (!isWall) return false;
if (_motor.GroundingStatus.IsStableOnGround) return false;
float velocityIntoWall = Vector3.Dot(_motor.Velocity, -hitNormal);
var velocityIntoWall = Vector3.Dot(_motor.Velocity, -hitNormal);
if (velocityIntoWall < 1f) return false;
StartWallRun(hitNormal, hitPoint);
@@ -95,13 +83,11 @@ namespace Code.Gameplay.Character.Controller.Abilities
private void StartWallRun(Vector3 wallNormal, Vector3 contactPoint)
{
_isWallRunning = true;
IsWallRunning = true;
_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;
@@ -109,43 +95,42 @@ namespace Code.Gameplay.Character.Controller.Abilities
_wallTangentUp = Vector3.Cross(_wallTangentRight, _wallNormal).normalized;
if (Vector3.Dot(_wallTangentUp, Vector3.up) < 0)
_wallTangentUp = -_wallTangentUp;
WallRunStartForward = _motor.CharacterForward;
_motor.ForceUnground();
}
public void HandleWallRun(ref Vector3 currentVelocity, CharacterInputs inputs, float deltaTime)
{
if (!_isWallRunning) return;
if (!IsWallRunning) return;
if (!IsWallStillPresent()) { DetachFromWall(false); return; }
Vector3 moveInputWorld = _inputHandler.MoveInputVector;
Vector3 moveInWallPlane = Vector3.ProjectOnPlane(moveInputWorld, _wallNormal);
var moveInputWorld = _inputHandler.MoveInputVector;
var moveInWallPlane = Vector3.ProjectOnPlane(moveInputWorld, _wallNormal);
Vector3 wsMove = Vector3.Project(moveInWallPlane, _wallTangentRight);
var wsMove = Vector3.Project(moveInWallPlane, _wallTangentRight);
float ad = inputs.MoveAxisRight;
var ad = inputs.MoveAxisRight;
float sideDot = Vector3.Dot(_wallNormal, _motor.CharacterRight);
var sideDot = Vector3.Dot(_wallNormal, _motor.CharacterRight);
if (sideDot < 0)
ad = -ad;
Vector3 adMove = _wallTangentUp * (-ad);
var adMove = _wallTangentUp * (-ad);
Vector3 finalMove = wsMove + adMove;
var finalMove = wsMove + adMove;
finalMove = finalMove.normalized * moveInputWorld.magnitude;
Vector3 targetVelocity = finalMove * WallRunSpeed;
var targetVelocity = finalMove * _wallRunSpeed;
currentVelocity = Vector3.Lerp(
currentVelocity,
targetVelocity,
1f - Mathf.Exp(-WallRunAcceleration * deltaTime)
1f - Mathf.Exp(-_wallRunAcceleration * deltaTime)
);
currentVelocity += Physics.gravity * (WallRunGravityScale * deltaTime);
currentVelocity += Physics.gravity * (_wallRunGravityScale * deltaTime);
float distanceToWall = Vector3.Dot(_motor.TransientPosition - _wallContactPoint, _wallNormal);
var distanceToWall = Vector3.Dot(_motor.TransientPosition - _wallContactPoint, _wallNormal);
if (Mathf.Abs(distanceToWall) > 0.8f)
{
DetachFromWall(false);
@@ -160,16 +145,15 @@ namespace Code.Gameplay.Character.Controller.Abilities
private bool IsWallStillPresent()
{
if (_motor == null) return false;
if (!_motor) return false;
Vector3 characterCenter = _motor.TransientPosition;
Vector3 characterForward = _motor.CharacterForward;
Vector3 characterRight = _motor.CharacterRight;
Vector3 characterUp = _motor.CharacterUp;
var characterCenter = _motor.TransientPosition;
var characterRight = _motor.CharacterRight;
var characterUp = _motor.CharacterUp;
float checkDistance = 0.45f;
Vector3 rayOrigin = characterCenter + characterUp * 0.2f;
Vector3 rayDir = -_wallNormal;
const float checkDistance = 0.45f;
var rayOrigin = characterCenter + characterUp * 0.2f;
var rayDir = -_wallNormal;
Vector3[] offsets = {
Vector3.zero,
@@ -181,83 +165,60 @@ namespace Code.Gameplay.Character.Controller.Abilities
foreach (var offset in offsets)
{
if (Physics.Raycast(rayOrigin + offset, rayDir, out RaycastHit hit, checkDistance,
_motor.CollidableLayers, QueryTriggerInteraction.Ignore))
{
float dotWithUp = Mathf.Abs(Vector3.Dot(hit.normal, characterUp));
if (dotWithUp < _surfaceAngleCos)
{
_wallNormal = hit.normal.normalized;
_wallContactPoint = hit.point;
if (!Physics.Raycast(rayOrigin + offset, rayDir, out var hit, checkDistance,
_motor.CollidableLayers, QueryTriggerInteraction.Ignore)) continue;
var dotWithUp = Mathf.Abs(Vector3.Dot(hit.normal, characterUp));
if (!(dotWithUp < _surfaceAngleCos)) continue;
_wallNormal = hit.normal.normalized;
_wallContactPoint = hit.point;
/*_wallTangentUp = Vector3.ProjectOnPlane(_motor.CharacterUp, _wallNormal).normalized;
if (_wallTangentUp.sqrMagnitude < 0.01f) _wallTangentUp = Vector3.up;
_wallTangentRight = Vector3.Cross(_wallNormal, _wallTangentUp).normalized;
*/
return true;
}
}
return true;
}
return false;
}
public void DetachFromWall(bool withImpulse)
private void DetachFromWall(bool withImpulse)
{
if (!_isWallRunning) return;
if (!IsWallRunning) return;
_isWallRunning = false;
IsWallRunning = false;
if (withImpulse && _motor != null)
{
Vector3 detachImpulse = -_wallNormal * WallDetachImpulse;
_motor.BaseVelocity += detachImpulse;
}
if (!withImpulse || !_motor) return;
var detachImpulse = -_wallNormal * _wallDetachImpulse;
_motor.BaseVelocity += detachImpulse;
}
public Vector3 GetWallNormal() => _wallNormal;
public bool TryGetWallTangents(out Vector3 up, out Vector3 right)
{
if (!_isWallRunning)
{
up = right = Vector3.zero;
return false;
}
up = _wallTangentUp;
right = _wallTangentRight;
return true;
}
public bool CanWallRun()
{
return !_isWallRunning && !_motor.GroundingStatus.IsStableOnGround;
}
public void PerformWallJump(CharacterInputs inputs, Quaternion cameraRotation)
{
if (!_isWallRunning || _motor == null) return;
if (!IsWallRunning || !_motor) return;
_isWallRunning = false;
IsWallRunning = false;
Vector3 wallAway = _wallNormal;
Vector3 wallUp = _wallTangentUp;
var wallAway = _wallNormal;
var wallUp = _wallTangentUp;
Vector3 playerForward = cameraRotation * Vector3.forward;
var playerForward = cameraRotation * Vector3.forward;
Vector3 forwardInWallPlane = Vector3.ProjectOnPlane(playerForward, _wallNormal).normalized;
var forwardInWallPlane = Vector3.ProjectOnPlane(playerForward, _wallNormal).normalized;
if (forwardInWallPlane.sqrMagnitude < 0.01f) forwardInWallPlane = _wallTangentRight;
Vector3 jumpDirection =
var jumpDirection =
forwardInWallPlane * 0.2f +
wallAway * 0.4f +
wallUp * 0.4f;
jumpDirection = jumpDirection.normalized;
float wallJumpForce = WallDetachImpulse * 2f;
var wallJumpForce = _wallDetachImpulse * 2f;
Vector3 jumpImpulse = jumpDirection * wallJumpForce;
var jumpImpulse = jumpDirection * wallJumpForce;
_motor.BaseVelocity += jumpImpulse;