diff --git a/Assets/TPSBR/Scripts/Gameplay/Agent/Agent.cs b/Assets/TPSBR/Scripts/Gameplay/Agent/Agent.cs index d353cbd..8bd8061 100644 --- a/Assets/TPSBR/Scripts/Gameplay/Agent/Agent.cs +++ b/Assets/TPSBR/Scripts/Gameplay/Agent/Agent.cs @@ -266,6 +266,9 @@ namespace TPSBR kcc.SetInputDirection(input.MoveDirection.IsZero() == true ? Vector3.zero : kcc.FixedData.TransformRotation * input.MoveDirection.X0Y()); + // Crouch handling (hold to crouch) + _character.SetCrouch(input.Crouch); + if (_agentInput.WasActivated(EGameplayInputAction.ToggleSide, input) == true) { LeftSide = !LeftSide; @@ -335,6 +338,9 @@ namespace TPSBR kcc.SetInputDirection(input.MoveDirection.IsZero() == true ? Vector3.zero : kcc.RenderData.TransformRotation * input.MoveDirection.X0Y()); + // Crouch handling (hold to crouch) + _character.SetCrouch(input.Crouch); + kcc.SetAim(input.Aim); if (_agentInput.WasActivated(EGameplayInputAction.Jump, input) == true && _character.AnimationController.CanJump() == true) diff --git a/Assets/TPSBR/Scripts/Gameplay/Agent/AgentInput.Gamepad.cs b/Assets/TPSBR/Scripts/Gameplay/Agent/AgentInput.Gamepad.cs index b58acb6..2e748fb 100644 --- a/Assets/TPSBR/Scripts/Gameplay/Agent/AgentInput.Gamepad.cs +++ b/Assets/TPSBR/Scripts/Gameplay/Agent/AgentInput.Gamepad.cs @@ -34,6 +34,7 @@ namespace TPSBR _renderInput.Reload |= gamepad.xButton.isPressed; _renderInput.ToggleJetpack |= gamepad.bButton.isPressed; _renderInput.ToggleSide |= gamepad.yButton.isPressed; + _renderInput.Crouch |= gamepad.leftStickButton.isPressed; } } } diff --git a/Assets/TPSBR/Scripts/Gameplay/Agent/AgentInput.Standalone.cs b/Assets/TPSBR/Scripts/Gameplay/Agent/AgentInput.Standalone.cs index f6aedc4..dcb3499 100644 --- a/Assets/TPSBR/Scripts/Gameplay/Agent/AgentInput.Standalone.cs +++ b/Assets/TPSBR/Scripts/Gameplay/Agent/AgentInput.Standalone.cs @@ -48,6 +48,7 @@ namespace TPSBR _renderInput.ToggleJetpack = keyboard.xKey.isPressed; _renderInput.Thrust = keyboard.spaceKey.isPressed; _renderInput.ToggleSide = keyboard.eKey.isPressed; + _renderInput.Crouch = keyboard.leftCtrlKey.isPressed || keyboard.cKey.isPressed; } } } diff --git a/Assets/TPSBR/Scripts/Gameplay/Agent/Character/Character.cs b/Assets/TPSBR/Scripts/Gameplay/Agent/Character/Character.cs index 767f677..3626aa6 100644 --- a/Assets/TPSBR/Scripts/Gameplay/Agent/Character/Character.cs +++ b/Assets/TPSBR/Scripts/Gameplay/Agent/Character/Character.cs @@ -75,6 +75,12 @@ namespace TPSBR [SerializeField] private float _runDispersionMultiplier = 5f; + [Header("Crouch")] + [SerializeField][Tooltip("Target collider height when crouched. If 0, uses StandingHeight * 0.6.")] + private float _crouchHeight = 0f; + [SerializeField][Tooltip("Optional camera Y offset while crouched (visual-only). Not tied to animation.")] + private float _crouchCameraYOffset = 0f; + private KCC _characterController; private CharacterAnimationController _animationController; private Agent _agent; @@ -97,8 +103,45 @@ namespace TPSBR private TransformSampler _fireTransformSampler = new TransformSampler(); private TransformSampler _cameraTransformSampler = new TransformSampler(); + private float _standingHeight; + private float _currentCrouchHeight; + private bool _isCrouched; + private KCCOverlapInfo _tempOverlapInfo = new KCCOverlapInfo(8); + // PUBLIC METHODS + public bool IsCrouched => _isCrouched; + + public void SetCrouch(bool crouchRequested) + { + var kcc = _characterController; + if (kcc == null) + return; + + // Enter crouch + if (crouchRequested == true && _isCrouched == false) + { + kcc.SetHeight(_currentCrouchHeight); + _isCrouched = true; + return; + } + + // Exit crouch: ensure there is enough headroom for standing height + if (crouchRequested == false && _isCrouched == true) + { + // Use current target position and radius + Vector3 position = kcc.Data.TargetPosition; + float radius = kcc.Settings.Radius; + bool blocked = kcc.CapsuleOverlap(_tempOverlapInfo, position, radius, _standingHeight, QueryTriggerInteraction.Ignore); + + if (blocked == false) + { + kcc.SetHeight(_standingHeight); + _isCrouched = false; + } + } + } + public Transform GetCameraHandle() { return _thirdPersonView.CameraHandle; @@ -157,6 +200,11 @@ namespace TPSBR _fireTransformSampler.Clear(); _cameraTransformSampler.Clear(); + + // Crouch setup + _standingHeight = _characterController.Settings.Height; + _currentCrouchHeight = _crouchHeight > 0.0f ? _crouchHeight : (_standingHeight * 0.6f); + _isCrouched = false; } public void OnFixedUpdate() diff --git a/Assets/TPSBR/Scripts/Input/GameplayInput.cs b/Assets/TPSBR/Scripts/Input/GameplayInput.cs index 19bc5af..4776ce7 100644 --- a/Assets/TPSBR/Scripts/Input/GameplayInput.cs +++ b/Assets/TPSBR/Scripts/Input/GameplayInput.cs @@ -4,17 +4,18 @@ namespace TPSBR { using UnityEngine; - public enum EGameplayInputAction - { - Jump = 1, - Aim = 2, - Attack = 3, - Reload = 6, - Interact = 7, - ToggleSide = 8, - ToggleJetpack = 9, - Thrust = 10, - } + public enum EGameplayInputAction + { + Jump = 1, + Aim = 2, + Attack = 3, + Crouch = 4, + Reload = 6, + Interact = 7, + ToggleSide = 8, + ToggleJetpack = 9, + Thrust = 10, + } public struct GameplayInput : INetworkInput { @@ -32,6 +33,7 @@ namespace TPSBR public bool Jump { get { return Actions.IsSet(EGameplayInputAction.Jump); } set { Actions.Set(EGameplayInputAction.Jump, value); } } public bool Aim { get { return Actions.IsSet(EGameplayInputAction.Aim); } set { Actions.Set(EGameplayInputAction.Aim, value); } } public bool Attack { get { return Actions.IsSet(EGameplayInputAction.Attack); } set { Actions.Set(EGameplayInputAction.Attack, value); } } + public bool Crouch { get { return Actions.IsSet(EGameplayInputAction.Crouch); } set { Actions.Set(EGameplayInputAction.Crouch, value); } } public bool Reload { get { return Actions.IsSet(EGameplayInputAction.Reload); } set { Actions.Set(EGameplayInputAction.Reload, value); } } public bool Interact { get { return Actions.IsSet(EGameplayInputAction.Interact); } set { Actions.Set(EGameplayInputAction.Interact, value); } } public bool ToggleSide { get { return Actions.IsSet(EGameplayInputAction.ToggleSide); } set { Actions.Set(EGameplayInputAction.ToggleSide, value); } }