Files
2024-11-20 15:21:28 +01:00

1030 lines
38 KiB
C#

using Invector.IK;
using Invector.vShooter;
using System.Collections;
using UnityEngine;
namespace Invector.vCharacterController.AI
{
[vClassHeader(" AI SHOOTER CONTROLLER", iconName = "AI-icon")]
public partial class vControlAIShooter : vControlAICombat, vIControlAIShooter, vIShooterIKController
{
[vEditorToolbar("Shooter Settings", order = 10)]
[Header("Shooter Settings")]
public float minTimeShooting = 2f;
public float maxTimeShooting = 5f;
public float minShotWaiting = 3f;
public float maxShotWaiting = 6f;
public float aimTargetHeight = .35f;
public bool doReloadWhileWaiting = true;
public float aimSmoothDamp = 10f;
public float smoothArmAlignmentWeight = 4f;
public float aimTurnAngle = 60f;
public float maxAngleToShot = 60f;
public bool IsReloading { get; protected set; }
public bool IsEquipping { get; protected set; }
public bool IsInShotAngle { get; protected set; }
public vAIShooterManager shooterManager { get; set; }
protected float _timeShotting;
protected float _waitingToShot;
protected float _upperBodyID;
protected float _shotID;
protected Quaternion handRotationAlignment;
protected Quaternion upperArmRotationAlignment;
protected float armAlignmentWeight;
#region IKController Interface Properties
protected IKAdjust _currentIKAdjust;
public vIKSolver LeftIK { get; set; }
public vIKSolver RightIK { get; set; }
public vWeaponIKAdjustList WeaponIKAdjustList
{
get
{
if (shooterManager)
{
return shooterManager.weaponIKAdjustList;
}
return null;
}
set
{
if (shooterManager)
{
shooterManager.weaponIKAdjustList = value;
}
}
}
public 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 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 EditingIKGlobalOffset
{
get; 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 IsAnimatorTag("IgnoreIK");
}
}
public virtual bool IsSupportHandIKEnabled
{
get;protected set;
}
public void UpdateWeaponIK()
{
if (shooterManager)
{
shooterManager.UpdateWeaponIK();
if(CurrentWeaponIK) _currentIKAdjust = CurrentWeaponIK.GetIKAdjust(CurrentIKAdjustState, CurrentActiveWeapon.isLeftWeapon);
}
}
public bool LockAiming
{
get
{
return lockAimDebug;
}
set
{
lockAimDebug = value;
}
}
public virtual bool LockHipFireAiming
{
get; set;
}
public bool IsCrouching
{
get
{
return isCrouching;
}
set
{
isCrouching = value;
}
}
public bool IsLeftWeapon
{
get
{
return shooterManager && shooterManager.IsLeftWeapon;
}
}
public bool IsAiming
{
get
{
return isAiming || lockAimDebug;
}
}
#endregion
private Transform leftUpperArm, rightUpperArm, leftHand, rightHand;
private GameObject aimAngleReference;
private Quaternion upperArmRotation, handRotation;
private readonly float rightRotationWeight;
private float _onlyArmsLayerWeight;
private float handIKWeight;
private float weaponIKWeight;
private float aimTime;
private float delayEnableAimAfterRagdolled;
private int onlyArmsLayer;
private int _moveSetID;
private int _attackID;
private bool aimEnable;
[vEditorToolbar("Debug", overrideChildOrder: true, order = 100)]
[SerializeField, vReadOnly(false)] protected bool _canAiming;
[SerializeField, vReadOnly(false)] protected bool _canShot;
[SerializeField, vReadOnly(false)] protected bool _waitingReload;
[SerializeField, vReadOnly(false)] protected int shots;
public bool debugAim;
public bool lockAimDebug;
[SerializeField]
[vHideInInspector("lockAimDebug")]
private Transform aimDebugTarget = null;
[SerializeField]
[vHideInInspector("lockAimDebug")]
private bool debugShoots = false;
private Vector3 aimVelocity;
private Vector3 aimTarget;
Vector3 _lastaValidAimLocal;
protected bool forceCanShot;
public event IKUpdateEvent onStartUpdateIK;
public event IKUpdateEvent onFinishUpdateIK;
public Vector3 AimPosition { get; protected set; }
public override void CreateSecondaryComponents()
{
base.CreateSecondaryComponents();
if (GetComponent<vAIShooterManager>() == null) gameObject.AddComponent<vAIShooterManager>();
if (GetComponent<vAIHeadtrack>() == null) gameObject.AddComponent<vAIHeadtrack>();
}
protected virtual int MoveSetID
{
get
{
return _moveSetID;
}
set
{
if (value != _moveSetID || animator.GetFloat("MoveSet_ID") != value)
{
_moveSetID = value;
animator.SetFloat("MoveSet_ID", (float)_moveSetID, 0.25f, Time.deltaTime);
}
}
}
protected virtual int AttackID
{
get
{
return _attackID;
}
set
{
if (value != _attackID)
{
_attackID = value;
animator.SetInteger("AttackID", _attackID);
}
}
}
public virtual void CheckCanShot()
{
if (isAiming && _waitingToShot < Time.time && (isStrafing || debugShoots || input.magnitude < 0.1f))
{
_timeShotting = Random.Range(minTimeShooting, maxTimeShooting) + Time.time;
}
_canShot = _timeShotting > Time.time;
if (_canShot)
{
_waitingToShot = Time.time + Random.Range(minShotWaiting, maxShotWaiting);
}
}
protected override void Start()
{
base.Start();
_lastaValidAimLocal = defaultValidAimLocal;
_waitingReload = false;
InitShooter();
}
public Vector3 _debugAimPosition;
public virtual Vector3 defaultValidAimLocal
{
get
{
return Vector3.forward * 10f + Vector3.up * ((_capsuleCollider.height * 0.5f) + aimTargetHeight);
}
}
protected virtual float UpperBodyID
{
get { return _upperBodyID; }
set
{
if (_upperBodyID != value || animator.GetFloat("UpperBody_ID") != value)
{
_upperBodyID = value;
animator.SetFloat("UpperBody_ID", _upperBodyID);
}
}
}
protected virtual float ShotID
{
get { return _shotID; }
set
{
if (_shotID != value || animator.GetFloat("Shot_ID") != value)
{
_shotID = value;
animator.SetFloat("Shot_ID", _shotID);
}
}
}
protected virtual Vector3 DebugAimPosition
{
get
{
return !aimDebugTarget ? (transform.position + transform.forward * (2f + _debugAimPosition.z) + transform.right * _debugAimPosition.x + transform.up * (1.5f + _debugAimPosition.y)) : aimDebugTarget.position;
}
}
protected override void OnDrawGizmos()
{
base.OnDrawGizmos();
if (lockAimDebug)
{
Gizmos.DrawSphere(DebugAimPosition, 0.1f);
}
if (debugAim && currentTarget.transform)
{
Gizmos.DrawSphere(AimPosition, 0.1f);
if(currentTarget.collider)
Gizmos.DrawWireCube(currentTarget.collider.bounds.center, currentTarget.collider.bounds.size);
else Gizmos.DrawWireCube(currentTarget.transform.position, Vector3.one*0.5f);
}
}
public virtual void SetShooterHitLayer(LayerMask mask)
{
if (shooterManager)
{
shooterManager.SetDamageLayer(mask);
}
}
public override void Attack(bool strongAttack = false, int attackID = -1, bool forceCanAttack = false)
{
if (ragdolled) return;
if (shooterManager && attackID != -1)
AttackID = attackID;
else
AttackID = shooterManager.GetAttackID();
if (currentTarget.transform || (debugShoots && lockAimDebug) || forceCanAttack)
{
forceCanShot = forceCanAttack;
if (_canShot || forceCanShot)
{
if (shots == 0)
shots++;
}
}
}
public override void InitAttackTime()
{
base.InitAttackTime();
_waitingToShot = Time.time + Random.Range(minShotWaiting, maxShotWaiting);
_waitingReload = false;
}
public override void ResetAttackTime()
{
base.ResetAttackTime();
_waitingToShot = Time.time + Random.Range(minShotWaiting, maxShotWaiting);
}
protected virtual void InitShooter()
{
if (_headtrack)
{
_headtrack.onPreUpdateSpineIK.AddListener(HandleAim);
_headtrack.onPosUpdateSpineIK.AddListener(IKBehaviour);
}
shooterManager = GetComponent<vAIShooterManager>();
leftHand = animator.GetBoneTransform(HumanBodyBones.LeftHand);
rightHand = animator.GetBoneTransform(HumanBodyBones.RightHand);
leftUpperArm = animator.GetBoneTransform(HumanBodyBones.LeftUpperArm);
rightUpperArm = animator.GetBoneTransform(HumanBodyBones.RightUpperArm);
onlyArmsLayer = animator.GetLayerIndex("OnlyArms");
aimAngleReference = new GameObject("aimAngleReference");
aimAngleReference.transform.rotation = transform.rotation;
var head = animator.GetBoneTransform(HumanBodyBones.Head);
aimAngleReference.transform.SetParent(head);
aimAngleReference.transform.localPosition = Vector3.zero;
AimPosition = DebugAimPosition;
}
protected virtual void HandleAim()
{
if (ragdolled)
{
aimTime = 0;
isAiming = false;
delayEnableAimAfterRagdolled = 2f;
return;
}
else if (delayEnableAimAfterRagdolled <= 0)
{
ControlAimTime();
if (isAiming) _headtrack.LookAtPoint(AimPositionClamped(), 1f, 0);
}
else
{
aimTime = 0;
isAiming = false;
delayEnableAimAfterRagdolled -= Time.deltaTime;
}
}
protected virtual void IKBehaviour()
{
if (lockAimDebug)
{
if (!IsStrafingAnim)
{
isStrafing = true;
IsStrafingAnim = true;
}
AimTo(DebugAimPosition, .5f);
}
UpdateAimBehaviour();
if (lockAimDebug && debugShoots) Attack();
}
protected override void UpdateAnimator()
{
base.UpdateAnimator();
UpdateCombatAnimator();
}
protected override void UpdateCombatAnimator()
{
base.UpdateCombatAnimator();
UpdateShooterAnimator();
}
protected virtual void UpdateShooterAnimator()
{
if (shooterManager.CurrentWeapon)
{
IsReloading = IsAnimatorTag("IsReloading");
// find states with the IsEquipping tag
IsEquipping = IsAnimatorTag("IsEquipping");
var _isAiming = isAiming && !IsReloading;
if (_isAiming && !aimEnable)
{
shooterManager.CurrentWeapon.onEnableAim.Invoke();
aimEnable = true;
}
else if (!_isAiming && aimEnable)
{
shooterManager.CurrentWeapon.onDisableAim.Invoke();
aimEnable = false;
}
animator.SetBool("CanAim", _isAiming && _canAiming);
ShotID = shooterManager.GetShotID();
UpperBodyID = shooterManager.GetUpperBodyID();
MoveSetID = shooterManager.GetMoveSetID();
animator.SetBool("IsAiming", _isAiming);
}
else
{
IsReloading = false;
animator.SetBool("IsAiming", false);
animator.SetBool("CanAim", false);
if (aimEnable)
{
shooterManager.CurrentWeapon.onDisableAim.Invoke();
aimEnable = false;
}
}
_onlyArmsLayerWeight = Mathf.Lerp(_onlyArmsLayerWeight, isAiming || isRolling ? 0f : shooterManager && shooterManager.CurrentWeapon ? 1f : 0f, 6f * Time.deltaTime);
animator.SetLayerWeight(onlyArmsLayer, _onlyArmsLayerWeight);
}
protected virtual void UpdateAimBehaviour()
{
if (isDead) return;
UpdateHeadTrack();
CheckCanAiming();
CheckCanShot();
HandleShots();
UpdateValidAim();
ValidateShotAngle();
}
protected virtual void HandleShots()
{
onStartUpdateIK?.Invoke();
if (!IsIgnoreIK)
{
if (shooterManager && shooterManager.rWeapon && shooterManager.rWeapon.gameObject.activeSelf)
{
UpdateIKAdjust(false);
RotateAimArm();
RotateAimHand();
if (!shooterManager.lWeapon || !shooterManager.lWeapon.gameObject.activeSelf)
UpdateSupportHandIK();
}
if (shooterManager && shooterManager.lWeapon && shooterManager.lWeapon.gameObject.activeSelf)
{
UpdateIKAdjust(true);
RotateAimArm(true);
RotateAimHand(true);
if (!shooterManager.rWeapon || !shooterManager.rWeapon.gameObject.activeSelf)
UpdateSupportHandIK(true);
}
if (shots > 0)
{
Shot();
}
}
onFinishUpdateIK?.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 || IsIgnoreIK)
{
LeftIK.UpdateIK();
RightIK.UpdateIK();
RightIK.SetIKWeight(0);
LeftIK.SetIKWeight(0);
weaponIKWeight = 0;
return;
}
bool isValidIK = !customAction && !IsReloading && !IsEquipping && CurrentWeaponIK != null && CurrentIKAdjust != null;
weaponIKWeight = Mathf.Lerp(weaponIKWeight, isValidIK ? 1 : 0, 25f * vTime.deltaTime);
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(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
// supportHand.SetIKWeight(weaponIKWeight);
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 isValid)
{
target.localPosition = Vector3.Lerp(target.localPosition, isValid ? iKOffset.position : Vector3.zero, 10f * Time.deltaTime);
target.localRotation = Quaternion.Lerp(target.localRotation, isValid ? Quaternion.Euler(iKOffset.eulerAngles) : Quaternion.Euler(Vector3.zero), 10f * Time.deltaTime);
}
protected virtual void UpdateValidAim()
{
if (isAiming && _canAiming)
{
AimPosition = Vector3.SmoothDamp(AimPosition, aimTarget, ref aimVelocity, aimSmoothDamp * Time.deltaTime);
_lastaValidAimLocal = transform.InverseTransformPoint(AimPosition);
}
else
{
if (!isAiming) _lastaValidAimLocal = defaultValidAimLocal;
AimPosition = transform.TransformPoint(_lastaValidAimLocal);
}
}
protected virtual Vector3 AimPositionClamped()
{
var _localAim = defaultValidAimLocal;
if (_canAiming)
{
_localAim = transform.InverseTransformPoint(AimPosition);
if (_localAim.z < .5f) _localAim.z = .5f;
}
return transform.TransformPoint(_localAim);
}
protected virtual void UpdateHeadTrack()
{
if (!shooterManager || !_headtrack)
{
if (_headtrack)
{
_headtrack.offsetSpine = Vector2.Lerp(_headtrack.offsetSpine, Vector2.zero, _headtrack.smooth * Time.deltaTime);
_headtrack.offsetHead = Vector2.Lerp(_headtrack.offsetHead, Vector2.zero, _headtrack.smooth * Time.deltaTime);
}
return;
}
if (!CurrentActiveWeapon || !_headtrack || !shooterManager.CurrentWeaponIK)
{
if (_headtrack)
{
_headtrack.offsetSpine = Vector2.Lerp(_headtrack.offsetSpine, Vector2.zero, _headtrack.smooth * Time.deltaTime);
_headtrack.offsetHead = Vector2.Lerp(_headtrack.offsetHead, Vector2.zero, _headtrack.smooth * Time.deltaTime);
}
return;
}
if (isAiming)
{
var ikAdjust = isCrouching ? CurrentActiveWeapon.isLeftWeapon ? shooterManager.CurrentWeaponIK.crouchingAimingLeft : shooterManager.CurrentWeaponIK.crouchingAimingRight :
CurrentActiveWeapon.isLeftWeapon ? shooterManager.CurrentWeaponIK.standingAimingLeft : shooterManager.CurrentWeaponIK.standingAimingRight;
var offsetSpine = ikAdjust.spineOffset.spine;
var offsetHead = ikAdjust.spineOffset.head;
_headtrack.offsetSpine = Vector2.Lerp(_headtrack.offsetSpine, offsetSpine, _headtrack.smooth * Time.deltaTime);
_headtrack.offsetHead = Vector2.Lerp(_headtrack.offsetHead, offsetHead, _headtrack.smooth * Time.deltaTime);
}
else
{
var ikAdjust = isCrouching ? CurrentActiveWeapon.isLeftWeapon ? shooterManager.CurrentWeaponIK.crouchingLeft : shooterManager.CurrentWeaponIK.crouchingRight :
CurrentActiveWeapon.isLeftWeapon ? shooterManager.CurrentWeaponIK.standingLeft : shooterManager.CurrentWeaponIK.standingRight;
var offsetSpine = ikAdjust.spineOffset.spine;
var offsetHead = ikAdjust.spineOffset.head;
_headtrack.offsetSpine = Vector2.Lerp(_headtrack.offsetSpine, offsetSpine, _headtrack.smooth * Time.deltaTime);
_headtrack.offsetHead = Vector2.Lerp(_headtrack.offsetHead, offsetHead, _headtrack.smooth * Time.deltaTime);
}
}
/// <summary>
/// Current active weapon (if weapon gameobject is disabled this return null)
/// </summary>
public virtual vShooter.vShooterWeapon CurrentActiveWeapon
{
get
{
return shooterManager.CurrentWeapon && shooterManager.CurrentWeapon.gameObject.activeInHierarchy ? shooterManager.CurrentWeapon : null;
}
}
protected virtual void ValidateShotAngle()
{
if (shooterManager && isAiming && _canAiming)
{
var weapon = shooterManager.rWeapon ? shooterManager.rWeapon : shooterManager.lWeapon;
if (weapon)
{
var angle = Vector3.Angle(weapon.aimReference.forward, (aimTarget - weapon.aimReference.position).normalized);
IsInShotAngle = angle <= maxAngleToShot;
if (debugAim)
{
Debug.DrawRay(weapon.aimReference.position, weapon.aimReference.forward * 100f, IsInShotAngle ? Color.green : Color.red);
}
return;
}
}
IsInShotAngle = false;
}
protected virtual void ControlAimTime()
{
if (aimTime > 0)
{
aimTime -= Time.deltaTime;
}
else if (isAiming) isAiming = false;
}
protected virtual void UpdateSupportHandIK(bool isUsingLeftHand = false)
{
if (ragdolled) return;
var weapon = isUsingLeftHand ? shooterManager.lWeapon : shooterManager.rWeapon;
// 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 = shooterManager.rWeapon ? shooterManager.useLeftIK : shooterManager.useRightIK;
if (!shooterManager || !weapon || !weapon.gameObject.activeInHierarchy || !useIK) return;
if (IsAnimatorTag("Shot") && weapon.disableIkOnShot) { handIKWeight = 0; return; }
bool useIkConditions = false;
var animatorInput = System.Math.Round(animator.GetFloat("InputMagnitude"),1);
if (!IsAiming && !isAttacking)
{
var locomotionValidation = 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;
if (isUsingLeftHand)
{
targetIK = RightIK;
}
else
{
targetIK = LeftIK;
}
if (targetIK != null)
{
Vector3 ikRotationOffset = Vector3.zero;
Vector3 ikPositionOffset = Vector3.zero;
if (shooterManager.weaponIKAdjustList)
{
if (isUsingLeftHand)
{
ikRotationOffset = shooterManager.weaponIKAdjustList.ikTargetRotationOffsetR;
ikPositionOffset = shooterManager.weaponIKAdjustList.ikTargetPositionOffsetR;
}
else
{
ikRotationOffset = shooterManager.weaponIKAdjustList.ikTargetRotationOffsetL;
ikPositionOffset = shooterManager.weaponIKAdjustList.ikTargetPositionOffsetL;
}
}
// control weight of ik
if (weapon && weapon.handIKTarget && Time.timeScale > 0 && !IsReloading && !actions && !customAction && !IsEquipping && (isGrounded || isAiming) && !lockMovement && useIkConditions)
handIKWeight = Mathf.Lerp(handIKWeight, 1, 10f * Time.deltaTime);
else
handIKWeight = Mathf.Lerp(handIKWeight, 0, 10f * Time.deltaTime);
if (handIKWeight <= 0) return;
// update IK
targetIK.SetIKWeight(handIKWeight);
if (shooterManager && weapon && weapon.handIKTarget)
{
targetIK.SetIKPosition(weapon.handIKTargetOffset.position);
targetIK.SetIKRotation(weapon.handIKTargetOffset.rotation);
if (shooterManager.CurrentWeaponIK)
{
targetIK.AnimationToIK();
}
}
}
}
protected virtual bool CanRotateAimArm()
{
return IsAnimatorTag("Upperbody Pose");
}
protected virtual void RotateAimArm(bool isUsingLeftHand = false)
{
if (!shooterManager) return;
armAlignmentWeight = (isAiming) && !IsReloading && CanRotateAimArm()&&_canAiming ? Mathf.Lerp(armAlignmentWeight, 1f, smoothArmAlignmentWeight * (Time.deltaTime)) : 0f;
if (CurrentActiveWeapon && armAlignmentWeight > 0.1f && CurrentActiveWeapon.alignRightUpperArmToAim)
{
var aimPoint = AimPositionClamped();
Vector3 v = aimPoint - CurrentActiveWeapon.aimReference.position;
var orientation = CurrentActiveWeapon.aimReference.forward;
var upperArm = isUsingLeftHand ? leftUpperArm : rightUpperArm;
var rot = Quaternion.FromToRotation(upperArm.InverseTransformDirection(orientation), upperArm.InverseTransformDirection(v));
if ((!float.IsNaN(rot.x) && !float.IsNaN(rot.y) && !float.IsNaN(rot.z)))
upperArmRotationAlignment = shooterManager.isShooting ? upperArmRotation : rot;
var angle = Vector3.Angle(aimPoint - aimAngleReference.transform.position, aimAngleReference.transform.forward);
if ((!(angle > shooterManager.maxHandAngle || angle < -shooterManager.maxHandAngle)))
{
upperArmRotation = Quaternion.Lerp(upperArmRotation, upperArmRotationAlignment, shooterManager.smoothHandRotation * (Time.deltaTime));
}
else
{
upperArmRotation = Quaternion.Euler(0, 0, 0);
}
if (!float.IsNaN(upperArmRotation.x) && !float.IsNaN(upperArmRotation.y) && !float.IsNaN(upperArmRotation.z))
{
float _armAlignmentWeight = CurrentActiveWeapon.alignRightHandToAim ? armAlignmentWeight * 0.5f : armAlignmentWeight;
upperArm.localRotation *= Quaternion.Euler(upperArmRotation.eulerAngles.NormalizeAngle() * _armAlignmentWeight);
}
}
else
{
upperArmRotation = Quaternion.Euler(0, 0, 0);
}
}
protected virtual void RotateAimHand(bool isUsingLeftHand = false)
{
if (!shooterManager) return;
if (CurrentActiveWeapon && armAlignmentWeight > 0.1f && CurrentActiveWeapon.alignRightHandToAim)
{
var aimPoint = AimPositionClamped();
Vector3 v = aimPoint - CurrentActiveWeapon.aimReference.position;
var orientation = CurrentActiveWeapon.aimReference.forward;
var hand = isUsingLeftHand ? leftHand : rightHand;
var rot = Quaternion.FromToRotation(hand.InverseTransformDirection(orientation), hand.InverseTransformDirection(v));
if ((!float.IsNaN(rot.x) && !float.IsNaN(rot.y) && !float.IsNaN(rot.z)))
handRotationAlignment = shooterManager.isShooting ? handRotation : rot;
var angle = Vector3.Angle(aimPoint - aimAngleReference.transform.position, aimAngleReference.transform.forward);
if ((!(angle > shooterManager.maxHandAngle || angle < -shooterManager.maxHandAngle)))
handRotation = Quaternion.Lerp(handRotation, handRotationAlignment, shooterManager.smoothHandRotation * (Time.deltaTime));
else handRotation = Quaternion.Euler(0, 0, 0);
if (!float.IsNaN(handRotation.x) && !float.IsNaN(handRotation.y) && !float.IsNaN(handRotation.z))
hand.localRotation *= Quaternion.Euler(handRotation.eulerAngles.NormalizeAngle() * armAlignmentWeight);
CurrentActiveWeapon.SetScopeLookTarget(aimPoint);
}
else handRotation = Quaternion.Euler(0, 0, 0);
}
protected virtual void CheckCanAiming()
{
if (ragdolled || (!isStrafing && !lockAimDebug) || customAction || IsReloading)
{
_canAiming = false;
return;
}
var p1 = aimTarget;
p1.y = transform.position.y;
var angle = Vector3.Angle(transform.forward, p1 - transform.position);
var outAngle = (angle > aimTurnAngle);
//var aimLocalPoint = transform.InverseTransformPoint(aimTarget);
//var can = aimLocalPoint.z > _capsuleCollider.radius && Mathf.Abs(aimLocalPoint.x) > _capsuleCollider.radius;
_canAiming = !outAngle;
if (outAngle && isAiming) RotateTo(aimTarget - transform.position);
}
protected virtual void Shot()
{
if (isDead || !shooterManager || !shooterManager.CurrentWeapon || customAction) return;
if ((_canShot || forceCanShot) && !IsReloading && !_waitingReload && _canAiming && IsInShotAngle && isAiming)
{
forceCanShot = false;
if (shooterManager.weaponHasAmmo)
{
if (shots > 0)
{
shooterManager.Shoot(CurrentActiveWeapon.muzzle.position + CurrentActiveWeapon.muzzle.forward * 100);
shots--;
}
}
else if (!IsReloading && !_waitingReload)
StartCoroutine(Reload());
}
if (!_canShot && !IsReloading && !_waitingReload && doReloadWhileWaiting && shooterManager.CurrentWeapon.ammoCount < shooterManager.CurrentWeapon.clipSize)
{
shooterManager.ReloadWeapon();
}
}
protected virtual IEnumerator Reload()
{
_waitingReload = true;
yield return new WaitForSeconds(.5f);
shooterManager.ReloadWeapon();
float minTimeToStartReload = 2f;
///Wait enter in Reload State
while (!IsReloading)
{
minTimeToStartReload -= Time.deltaTime;
if (minTimeToStartReload <= 0) break;
yield return null;
}
///Wait exit Reload State
while (IsReloading)
{
yield return null;
}
yield return new WaitForSeconds(.5f);
_waitingReload = false;
}
protected override void TryBlockAttack(vDamage damage)
{
if (shooterManager.CurrentWeapon != null) { isBlocking = false; }
else base.TryBlockAttack(damage);
}
public override void Blocking()
{
if (shooterManager.CurrentWeapon != null) { isBlocking = false; return; }
base.Blocking();
}
public override void AimTo(Vector3 point, float timeToCancelAim = 1f, object sender = null)
{
aimTime = timeToCancelAim;
isAiming = true;
aimTarget = point;
}
public override void AimToTarget(float stayLookTime = 1, object sender = null)
{
aimTime = stayLookTime;
isAiming = true;
if (currentTarget.transform && currentTarget.collider)
aimTarget = _lastTargetPosition + Vector3.up * ((currentTarget.collider.bounds.size.y * 0.5f) + aimTargetHeight);
else
aimTarget = _lastTargetPosition + Vector3.up * aimTargetHeight;
if (!isStrafing && input.magnitude > 0.1f) isStrafing = true;
}
public override void StrafeMoveTo(Vector3 newDestination, Vector3 targetDirection, vAIMovementSpeed speed = vAIMovementSpeed.Walking)
{
if (isAiming)
{
if (useNavMeshAgent && navMeshAgent && navMeshAgent.isOnNavMesh && navMeshAgent.isStopped) navMeshAgent.isStopped = false;
SetStrafeLocomotion();
SetSpeed(speed);
destination = newDestination;
if (input.magnitude > 0.1f)
{
temporaryDirection = targetDirection;
temporaryDirectionTime = 1f;
}
}
else
base.StrafeMoveTo(newDestination, targetDirection, speed);
}
}
}