2026-05-30 09:16:35 +07:00
using UnityEngine ;
namespace Invector.vCharacterController
{
using IK ;
using vShooter ;
[vClassHeader("SHOOTER/MELEE INPUT", iconName = "inputIcon")]
public class vShooterMeleeInput : vMeleeCombatInput , vIShooterIKController , PlayerController . vILockCamera
{
#region Shooter Variables
[HideInInspector] public vShooterManager shooterManager ;
public vArmAimAlign leftArmAim , rightArmAim ;
public virtual bool isAimingByInput { get ; set ; }
public virtual bool isReloading { get ; set ; }
public virtual bool ignoreIK { get ; set ; }
public virtual bool aimConditions { get ; protected set ; }
public virtual bool allowAttack { get ; set ; }
public virtual bool isCameraRightSwitched { get ; set ; }
protected virtual bool wasAiming { get ; set ; }
protected virtual bool wasAimingWithScope { get ; set ; }
protected virtual bool lockShooterInput { get ; set ; }
protected virtual bool checkCanAimInit { get ; set ; }
protected virtual bool _ignoreIKFromAnimator { get ; set ; }
protected virtual bool _walkingByDefaultWasChanged { get ; set ; }
protected bool _isUsingScopeView ;
protected virtual bool isUsingScopeView { get { return _isUsingScopeView ; } set { _isUsingScopeView = value ; } }
public virtual int onlyArmsLayer { get ; set ; }
public virtual int shotLayer { get ; set ; }
public virtual int shootCountA { get ; set ; }
public virtual float onlyArmsLayerWeight { get ; set ; }
public virtual float supportIKWeight { get ; set ; }
public virtual float weaponIKWeight { get ; set ; }
public virtual float armAlignmentWeight { get ; protected set ; }
protected virtual float _aimTiming { get ; set ; }
protected virtual float checkCanAimOffsetStartX { get ; set ; }
protected virtual float checkCanAimOffsetStartY { get ; set ; }
protected virtual float checkCanAimOffsetEndX { get ; set ; }
protected virtual float checkCanAimOffsetEndY { get ; set ; }
protected virtual float checkCanAimHeight { get ; set ; }
protected virtual float scopeDirectionWeight { get ; set ; }
protected virtual GameObject aimAngleReference { get ; set ; }
protected virtual GameObject lastShooterWeapon { get ; set ; }
protected virtual Vector3 localAimPosition { get ; set ; }
protected virtual Vector3 aimHitPoint { get ; set ; }
protected virtual Vector3 upperArmPosition { get ; set ; }
protected virtual Vector3 muzzlePosition { get ; set ; }
protected virtual Vector3 muzzleForward { get ; set ; }
protected virtual Vector3 ikRotationOffset { get ; set ; }
protected virtual Vector3 ikPositionOffset { get ; set ; }
protected virtual Vector3 scopeLocalPosition { get ; set ; }
protected virtual Vector3 scopeCameraLocalPosition { get ; set ; }
protected virtual Vector3 scopeLocalForward { get ; set ; }
protected virtual Vector3 scopeCameraLocalForward { get ; set ; }
protected virtual Vector3 lastTargetCameraEuler { get ; set ; }
protected virtual Quaternion handRotation { get ; set ; }
protected virtual Quaternion upperArmRotation { get ; set ; }
protected virtual Quaternion upperArmRotationAlignment { get ; set ; }
protected virtual Quaternion handRotationAlignment { get ; set ; }
protected vHeadTrack headTrack ;
protected vControlAimCanvas _controlAimCanvas ;
protected IKAdjust _currentIKAdjust ;
protected RaycastHit checkCanAimHit ;
protected Transform leftHand , rightHand , rightLowerArm , leftLowerArm , rightUpperArm , leftUpperArm ;
#region IKController Interface Properties
public virtual vIKSolver LeftIK { get ; set ; }
public virtual vIKSolver RightIK { get ; set ; }
public virtual vWeaponIKAdjustList WeaponIKAdjustList
{
get
{
if ( shooterManager )
{
return shooterManager . weaponIKAdjustList ;
}
return null ;
}
set
{
if ( shooterManager )
{
shooterManager . weaponIKAdjustList = value ;
}
}
}
public virtual vWeaponIKAdjust CurrentWeaponIK
{
get
{
if ( shooterManager )
{
return shooterManager . CurrentWeaponIK ;
}
return null ;
}
}
public virtual IKAdjust CurrentIKAdjust
{
get
{
if ( CurrentWeaponIK = = null ) return null ;
if ( CurrentIKAdjustStateWithTag ! = ( IKWeaponTag + TargetIKAdjustState ) | | _currentIKAdjust = = null )
{
CurrentIKAdjustStateWithTag = ( IKWeaponTag + TargetIKAdjustState ) ;
CurrentIKAdjustState = TargetIKAdjustState ;
_currentIKAdjust = CurrentWeaponIK . GetIKAdjust ( CurrentIKAdjustState , CurrentActiveWeapon . isLeftWeapon ) ;
}
return _currentIKAdjust ;
}
}
public virtual bool EditingIKGlobalOffset
{
get ; set ;
}
public virtual string DefaultIKAdjustState = > CurrentWeaponIK ? CurrentWeaponIK . GetDefaultStateName ( this ) : string . Empty ;
protected virtual string TargetIKAdjustState = > ( ! IsUsingCustomIKAdjust ? DefaultIKAdjustState : CustomIKAdjustState ) ;
protected virtual string IKWeaponTag = > CurrentActiveWeapon ? CurrentActiveWeapon . weaponCategory + "@" : "" ;
public virtual string CurrentIKAdjustStateWithTag { get ; set ; }
public virtual string CurrentIKAdjustState { get ; protected set ; }
public virtual bool IsUsingCustomIKAdjust = > ! string . IsNullOrEmpty ( CustomIKAdjustState ) ;
public string CustomIKAdjustState { get ; protected set ; }
public virtual void SetCustomIKAdjustState ( string value )
{
if ( ! string . IsNullOrEmpty ( value ) ) CustomIKAdjustState = value ;
}
public virtual void ResetCustomIKAdjustState ( )
{
if ( ! string . IsNullOrEmpty ( CustomIKAdjustState ) ) CustomIKAdjustState = string . Empty ;
}
public virtual bool IsIgnoreIK
{
get
{
return ignoreIK | | _ignoreIKFromAnimator ;
}
}
public virtual bool IsIgnoreSupportHandIK
{
get
{
return cc . IsAnimatorTag ( "IgnoreSupportHandIK" ) ;
}
}
public virtual bool IsSupportHandIKEnabled
{
get ; protected set ;
}
public virtual void UpdateWeaponIK ( )
{
if ( shooterManager )
{
shooterManager . UpdateWeaponIK ( ) ;
if ( CurrentWeaponIK = = null ) return ;
_currentIKAdjust = CurrentWeaponIK . GetIKAdjust ( CurrentIKAdjustState , CurrentActiveWeapon . isLeftWeapon ) ;
}
}
public event IKUpdateEvent onStartUpdateIK ;
public event IKUpdateEvent onFinishUpdateIK ;
/// <summary>
/// Aim position including <seealso cref="vShooterManager.damageLayer"/>.
/// This is a point calculated from <seealso cref="vThirdPersonInput.cameraMain"/> position and <seealso cref="vThirdPersonInput.cameraMain"/> forward to get the desired aim position.
/// Used to align the arms and to define the<see cref="AimPosition"/>
/// </summary>
public virtual Vector3 DesiredAimPosition { get ; protected set ; }
/// <summary>
/// Aim position including <seealso cref="vShooterManager.blockAimLayer"/>.
/// This is a point calculated from <see cref="vShooterWeapon.aimReference"/> of the weapon and <seealso cref="DesiredAimPosition"/>
/// </summary>
public virtual Vector3 AimPosition { get ; protected set ; }
public virtual bool LockAiming
{
get
{
return shooterManager & & shooterManager . alwaysAiming ;
}
set
{
shooterManager . alwaysAiming = value ;
}
}
public virtual bool LockHipFireAiming
{
get ; set ;
}
public virtual bool IsCrouching
{
get
{
return cc . isCrouching ;
}
set
{
cc . isCrouching = value ;
}
}
public virtual bool IsLeftWeapon
{
get
{
return shooterManager & & shooterManager . IsLeftWeapon ;
}
}
public virtual bool LockCamera
{
get
{
return tpCamera & & tpCamera . LockCamera ;
}
set
{
if ( tpCamera )
{
tpCamera . LockCamera = value ;
}
}
}
#endregion
/// <summary>
/// Is Aiming by <see cref="isAimingByInput"/> or <see cref="isAimingByHipFire"/>
/// </summary>
public virtual bool IsAiming
{
get
{
return lockShooterInput = = false & & ( ! cc . isRolling ) & & ( isAimingByInput | | isAimingByHipFire ) ;
}
}
public virtual bool isAimingByHipFire
{
get
{
if ( ! shooterManager . hipfireShot & & _aimTiming > 0 | | ( isReloading & & ! shooterManager . keepAimingWhenReload ) | | isEquipping | | lockShooterInput | | cc . customAction )
{
_aimTiming = 0 ;
return false ;
}
2026-06-04 12:42:00 +07:00
return shooterManager . hipfireShot & & ( _aimTiming > 0 | | ( inputReader ! = null & & inputReader . IsAttackHeld & & shooterManager . CurrentWeapon ! = null ) | | ( ! isAimingByInput & & shootCountA > 0 ) ) ;
2026-05-30 09:16:35 +07:00
}
}
public virtual vControlAimCanvas controlAimCanvas
{
get
{
if ( ! _controlAimCanvas )
{
_controlAimCanvas = FindObjectOfType < vControlAimCanvas > ( ) ;
if ( _controlAimCanvas )
{
_controlAimCanvas . Init ( cc ) ;
}
}
return _controlAimCanvas ;
}
}
public override bool lockInventory
{
get
{
return base . lockInventory | | isReloading | | cc . customAction | | cc . isRolling ;
}
}
#endregion
protected override void Start ( )
{
shooterManager = GetComponent < vShooterManager > ( ) ;
base . Start ( ) ;
checkCanAimHeight = cc . _capsuleCollider . height ;
leftHand = animator . GetBoneTransform ( HumanBodyBones . LeftHand ) ;
rightHand = animator . GetBoneTransform ( HumanBodyBones . RightHand ) ;
leftLowerArm = animator . GetBoneTransform ( HumanBodyBones . LeftLowerArm ) ;
rightLowerArm = animator . GetBoneTransform ( HumanBodyBones . RightLowerArm ) ;
leftUpperArm = animator . GetBoneTransform ( HumanBodyBones . LeftUpperArm ) ;
rightUpperArm = animator . GetBoneTransform ( HumanBodyBones . RightUpperArm ) ;
onlyArmsLayer = animator . GetLayerIndex ( "OnlyArms" ) ;
shotLayer = animator . GetLayerIndex ( "Shot" ) ;
aimAngleReference = new GameObject ( "aimAngleReference" ) ;
aimAngleReference . tag = ( "Ignore Ragdoll" ) ;
aimAngleReference . transform . rotation = transform . rotation ;
var aimAngleParent = animator . GetBoneTransform ( HumanBodyBones . Head ) ;
aimAngleReference . transform . SetParent ( aimAngleParent ) ;
aimAngleReference . transform . localPosition = Vector3 . zero ;
headTrack = GetComponent < vHeadTrack > ( ) ;
if ( headTrack )
{
headTrack . onInitUpdate . AddListener ( UpdateAimAngleReference ) ;
}
if ( ! controlAimCanvas )
{
Debug . LogWarning ( "Missing the AimCanvas, drag and drop the prefab to this scene in order to Aim" , gameObject ) ;
}
muzzlePosition = Vector3 . forward * cc . _capsuleCollider . radius * 2 ;
muzzleForward = Vector3 . forward ;
}
protected override void LateUpdate ( )
{
if ( ( ! updateIK & & animator . updateMode = = AnimatorUpdateMode . Fixed ) )
{
return ;
}
base . LateUpdate ( ) ;
UpdateAimBehaviour ( ) ;
}
#region Shooter Inputs
protected virtual void Reset ( )
{
}
/// <summary>
/// Lock only shooter inputs
/// </summary>
/// <param name="value">lock or unlock</param>
public virtual void SetLockShooterInput ( bool value )
{
lockShooterInput = value ;
if ( value )
{
isBlocking = false ;
isAimingByInput = false ;
_aimTiming = 0f ;
if ( controlAimCanvas )
{
controlAimCanvas . SetActiveAim ( false ) ;
controlAimCanvas . SetActiveScopeCamera ( false ) ;
}
}
}
public override void SetLockAllInput ( bool value )
{
base . SetLockAllInput ( value ) ;
SetLockShooterInput ( value ) ;
}
/// <summary>
/// Set Always Aiming
/// </summary>
/// <param name="value">value to set aiming</param>
public virtual void SetAlwaysAim ( bool value )
{
shooterManager . alwaysAiming = value ;
}
/// <summary>
/// Current active weapon (if weapon gameobject is disabled this return null)
/// </summary>
public virtual vShooterWeapon CurrentActiveWeapon
{
get
{
return shooterManager . CurrentActiveWeapon ;
}
}
/// <summary>
/// Handles all the Controller Input
/// </summary>
public override void InputHandle ( )
{
if ( cc = = null | | cc . isDead )
{
return ;
}
#region BasicInput
if ( ! cc . ragdolled & & ! lockInput )
{
MoveInput ( ) ;
SprintInput ( ) ;
CrouchInput ( ) ;
StrafeInput ( ) ;
JumpInput ( ) ;
RollInput ( ) ;
}
#endregion
#region MeleeInput
if ( MeleeAttackConditions ( ) & & ! IsAiming & & ! isReloading & & ! lockMeleeInput & & ! CurrentActiveWeapon )
{
if ( shooterManager . canUseMeleeWeakAttack_H | | shooterManager . CurrentWeapon = = null )
{
MeleeWeakAttackInput ( ) ;
}
if ( shooterManager . canUseMeleeStrongAttack_H | | shooterManager . CurrentWeapon = = null )
{
MeleeStrongAttackInput ( ) ;
}
if ( shooterManager . canUseMeleeBlock_H | | shooterManager . CurrentWeapon = = null )
{
BlockingInput ( ) ;
}
else
{
isBlocking = false ;
}
}
#endregion
#region ShooterInput
if ( lockShooterInput )
{
isAimingByInput = false ;
_aimTiming = 0 ;
if ( controlAimCanvas ! = null )
{
if ( controlAimCanvas . isAimActive | | controlAimCanvas . isScopeCameraActive )
{
isUsingScopeView = false ;
controlAimCanvas . DisableAim ( ) ;
}
}
}
else if ( shooterManager . CurrentWeapon )
{
if ( MeleeAttackConditions ( ) & & ( ! IsAiming | | shooterManager . canUseMeleeAiming ) )
{
if ( shooterManager . canUseMeleeWeakAttack_E )
{
MeleeWeakAttackInput ( ) ;
}
if ( shooterManager . canUseMeleeStrongAttack_E )
{
MeleeStrongAttackInput ( ) ;
}
if ( shooterManager . canUseMeleeBlock_E )
{
BlockingInput ( ) ;
}
else
{
isBlocking = false ;
}
}
else
{
isBlocking = false ;
}
if ( shooterManager = = null | | CurrentActiveWeapon = = null | | isEquipping )
{
if ( _walkingByDefaultWasChanged )
{
_walkingByDefaultWasChanged = false ;
ResetWalkByDefault ( ) ;
}
if ( IsAiming )
{
isAimingByInput = false ;
_aimTiming = 0 ;
if ( ! cc . lockInStrafe & & cc . isStrafing )
{
cc . Strafe ( ) ;
}
if ( controlAimCanvas ! = null )
{
if ( controlAimCanvas . isAimActive | | controlAimCanvas . isScopeCameraActive )
{
isUsingScopeView = false ;
controlAimCanvas . DisableAim ( ) ;
}
}
if ( shooterManager & & shooterManager . CurrentWeapon & & shooterManager . CurrentWeapon . chargeWeapon & & shooterManager . CurrentWeapon . powerCharge ! = 0 )
{
CurrentActiveWeapon . powerCharge = 0 ;
}
shootCountA = 0 ;
}
}
else
{
AimInput ( ) ;
ShotInput ( ) ;
ReloadInput ( ) ;
SwitchCameraSideInput ( ) ;
ScopeViewInput ( ) ;
}
}
else
{
isAimingByInput = false ;
_aimTiming = 0 ;
if ( ! cc . lockInStrafe & & cc . isStrafing & & cc . locomotionType ! = vThirdPersonMotor . LocomotionType . OnlyStrafe )
{
cc . Strafe ( ) ;
}
if ( _walkingByDefaultWasChanged & & ! IsAiming )
{
_walkingByDefaultWasChanged = false ;
ResetWalkByDefault ( ) ;
}
if ( controlAimCanvas ! = null )
{
if ( controlAimCanvas . isAimActive | | controlAimCanvas . isScopeCameraActive )
{
isUsingScopeView = false ;
controlAimCanvas . DisableAim ( ) ;
}
}
}
#endregion
}
/// <summary>
/// Override the Melee TriggerStrongAttack method to add the call to CancelReload when attacking
/// </summary>
public override void TriggerStrongAttack ( )
{
shooterManager . CancelReload ( ) ;
base . TriggerStrongAttack ( ) ;
}
/// <summary>
/// Control Aim Input
/// </summary>
public virtual void AimInput ( )
{
//Change Rotation Method While Aiming
cc . strafeSpeed . rotateWithCamera = IsAiming ? true : cc . strafeSpeed . defaultRotateWithCamera ;
if ( _walkingByDefaultWasChanged & & ! IsAiming )
{
_walkingByDefaultWasChanged = false ;
ResetWalkByDefault ( ) ;
}
if ( ! shooterManager | | isEquipping | | isAttacking | | ( isReloading & & ( isUsingScopeView | | ! shooterManager . keepAimingWhenReload ) ) )
{
if ( ! isReloading | | ( isReloading & & ! shooterManager . keepAimingWhenReload ) )
{
isAimingByInput = false ;
ResetWalkByDefault ( ) ;
_walkingByDefaultWasChanged = false ;
if ( cc . isStrafing & & cc . locomotionType ! = vThirdPersonMotor . LocomotionType . OnlyStrafe )
{
cc . Strafe ( ) ;
}
}
if ( controlAimCanvas )
{
if ( controlAimCanvas . isAimActive | | controlAimCanvas . isScopeCameraActive )
{
isUsingScopeView = false ;
controlAimCanvas . DisableAim ( ) ;
}
}
return ;
}
if ( LockHipFireAiming ) _aimTiming = 1f ;
if ( shooterManager . onlyWalkWhenAiming & & ( ! isReloading | | shooterManager . keepAimingWhenReload ) )
{
if ( isAimingByInput )
{
SetWalkByDefault ( true ) ;
_walkingByDefaultWasChanged = true ;
}
else
{
ResetWalkByDefault ( ) ;
_walkingByDefaultWasChanged = false ;
}
}
if ( cc . locomotionType = = vThirdPersonMotor . LocomotionType . OnlyFree )
{
Debug . LogWarning ( "Shooter behaviour needs to be OnlyStrafe or Free with Strafe. \n Please change the Locomotion Type." ) ;
return ;
}
if ( shooterManager . hipfireShot & & ! LockHipFireAiming )
{
// countdown for the hipfire to reset the aim back to idle
if ( _aimTiming > 0 & & CanRotateAimArm ( ) )
{
_aimTiming - = Time . deltaTime ;
}
// reset the aimTimming if you sprint while still aiming through the hipfire
2026-05-31 10:31:59 +07:00
// if (sprintInput.GetButtonDown() && _aimTiming > 0f)
// {
// _aimTiming = 0f;
// }
2026-06-02 10:00:42 +07:00
if ( inputReader ! = null & & inputReader . IsSprintHeld & & _aimTiming > 0f )
2026-05-30 09:16:35 +07:00
{
_aimTiming = 0f ;
}
}
if ( ! shooterManager | | ! CurrentActiveWeapon )
{
if ( controlAimCanvas )
{
if ( controlAimCanvas . isAimActive | | controlAimCanvas . isScopeCameraActive )
{
isUsingScopeView = false ;
controlAimCanvas . DisableAim ( ) ;
}
}
isAimingByInput = false ;
if ( cc . isStrafing )
{
cc . Strafe ( ) ;
}
return ;
}
if ( ! cc . isRolling )
{
2026-05-31 10:31:59 +07:00
isAimingByInput = ( ! isReloading | | shooterManager . keepAimingWhenReload ) & & ( inputReader . IsAimHeld | | ( shooterManager . alwaysAiming & & CurrentActiveWeapon ) ) & & ! cc . ragdolled & & ! cc . customAction ;
2026-05-30 09:16:35 +07:00
}
2026-06-04 12:42:00 +07:00
if ( inputReader . ConsumeAimReleased ( ) & & ! inputReader . IsAttackHeld )
2026-05-30 09:16:35 +07:00
{
_aimTiming = 0f ;
}
if ( headTrack )
{
headTrack . alwaysFollowCamera = isAimingByInput ;
}
if ( cc . locomotionType = = vThirdPersonMotor . LocomotionType . FreeWithStrafe )
{
if ( ! cc . lockInStrafe )
{
if ( IsAiming & & ! cc . isStrafing )
{
cc . Strafe ( ) ;
}
else if ( ! IsAiming & & cc . isStrafing )
{
cc . Strafe ( ) ;
}
}
}
if ( IsAiming & & shooterManager . onlyWalkWhenAiming & & cc . isSprinting )
{
cc . isSprinting = false ;
}
if ( controlAimCanvas )
{
if ( ! isUsingScopeView )
{
if ( IsAiming & & ! controlAimCanvas . isAimActive )
{
controlAimCanvas . SetActiveAim ( true ) ;
}
if ( ! IsAiming & & controlAimCanvas . isAimActive )
{
controlAimCanvas . SetActiveAim ( false ) ;
}
}
}
if ( shooterManager . rWeapon )
{
shooterManager . rWeapon . SetActiveAim ( IsAiming & & aimConditions ) ;
shooterManager . rWeapon . SetActiveScope ( IsAiming & & isUsingScopeView ) ;
}
else if ( shooterManager . lWeapon )
{
shooterManager . lWeapon . SetActiveAim ( IsAiming & & aimConditions ) ;
shooterManager . lWeapon . SetActiveScope ( IsAiming & & isUsingScopeView ) ;
}
}
/// <summary>
/// Control shot inputs (primary and secundary weapons)
/// </summary>
public virtual void ShotInput ( )
{
if ( ! shooterManager | | CurrentActiveWeapon = = null | | cc . isDead | | isReloading | | isAttacking | | isEquipping )
{
if ( shooterManager & & shooterManager . CurrentWeapon . chargeWeapon & & shooterManager . CurrentWeapon . powerCharge ! = 0 )
{
CurrentActiveWeapon . powerCharge = 0 ;
}
shootCountA = 0 ;
return ;
}
if ( IsAiming & & ! shooterManager . isShooting & & aimConditions )
{
if ( CurrentActiveWeapon | | ( shooterManager . CurrentWeapon & & shooterManager . hipfireShot ) )
{
2026-05-31 10:31:59 +07:00
// HandleShotCount(shooterManager.CurrentWeapon, shotInput.GetButton());
HandleShotCount ( shooterManager . CurrentWeapon , inputReader . IsAttackHeld ) ;
2026-05-30 09:16:35 +07:00
}
}
else if ( ! IsAiming )
{
if ( shooterManager . CurrentWeapon . chargeWeapon & & shooterManager . CurrentWeapon . powerCharge ! = 0 )
{
CurrentActiveWeapon . powerCharge = 0 ;
}
shootCountA = 0 ;
}
}
/// <summary>
/// Control Shot count
/// </summary>
/// <param name="weapon">target weapon</param>
/// <param name="weaponInput">check input</param>
public virtual void HandleShotCount ( vShooterWeapon weapon , bool weaponInput = true )
{
if ( weapon . chargeWeapon )
{
if ( shooterManager . WeaponHasLoadedAmmo ( ) & & weapon . powerCharge < 1 & & weaponInput )
{
if ( shooterManager . hipfireShot )
{
_aimTiming = shooterManager . HipfireAimTime ;
}
weapon . powerCharge + = Time . fixedDeltaTime * weapon . chargeSpeed ;
}
else if ( ( weapon . powerCharge > = 1 & & weapon . autoShotOnFinishCharge & & weaponInput ) | |
( ! weaponInput & & IsAiming & & weapon . powerCharge > 0f ) )
{
if ( shooterManager . hipfireShot )
{
_aimTiming = shooterManager . HipfireAimTime ;
}
shootCountA = 1 ;
}
animator . SetFloat ( vAnimatorParameters . PowerCharger , weapon . powerCharge ) ;
}
else if ( weapon . automaticWeapon & & weaponInput )
{
if ( shooterManager . hipfireShot & & ! isAimingByInput )
{
_aimTiming = shooterManager . HipfireAimTime ;
}
shootCountA = 1 ;
}
else if ( weaponInput )
{
if ( shooterManager . hipfireShot & & ! isAimingByInput )
{
_aimTiming = shooterManager . HipfireAimTime ;
}
if ( allowAttack = = false )
{
shootCountA = 1 ;
allowAttack = true ;
}
}
else
{
allowAttack = false ;
}
}
/// <summary>
/// Do Shots by shotcount after Ik behaviour updated
/// </summary>
public virtual void DoShots ( )
{
if ( CanDoShots ( ) )
{
TriggerShot ( ) ;
}
}
public virtual void TriggerShot ( )
{
animator . SetFloat ( vAnimatorParameters . Shot_ID , shooterManager . GetShotID ( ) ) ;
shooterManager . Shoot ( AimPosition , ! isAimingByInput ) ;
if ( CurrentActiveWeapon . chargeWeapon ) CurrentActiveWeapon . powerCharge = 0 ;
shootCountA - - ;
}
/// <summary>
/// Reload current weapon
/// </summary>
public virtual void ReloadInput ( )
{
if ( ! shooterManager | | CurrentActiveWeapon = = null | | isReloading | | cc . customAction | | shooterManager . isShooting | | cc . ragdolled )
{
return ;
}
2026-06-04 12:42:00 +07:00
if ( inputReader . ConsumeReload ( ) )
2026-05-30 09:16:35 +07:00
{
shootCountA = 0 ;
_aimTiming = 0f ;
shooterManager . ReloadWeapon ( ) ;
}
else
{
if ( CurrentActiveWeapon . autoReload & & ! shooterManager . WeaponHasLoadedAmmo ( ) & & shooterManager . WeaponHasUnloadedAmmo ( ) )
{
switch ( CurrentActiveWeapon . autoReloadStyle )
{
case vShooterWeapon . AutoReloadStyle . WhenAiming :
if ( IsAiming ) shooterManager . ReloadWeapon ( ) ;
break ;
case vShooterWeapon . AutoReloadStyle . WhenShot :
2026-06-04 12:42:00 +07:00
if ( inputReader . ConsumeAttack ( ) ) shooterManager . ReloadWeapon ( ) ;
2026-05-30 09:16:35 +07:00
break ;
case vShooterWeapon . AutoReloadStyle . WhenAmmoAvailable :
shooterManager . ReloadWeapon ( ) ;
break ;
}
}
}
}
/// <summary>
/// Control Switch Camera side Input
/// </summary>
public virtual void SwitchCameraSideInput ( )
{
2026-06-04 12:42:00 +07:00
if ( tpCamera = = null | | inputReader = = null )
2026-05-30 09:16:35 +07:00
{
return ;
}
2026-06-04 12:42:00 +07:00
if ( inputReader . ConsumeSwitchSide ( ) )
2026-05-30 09:16:35 +07:00
{
SwitchCameraSide ( ) ;
}
}
/// <summary>
/// Change side view of the <seealso cref="Invector.vCamera.vThirdPersonCamera"/>
/// </summary>
public virtual void SwitchCameraSide ( )
{
if ( tpCamera = = null )
{
return ;
}
isCameraRightSwitched = ! isCameraRightSwitched ;
tpCamera . SwitchRight ( isCameraRightSwitched ) ;
}
/// <summary>
/// Reset the Aiming and AimCanvas to false
/// </summary>
public virtual void CancelAiming ( )
{
isAimingByInput = false ;
_aimTiming = 0 ;
if ( controlAimCanvas )
{
controlAimCanvas . SetActiveAim ( false ) ;
controlAimCanvas . SetActiveScopeCamera ( false ) ;
}
}
/// <summary>
/// Control Scope view input
/// </summary>
public virtual void ScopeViewInput ( )
{
if ( ! shooterManager | | CurrentActiveWeapon = = null )
{
return ;
}
2026-06-04 12:42:00 +07:00
if ( isAimingByInput & & aimConditions & & ( inputReader . ConsumeScopeView ( ) | | CurrentActiveWeapon . onlyUseScopeUIView ) )
2026-05-30 09:16:35 +07:00
{
if ( controlAimCanvas & & CurrentActiveWeapon . scopeTarget )
{
if ( ! isUsingScopeView & & CurrentActiveWeapon . onlyUseScopeUIView )
{
EnableScopeView ( ) ;
}
else if ( isUsingScopeView & & ! CurrentActiveWeapon . onlyUseScopeUIView )
{
DisableScopeView ( ) ;
}
else if ( ! isUsingScopeView )
{
EnableScopeView ( ) ;
}
}
}
else if ( isUsingScopeView & & ( controlAimCanvas & & ! isAimingByInput | | controlAimCanvas & & ! aimConditions | | cc . isRolling ) )
{
DisableScopeView ( ) ;
}
}
/// <summary>
/// Enable scope view (just if is aiming)
/// </summary>
public virtual void EnableScopeView ( )
{
if ( ! isAimingByInput | | ! controlAimCanvas . scopeBackgroundCamera | | isReloading | | isEquipping )
{
return ;
}
isUsingScopeView = true ;
controlAimCanvas . SetActiveScopeCamera ( true , CurrentActiveWeapon . useUI ) ;
controlAimCanvas . SetActiveAim ( false ) ;
}
/// <summary>
/// Disable scope view
/// </summary>
public virtual void DisableScopeView ( )
{
if ( ! controlAimCanvas . scopeBackgroundCamera ) return ;
isUsingScopeView = false ;
var lastState = tpCamera . useSmooth ;
tpCamera . useSmooth = false ;
tpCamera . mouseX = lastTargetCameraEuler . y ;
tpCamera . mouseY = lastTargetCameraEuler . x ;
tpCamera . CameraMovement ( ) ;
tpCamera . useSmooth = lastState ;
controlAimCanvas . SetActiveScopeCamera ( false ) ;
controlAimCanvas . SetActiveAim ( IsAiming ) ;
}
#endregion
#region Update Animations
protected override void UpdateMeleeAnimations ( )
{
// disable the onlyarms layer and run the melee methods if the character is not using any shooter weapon
if ( ! animator )
{
return ;
}
// find states with the IsEquipping tag
isEquipping = cc . IsAnimatorTag ( "IsEquipping" ) ;
// Check if Animator state need to ignore IK
_ignoreIKFromAnimator = cc . IsAnimatorTag ( "IgnoreIK" ) ;
if ( cc . customAction )
{
ResetMeleeAnimations ( ) ;
ResetShooterAnimations ( ) ;
// reset to the default camera state
UpdateCameraStates ( ) ;
// reset the aiming
CancelAiming ( ) ;
return ;
}
// update MeleeManager Animator Properties
if ( ( shooterManager = = null | | ! CurrentActiveWeapon ) & & meleeManager )
{
base . UpdateMeleeAnimations ( ) ;
// set the uppbody id (armsonly layer)
//animator.SetFloat(vAnimatorParameters.UpperBody_ID, 0, .2f, Time.fixedDeltaTime);
// turn on the onlyarms layer to aim
onlyArmsLayerWeight = Mathf . Lerp ( onlyArmsLayerWeight , 0 , 6f * vTime . fixedDeltaTime ) ;
animator . SetLayerWeight ( onlyArmsLayer , onlyArmsLayerWeight ) ;
// reset aiming parameter
animator . SetBool ( vAnimatorParameters . IsAiming , false ) ;
// animator.SetBool(vAnimatorParameters.IsHipFire, false);
isReloading = false ;
}
// update ShooterManager Animator Properties
else if ( shooterManager & & CurrentActiveWeapon )
{
UpdateShooterAnimations ( ) ;
}
// reset Animator Properties
else
{
ResetMoveSet ( ) ;
ResetMeleeAnimations ( ) ;
ResetShooterAnimations ( ) ;
}
}
public virtual void ResetMoveSet ( )
{
cc . animator . SetFloat ( vAnimatorParameters . MoveSet_ID , defaultMoveSetID , . 2f , Time . fixedDeltaTime ) ;
}
public virtual void ResetShooterAnimations ( )
{
if ( shooterManager = = null | | ! animator )
{
return ;
}
// set the uppbody id (armsonly layer)
animator . SetFloat ( vAnimatorParameters . UpperBody_ID , 0 , . 2f , vTime . fixedDeltaTime ) ;
// set if the character can aim or not (upperbody layer)
animator . SetBool ( vAnimatorParameters . CanAim , false ) ;
// character is aiming
animator . SetBool ( vAnimatorParameters . IsAiming , false ) ;
// animator.SetBool(vAnimatorParameters.IsHipFire, false);
// turn on the onlyarms layer to aim
onlyArmsLayerWeight = Mathf . Lerp ( onlyArmsLayerWeight , 0 , 6f * vTime . fixedDeltaTime ) ;
animator . SetLayerWeight ( onlyArmsLayer , onlyArmsLayerWeight ) ;
}
protected virtual void UpdateShooterAnimations ( )
{
if ( shooterManager = = null )
{
return ;
}
// turn on the onlyarms layer to aim
onlyArmsLayerWeight = Mathf . Lerp ( onlyArmsLayerWeight , ( CurrentActiveWeapon | | isEquipping ) ? 1f : 0f , shooterManager . onlyArmsSpeed * vTime . fixedDeltaTime ) ;
animator . SetLayerWeight ( onlyArmsLayer , onlyArmsLayerWeight ) ;
if ( CurrentActiveWeapon & & IsAiming ) animator . SetLayerWeight ( shotLayer , isUsingScopeView ? CurrentActiveWeapon . scopeShootAnimationWeight : 1f ) ;
if ( CurrentActiveWeapon & & ! shooterManager . useDefaultMovesetWhenNotAiming | | IsAiming )
{
// set the move set id (base layer)
animator . SetFloat ( vAnimatorParameters . MoveSet_ID , shooterMoveSetID , . 1f , vTime . fixedDeltaTime ) ;
}
else if ( ! CurrentActiveWeapon & & ! shooterManager . useDefaultMovesetWhenNotAiming | | shooterManager . useDefaultMovesetWhenNotAiming )
{
// set the move set id (base layer)
animator . SetFloat ( vAnimatorParameters . MoveSet_ID , defaultMoveSetID , . 1f , vTime . fixedDeltaTime ) ;
}
animator . SetInteger ( vAnimatorParameters . DefenseID , DefenseID ) ;
// set the isBlocking false while using shooter weapons
animator . SetBool ( vAnimatorParameters . IsBlocking , isBlocking ) ;
// set the uppbody id (armsonly layer)
animator . SetFloat ( vAnimatorParameters . UpperBody_ID , shooterManager . GetUpperBodyID ( ) ) ;
// set if the character can aim or not (upperbody layer)
animator . SetBool ( vAnimatorParameters . CanAim , aimConditions ) ;
// character is aiming
animator . SetBool ( vAnimatorParameters . IsAiming , IsAiming ) ;
// animator.SetBool(vAnimatorParameters.IsHipFire, isAimingByHipFire);
// find states with the Reload tag
isReloading = cc . IsAnimatorTag ( "IsReloading" ) | | shooterManager . isReloadingWeapon ;
vAnimatorParameter ap = new vAnimatorParameter ( animator , "IsReloading" ) ;
}
/// <summary>
/// Current moveset id based if is using weapon or not
/// </summary>
public virtual int shooterMoveSetID
{
get
{
int id = shooterManager . GetMoveSetID ( ) ;
if ( id = = 0 | | overrideWeaponMoveSetID )
{
id = defaultMoveSetID ;
}
return id ;
}
}
public override void UpdateCameraStates ( )
{
// CAMERA STATE - you can change the CameraState here, the bool means if you want lerp of not, make sure to use the same CameraState String that you named on TPCameraListData
if ( ignoreTpCamera )
{
return ;
}
if ( tpCamera = = null )
{
tpCamera = FindObjectOfType < vCamera . vThirdPersonCamera > ( ) ;
if ( tpCamera = = null )
{
return ;
}
if ( tpCamera )
{
tpCamera . SetMainTarget ( this . transform ) ;
tpCamera . Init ( ) ;
}
}
if ( changeCameraState )
{
tpCamera . ChangeState ( customCameraState , customlookAtPoint , true ) ;
}
else if ( cc . isCrouching & & ! isAimingByInput )
{
tpCamera . ChangeState ( "Crouch" , true ) ;
}
else if ( cc . isStrafing & & ! isAimingByInput )
{
tpCamera . ChangeState ( "Strafing" , true ) ;
}
else if ( isAimingByInput & & CurrentActiveWeapon )
{
if ( isUsingScopeView )
{
if ( string . IsNullOrEmpty ( CurrentActiveWeapon . customScopeCameraState ) )
{
tpCamera . ChangeState ( cc . isCrouching ? "CrouchingAiming" : "Aiming" , true ) ;
}
else
{
tpCamera . ChangeState ( CurrentActiveWeapon . customScopeCameraState , true ) ;
}
}
else
{
if ( string . IsNullOrEmpty ( CurrentActiveWeapon . customAimCameraState ) )
{
tpCamera . ChangeState ( cc . isCrouching ? "CrouchingAiming" : "Aiming" , true ) ;
}
else
{
tpCamera . ChangeState ( CurrentActiveWeapon . customAimCameraState , true ) ;
}
}
}
else
{
tpCamera . ChangeState ( "Default" , true ) ;
}
}
#endregion
#region Update Aim
protected Ray ray = new Ray ( ) ;
/// <summary>
/// Calculate the <see cref="DesiredAimPosition"/>
/// </summary>
protected virtual void UpdateDesiredAimPosition ( )
{
if ( ! shooterManager )
{
return ;
}
if ( CurrentActiveWeapon = = null )
{
return ;
}
if ( isUsingScopeView )
{
DesiredAimPosition = cameraMain . transform . TransformPoint ( localAimPosition ) ;
return ;
}
var camT = cameraMain . transform ;
var vOrigin = camT . position ;
var desiredAimPoint = camT . position + camT . forward * cameraMain . farClipPlane ;
ray . origin = vOrigin ;
ray . direction = camT . forward ;
if ( shooterManager . raycastAimTarget & & CurrentActiveWeapon . raycastAimTarget )
{
RaycastHit hit ;
if ( Physics . Raycast ( ray , out hit , cameraMain . farClipPlane , shooterManager . damageLayer ) )
{
bool canAimToHit = false ;
var dist = cameraMain . farClipPlane ;
//Check if hit object is child of character transform
if ( hit . collider . transform . IsChildOf ( transform ) )
{
var collider = hit . collider ;
//Clear last hit infor
hit = new RaycastHit ( ) ;
var hits = Physics . RaycastAll ( ray , cameraMain . farClipPlane , shooterManager . damageLayer ) ;
///Try to find other hit point next to character transform
for ( int i = 0 ; i < hits . Length ; i + + )
{
if ( hits [ i ] . distance < dist & & hits [ i ] . collider . gameObject ! = collider . gameObject & & ! hits [ i ] . collider . transform . IsChildOf ( transform ) )
{
dist = hits [ i ] . distance ;
hit = hits [ i ] ;
canAimToHit = true ;
}
}
}
else canAimToHit = true ;
if ( canAimToHit )
{
desiredAimPoint = hit . point ;
}
}
}
var localAimPoint = aimAngleReference . transform . InverseTransformPoint ( desiredAimPoint ) ;
if ( ! isUsingScopeView )
{
if ( ! shooterManager . ignoreBackAimPoint ) localAimPoint . z = Mathf . Max ( localAimPoint . z , ( muzzlePosition . z + shooterManager . backAimPointOffset + shooterManager . minAimHitPointDistance ) ) ;
desiredAimPoint = aimAngleReference . transform . TransformPoint ( localAimPoint ) ;
}
DesiredAimPosition = desiredAimPoint ;
localAimPosition = cameraMain . transform . InverseTransformPoint ( DesiredAimPosition ) ;
}
/// <summary>
/// Calculate the <see cref="AimPosition"/>
/// </summary>
protected virtual void UpdateAimPosition ( )
{
if ( ! shooterManager )
{
return ;
}
if ( CurrentActiveWeapon = = null )
{
return ;
}
Vector3 rayDirection = DesiredAimPosition - CurrentActiveWeapon . aimReference . position ;
ray . origin = CurrentActiveWeapon . aimReference . position ;
ray . direction = rayDirection ;
Vector3 desiredAimPoint = DesiredAimPosition ;
RaycastHit hit ;
var castLayer = shooterManager . blockAimLayer ;
var castDistance = rayDirection . magnitude ;
var castRay = ray ;
if ( Physics . Raycast ( castRay , out hit , castDistance , castLayer ) )
{
bool canAimToHit = false ;
var dist = cameraMain . farClipPlane ;
//Check if hit object is child of character transform
if ( hit . collider . transform . IsChildOf ( transform ) )
{
var collider = hit . collider ;
//Clear last hit infor
hit = new RaycastHit ( ) ;
var hits = Physics . RaycastAll ( castRay , castDistance , castLayer ) ;
///Try to find other hit point next to character transform
for ( int i = 0 ; i < hits . Length ; i + + )
{
if ( hits [ i ] . distance < dist & & hits [ i ] . collider . gameObject ! = collider . gameObject & & ! hits [ i ] . collider . transform . IsChildOf ( transform ) )
{
dist = hits [ i ] . distance ;
hit = hits [ i ] ;
canAimToHit = true ;
}
}
}
else canAimToHit = true ;
if ( hit . collider & & canAimToHit )
{
desiredAimPoint = hit . point ;
}
}
AimPosition = desiredAimPoint ;
if ( isUsingScopeView )
{
var rotation = Quaternion . LookRotation ( AimPosition - cameraMain . transform . position , cameraMain . transform . up ) ;
lastTargetCameraEuler = rotation . eulerAngles . NormalizeAngle ( ) ;
}
if ( isAimingByInput )
{
shooterManager . CameraSway ( ) ;
}
}
public override void ControlRotation ( )
{
base . ControlRotation ( ) ;
}
public override void CameraInput ( )
{
base . CameraInput ( ) ;
}
#endregion
#region IK behaviour
protected virtual void UpdateAimBehaviour ( )
{
if ( cc . isDead | | cc . ragdolled )
{
return ;
}
UpdateDesiredAimPosition ( ) ;
UpdateHeadTrack ( ) ;
OnStartUpdateIK ( ) ;
CheckAimConditions ( ) ;
if ( shooterManager & & CurrentActiveWeapon )
{
UpdateIKAdjust ( shooterManager . IsLeftWeapon ) ;
AlignArmToAimPosition ( shooterManager . IsLeftWeapon ) ;
UpdateArmsIK ( shooterManager . IsLeftWeapon ) ;
}
UpdateAimPosition ( ) ;
OnFinishUpdateIK ( ) ;
UpdateAimHud ( ) ;
DoShots ( ) ;
CheckAimEvents ( ) ;
}
protected virtual void CheckAimEvents ( )
{
if ( IsAiming ! = wasAiming )
{
wasAiming = IsAiming ;
if ( IsAiming ) shooterManager . onEnableAim . Invoke ( shooterManager . CurrentWeapon ) ;
else shooterManager . onDisableAim . Invoke ( shooterManager . CurrentWeapon ) ;
}
if ( isUsingScopeView ! = wasAimingWithScope )
{
wasAimingWithScope = isUsingScopeView ;
if ( IsAiming ) shooterManager . onEnableScopeView . Invoke ( shooterManager . CurrentWeapon ) ;
else shooterManager . onDisableScopeView . Invoke ( shooterManager . CurrentWeapon ) ;
}
}
protected virtual void UpdateAimAngleReference ( )
{
aimAngleReference . transform . rotation = transform . rotation ;
UpdateCheckAimHelpers ( shooterManager . IsLeftWeapon ) ;
}
protected void UpdateCheckAimHelpers ( bool isUsingLeftHand )
{
if ( ! CurrentActiveWeapon ) return ;
var weight = ( float ) System . Math . Round ( armAlignmentWeight , 1 ) ;
var upperArm = isUsingLeftHand ? leftUpperArm : rightUpperArm ;
upperArmPosition = Vector3 . Lerp ( upperArmPosition , aimAngleReference . transform . InverseTransformPoint ( upperArm . position ) , weight ) ;
muzzlePosition = Vector3 . Lerp ( muzzlePosition , aimAngleReference . transform . InverseTransformPoint ( CurrentActiveWeapon . muzzle . position ) , weight ) ;
muzzleForward = Vector3 . Lerp ( muzzleForward , aimAngleReference . transform . InverseTransformDirection ( CurrentActiveWeapon . muzzle . forward ) , weight ) ;
}
public virtual void UpdateCheckAimPoints ( ref Vector3 start , ref Vector3 end )
{
if ( CurrentActiveWeapon )
{
float checkAimSmooth = shooterManager . checkAimOffsetSmooth ;
///Lerp offsets
checkCanAimOffsetStartX = Mathf . Lerp ( checkCanAimOffsetStartX , IsCrouching ? shooterManager . checkAimCrouchedOffsetStartX : shooterManager . checkAimStandingOffsetStartX , checkAimSmooth * Time . fixedDeltaTime ) ;
checkCanAimOffsetStartY = Mathf . Lerp ( checkCanAimOffsetStartY , IsCrouching ? shooterManager . checkAimCrouchedOffsetStartY : shooterManager . checkAimStandingOffsetStartY , checkAimSmooth * Time . fixedDeltaTime ) ;
checkCanAimOffsetEndX = Mathf . Lerp ( checkCanAimOffsetEndX , IsCrouching ? shooterManager . checkAimCrouchedOffsetEndX : shooterManager . checkAimStandingOffsetEndX , checkAimSmooth * Time . fixedDeltaTime ) ;
checkCanAimOffsetEndY = Mathf . Lerp ( checkCanAimOffsetEndY , IsCrouching ? shooterManager . checkAimCrouchedOffsetEndY : shooterManager . checkAimStandingOffsetEndY , checkAimSmooth * Time . fixedDeltaTime ) ;
var startX = checkCanAimOffsetStartX ;
var startY = checkCanAimOffsetStartY ;
var endX = checkCanAimOffsetEndX ;
var endY = checkCanAimOffsetEndY ;
onUpdateCheckAimPointsEvent ? . Invoke ( ref startX , ref endX , ref startY , ref endY ) ;
/// Make original points to check aim
Vector3 startPoint = aimAngleReference . transform . TransformPoint ( upperArmPosition ) ;
float upperArmToMuzzleDistance = Vector3 . Distance ( startPoint , aimAngleReference . transform . TransformPoint ( muzzlePosition ) ) ;
var endPoint = startPoint + ( DesiredAimPosition - startPoint ) . normalized * upperArmToMuzzleDistance ;
Vector3 forward = ( DesiredAimPosition - startPoint ) . normalized ;
///Apply offsets
Vector3 newStartPoint = startPoint + cameraMain . transform . right * ( startX * ( tpCamera . switchRight > 0 ? 1 : - 1 ) ) + cameraMain . transform . up * startY ;
Vector3 newEndPoint = endPoint + cameraMain . transform . right * ( endX * ( tpCamera . switchRight > 0 ? 1 : - 1 ) ) + cameraMain . transform . up * endY + forward * shooterManager . checkAimOffsetZ ;
start = newStartPoint ;
end = newEndPoint ;
}
}
public delegate void UpdateCheckAimPointsEvent ( ref float startX , ref float endX , ref float startY , ref float endY ) ;
public UpdateCheckAimPointsEvent onUpdateCheckAimPointsEvent ;
protected virtual void OnFinishUpdateIK ( )
{
onFinishUpdateIK ? . Invoke ( ) ;
}
protected virtual void OnStartUpdateIK ( )
{
onStartUpdateIK ? . Invoke ( ) ;
}
protected virtual void UpdateIKAdjust ( bool isUsingLeftHand )
{
// create left arm ik solver if equal null
if ( LeftIK = = null | | ! LeftIK . isValidBones )
{
LeftIK = new vIKSolver ( animator , AvatarIKGoal . LeftHand ) ;
LeftIK . UpdateIK ( ) ;
}
if ( RightIK = = null | | ! RightIK . isValidBones )
{
RightIK = new vIKSolver ( animator , AvatarIKGoal . RightHand ) ;
RightIK . UpdateIK ( ) ;
}
if ( WeaponIKAdjustList = = null ) return ;
else
{
CurrentActiveWeapon . handIKTargetOffset . localPosition = isUsingLeftHand ? WeaponIKAdjustList . ikTargetPositionOffsetL : WeaponIKAdjustList . ikTargetPositionOffsetR ;
CurrentActiveWeapon . handIKTargetOffset . localEulerAngles = isUsingLeftHand ? WeaponIKAdjustList . ikTargetRotationOffsetL : WeaponIKAdjustList . ikTargetRotationOffsetR ;
}
if ( ! CurrentWeaponIK )
{
LeftIK . UpdateIK ( ) ;
RightIK . UpdateIK ( ) ;
RightIK . SetIKWeight ( 0 ) ;
LeftIK . SetIKWeight ( 0 ) ;
weaponIKWeight = 0 ;
return ;
}
bool isValidIK = ! IsIgnoreIK & & ! cc . customAction & & ! isReloading & & ! isEquipping & & CurrentWeaponIK ! = null & & CurrentIKAdjust ! = null ;
weaponIKWeight = Mathf . Lerp ( weaponIKWeight , isValidIK ? 1 : 0 , shooterManager . ikAdjustSmooth * Time . fixedDeltaTime ) ;
if ( weaponIKWeight < = 0 )
{
return ;
}
if ( isUsingLeftHand )
{
ApplyOffsets ( LeftIK , RightIK , isValidIK ) ;
}
else
{
ApplyOffsets ( RightIK , LeftIK , isValidIK ) ;
}
}
protected virtual void ApplyOffsets ( vIKSolver weaponHand , vIKSolver supportHand , bool isValidIK = true )
{
if ( ! weaponHand . isValidBones | | ! supportHand . isValidBones ) return ;
//Apply Offset to Weapon Arm
weaponHand . SetIKWeight ( shooterManager . ikAdjustWeightCurve . Evaluate ( weaponIKWeight ) ) ;
ApplyOffsetToTargetBone ( isValidIK ? CurrentIKAdjust . weaponHandOffset : null , weaponHand . endBoneOffset , isValidIK ) ;
ApplyOffsetToTargetBone ( isValidIK ? CurrentIKAdjust . weaponHintOffset : null , weaponHand . middleBoneOffset , isValidIK ) ;
weaponHand . AnimationToIK ( ) ;
//Apply offset to Support Weapon Arm
ApplyOffsetToTargetBone ( isValidIK ? CurrentIKAdjust . supportHandOffset : null , supportHand . endBoneOffset , ! EditingIKGlobalOffset & & isValidIK ) ;
ApplyOffsetToTargetBone ( isValidIK ? CurrentIKAdjust . supportHintOffset : null , supportHand . middleBoneOffset , ! EditingIKGlobalOffset & & isValidIK ) ;
}
protected virtual void ApplyOffsetToTargetBone ( IKOffsetTransform iKOffset , Transform target , bool isValidIK )
{
try
{
target . localPosition = Vector3 . Lerp ( target . localPosition , isValidIK ? iKOffset . position : Vector3 . zero , shooterManager . ikAdjustSmooth * vTime . fixedDeltaTime ) ;
target . localRotation = Quaternion . Lerp ( target . localRotation , isValidIK ? Quaternion . Euler ( iKOffset . eulerAngles ) : Quaternion . Euler ( Vector3 . zero ) , shooterManager . ikAdjustSmooth * vTime . fixedDeltaTime ) ;
}
catch
{
Debug . LogWarning ( "Can't Get IK Adjust" ) ;
}
}
protected virtual void UpdateArmsIK ( bool isUsingLeftHand = false )
{
// create left arm ik solver if equal null
if ( LeftIK = = null | | ! LeftIK . isValidBones )
{
LeftIK = new vIKSolver ( animator , AvatarIKGoal . LeftHand ) ;
}
if ( RightIK = = null | | ! RightIK . isValidBones )
{
RightIK = new vIKSolver ( animator , AvatarIKGoal . RightHand ) ;
}
vIKSolver targetIK = null ;
if ( isUsingLeftHand )
{
targetIK = RightIK ;
}
else
{
targetIK = LeftIK ;
}
bool useIK = isUsingLeftHand ? shooterManager . useLeftIK : shooterManager . useRightIK ;
if ( ( ! shooterManager | | ! CurrentActiveWeapon | | IsIgnoreIK | | isEquipping ) | |
( cc . IsAnimatorTag ( "Shot Fire" ) & & CurrentActiveWeapon . disableIkOnShot ) )
{
useIK = false ;
}
bool useIkConditions = false ;
var animatorInput = System . Math . Round ( cc . inputMagnitude , 1 ) ;
if ( ! useIK )
{
useIkConditions = false ;
}
else if ( ! IsAiming & & ! isAttacking )
{
var locomotionValidation = cc . isStrafing ? CurrentActiveWeapon . strafeIKOptions : CurrentActiveWeapon . freeIKOptions ;
if ( locomotionValidation . use )
{
if ( animatorInput < = 0.1f )
{
useIkConditions = locomotionValidation . useOnIdle ;
}
else if ( animatorInput < = 0.5f )
{
useIkConditions = locomotionValidation . useOnWalk ;
}
else if ( animatorInput < = 1f )
{
useIkConditions = locomotionValidation . useOnRun ;
}
else if ( animatorInput < = 1.5f )
{
useIkConditions = locomotionValidation . useOnSprint ;
}
}
else useIkConditions = false ;
}
else if ( IsAiming & & ! isAttacking )
{
useIkConditions = shooterManager . isShooting ? ! CurrentActiveWeapon . disableIkOnShot : CurrentActiveWeapon . useIKOnAiming ;
}
else if ( isAttacking )
{
useIkConditions = CurrentActiveWeapon . useIkAttacking ;
}
IsSupportHandIKEnabled = useIkConditions & & ! IsIgnoreSupportHandIK ;
if ( targetIK ! = null )
{
if ( shooterManager . weaponIKAdjustList )
{
if ( isUsingLeftHand )
{
ikRotationOffset = shooterManager . weaponIKAdjustList . ikTargetRotationOffsetR ;
ikPositionOffset = shooterManager . weaponIKAdjustList . ikTargetPositionOffsetR ;
}
else
{
ikRotationOffset = shooterManager . weaponIKAdjustList . ikTargetRotationOffsetL ;
ikPositionOffset = shooterManager . weaponIKAdjustList . ikTargetPositionOffsetL ;
}
}
// Debug.Log($"using ik {useIkConditions.ToStringColor()}");//Debug IK Conditions
// control weight of ik
if ( CurrentActiveWeapon & & CurrentActiveWeapon . handIKTargetOffset & & ! isReloading & & ! cc . customAction & & ( cc . isGrounded | | ( IsAiming ) ) & & IsSupportHandIKEnabled )
{
supportIKWeight = Mathf . Lerp ( supportIKWeight , 1 , shooterManager . armIKSmoothIn * vTime . fixedDeltaTime ) ;
}
else
{
supportIKWeight = Mathf . Lerp ( supportIKWeight , 0 , shooterManager . armIKSmoothOut * vTime . fixedDeltaTime ) ;
}
if ( supportIKWeight < = 0 )
{
if ( ! IsSupportHandIKEnabled & & shooterManager . CurrentWeaponIK )
{
targetIK . SetIKWeight ( shooterManager . armIKCurve . Evaluate ( supportIKWeight ) ) ;
targetIK . AnimationToIK ( ) ;
}
return ;
}
// update IK
targetIK . SetIKWeight ( shooterManager . armIKCurve . Evaluate ( supportIKWeight ) ) ;
if ( shooterManager & & CurrentActiveWeapon & & CurrentActiveWeapon . handIKTargetOffset )
{
targetIK . SetIKPosition ( CurrentActiveWeapon . handIKTargetOffset . position ) ;
targetIK . SetIKRotation ( CurrentActiveWeapon . handIKTargetOffset . rotation ) ;
if ( shooterManager . CurrentWeaponIK )
{
targetIK . AnimationToIK ( ) ;
}
}
}
}
protected virtual bool CanRotateAimArm ( )
{
return cc . IsAnimatorTag ( "Upperbody Pose" ) & & cc . animatorStateInfos . GetCurrentNormalizedTime ( cc . upperBodyLayer ) > 0.5f ;
}
protected virtual bool CanDoShots ( )
{
return armAlignmentWeight > = 0.5f & & cc . IsAnimatorTag ( "Upperbody Pose" ) & & shootCountA > 0 & & ! isReloading ;
}
protected virtual void AlignArmToAimPosition ( bool isUsingLeftHand = false )
{
if ( ! shooterManager )
{
return ;
}
///Init the arms, if needs that
if ( leftArmAim = = null ) leftArmAim = new vArmAimAlign ( leftUpperArm , leftLowerArm , leftHand ) ;
if ( rightArmAim = = null ) rightArmAim = new vArmAimAlign ( rightUpperArm , rightLowerArm , rightHand ) ;
/// Select the arm
vArmAimAlign arm = isUsingLeftHand ? leftArmAim : rightArmAim ;
///Calculate the Alignment weight based on aim conditions.
armAlignmentWeight = IsAiming & & aimConditions & & CanRotateAimArm ( ) ? Mathf . Lerp ( armAlignmentWeight , Mathf . Clamp ( cc . upperBodyInfo . normalizedTime , 0 , 1f ) , shooterManager . smoothArmWeight * ( . 001f + Time . fixedDeltaTime ) ) : 0 ;
if ( CurrentActiveWeapon )
{
if ( ! shooterManager . isShooting )
{
///Update arm to use default animation rotation while not shooting
arm . UpdateDefaultAlignment ( ) ;
}
else
{
///Use last alignment to ignore shoot animation rotation
///When shooting the arm position and rotation will be changed by the animation
///This method avoid this changes using the last alignment before the shot was performed
arm . RestoreToLastAlignment ( ) ;
}
/// Set the Arm aligment values
arm . smoothIKAlignmentPoint = shooterManager . smoothIKAlignmentPoint ;
arm . aimReference = CurrentActiveWeapon . aimReference ;
arm . smooth = shooterManager . smoothArmIKRotation ;
arm . maxVerticalAligmentAngle = shooterManager . maxVerticalAimAngle ;
arm . maxHorizontalAligmentAngle = shooterManager . maxHorizontalAimAngle ;
if ( shooterManager . showCheckAimGizmos ) arm . DrawBones ( Color . blue ) ;
///Align arm to target aim position
arm . AlignToArmToPosition ( targetArmAlignmentPosition , armAlignmentWeight , CurrentActiveWeapon . alignRightUpperArmToAim , CurrentActiveWeapon . alignRightHandToAim ) ;
if ( shooterManager . showCheckAimGizmos ) arm . DrawHelpers ( Color . green ) ;
}
}
protected virtual void CheckAimConditions ( )
{
if ( ! shooterManager )
{
return ;
}
var weaponSide = ( tpCamera . switchRight < 0 ? - 1 : 1 ) ;
if ( CurrentActiveWeapon = = null )
{
aimConditions = false ;
return ;
}
if ( shooterManager . useCheckAim = = false )
{
aimConditions = true ;
return ;
}
Vector3 startPoint = Vector3 . zero ;
Vector3 endPoint = Vector3 . zero ;
Ray _ray = new Ray ( startPoint , ( ( endPoint ) - startPoint ) . normalized ) ;
bool _aimCondition = aimConditions ;
if ( animator . IsInTransition ( 0 ) )
{
if ( Physics . SphereCast ( _ray , shooterManager . checkAimRadius , out checkCanAimHit , ( endPoint - startPoint ) . magnitude , shooterManager . blockAimLayer ) )
{
aimConditions = false ;
}
_aimCondition = aimConditions ;
checkAimConditionOverride ? . Invoke ( startPoint , endPoint , ref _aimCondition ) ;
aimConditions = _aimCondition ;
return ;
}
UpdateCheckAimPoints ( ref startPoint , ref endPoint ) ;
_ray = new Ray ( startPoint , ( ( endPoint ) - startPoint ) . normalized ) ;
if ( Vector3 . Distance ( startPoint , AimPosition ) < Vector3 . Distance ( startPoint , endPoint ) )
aimConditions = false ;
if ( Physics . SphereCast ( _ray , shooterManager . checkAimRadius , out checkCanAimHit , ( endPoint - startPoint ) . magnitude , shooterManager . blockAimLayer ) )
{
aimConditions = false ;
}
else
{
aimConditions = true ;
}
_aimCondition = aimConditions ;
checkAimConditionOverride ? . Invoke ( startPoint , endPoint , ref _aimCondition ) ;
aimConditions = _aimCondition ;
}
public delegate void CheckAimConditionsEvent ( Vector3 startPoint , Vector3 endPoint , ref bool aimConditions ) ;
public CheckAimConditionsEvent checkAimConditionOverride ;
protected virtual Vector3 targetArmAlignmentPosition
{
get
{
return shooterManager . alignArmToHitPoint | | isUsingScopeView ? DesiredAimPosition : cameraMain . transform . position + cameraMain . transform . forward * 100 ;
}
}
protected virtual Transform targetCamera
{
get
{
var t = controlAimCanvas & & controlAimCanvas . isScopeCameraActive & & controlAimCanvas . scopeBackgroundCamera ? controlAimCanvas . scopeBackgroundCamera . transform : cameraMain . transform ;
return t ;
}
}
protected virtual Vector3 targetArmAlignmentDirection
{
get
{
return targetCamera . forward ;
}
}
protected virtual void UpdateHeadTrack ( )
{
if ( headTrack )
{
UpdateHeadTrackLookPoint ( ) ;
}
if ( ! shooterManager | | ! headTrack )
{
if ( headTrack )
{
headTrack . offsetSpine = Vector2 . Lerp ( headTrack . offsetSpine , Vector2 . zero , weaponIKWeight ) ;
headTrack . offsetHead = Vector2 . Lerp ( headTrack . offsetHead , Vector2 . zero , weaponIKWeight ) ;
}
return ;
}
if ( ! CurrentActiveWeapon | | ! headTrack | | ! CurrentWeaponIK | | CurrentIKAdjust = = null )
{
if ( headTrack )
{
headTrack . offsetSpine = Vector2 . Lerp ( headTrack . offsetSpine , Vector2 . zero , weaponIKWeight ) ;
headTrack . offsetHead = Vector2 . Lerp ( headTrack . offsetHead , Vector2 . zero , weaponIKWeight ) ;
}
return ;
}
if ( IsAiming )
{
var ikAdjust = CurrentIKAdjust ;
var offsetSpine = ikAdjust . spineOffset . spine ;
var offsetHead = ikAdjust . spineOffset . head ;
headTrack . offsetSpine = Vector2 . Lerp ( headTrack . offsetSpine , offsetSpine , weaponIKWeight ) ;
headTrack . offsetHead = Vector2 . Lerp ( headTrack . offsetHead , offsetHead , weaponIKWeight ) ;
}
else
{
var ikAdjust = CurrentIKAdjust ;
var offsetSpine = ikAdjust . spineOffset . spine ;
var offsetHead = ikAdjust . spineOffset . head ;
headTrack . offsetSpine = Vector2 . Lerp ( headTrack . offsetSpine , offsetSpine , headTrack . Smooth ) ;
headTrack . offsetHead = Vector2 . Lerp ( headTrack . offsetHead , offsetHead , headTrack . Smooth ) ;
}
}
protected virtual void UpdateHeadTrackLookPoint ( )
{
if ( IsAiming /*&& !isUsingScopeView*/ & & CurrentActiveWeapon & & aimConditions )
{
headTrack . SetTemporaryLookPoint ( targetArmAlignmentPosition ) ; //cameraMain.transform.TransformPoint(Vector3.forward * (cameraMain.transform.InverseTransformPoint(CurrentActiveWeapon.muzzle.position).z + 10)), 0.1f);
}
}
protected virtual void UpdateAimHud ( )
{
if ( ! shooterManager | | ! controlAimCanvas )
{
return ;
}
if ( CurrentActiveWeapon = = null )
{
return ;
}
var _aimPoint = AimPosition ;
controlAimCanvas . SetAimCanvasID ( CurrentActiveWeapon . scopeID ) ;
if ( controlAimCanvas . scopeBackgroundCamera & & controlAimCanvas . scopeBackgroundCamera . gameObject . activeSelf )
{
controlAimCanvas . SetAimToCenter ( true ) ;
}
else if ( IsAiming & & aimConditions )
{
var aimDistance = Vector3 . Distance ( aimAngleReference . transform . position , _aimPoint ) ;
var validAim = ( aimDistance > shooterManager . maxAimHitPointIndicator | | Vector3 . Distance ( AimPosition , DesiredAimPosition ) < 0.1f ) & & aimConditions ;
if ( aimDistance > shooterManager . maxAimHitPointIndicator | | Vector3 . Distance ( AimPosition , DesiredAimPosition ) < 0.1f )
controlAimCanvas . SetAimToCenter ( true ) ;
else
controlAimCanvas . SetWordPosition ( _aimPoint , validAim ) ;
}
else
{
controlAimCanvas . SetAimToCenter ( aimConditions ) ;
}
if ( ( controlAimCanvas . scopeBackgroundCamera & & CurrentActiveWeapon . scopeTarget ) )
{
if ( isUsingScopeView | | controlAimCanvas . isScopeCameraActive )
{
vArmAimAlign arm = shooterManager . IsLeftWeapon ? leftArmAim : rightArmAim ;
if ( ! shooterManager . isShooting )
{
scopeLocalForward = arm . aimReferenceHelper . InverseTransformDirection ( CurrentActiveWeapon . scopeTarget . forward ) ;
scopeLocalPosition = arm . aimReferenceHelper . InverseTransformPoint ( CurrentActiveWeapon . scopeTarget . position ) ;
scopeCameraLocalForward = aimAngleReference . transform . InverseTransformDirection ( controlAimCanvas . scopeBackgroundCamera . transform . forward ) ;
scopeCameraLocalPosition = aimAngleReference . transform . InverseTransformPoint ( controlAimCanvas . scopeBackgroundCamera . transform . position ) ;
}
var weight = ( shooterManager . isShooting ? ( 1 - CurrentActiveWeapon . scopeShootAnimationWeight ) : 1f ) ;
var scopCameraPosition = aimAngleReference . transform . TransformPoint ( scopeCameraLocalPosition ) ;
var scopCameraForward = aimAngleReference . transform . TransformDirection ( scopeCameraLocalForward ) ;
var scopeLookDirection = Vector3 . Lerp ( scopCameraForward , arm . aimReferenceHelper . TransformDirection ( scopeLocalForward ) , scopeDirectionWeight = Mathf . Lerp ( scopeDirectionWeight , 1.001f , ( 10f / CurrentActiveWeapon . shootFrequency ) * Time . fixedDeltaTime ) ) ;
var scopePosition = Vector3 . Lerp ( scopCameraPosition , arm . aimReferenceHelper . TransformPoint ( scopeLocalPosition ) , weight ) ;
controlAimCanvas . UpdateScopeCamera ( scopePosition , scopeLookDirection , aimAngleReference . transform . up , CurrentActiveWeapon . backGroundScopeZoom , IsAiming ) ;
}
else scopeDirectionWeight = 1f ;
}
}
#endregion
}
public static partial class vAnimatorParameters
{
public static int UpperBody_ID = Animator . StringToHash ( "UpperBody_ID" ) ;
public static int CanAim = Animator . StringToHash ( "CanAim" ) ;
public static int IsAiming = Animator . StringToHash ( "IsAiming" ) ;
public static int IsHipFire = Animator . StringToHash ( "IsHipFire" ) ;
public static int Shot_ID = Animator . StringToHash ( "Shot_ID" ) ;
public static int PowerCharger = Animator . StringToHash ( "PowerCharger" ) ;
}
}