Merge branch 'Dev' into Levels2
This commit is contained in:
commit
7e1f7cecc2
4 files changed
+167
-32
No files matched your search
@@ -23,7 +23,11 @@ namespace Code.Configs
|
|||||||
);
|
);
|
||||||
public float
|
public float
|
||||||
slideMinVelocityThreshold = 3f,
|
slideMinVelocityThreshold = 3f,
|
||||||
slideCooldown = 1.5f;
|
slideCooldown = 1.5f,
|
||||||
|
slideColliderHeightScale = 0.5f,
|
||||||
|
slideCameraOffsetY = -0.5f,
|
||||||
|
slideEnterDuration = 0.2f,
|
||||||
|
slideExitDuration = 0.25f;
|
||||||
|
|
||||||
public float
|
public float
|
||||||
leanAngle = 25f,
|
leanAngle = 25f,
|
||||||
|
|||||||
+16
-26
@@ -1,4 +1,3 @@
|
|||||||
using Code.Gameplay.Character.Controller.Input;
|
|
||||||
using Code.Gameplay.Character.Core;
|
using Code.Gameplay.Character.Core;
|
||||||
using KinematicCharacterController;
|
using KinematicCharacterController;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -25,7 +24,6 @@ namespace Code.Gameplay.Character.Controller.Abilities
|
|||||||
private bool _canWallRun;
|
private bool _canWallRun;
|
||||||
|
|
||||||
private KinematicCharacterMotor _motor;
|
private KinematicCharacterMotor _motor;
|
||||||
private CharacterInputHandler _inputHandler;
|
|
||||||
|
|
||||||
public bool IsWallRunning { get; private set; }
|
public bool IsWallRunning { get; private set; }
|
||||||
|
|
||||||
@@ -45,10 +43,9 @@ namespace Code.Gameplay.Character.Controller.Abilities
|
|||||||
_wallContactAngleThreshold = wallContactAngleThreshold;
|
_wallContactAngleThreshold = wallContactAngleThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(KinematicCharacterMotor motor, CharacterInputHandler inputHandler)
|
public void Initialize(KinematicCharacterMotor motor)
|
||||||
{
|
{
|
||||||
_motor = motor;
|
_motor = motor;
|
||||||
_inputHandler = inputHandler;
|
|
||||||
_surfaceAngleCos = Mathf.Cos(Mathf.Deg2Rad * _wallContactAngleThreshold);
|
_surfaceAngleCos = Mathf.Cos(Mathf.Deg2Rad * _wallContactAngleThreshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,13 +85,16 @@ namespace Code.Gameplay.Character.Controller.Abilities
|
|||||||
_wallNormal = wallNormal.normalized;
|
_wallNormal = wallNormal.normalized;
|
||||||
_wallContactPoint = contactPoint;
|
_wallContactPoint = contactPoint;
|
||||||
|
|
||||||
if (_wallTangentUp.sqrMagnitude < 0.01f) _wallTangentUp = Vector3.up;
|
var forwardInWallPlane = Vector3.ProjectOnPlane(_motor.CharacterForward, _wallNormal).normalized;
|
||||||
|
if (forwardInWallPlane.sqrMagnitude < 0.01f)
|
||||||
|
{
|
||||||
|
var fallbackRight = Vector3.Cross(_wallNormal, _wallTangentUp).normalized;
|
||||||
|
var dotWithRight = Vector3.Dot(_motor.CharacterRight, _wallNormal);
|
||||||
|
forwardInWallPlane = dotWithRight < 0 ? fallbackRight : -fallbackRight;
|
||||||
|
}
|
||||||
|
|
||||||
_wallTangentRight = Vector3.Cross(_wallNormal, _wallTangentUp).normalized;
|
_wallTangentRight = forwardInWallPlane;
|
||||||
|
_wallTangentUp = Vector3.Cross(_wallTangentRight, -_wallNormal).normalized;
|
||||||
_wallTangentUp = Vector3.Cross(_wallTangentRight, _wallNormal).normalized;
|
|
||||||
if (Vector3.Dot(_wallTangentUp, Vector3.up) < 0)
|
|
||||||
_wallTangentUp = -_wallTangentUp;
|
|
||||||
|
|
||||||
_motor.ForceUnground();
|
_motor.ForceUnground();
|
||||||
}
|
}
|
||||||
@@ -104,23 +104,11 @@ namespace Code.Gameplay.Character.Controller.Abilities
|
|||||||
if (!IsWallRunning) return;
|
if (!IsWallRunning) return;
|
||||||
if (!IsWallStillPresent()) { DetachFromWall(false); return; }
|
if (!IsWallStillPresent()) { DetachFromWall(false); return; }
|
||||||
|
|
||||||
var moveInputWorld = _inputHandler.MoveInputVector;
|
var forwardInput = inputs.MoveAxisForward;
|
||||||
var moveInWallPlane = Vector3.ProjectOnPlane(moveInputWorld, _wallNormal);
|
var moveDirection = _wallTangentRight * forwardInput;
|
||||||
|
|
||||||
var wsMove = Vector3.Project(moveInWallPlane, _wallTangentRight);
|
|
||||||
|
|
||||||
var ad = inputs.MoveAxisRight;
|
var targetSpeed = moveDirection.sqrMagnitude > 0.01f ? _wallRunSpeed : currentVelocity.magnitude;
|
||||||
|
var targetVelocity = moveDirection.normalized * targetSpeed;
|
||||||
var sideDot = Vector3.Dot(_wallNormal, _motor.CharacterRight);
|
|
||||||
if (sideDot < 0)
|
|
||||||
ad = -ad;
|
|
||||||
|
|
||||||
var adMove = _wallTangentUp * (-ad);
|
|
||||||
|
|
||||||
var finalMove = wsMove + adMove;
|
|
||||||
finalMove = finalMove.normalized * moveInputWorld.magnitude;
|
|
||||||
|
|
||||||
var targetVelocity = finalMove * _wallRunSpeed;
|
|
||||||
|
|
||||||
currentVelocity = Vector3.Lerp(
|
currentVelocity = Vector3.Lerp(
|
||||||
currentVelocity,
|
currentVelocity,
|
||||||
@@ -146,6 +134,8 @@ namespace Code.Gameplay.Character.Controller.Abilities
|
|||||||
private bool IsWallStillPresent()
|
private bool IsWallStillPresent()
|
||||||
{
|
{
|
||||||
if (!_motor) return false;
|
if (!_motor) return false;
|
||||||
|
|
||||||
|
if (_motor.GroundingStatus.IsStableOnGround) return false;
|
||||||
|
|
||||||
var characterCenter = _motor.TransientPosition;
|
var characterCenter = _motor.TransientPosition;
|
||||||
var characterRight = _motor.CharacterRight;
|
var characterRight = _motor.CharacterRight;
|
||||||
|
|||||||
+144
-5
@@ -15,7 +15,7 @@ namespace Code.Gameplay.Character.Controller
|
|||||||
* Реализует физическое движение персонажа с использованием Kinematic Character Controller
|
* Реализует физическое движение персонажа с использованием Kinematic Character Controller
|
||||||
* Обрабатывает ввод пользователя, применяет движение и вращение с учетом поверхности
|
* Обрабатывает ввод пользователя, применяет движение и вращение с учетом поверхности
|
||||||
*
|
*
|
||||||
* Источник: Tvtig, https://www.youtube.com/watch?v=9ibpY64wBYM
|
* Источник: Tvtig, https://www.youtube.com/watch?v=9ibpY64wBYM
|
||||||
*/
|
*/
|
||||||
public class CustomCharacterController : MonoBehaviour, ICharacterController
|
public class CustomCharacterController : MonoBehaviour, ICharacterController
|
||||||
{
|
{
|
||||||
@@ -25,6 +25,20 @@ namespace Code.Gameplay.Character.Controller
|
|||||||
|
|
||||||
[SerializeField] private Transform characterTransform; // Трансформ персонажа (с точкой отслеживания камеры)
|
[SerializeField] private Transform characterTransform; // Трансформ персонажа (с точкой отслеживания камеры)
|
||||||
|
|
||||||
|
[SerializeField] private CapsuleCollider _capsuleCollider;
|
||||||
|
[SerializeField] private Transform _cameraFollowPoint;
|
||||||
|
private Vector3 _originalColliderCenter;
|
||||||
|
private float _originalColliderHeight;
|
||||||
|
private Vector3 _originalFollowPointLocalPosition;
|
||||||
|
private bool _isEnteringSlide;
|
||||||
|
private bool _isExitingSlide;
|
||||||
|
private float _slideTransitionTime;
|
||||||
|
private float _slideTransitionDuration;
|
||||||
|
private float _currentColliderHeight;
|
||||||
|
private Vector3 _currentColliderCenter;
|
||||||
|
private Vector3 _currentFollowPointLocalPosition;
|
||||||
|
private bool _wasSlidingLastFrame;
|
||||||
|
|
||||||
// Подсистемы
|
// Подсистемы
|
||||||
private CharacterInputHandler _inputHandler;
|
private CharacterInputHandler _inputHandler;
|
||||||
private DashMechanic _dashMechanic;
|
private DashMechanic _dashMechanic;
|
||||||
@@ -91,7 +105,15 @@ namespace Code.Gameplay.Character.Controller
|
|||||||
_inputHandler.FirstPersonCameraRotation =
|
_inputHandler.FirstPersonCameraRotation =
|
||||||
motor.Transform.rotation; // Начальное вращение совпадает с персонажемс
|
motor.Transform.rotation; // Начальное вращение совпадает с персонажемс
|
||||||
_wallLeanMechanic.SetModel(characterTransform);
|
_wallLeanMechanic.SetModel(characterTransform);
|
||||||
_wallRunningMechanic.Initialize(motor, _inputHandler);
|
_wallRunningMechanic.Initialize(motor);
|
||||||
|
|
||||||
|
_originalColliderCenter = _capsuleCollider.center;
|
||||||
|
_originalColliderHeight = _capsuleCollider.height;
|
||||||
|
_originalFollowPointLocalPosition = _cameraFollowPoint.localPosition;
|
||||||
|
|
||||||
|
_currentColliderHeight = _originalColliderHeight;
|
||||||
|
_currentColliderCenter = _originalColliderCenter;
|
||||||
|
_currentFollowPointLocalPosition = _originalFollowPointLocalPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Текущий режим камеры для адаптации поведения
|
// Текущий режим камеры для адаптации поведения
|
||||||
@@ -184,14 +206,32 @@ namespace Code.Gameplay.Character.Controller
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_slideMechanic.IsSliding)
|
var wasSliding = _wasSlidingLastFrame;
|
||||||
|
var isSlidingNow = _slideMechanic.IsSliding;
|
||||||
|
|
||||||
|
if (!isSlidingNow)
|
||||||
|
{
|
||||||
_slideMechanic.TryStartSlide(motor, _currentCameraMode, _inputHandler.FirstPersonCameraRotation, _inputHandler.LookInputVector);
|
_slideMechanic.TryStartSlide(motor, _currentCameraMode, _inputHandler.FirstPersonCameraRotation, _inputHandler.LookInputVector);
|
||||||
else
|
isSlidingNow = _slideMechanic.IsSliding;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (isSlidingNow)
|
||||||
|
{
|
||||||
|
case true when !wasSliding:
|
||||||
|
EnterSlideState();
|
||||||
|
break;
|
||||||
|
case false when wasSliding:
|
||||||
|
ExitSlideState();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSlidingNow)
|
||||||
{
|
{
|
||||||
_slideMechanic.HandleSlide(ref currentVelocity, deltaTime, motor);
|
_slideMechanic.HandleSlide(ref currentVelocity, deltaTime, motor);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_wasSlidingLastFrame = isSlidingNow;
|
||||||
|
|
||||||
// === WALL RUNNING: обработка состояния ===
|
// === WALL RUNNING: обработка состояния ===
|
||||||
if (_wallRunningMechanic.IsWallRunning)
|
if (_wallRunningMechanic.IsWallRunning)
|
||||||
{
|
{
|
||||||
@@ -226,6 +266,103 @@ namespace Code.Gameplay.Character.Controller
|
|||||||
isAbilitiesBlocked = true;
|
isAbilitiesBlocked = true;
|
||||||
abilityBlockTimer = duration;
|
abilityBlockTimer = duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EnterSlideState()
|
||||||
|
{
|
||||||
|
_isEnteringSlide = true;
|
||||||
|
_isExitingSlide = false;
|
||||||
|
_slideTransitionTime = 0f;
|
||||||
|
_slideTransitionDuration = _characterConfig.slideEnterDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExitSlideState()
|
||||||
|
{
|
||||||
|
_isExitingSlide = true;
|
||||||
|
_isEnteringSlide = false;
|
||||||
|
_slideTransitionTime = 0f;
|
||||||
|
_slideTransitionDuration = _characterConfig.slideExitDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSlideTransition(float deltaTime)
|
||||||
|
{
|
||||||
|
if (!_isEnteringSlide && !_isExitingSlide) return;
|
||||||
|
|
||||||
|
_slideTransitionTime += deltaTime;
|
||||||
|
var t = Mathf.Clamp01(_slideTransitionTime / _slideTransitionDuration);
|
||||||
|
|
||||||
|
t = Mathf.SmoothStep(0f, 1f, t);
|
||||||
|
|
||||||
|
if (_isEnteringSlide)
|
||||||
|
{
|
||||||
|
var targetHeight = _originalColliderHeight * _characterConfig.slideColliderHeightScale;
|
||||||
|
var targetCenterY = targetHeight * 0.5f - _originalColliderHeight * 0.5f;
|
||||||
|
var targetCenter = _originalColliderCenter + Vector3.up * targetCenterY;
|
||||||
|
|
||||||
|
var targetFollowPos = _originalFollowPointLocalPosition + Vector3.up * _characterConfig.slideCameraOffsetY;
|
||||||
|
|
||||||
|
_currentColliderHeight = Mathf.Lerp(_originalColliderHeight, targetHeight, t);
|
||||||
|
_currentColliderCenter = Vector3.Lerp(_originalColliderCenter, targetCenter, t);
|
||||||
|
_currentFollowPointLocalPosition = Vector3.Lerp(_originalFollowPointLocalPosition, targetFollowPos, t);
|
||||||
|
}
|
||||||
|
else if (_isExitingSlide)
|
||||||
|
{
|
||||||
|
_currentColliderHeight = Mathf.Lerp(_originalColliderHeight * _characterConfig.slideColliderHeightScale, _originalColliderHeight, t);
|
||||||
|
|
||||||
|
var prevHeight = _originalColliderHeight * _characterConfig.slideColliderHeightScale;
|
||||||
|
var prevCenterY = prevHeight * 0.5f - _originalColliderHeight * 0.5f;
|
||||||
|
var prevCenter = _originalColliderCenter + Vector3.up * prevCenterY;
|
||||||
|
|
||||||
|
var prevFollowPos = _originalFollowPointLocalPosition + Vector3.up * _characterConfig.slideCameraOffsetY;
|
||||||
|
|
||||||
|
_currentColliderCenter = Vector3.Lerp(prevCenter, _originalColliderCenter, t);
|
||||||
|
_currentFollowPointLocalPosition = Vector3.Lerp(prevFollowPos, _originalFollowPointLocalPosition, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_capsuleCollider)
|
||||||
|
{
|
||||||
|
_capsuleCollider.height = _currentColliderHeight;
|
||||||
|
_capsuleCollider.center = _currentColliderCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cameraFollowPoint)
|
||||||
|
{
|
||||||
|
_cameraFollowPoint.localPosition = _currentFollowPointLocalPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(t >= 1f)) return;
|
||||||
|
|
||||||
|
if (_isEnteringSlide)
|
||||||
|
{
|
||||||
|
_isEnteringSlide = false;
|
||||||
|
if (_capsuleCollider)
|
||||||
|
{
|
||||||
|
_capsuleCollider.height = _originalColliderHeight * _characterConfig.slideColliderHeightScale;
|
||||||
|
var h = _capsuleCollider.height;
|
||||||
|
_capsuleCollider.center = _originalColliderCenter + Vector3.up * (h * 0.5f - _originalColliderHeight * 0.5f);
|
||||||
|
}
|
||||||
|
if (_cameraFollowPoint)
|
||||||
|
{
|
||||||
|
_cameraFollowPoint.localPosition = _originalFollowPointLocalPosition + Vector3.up * _characterConfig.slideCameraOffsetY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_isExitingSlide)
|
||||||
|
{
|
||||||
|
_isExitingSlide = false;
|
||||||
|
if (_capsuleCollider)
|
||||||
|
{
|
||||||
|
_capsuleCollider.height = _originalColliderHeight;
|
||||||
|
_capsuleCollider.center = _originalColliderCenter;
|
||||||
|
}
|
||||||
|
if (_cameraFollowPoint)
|
||||||
|
{
|
||||||
|
_cameraFollowPoint.localPosition = _originalFollowPointLocalPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentColliderHeight = _capsuleCollider ? _capsuleCollider.height : _originalColliderHeight;
|
||||||
|
_currentColliderCenter = _capsuleCollider ? _capsuleCollider.center : _originalColliderCenter;
|
||||||
|
_currentFollowPointLocalPosition = _cameraFollowPoint ? _cameraFollowPoint.localPosition : _originalFollowPointLocalPosition;
|
||||||
|
}
|
||||||
|
|
||||||
public void BeforeCharacterUpdate(float deltaTime)
|
public void BeforeCharacterUpdate(float deltaTime)
|
||||||
{
|
{
|
||||||
@@ -241,6 +378,8 @@ namespace Code.Gameplay.Character.Controller
|
|||||||
|
|
||||||
public void AfterCharacterUpdate(float deltaTime)
|
public void AfterCharacterUpdate(float deltaTime)
|
||||||
{
|
{
|
||||||
|
UpdateSlideTransition(deltaTime);
|
||||||
|
|
||||||
_wallLeanMechanic.Update(
|
_wallLeanMechanic.Update(
|
||||||
_wallRunningMechanic.IsWallRunning,
|
_wallRunningMechanic.IsWallRunning,
|
||||||
_wallRunningMechanic.GetWallNormal(),
|
_wallRunningMechanic.GetWallNormal(),
|
||||||
|
|||||||
@@ -173,6 +173,8 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier: Assembly-CSharp::Code.Gameplay.Player.CharacterController
|
m_EditorClassIdentifier: Assembly-CSharp::Code.Gameplay.Player.CharacterController
|
||||||
motor: {fileID: 8476708390679839925}
|
motor: {fileID: 8476708390679839925}
|
||||||
characterTransform: {fileID: 4122797476271397740}
|
characterTransform: {fileID: 4122797476271397740}
|
||||||
|
_capsuleCollider: {fileID: 8541228187116599584}
|
||||||
|
_cameraFollowPoint: {fileID: 1047840484662430186}
|
||||||
--- !u!114 &3283650228831796584
|
--- !u!114 &3283650228831796584
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
Reference in new issue
Block a user