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