fix in autoweapon draw/ hide, bLock, bMeleeCombat and Input
This commit is contained in:
@@ -65,6 +65,27 @@ namespace Beyond
|
||||
|
||||
BindWeaponDrawEffectsOnEquipped();
|
||||
HideWeapons(true);
|
||||
GameStateManager.Instance.m_OnStateChanged.AddListener(OnGameStateChanged);
|
||||
}
|
||||
|
||||
private void OnGameStateChanged(GameStateManager.State arg0)
|
||||
{
|
||||
if (weaponsHided && arg0 == GameStateManager.State.NORMAL)
|
||||
{
|
||||
if (debugMode)
|
||||
{
|
||||
Debug.Log("Returning to normal state, drawing weapons");
|
||||
}
|
||||
HideWeapons(true);
|
||||
}
|
||||
else if (!weaponsHided && arg0 == GameStateManager.State.COMBAT)
|
||||
{
|
||||
if (debugMode)
|
||||
{
|
||||
Debug.Log("Entering combat state, hiding weapons");
|
||||
}
|
||||
DrawWeapons(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
@@ -78,6 +99,10 @@ namespace Beyond
|
||||
itemManager.onEquipItem.RemoveListener(PlayWeaponHideEffect);
|
||||
itemManager.onFinishEquipItem.RemoveListener(BindNewlyEquippedWeaponDrawHideEffects);
|
||||
}
|
||||
if (GameStateManager.Instance != null)
|
||||
{
|
||||
GameStateManager.Instance.m_OnStateChanged.RemoveListener(OnGameStateChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void BindWeaponDrawEffectsOnEquipped()
|
||||
@@ -256,7 +281,7 @@ namespace Beyond
|
||||
|
||||
protected virtual bool CanHideWeapons()
|
||||
{
|
||||
return melee && melee.meleeManager && (forceHide || (!melee.isAttacking && !melee.isBlocking && (melee.meleeManager.rightWeapon || melee.meleeManager.leftWeapon)));
|
||||
return melee && melee.meleeManager && (forceHide || (!melee.isAttacking && !melee.isBlocking && (GameStateManager.Instance.CurrentState != GameStateManager.State.COMBAT) && (melee.meleeManager.rightWeapon || melee.meleeManager.leftWeapon)));
|
||||
}
|
||||
|
||||
protected virtual bool CanDrawWeapons()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Beyond;
|
||||
using Invector;
|
||||
using System.Linq;
|
||||
using Invector; // Assuming vIHealthController is in this namespace or vCharacterController
|
||||
using Invector.vCharacterController;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@@ -9,20 +9,18 @@ using UnityEngine.UI;
|
||||
namespace Beyond
|
||||
{
|
||||
[vClassHeader("MELEE LOCK-ON")]
|
||||
public class bLockOn : vLockOnBehaviour
|
||||
public class bLockOn : vLockOnBehaviour // Inherits from your provided vLockOnBehaviour
|
||||
{
|
||||
#region variables
|
||||
|
||||
[System.Serializable]
|
||||
public class LockOnEvent : UnityEngine.Events.UnityEvent<Transform>
|
||||
{ }
|
||||
public class LockOnEvent : UnityEngine.Events.UnityEvent<Transform> { }
|
||||
|
||||
[Tooltip("Make sure to disable or change the StrafeInput to a different key at the Player Input component")]
|
||||
public bool strafeWhileLockOn = true;
|
||||
|
||||
[Tooltip("Create a Image inside the UI and assign here")]
|
||||
public RectTransform aimImagePrefab;
|
||||
|
||||
public Canvas aimImageContainer;
|
||||
public Vector2 aimImageSize = new Vector2(30, 30);
|
||||
|
||||
@@ -33,70 +31,95 @@ namespace Beyond
|
||||
[Range(-0.5f, 0.5f)]
|
||||
public float spriteHeight = 0.25f;
|
||||
|
||||
[Tooltip("Offset for the camera height")]
|
||||
[Tooltip("Offset for the camera height when locking on")]
|
||||
public float cameraHeightOffset;
|
||||
|
||||
[Tooltip("Transition Speed for the Camera")]
|
||||
[Tooltip("Transition Speed for the Camera to rotate towards the target when locking on.")]
|
||||
public float lockSpeed = 0.5f;
|
||||
|
||||
[Header("LockOn Inputs")]
|
||||
public GenericInput lockOnInput = new GenericInput("Tab", "RightStickClick", "RightStickClick");
|
||||
|
||||
// Inputs for Next/Previous target are now handled by calling base.ChangeTarget(1) or base.ChangeTarget(-1)
|
||||
public GenericInput nexTargetInput = new GenericInput("X", false, false, "RightAnalogHorizontal", true, false, "X", false, false);
|
||||
public GenericInput previousTargetInput = new GenericInput("Z", false, false, "RightAnalogHorizontal", true, true, "Z", false, false);
|
||||
|
||||
internal bool isLockingOn;
|
||||
|
||||
public bool isLockingOn { get; private set; } // Keep this for external systems like AutoTargetting
|
||||
public LockOnEvent onLockOnTarget;
|
||||
public LockOnEvent onUnLockOnTarget;
|
||||
private Canvas _aimCanvas;
|
||||
private RectTransform _aimImage;
|
||||
|
||||
protected bool inTarget;
|
||||
private RectTransform _aimImageInstance;
|
||||
// 'inTarget' might be redundant if we rely on base.currentTarget != null and isLockingOn
|
||||
// protected bool inTarget;
|
||||
protected bMeleeCombatInput tpInput;
|
||||
private AutoTargetting autoTargetingSystem;
|
||||
|
||||
#endregion variables
|
||||
|
||||
protected virtual void Start()
|
||||
protected void Start() // Override if base has Start, otherwise just 'void Start()'
|
||||
{
|
||||
Init();
|
||||
// If vLockOnBehaviour.Start is not virtual, you might not need base.Start()
|
||||
// but Init() is crucial from the base class.
|
||||
base.Init(); // Call the Init from vLockOnBehaviour
|
||||
|
||||
tpInput = GetComponent<bMeleeCombatInput>();
|
||||
if (tpInput)
|
||||
{
|
||||
tpInput.onUpdate -= UpdateLockOn;
|
||||
tpInput.onUpdate += UpdateLockOn;
|
||||
|
||||
// access the HealthController to Reset the LockOn when Dead
|
||||
GetComponent<vHealthController>().onDead.AddListener((GameObject g) =>
|
||||
// Player health for unlocking on death (assuming player has vIHealthController)
|
||||
var playerHealth = GetComponent<vIHealthController>();
|
||||
if (playerHealth != null)
|
||||
{
|
||||
// action to reset lockOn
|
||||
isLockingOn = false;
|
||||
LockOn(false);
|
||||
UpdateLockOn();
|
||||
});
|
||||
// This part might need adjustment based on how vIHealthController handles death events
|
||||
// For now, let's assume a simple check or that other systems handle player death state.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("bLockOn: bMeleeCombatInput not found. Lock-on system disabled.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aimImageContainer)
|
||||
if (!aimImageContainer) aimImageContainer = GetComponentInChildren<Canvas>(true);
|
||||
if (aimImagePrefab && aimImageContainer && _aimImageInstance == null)
|
||||
{
|
||||
aimImageContainer = gameObject.GetComponentInChildren<Canvas>(true);
|
||||
_aimImageInstance = Instantiate(aimImagePrefab, aimImageContainer.transform, false);
|
||||
_aimImageInstance.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// Get AutoTargetting system
|
||||
if (Player.Instance != null) autoTargetingSystem = Player.Instance.GetComponentInChildren<AutoTargetting>(true);
|
||||
if (autoTargetingSystem == null) autoTargetingSystem = FindObjectOfType<AutoTargetting>();
|
||||
|
||||
if (autoTargetingSystem != null)
|
||||
{
|
||||
// Set the 'range' field from the base class
|
||||
base.range = autoTargetingSystem.maxTargetingDistance;
|
||||
// Note: findTargetAngle from AutoTargetting is not directly used by this base class.
|
||||
// The base class uses screen-space sorting. We can't easily inject world-space angle here
|
||||
// without modifying vLockOnBehaviour.GetPossibleTargets() or SortTargets().
|
||||
// For now, switching will respect AutoTargetting's *distance* but use base class's screen-angle logic.
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("bLockOn: AutoTargetting system not found. Using default vLockOnBehaviour range.");
|
||||
}
|
||||
}
|
||||
|
||||
public RectTransform aimImage
|
||||
public RectTransform AimImageDisplay
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_aimImage) return _aimImage;
|
||||
if (aimImageContainer)
|
||||
if (_aimImageInstance == null && aimImagePrefab && aimImageContainer)
|
||||
{
|
||||
_aimImage = Instantiate(aimImagePrefab, Vector2.zero, Quaternion.identity) as RectTransform;
|
||||
_aimImage.SetParent(aimImageContainer.transform);
|
||||
return _aimImage;
|
||||
_aimImageInstance = Instantiate(aimImagePrefab, aimImageContainer.transform, false);
|
||||
_aimImageInstance.anchoredPosition = Vector2.zero;
|
||||
// ... other setup for _aimImageInstance
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Missing UI Canvas in the scene, please add one");
|
||||
}
|
||||
return null;
|
||||
return _aimImageInstance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,139 +128,271 @@ namespace Beyond
|
||||
if (this.tpInput == null) return;
|
||||
LockOnInput();
|
||||
SwitchTargetsInput();
|
||||
CheckForCharacterAlive();
|
||||
CheckForCharacterAlive(); // Checks base.currentTarget
|
||||
UpdateAimImage();
|
||||
}
|
||||
|
||||
protected virtual void LockOnInput()
|
||||
{
|
||||
if (tpInput.tpCamera == null || tpInput.cc == null) return;
|
||||
|
||||
// lock the camera into a target, if there is any around
|
||||
if (lockOnInput.GetButtonDown() && !tpInput.cc.customAction)
|
||||
{
|
||||
isLockingOn = !isLockingOn;
|
||||
LockOn(isLockingOn);
|
||||
}
|
||||
// unlock the camera if the target is null
|
||||
else if (isLockingOn && (tpInput.tpCamera.lockTarget == null))
|
||||
{
|
||||
isLockingOn = false;
|
||||
LockOn(false);
|
||||
}
|
||||
// choose to use lock-on with strafe of free movement
|
||||
if (strafeWhileLockOn && !tpInput.cc.locomotionType.Equals(vThirdPersonMotor.LocomotionType.OnlyStrafe))
|
||||
{
|
||||
if (isLockingOn && tpInput.tpCamera.lockTarget != null)
|
||||
// Toggle lock-on state
|
||||
if (isLockingOn)
|
||||
{
|
||||
tpInput.cc.lockInStrafe = true;
|
||||
tpInput.cc.isStrafing = true;
|
||||
UnlockTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
tpInput.cc.lockInStrafe = false;
|
||||
tpInput.cc.isStrafing = false;
|
||||
AttemptLockOn(null); // Attempt to find a new target
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method is called by base.ChangeTargetRoutine when a target is selected
|
||||
protected override void SetTarget()
|
||||
{
|
||||
if (tpInput.tpCamera != null)
|
||||
// base.currentTarget (which is base.target) has been set by ChangeTargetRoutine
|
||||
// or by our AttemptLockOn/ManuallySetLockOnTarget.
|
||||
// We just need to react to it.
|
||||
if (tpInput.tpCamera != null && base.currentTarget != null)
|
||||
{
|
||||
tpInput.tpCamera.SetLockTarget(currentTarget.transform, cameraHeightOffset, lockSpeed);
|
||||
onLockOnTarget.Invoke(currentTarget);
|
||||
tpInput.tpCamera.SetLockTarget(base.currentTarget.transform, cameraHeightOffset, lockSpeed);
|
||||
if (isLockingOn) // Only invoke if we are truly in a locking state
|
||||
{
|
||||
onLockOnTarget.Invoke(base.currentTarget.transform);
|
||||
}
|
||||
}
|
||||
else if (base.currentTarget == null && isLockingOn) // Target became null while we thought we were locked
|
||||
{
|
||||
UnlockTarget(false); // Silently unlock if target disappeared
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected virtual void SwitchTargetsInput()
|
||||
{
|
||||
if (tpInput.tpCamera == null) return;
|
||||
|
||||
if (tpInput.tpCamera.lockTarget)
|
||||
if (tpInput.tpCamera == null || !isLockingOn) return;
|
||||
// base.currentTarget is the currently locked Transform
|
||||
if (base.currentTarget != null)
|
||||
{
|
||||
// switch between targets using Keyboard
|
||||
if (previousTargetInput.GetButtonDown()) PreviousTarget();
|
||||
else if (nexTargetInput.GetButtonDown()) NextTarget();
|
||||
if (previousTargetInput.GetButtonDown()) base.ChangeTarget(-1); // Calls base class method
|
||||
else if (nexTargetInput.GetButtonDown()) base.ChangeTarget(1); // Calls base class method
|
||||
}
|
||||
}
|
||||
|
||||
// 'ChangeTarget' is already defined in the base class and handles index changes.
|
||||
// We override SetTarget() which is called by the base ChangeTargetRoutine.
|
||||
|
||||
protected virtual void CheckForCharacterAlive()
|
||||
{
|
||||
if (currentTarget && !isCharacterAlive() && inTarget || (inTarget && !isCharacterAlive()))
|
||||
// base.isCharacterAlive() checks the base.currentTarget
|
||||
if (isLockingOn && base.currentTarget != null && !base.isCharacterAlive())
|
||||
{
|
||||
ResetLockOn();
|
||||
inTarget = false;
|
||||
LockOn(true);
|
||||
StopLockOn();
|
||||
// Debug.Log($"bLockOn: Locked target {base.currentTarget.name} died. Attempting to find new one or unlock.");
|
||||
Transform oldDeadTarget = base.currentTarget;
|
||||
AttemptLockOn(null, oldDeadTarget); // Try to find a new target, excluding the dead one for this attempt
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void LockOn(bool value)
|
||||
/// <summary>
|
||||
/// Attempts to lock onto a target. If preferredTarget is provided and valid, locks that.
|
||||
/// Otherwise, finds the best available target.
|
||||
/// </summary>
|
||||
protected void AttemptLockOn(Transform preferredTarget, Transform excludeTarget = null)
|
||||
{
|
||||
base.UpdateLockOn(value);
|
||||
if (!inTarget && currentTarget)
|
||||
if (tpInput == null || tpInput.cc == null || tpInput.tpCamera == null) return;
|
||||
|
||||
Transform targetToLock = null;
|
||||
|
||||
if (preferredTarget != null && base.isCharacterAlive(preferredTarget))
|
||||
{
|
||||
inTarget = true;
|
||||
// send current target if inTarget
|
||||
SetTarget();
|
||||
targetToLock = preferredTarget;
|
||||
}
|
||||
else if (inTarget && !currentTarget)
|
||||
else
|
||||
{
|
||||
inTarget = false;
|
||||
// send message to clear current target
|
||||
StopLockOn();
|
||||
// Update range from AutoTargetting before finding targets
|
||||
if (autoTargetingSystem != null) base.range = autoTargetingSystem.maxTargetingDistance;
|
||||
|
||||
List<Transform> possible = base.GetPossibleTargets(); // This uses base.range
|
||||
if (possible != null && possible.Count > 0)
|
||||
{
|
||||
// Filter out the excludeTarget if provided
|
||||
if (excludeTarget != null)
|
||||
{
|
||||
possible.Remove(excludeTarget);
|
||||
}
|
||||
// Optional: Re-filter 'possible' list here using AutoTargetting's angle
|
||||
// This would require iterating 'possible' and doing Vector3.Angle checks.
|
||||
// For now, we rely on base.SortTargets() which is screen-based.
|
||||
if (possible.Count > 0)
|
||||
{
|
||||
targetToLock = possible.FirstOrDefault(); // Base.GetPossibleTargets already sorts them
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targetToLock != null)
|
||||
{
|
||||
// If we were previously locked on a different target
|
||||
if (isLockingOn && base.currentTarget != null && base.currentTarget != targetToLock)
|
||||
{
|
||||
onUnLockOnTarget.Invoke(base.currentTarget); // Invoke for old target
|
||||
}
|
||||
|
||||
// This directly sets the protected 'target' field in the base class
|
||||
// Since we can't call a base.SelectTarget(), we mimic what base.UpdateLockOn(true) would do.
|
||||
this.GetType().GetField("target", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(this, targetToLock);
|
||||
// this.target = targetToLock; // This would create a new field in bLockOn, not set base.target
|
||||
|
||||
isLockingOn = true;
|
||||
base.UpdateLockOn(true); // This will set base.target if list not empty, and also set _inLockOn
|
||||
// and might call SetTarget if list was empty and now has one.
|
||||
// It's a bit of a dance because the base class design is restrictive.
|
||||
|
||||
// We need to ensure our 'isLockingOn' and the base class's internal lock state are synced.
|
||||
// And that SetTarget() (our override) is called to update camera & events.
|
||||
if (base.currentTarget == targetToLock) // If base.UpdateLockOn successfully set it
|
||||
{
|
||||
this.SetTarget(); // Manually call our override to ensure camera and events fire
|
||||
UpdateStrafeState(true);
|
||||
UpdateAimImage();
|
||||
}
|
||||
else // Fallback if base.UpdateLockOn didn't pick our target (e.g. list was empty for it)
|
||||
{
|
||||
// This case should ideally not happen if targetToLock was valid.
|
||||
// If it does, it means base.GetPossibleTargets within UpdateLockOn failed.
|
||||
UnlockTarget(false); // Silently unlock
|
||||
}
|
||||
}
|
||||
else // No target found or preferred target was invalid
|
||||
{
|
||||
UnlockTarget();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLockOnToFalse()
|
||||
protected void UnlockTarget(bool invokeEvent = true)
|
||||
{
|
||||
LockOn(false);
|
||||
if (tpInput == null || tpInput.tpCamera == null) return;
|
||||
|
||||
Transform previouslyLocked = base.currentTarget; // Get before clearing
|
||||
|
||||
base.UpdateLockOn(false); // This sets base.target to null and base._inLockOn to false
|
||||
isLockingOn = false;
|
||||
|
||||
if (previouslyLocked != null && invokeEvent)
|
||||
{
|
||||
onUnLockOnTarget.Invoke(previouslyLocked);
|
||||
}
|
||||
|
||||
tpInput.tpCamera.RemoveLockTarget();
|
||||
UpdateStrafeState(false);
|
||||
UpdateAimImage();
|
||||
}
|
||||
|
||||
|
||||
public void ManuallySetLockOnTarget(Transform newTargetTransform, bool shouldLock)
|
||||
{
|
||||
if (shouldLock)
|
||||
{
|
||||
AttemptLockOn(newTargetTransform);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnlockTarget();
|
||||
}
|
||||
}
|
||||
|
||||
public Transform GetCurrentLockOnTarget()
|
||||
{
|
||||
// Relies on base.currentTarget which is the Transform 'target' from base class
|
||||
return isLockingOn ? base.currentTarget : null;
|
||||
}
|
||||
|
||||
private void UpdateStrafeState(bool shouldStrafe)
|
||||
{
|
||||
if (strafeWhileLockOn && tpInput?.cc != null && !tpInput.cc.locomotionType.Equals(vThirdPersonMotor.LocomotionType.OnlyStrafe))
|
||||
{
|
||||
bool canStrafe = shouldStrafe && isLockingOn && base.currentTarget != null;
|
||||
tpInput.cc.lockInStrafe = canStrafe;
|
||||
tpInput.cc.isStrafing = canStrafe;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLockOnToFalse() => UnlockTarget();
|
||||
|
||||
protected virtual void UpdateAimImage()
|
||||
{
|
||||
if (!aimImageContainer || !aimImage) return;
|
||||
if (hideSprite)
|
||||
var displayImage = AimImageDisplay;
|
||||
if (!aimImageContainer || displayImage == null) return;
|
||||
|
||||
displayImage.sizeDelta = aimImageSize;
|
||||
// base.currentTarget is the Transform, base.isCharacterAlive() checks it
|
||||
bool shouldShowAimImage = isLockingOn && base.currentTarget != null && base.isCharacterAlive(base.currentTarget);
|
||||
|
||||
|
||||
if (hideSprite) displayImage.gameObject.SetActive(shouldShowAimImage);
|
||||
else if (!displayImage.gameObject.activeSelf) displayImage.gameObject.SetActive(true);
|
||||
|
||||
if (shouldShowAimImage && tpCamera != null && base.currentTarget != null)
|
||||
{
|
||||
aimImage.sizeDelta = aimImageSize;
|
||||
if (currentTarget && !aimImage.transform.gameObject.activeSelf && isCharacterAlive())
|
||||
aimImage.transform.gameObject.SetActive(true);
|
||||
else if (!currentTarget && aimImage.transform.gameObject.activeSelf)
|
||||
aimImage.transform.gameObject.SetActive(false);
|
||||
else if (_aimImage.transform.gameObject.activeSelf && !isCharacterAlive())
|
||||
aimImage.transform.gameObject.SetActive(false);
|
||||
// Using the extension method from vLockOnHelper
|
||||
displayImage.anchoredPosition = base.currentTarget.GetScreenPointOffBoundsCenter(aimImageContainer, tpCamera.targetCamera, spriteHeight);
|
||||
}
|
||||
if (currentTarget && aimImage && aimImageContainer)
|
||||
aimImage.anchoredPosition = currentTarget.GetScreenPointOffBoundsCenter(aimImageContainer, tpCamera.targetCamera, spriteHeight);
|
||||
else if (aimImageContainer)
|
||||
aimImage.anchoredPosition = Vector2.zero;
|
||||
else if (!hideSprite) displayImage.anchoredPosition = Vector2.zero;
|
||||
}
|
||||
|
||||
public virtual void StopLockOn()
|
||||
// StopLockOn is effectively UnlockTarget now
|
||||
// public virtual void StopLockOn() { UnlockTarget(); }
|
||||
|
||||
|
||||
public List<Transform> GetNearbyTargets() // For AutoTargetting/MagicAttacks
|
||||
{
|
||||
if (currentTarget == null && tpInput.tpCamera != null)
|
||||
if (autoTargetingSystem != null)
|
||||
{
|
||||
onUnLockOnTarget.Invoke(tpInput.tpCamera.lockTarget);
|
||||
tpInput.tpCamera.RemoveLockTarget();
|
||||
isLockingOn = false;
|
||||
inTarget = false;
|
||||
base.range = autoTargetingSystem.maxTargetingDistance;
|
||||
// Angle filtering from AutoTargetting would need to be applied manually here
|
||||
// if we want to override the base class's screen-based sorting/filtering for this specific call.
|
||||
}
|
||||
}
|
||||
// base.GetPossibleTargets() returns List<Transform>
|
||||
List<Transform> allTargetsInBaseRange = base.GetPossibleTargets();
|
||||
|
||||
public virtual void NextTarget()
|
||||
{
|
||||
base.ChangeTarget(1);
|
||||
}
|
||||
if (allTargetsInBaseRange == null) return new List<Transform>();
|
||||
|
||||
public virtual void PreviousTarget()
|
||||
{
|
||||
base.ChangeTarget(-1);
|
||||
}
|
||||
// Optional: Further filter allTargetsInBaseRange by AutoTargetting's angle
|
||||
if (autoTargetingSystem != null && _playerTransform != null) // Assuming _playerTransform is accessible or passed
|
||||
{
|
||||
List<Transform> angleFilteredTargets = new List<Transform>();
|
||||
Vector3 playerPos = _playerTransform.position; // Need player transform
|
||||
Vector3 playerFwd = _playerTransform.forward;
|
||||
|
||||
public List<Transform> GetNearbyTargets()
|
||||
foreach (Transform t in allTargetsInBaseRange)
|
||||
{
|
||||
if (t == null) continue;
|
||||
Vector3 dirToTarget = (t.position - playerPos);
|
||||
dirToTarget.y = 0; // Assuming 2D angle check for simplicity
|
||||
if (dirToTarget.sqrMagnitude < 0.001f) // Target is at player's feet
|
||||
{
|
||||
angleFilteredTargets.Add(t);
|
||||
continue;
|
||||
}
|
||||
float angle = Vector3.Angle(playerFwd, dirToTarget.normalized);
|
||||
if (angle <= autoTargetingSystem.targetingAngleThreshold)
|
||||
{
|
||||
angleFilteredTargets.Add(t);
|
||||
}
|
||||
}
|
||||
return angleFilteredTargets;
|
||||
}
|
||||
|
||||
return allTargetsInBaseRange;
|
||||
}
|
||||
// Need player transform for angle filtering in GetNearbyTargets
|
||||
private Transform _playerTransform;
|
||||
void Awake() // Get player transform
|
||||
{
|
||||
return base.GetPossibleTargets();
|
||||
if (Player.Instance != null) _playerTransform = Player.Instance.transform;
|
||||
else _playerTransform = transform; // Fallback if bLockOn is on player
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,20 +3,20 @@ using Invector.vCharacterController;
|
||||
using Invector.vEventSystems;
|
||||
using Invector.vMelee;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace Beyond
|
||||
{
|
||||
// here you can modify the Melee Combat inputs
|
||||
// if you want to modify the Basic Locomotion inputs, go to the vThirdPersonInput
|
||||
[vClassHeader("MELEE INPUT MANAGER", iconName = "inputIcon")]
|
||||
public class bMeleeCombatInput : bThirdPersonInput, vIMeleeFighter
|
||||
{
|
||||
// ... (rest of your existing bMeleeCombatInput variables) ...
|
||||
|
||||
#region Variables
|
||||
|
||||
[vEditorToolbar("Inputs")]
|
||||
[Header("Melee Inputs")]
|
||||
public GenericInput weakAttackInput = new GenericInput("Mouse0", "RB", "RB");
|
||||
|
||||
public GenericInput strongAttackInput = new GenericInput("Alpha1", false, "RT", true, "RT", false);
|
||||
public GenericInput blockInput = new GenericInput("Mouse1", "LB", "LB");
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Beyond
|
||||
|
||||
public bool isAttacking
|
||||
{
|
||||
get => _isAttacking || cc.IsAnimatorTag("Attack");
|
||||
get => _isAttacking || (cc != null && cc.IsAnimatorTag("Attack"));
|
||||
protected set { _isAttacking = value; }
|
||||
}
|
||||
|
||||
@@ -44,10 +44,20 @@ namespace Beyond
|
||||
|
||||
[HideInInspector] public bool lockMeleeInput;
|
||||
|
||||
[Header("Dash Settings")]
|
||||
[Tooltip("Speed at which the player rotates towards the target before dashing.")]
|
||||
public float dashRotationSpeed = 15f;
|
||||
[Tooltip("Angle threshold (degrees). If angle to target is less than this, player dashes immediately without pre-rotation.")]
|
||||
public float dashFacingAngleThreshold = 10f;
|
||||
[Tooltip("Maximum time (seconds) the pre-dash rotation will attempt before dashing anyway.")]
|
||||
public float maxDashRotationTime = 0.5f;
|
||||
|
||||
private AutoTargetting autoTargeting;
|
||||
private bool isRotatingAndDashing = false;
|
||||
|
||||
public void SetLockMeleeInput(bool value)
|
||||
{
|
||||
lockMeleeInput = value;
|
||||
|
||||
if (value)
|
||||
{
|
||||
isAttacking = false;
|
||||
@@ -63,17 +73,30 @@ namespace Beyond
|
||||
|
||||
private MagicAttacks magicAttacks;
|
||||
|
||||
#endregion Variables
|
||||
#endregion
|
||||
|
||||
public virtual bool lockInventory
|
||||
{
|
||||
get { return isAttacking || cc.isDead || (cc.customAction || cc.IsAnimatorTag("special")) || cc.isRolling; }
|
||||
get { return isAttacking || (cc != null && (cc.isDead || cc.customAction || cc.IsAnimatorTag("special") || cc.isRolling)); }
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
base.Start(); // This will call bThirdPersonInput's Start, which gets 'cc'
|
||||
magicAttacks = GetComponent<MagicAttacks>();
|
||||
autoTargeting = GetComponent<AutoTargetting>();
|
||||
if (autoTargeting == null && Player.Instance != null && Player.Instance.gameObject == this.gameObject)
|
||||
{
|
||||
autoTargeting = Player.Instance.GetComponent<AutoTargetting>();
|
||||
}
|
||||
if (autoTargeting == null && cc != null && cc.transform.root != null)
|
||||
{
|
||||
autoTargeting = cc.transform.root.GetComponentInChildren<AutoTargetting>(true);
|
||||
}
|
||||
if (autoTargeting == null)
|
||||
{
|
||||
Debug.LogWarning("bMeleeCombatInput: AutoTargetting component not found. Dash towards target will require manual aiming.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LateUpdate()
|
||||
@@ -85,17 +108,12 @@ namespace Beyond
|
||||
protected override void FixedUpdate()
|
||||
{
|
||||
base.FixedUpdate();
|
||||
//force showing cursor
|
||||
ShowCursor(showCursorOnStart);
|
||||
isBlocking = Input.GetKeyDown(KeyCode.D);
|
||||
}
|
||||
|
||||
protected override void InputHandle()
|
||||
{
|
||||
if (cc == null || cc.isDead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (cc == null || cc.isDead) return;
|
||||
|
||||
base.InputHandle();
|
||||
|
||||
@@ -108,22 +126,18 @@ namespace Beyond
|
||||
else
|
||||
{
|
||||
ResetAttackTriggers();
|
||||
isBlocking = false;
|
||||
if (!blockInput.GetButton())
|
||||
{
|
||||
isBlocking = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region MeleeCombat Input Methods
|
||||
|
||||
/// <summary>
|
||||
/// WEAK ATK INPUT
|
||||
/// </summary>
|
||||
public virtual void MeleeWeakAttackInput()
|
||||
{
|
||||
if (cc.animator == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (cc.animator == null) return;
|
||||
if (weakAttackInput.GetButtonDown() && MeleeAttackStaminaConditions())
|
||||
{
|
||||
TriggerWeakAttack();
|
||||
@@ -136,16 +150,9 @@ namespace Beyond
|
||||
cc.animator.SetTrigger(vAnimatorParameters.WeakAttack);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// STRONG ATK INPUT
|
||||
/// </summary>
|
||||
public virtual void MeleeStrongAttackInput()
|
||||
{
|
||||
if (cc.animator == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (cc.animator == null) return;
|
||||
if (strongAttackInput.GetButtonDown() &&
|
||||
(!meleeManager.CurrentActiveAttackWeapon || meleeManager.CurrentActiveAttackWeapon.useStrongAttack) &&
|
||||
MeleeAttackStaminaConditions())
|
||||
@@ -160,22 +167,17 @@ namespace Beyond
|
||||
cc.animator.SetTrigger(vAnimatorParameters.StrongAttack);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BLOCK INPUT
|
||||
/// </summary>
|
||||
public virtual void BlockingInput()
|
||||
{
|
||||
if (cc.animator == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (cc.animator == null) return;
|
||||
isBlocking = blockInput.GetButton() && cc.currentStamina > 0 && !cc.customAction &&
|
||||
!cc.IsAnimatorTag("special") && !isAttacking;
|
||||
}
|
||||
|
||||
public override void ControlRotation()
|
||||
{
|
||||
if (cc == null || cc.lockRotation) return;
|
||||
|
||||
if (cameraMain && !lockUpdateMoveDirection)
|
||||
{
|
||||
if (!cc.keepDirection)
|
||||
@@ -183,148 +185,235 @@ namespace Beyond
|
||||
cc.UpdateMoveDirection(cameraMain.transform);
|
||||
}
|
||||
}
|
||||
|
||||
//here
|
||||
|
||||
if (tpCamera != null && tpCamera.lockTarget && cc.isStrafing && !cc.isRolling)
|
||||
{
|
||||
cc.RotateToPosition(tpCamera.lockTarget.position); // rotate the character to a specific target
|
||||
cc.RotateToPosition(tpCamera.lockTarget.position);
|
||||
}
|
||||
else
|
||||
{
|
||||
cc.ControlRotationType(); // handle the controller rotation type (strafe or free)
|
||||
cc.ControlRotationType();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override the Sprint method to cancel Sprinting when Attacking
|
||||
/// </summary>
|
||||
protected override void SprintInput()
|
||||
{
|
||||
if (sprintInput.useInput)
|
||||
if (lockSprintInput) return; // Check local lock first
|
||||
if (sprintInput.useInput && cc != null)
|
||||
{
|
||||
bool canSprint = cc.useContinuousSprint ? sprintInput.GetButtonDown() : sprintInput.GetButton();
|
||||
// Let base class (vThirdPersonInput) handle the cc.Sprint call if we don't override completely
|
||||
// For now, let's assume your bThirdPersonInput's SprintInput or vThirdPersonInput's one is what you want.
|
||||
// If it was base.SprintInput() before, and you have bThirdPersonInput overriding it, make sure that's intended.
|
||||
// For simplicity, directly call cc.Sprint if bThirdPersonInput doesn't add much, or call base.SprintInput() if it does.
|
||||
cc.Sprint(canSprint && !isAttacking);
|
||||
}
|
||||
}
|
||||
protected override void CrouchInput()
|
||||
{
|
||||
if (lockCrouchInput) return;
|
||||
base.CrouchInput(); // Call the base class logic from vThirdPersonInput/bThirdPersonInput
|
||||
}
|
||||
|
||||
#endregion MeleeCombat Input Methods
|
||||
protected override void StrafeInput()
|
||||
{
|
||||
if (lockStrafeInput) return;
|
||||
base.StrafeInput(); // Call the base class logic from vThirdPersonInput/bThirdPersonInput
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Conditions
|
||||
|
||||
protected virtual bool MeleeAttackStaminaConditions()
|
||||
{
|
||||
if (meleeManager == null) meleeManager = GetComponent<vMeleeManager>();
|
||||
if (meleeManager == null || cc == null) return false;
|
||||
var result = cc.currentStamina - meleeManager.GetAttackStaminaCost();
|
||||
return result >= 0;
|
||||
}
|
||||
|
||||
public virtual bool MeleeAttackConditions()
|
||||
{
|
||||
if (meleeManager == null)
|
||||
{
|
||||
meleeManager = GetComponent<vMeleeManager>();
|
||||
}
|
||||
|
||||
return meleeManager != null && cc.isGrounded && !cc.customAction && !cc.IsAnimatorTag("special") &&
|
||||
if (meleeManager == null) meleeManager = GetComponent<vMeleeManager>();
|
||||
return meleeManager != null && cc != null && cc.isGrounded && !cc.customAction && !cc.IsAnimatorTag("special") &&
|
||||
!cc.isJumping && !cc.isCrouching && !cc.isRolling && !isEquipping &&
|
||||
!cc.animator.IsInTransition(cc.baseLayer);
|
||||
(cc.animator != null && !cc.animator.IsInTransition(cc.baseLayer)) && !isRotatingAndDashing;
|
||||
}
|
||||
|
||||
protected override bool JumpConditions()
|
||||
// We override JumpInput, so we'll use the base JumpConditions if needed, or reimplement.
|
||||
// vThirdPersonInput.JumpConditions():
|
||||
// return !cc.customAction && !cc.isCrouching && cc.isGrounded && cc.GroundAngle() < cc.slopeLimit && cc.currentStamina >= cc.jumpStamina && !cc.isJumping && !cc.isRolling;
|
||||
protected override bool JumpConditions() // This is from vThirdPersonInput
|
||||
{
|
||||
return !isAttacking && base.JumpConditions();
|
||||
if (cc == null) return false;
|
||||
bool baseConditions = !cc.customAction && !cc.isCrouching && cc.isGrounded && cc.GroundAngle() < cc.slopeLimit && cc.currentStamina >= cc.jumpStamina && !cc.isJumping && !cc.isRolling;
|
||||
return baseConditions && !isAttacking && !isRotatingAndDashing; // Add our specific conditions
|
||||
}
|
||||
/*
|
||||
protected override bool RollConditions()
|
||||
|
||||
// We override RollInput, so we'll use the base RollConditions or reimplement.
|
||||
// vThirdPersonInput.RollConditions():
|
||||
// return (!cc.isRolling || cc.canRollAgain) && cc.isGrounded && !cc.customAction && cc.currentStamina > cc.rollStamina && !cc.isJumping && !cc.isSliding;
|
||||
protected override bool RollConditions() // This is from vThirdPersonInput
|
||||
{
|
||||
return base.RollConditions() && !isAttacking && !cc.animator.IsInTransition(cc.upperBodyLayer) &&
|
||||
!cc.animator.IsInTransition(cc.fullbodyLayer);
|
||||
if (cc == null) return false;
|
||||
bool baseConditions = (!cc.isRolling || cc.canRollAgain) && cc.isGrounded && !cc.customAction && cc.currentStamina > cc.rollStamina && !cc.isJumping && !cc.isSliding;
|
||||
// Add any bMeleeCombatInput specific conditions if necessary, like !isAttacking
|
||||
return baseConditions && !isAttacking && !isRotatingAndDashing;
|
||||
}
|
||||
*/
|
||||
#endregion Conditions
|
||||
|
||||
#region Update Animations
|
||||
|
||||
protected virtual void UpdateMeleeAnimations()
|
||||
#endregion
|
||||
|
||||
// MODIFIED JumpInput
|
||||
protected override void JumpInput()
|
||||
{
|
||||
if (cc.animator == null || meleeManager == null)
|
||||
if (lockJumpInput) return; // From bThirdPersonInput
|
||||
if (jumpInput.GetButtonDown() && JumpConditions()) // JumpConditions now includes !isAttacking & !isRotatingAndDashing
|
||||
{
|
||||
return;
|
||||
cc.Jump(true);
|
||||
}
|
||||
|
||||
cc.animator.SetInteger(vAnimatorParameters.AttackID, AttackID);
|
||||
cc.animator.SetInteger(vAnimatorParameters.DefenseID, DefenseID);
|
||||
cc.animator.SetBool(vAnimatorParameters.IsBlocking, isBlocking);
|
||||
cc.animator.SetFloat(vAnimatorParameters.MoveSet_ID, meleeMoveSetID, .2f, vTime.deltaTime);
|
||||
isEquipping = cc.IsAnimatorTag("IsEquipping");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default moveset id used when is without weapon
|
||||
/// </summary>
|
||||
public virtual int defaultMoveSetID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to ignore the Weapon moveset id and use the <seealso cref="defaultMoveSetID"/>
|
||||
/// </summary>
|
||||
public virtual bool overrideWeaponMoveSetID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current moveset id based if is using weapon or not
|
||||
/// </summary>
|
||||
public virtual int meleeMoveSetID
|
||||
// MODIFIED RollInput
|
||||
protected override void RollInput()
|
||||
{
|
||||
get
|
||||
if (lockRollInput) return; // From bThirdPersonInput
|
||||
if (cc == null) return;
|
||||
if (isRotatingAndDashing) return;
|
||||
|
||||
// Use the overridden RollConditions which now includes !isAttacking and !isRotatingAndDashing
|
||||
if (rollInput.GetButtonDown() && RollConditions())
|
||||
{
|
||||
int id = meleeManager.GetMoveSetID();
|
||||
if (id == 0 || overrideWeaponMoveSetID)
|
||||
bThirdPersonController beyondController = cc as bThirdPersonController;
|
||||
if (beyondController == null)
|
||||
{
|
||||
id = defaultMoveSetID;
|
||||
Debug.LogError("cc is not a bThirdPersonController instance! Cannot Dash/Roll.");
|
||||
if(cc != null) cc.Roll(); // Fallback to cc's roll if cast fails
|
||||
return;
|
||||
}
|
||||
|
||||
return id;
|
||||
bool isInputBackwards = cc.input.z * -1f >= 0 && Mathf.Abs(cc.input.x) < 0.2f; // Or cc.rawInput.z if you use raw input for this decision
|
||||
|
||||
if (!isInputBackwards)
|
||||
{
|
||||
beyondController.Roll(); // Or cc.Roll() if bThirdPersonController doesn't override it meaningfully
|
||||
}
|
||||
else // Forward, neutral, or sideways input
|
||||
{
|
||||
if (autoTargeting != null && autoTargeting.CurrentTarget != null)
|
||||
{
|
||||
Transform target = autoTargeting.CurrentTarget.transform;
|
||||
Vector3 directionToTarget = (target.position - cc.transform.position);
|
||||
directionToTarget.y = 0;
|
||||
|
||||
if (directionToTarget.sqrMagnitude < 0.01f) // Very close
|
||||
{
|
||||
beyondController.Dash();
|
||||
}
|
||||
else
|
||||
{
|
||||
float angleToTarget = Vector3.Angle(cc.transform.forward, directionToTarget.normalized);
|
||||
if (angleToTarget <= dashFacingAngleThreshold)
|
||||
{
|
||||
beyondController.Dash();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isRotatingAndDashing) // Should be redundant due to the check at the start of the method
|
||||
{
|
||||
StartCoroutine(RotateAndDashCoroutine(target, beyondController));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
beyondController.Dash(); // No target, regular dash
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ResetMeleeAnimations()
|
||||
|
||||
protected virtual IEnumerator RotateAndDashCoroutine(Transform target, bThirdPersonController controller)
|
||||
{
|
||||
if (meleeManager == null || !animator)
|
||||
if (isRotatingAndDashing || controller == null) yield break;
|
||||
isRotatingAndDashing = true;
|
||||
|
||||
bool previousLockRotation = controller.lockRotation;
|
||||
controller.lockRotation = true;
|
||||
|
||||
bool wasStrafing = controller.isStrafing;
|
||||
bool originalKeepDirection = controller.keepDirection;
|
||||
|
||||
if (wasStrafing && controller.isStrafing)
|
||||
{
|
||||
return;
|
||||
controller.Strafe();
|
||||
}
|
||||
controller.keepDirection = false;
|
||||
|
||||
cc.animator.SetBool(vAnimatorParameters.IsBlocking, false);
|
||||
float startTime = Time.time;
|
||||
Vector3 directionToTarget;
|
||||
Quaternion targetRotationQuaternion;
|
||||
|
||||
while (Time.time < startTime + maxDashRotationTime)
|
||||
{
|
||||
if (target == null || !target.gameObject.activeInHierarchy) break;
|
||||
if (controller == null) { isRotatingAndDashing = false; yield break; }
|
||||
|
||||
directionToTarget = (target.position - controller.transform.position);
|
||||
directionToTarget.y = 0;
|
||||
|
||||
if (directionToTarget.sqrMagnitude < 0.001f) break;
|
||||
|
||||
targetRotationQuaternion = Quaternion.LookRotation(directionToTarget.normalized);
|
||||
controller.transform.rotation = Quaternion.Slerp(controller.transform.rotation, targetRotationQuaternion, Time.deltaTime * dashRotationSpeed);
|
||||
|
||||
if (Vector3.Angle(controller.transform.forward, directionToTarget.normalized) <= dashFacingAngleThreshold)
|
||||
{
|
||||
controller.transform.rotation = targetRotationQuaternion;
|
||||
break;
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (controller == null) { isRotatingAndDashing = false; yield break; }
|
||||
|
||||
if (target != null && target.gameObject.activeInHierarchy &&
|
||||
(Time.time >= startTime + maxDashRotationTime || Vector3.Angle(controller.transform.forward, (target.position - controller.transform.position).normalized) > 0.1f) )
|
||||
{
|
||||
directionToTarget = (target.position - controller.transform.position);
|
||||
directionToTarget.y = 0;
|
||||
if (directionToTarget.sqrMagnitude > 0.001f)
|
||||
{
|
||||
controller.transform.rotation = Quaternion.LookRotation(directionToTarget.normalized);
|
||||
}
|
||||
}
|
||||
|
||||
controller.lockRotation = previousLockRotation;
|
||||
if (wasStrafing && !controller.isStrafing)
|
||||
{
|
||||
controller.Strafe();
|
||||
}
|
||||
controller.keepDirection = originalKeepDirection;
|
||||
|
||||
controller.Dash();
|
||||
|
||||
isRotatingAndDashing = false;
|
||||
}
|
||||
|
||||
public virtual int AttackID
|
||||
{
|
||||
get { return meleeManager ? meleeManager.GetAttackID() : 0; }
|
||||
}
|
||||
|
||||
public virtual int DefenseID
|
||||
{
|
||||
get { return meleeManager ? meleeManager.GetDefenseID() : 0; }
|
||||
}
|
||||
|
||||
#endregion Update Animations
|
||||
|
||||
#region Melee Methods
|
||||
|
||||
public virtual void OnEnableAttack()
|
||||
{
|
||||
if (meleeManager == null)
|
||||
{
|
||||
meleeManager = GetComponent<vMeleeManager>();
|
||||
}
|
||||
|
||||
if (meleeManager == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (meleeManager == null) meleeManager = GetComponent<vMeleeManager>();
|
||||
if (meleeManager == null || cc == null) return;
|
||||
|
||||
cc.currentStaminaRecoveryDelay = meleeManager.GetAttackStaminaRecoveryDelay();
|
||||
cc.currentStamina -= meleeManager.GetAttackStaminaCost();
|
||||
isAttacking = true;
|
||||
cc.isSprinting = false;
|
||||
if(cc!=null) cc.isSprinting = false;
|
||||
}
|
||||
|
||||
public virtual void OnDisableAttack()
|
||||
@@ -334,8 +423,11 @@ namespace Beyond
|
||||
|
||||
public virtual void ResetAttackTriggers()
|
||||
{
|
||||
cc.animator.ResetTrigger(vAnimatorParameters.WeakAttack);
|
||||
cc.animator.ResetTrigger(vAnimatorParameters.StrongAttack);
|
||||
if (cc != null && cc.animator != null)
|
||||
{
|
||||
cc.animator.ResetTrigger(vAnimatorParameters.WeakAttack);
|
||||
cc.animator.ResetTrigger(vAnimatorParameters.StrongAttack);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void BreakAttack(int breakAtkID)
|
||||
@@ -346,69 +438,71 @@ namespace Beyond
|
||||
|
||||
public virtual void OnRecoil(int recoilID)
|
||||
{
|
||||
cc.animator.SetInteger(vAnimatorParameters.RecoilID, recoilID);
|
||||
cc.animator.SetTrigger(vAnimatorParameters.TriggerRecoil);
|
||||
cc.animator.SetTrigger(vAnimatorParameters.ResetState);
|
||||
cc.animator.ResetTrigger(vAnimatorParameters.WeakAttack);
|
||||
cc.animator.ResetTrigger(vAnimatorParameters.StrongAttack);
|
||||
}
|
||||
|
||||
protected override void RollInput()
|
||||
{
|
||||
if (rollInput.GetButtonDown() && RollConditions())
|
||||
if (cc != null && cc.animator != null)
|
||||
{
|
||||
// cc.Roll();
|
||||
|
||||
if (cc.input.magnitude > 0.1f)
|
||||
{
|
||||
cc.Roll();
|
||||
}
|
||||
else
|
||||
{
|
||||
bThirdPersonController beyondController = (bThirdPersonController)cc;
|
||||
beyondController.Dash();
|
||||
}
|
||||
|
||||
cc.animator.SetInteger(vAnimatorParameters.RecoilID, recoilID);
|
||||
cc.animator.SetTrigger(vAnimatorParameters.TriggerRecoil);
|
||||
cc.animator.SetTrigger(vAnimatorParameters.ResetState);
|
||||
cc.animator.ResetTrigger(vAnimatorParameters.WeakAttack);
|
||||
cc.animator.ResetTrigger(vAnimatorParameters.StrongAttack);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual void OnReceiveAttack(vDamage damage, vIMeleeFighter attacker)
|
||||
{
|
||||
if (magicAttacks.shieldEffectIsActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// character is blocking
|
||||
if (cc == null) return;
|
||||
if (magicAttacks != null && magicAttacks.shieldEffectIsActive) return;
|
||||
|
||||
if (!damage.ignoreDefense && isBlocking && meleeManager != null &&
|
||||
meleeManager.CanBlockAttack(damage.sender.position))
|
||||
{
|
||||
var damageReduction = meleeManager.GetDefenseRate();
|
||||
if (damageReduction > 0)
|
||||
{
|
||||
damage.ReduceDamage(damageReduction);
|
||||
}
|
||||
|
||||
if (damageReduction > 0) damage.ReduceDamage(damageReduction);
|
||||
if (attacker != null && meleeManager != null && meleeManager.CanBreakAttack())
|
||||
{
|
||||
attacker.BreakAttack(meleeManager.GetDefenseRecoilID());
|
||||
}
|
||||
|
||||
meleeManager.OnDefense();
|
||||
cc.currentStaminaRecoveryDelay = damage.staminaRecoveryDelay;
|
||||
cc.currentStamina -= damage.staminaBlockCost;
|
||||
}
|
||||
|
||||
// apply damage
|
||||
damage.hitReaction = !isBlocking || damage.ignoreDefense;
|
||||
cc.TakeDamage(damage);
|
||||
}
|
||||
|
||||
public virtual vICharacter character
|
||||
{
|
||||
get { return cc; }
|
||||
}
|
||||
public virtual vICharacter character { get { return cc; } }
|
||||
|
||||
#endregion Melee Methods
|
||||
#endregion
|
||||
|
||||
#region Update Animations
|
||||
public virtual int defaultMoveSetID { get; set; }
|
||||
public virtual bool overrideWeaponMoveSetID { get; set; }
|
||||
public virtual int meleeMoveSetID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (meleeManager == null) meleeManager = GetComponent<vMeleeManager>();
|
||||
int id = meleeManager?.GetMoveSetID() ?? 0;
|
||||
if (id == 0 || overrideWeaponMoveSetID) id = defaultMoveSetID;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
public virtual void ResetMeleeAnimations()
|
||||
{
|
||||
if (meleeManager == null || cc == null || cc.animator == null) return;
|
||||
cc.animator.SetBool(vAnimatorParameters.IsBlocking, false);
|
||||
}
|
||||
public virtual int AttackID { get { if (meleeManager == null) meleeManager = GetComponent<vMeleeManager>(); return meleeManager?.GetAttackID() ?? 0; } }
|
||||
public virtual int DefenseID { get { if (meleeManager == null) meleeManager = GetComponent<vMeleeManager>(); return meleeManager?.GetDefenseID() ?? 0; } }
|
||||
protected virtual void UpdateMeleeAnimations()
|
||||
{
|
||||
if (cc == null || cc.animator == null || meleeManager == null) return;
|
||||
cc.animator.SetInteger(vAnimatorParameters.AttackID, AttackID);
|
||||
cc.animator.SetInteger(vAnimatorParameters.DefenseID, DefenseID);
|
||||
cc.animator.SetBool(vAnimatorParameters.IsBlocking, isBlocking);
|
||||
cc.animator.SetFloat(vAnimatorParameters.MoveSet_ID, meleeMoveSetID, .2f, vTime.deltaTime);
|
||||
isEquipping = cc.IsAnimatorTag("IsEquipping");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user