attack flow - breaking and blocking input, roll improvements
This commit is contained in:
@@ -105633,13 +105633,13 @@ MonoBehaviour:
|
||||
triggerDieBehaviour: 0
|
||||
m_ignoreTriggers: 1
|
||||
useAnimationBasedRotation: 0
|
||||
strafeRollInputThreshold: 0.3
|
||||
strafeRollForwardAnim: Roll_Forward
|
||||
strafeRollBackwardAnim: Roll_Backward
|
||||
strafeRollLeftAnim: Roll_Left
|
||||
strafeRollRightAnim: Roll_Right
|
||||
strafeRollLeftCorrectionAngle: 70.6
|
||||
strafeRollRightCorrectionAngle: 70
|
||||
strafeRollBackwardCorrectionAngle: 0
|
||||
--- !u!114 &9202663235077955828
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -772,8 +772,7 @@ MonoBehaviour:
|
||||
ignoreDefense: 0
|
||||
activeRagdoll: 0
|
||||
senselessTime: 0
|
||||
resetAttackTrigger: 1
|
||||
resetTriggerBeforeTime: 0.5
|
||||
blockInputBeforeTime: 0.5
|
||||
unlockRotationTime: 0.5
|
||||
lerpPositionTowardsTarget: 1
|
||||
maxLerpDistance: 3.5
|
||||
@@ -781,8 +780,8 @@ MonoBehaviour:
|
||||
stoppingDistance: 1.2
|
||||
useComboTimingWindow: 1
|
||||
comboWindowStartTime: 0.7
|
||||
comboWindowDuration: 0.4
|
||||
comboWindowTimeScale: 0.2
|
||||
comboWindowDuration: 0.3
|
||||
comboWindowTimeScale: 0.4
|
||||
useAttackTimeScale: 0
|
||||
maxTargetDistance: 3
|
||||
lowHealthTh: 10
|
||||
@@ -791,7 +790,7 @@ MonoBehaviour:
|
||||
attackTimeScaleEnd: 0.37
|
||||
rotatePlayerTowardsTarget: 1
|
||||
degreeThreshold: 100
|
||||
debug: 0
|
||||
debug: 1
|
||||
--- !u!1101 &-8051095333111886674
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
@@ -2749,8 +2748,7 @@ MonoBehaviour:
|
||||
ignoreDefense: 0
|
||||
activeRagdoll: 0
|
||||
senselessTime: 0
|
||||
resetAttackTrigger: 0
|
||||
resetTriggerBeforeTime: 0.3
|
||||
blockInputBeforeTime: 0.5
|
||||
unlockRotationTime: 0.7
|
||||
lerpPositionTowardsTarget: 1
|
||||
maxLerpDistance: 3.5
|
||||
@@ -2758,8 +2756,8 @@ MonoBehaviour:
|
||||
stoppingDistance: 1.2
|
||||
useComboTimingWindow: 1
|
||||
comboWindowStartTime: 0.6
|
||||
comboWindowDuration: 0.4
|
||||
comboWindowTimeScale: 0.2
|
||||
comboWindowDuration: 0.3
|
||||
comboWindowTimeScale: 0.4
|
||||
useAttackTimeScale: 1
|
||||
maxTargetDistance: 3
|
||||
lowHealthTh: 30
|
||||
@@ -4567,6 +4565,7 @@ MonoBehaviour:
|
||||
tags:
|
||||
- IsRolling
|
||||
- IgnoreIK
|
||||
- LockRotation
|
||||
--- !u!206 &-2581317115762456654
|
||||
BlendTree:
|
||||
m_ObjectHideFlags: 1
|
||||
@@ -5216,8 +5215,7 @@ MonoBehaviour:
|
||||
ignoreDefense: 0
|
||||
activeRagdoll: 0
|
||||
senselessTime: 0
|
||||
resetAttackTrigger: 0
|
||||
resetTriggerBeforeTime: 0.3
|
||||
blockInputBeforeTime: 0.5
|
||||
unlockRotationTime: 0.7
|
||||
lerpPositionTowardsTarget: 1
|
||||
maxLerpDistance: 3.5
|
||||
@@ -5225,8 +5223,8 @@ MonoBehaviour:
|
||||
stoppingDistance: 1.2
|
||||
useComboTimingWindow: 1
|
||||
comboWindowStartTime: 0.6
|
||||
comboWindowDuration: 0.4
|
||||
comboWindowTimeScale: 0.2
|
||||
comboWindowDuration: 0.3
|
||||
comboWindowTimeScale: 0.4
|
||||
useAttackTimeScale: 1
|
||||
maxTargetDistance: 3
|
||||
lowHealthTh: 10
|
||||
@@ -5738,8 +5736,7 @@ MonoBehaviour:
|
||||
ignoreDefense: 0
|
||||
activeRagdoll: 0
|
||||
senselessTime: 0
|
||||
resetAttackTrigger: 0
|
||||
resetTriggerBeforeTime: 0.5
|
||||
blockInputBeforeTime: 0.5
|
||||
unlockRotationTime: 0.7
|
||||
lerpPositionTowardsTarget: 0
|
||||
maxLerpDistance: 3.5
|
||||
@@ -26561,15 +26558,14 @@ MonoBehaviour:
|
||||
ignoreDefense: 1
|
||||
activeRagdoll: 0
|
||||
senselessTime: 0
|
||||
resetAttackTrigger: 0
|
||||
resetTriggerBeforeTime: 0.6
|
||||
blockInputBeforeTime: 1
|
||||
unlockRotationTime: 0.7
|
||||
lerpPositionTowardsTarget: 1
|
||||
maxLerpDistance: 3.5
|
||||
positionLerpSpeed: 2
|
||||
stoppingDistance: 1.2
|
||||
useComboTimingWindow: 0
|
||||
comboWindowStartTime: 0.9
|
||||
comboWindowStartTime: 1
|
||||
comboWindowDuration: 0.5
|
||||
comboWindowTimeScale: 0.3
|
||||
useAttackTimeScale: 0
|
||||
@@ -26580,7 +26576,7 @@ MonoBehaviour:
|
||||
attackTimeScaleEnd: 0.58
|
||||
rotatePlayerTowardsTarget: 1
|
||||
degreeThreshold: 100
|
||||
debug: 0
|
||||
debug: 1
|
||||
--- !u!1101 &542493047717198179
|
||||
AnimatorStateTransition:
|
||||
m_ObjectHideFlags: 1
|
||||
@@ -47984,8 +47980,7 @@ MonoBehaviour:
|
||||
ignoreDefense: 0
|
||||
activeRagdoll: 0
|
||||
senselessTime: 0
|
||||
resetAttackTrigger: 0
|
||||
resetTriggerBeforeTime: 0.5
|
||||
blockInputBeforeTime: 0.5
|
||||
unlockRotationTime: 0.7
|
||||
lerpPositionTowardsTarget: 0
|
||||
maxLerpDistance: 3.5
|
||||
@@ -48139,8 +48134,7 @@ MonoBehaviour:
|
||||
ignoreDefense: 0
|
||||
activeRagdoll: 0
|
||||
senselessTime: 0
|
||||
resetAttackTrigger: 1
|
||||
resetTriggerBeforeTime: 0.5
|
||||
blockInputBeforeTime: 0.5
|
||||
unlockRotationTime: 0.7
|
||||
lerpPositionTowardsTarget: 0
|
||||
maxLerpDistance: 3.5
|
||||
@@ -48542,8 +48536,7 @@ MonoBehaviour:
|
||||
ignoreDefense: 1
|
||||
activeRagdoll: 0
|
||||
senselessTime: 0
|
||||
resetAttackTrigger: 0
|
||||
resetTriggerBeforeTime: 0.6
|
||||
blockInputBeforeTime: 0.5
|
||||
unlockRotationTime: 0.7
|
||||
lerpPositionTowardsTarget: 1
|
||||
maxLerpDistance: 3.5
|
||||
@@ -49431,8 +49424,7 @@ MonoBehaviour:
|
||||
ignoreDefense: 1
|
||||
activeRagdoll: 0
|
||||
senselessTime: 0
|
||||
resetAttackTrigger: 0
|
||||
resetTriggerBeforeTime: 0.6
|
||||
blockInputBeforeTime: 0.5
|
||||
unlockRotationTime: 0.7
|
||||
lerpPositionTowardsTarget: 1
|
||||
maxLerpDistance: 3.5
|
||||
|
||||
@@ -9838,7 +9838,6 @@ GameObject:
|
||||
- component: {fileID: 7898212980114005163}
|
||||
- component: {fileID: 8020189233111417037}
|
||||
- component: {fileID: 8020706684658151899}
|
||||
- component: {fileID: 7789765392435096873}
|
||||
m_Layer: 0
|
||||
m_Name: Particles
|
||||
m_TagString: Untagged
|
||||
@@ -14484,21 +14483,6 @@ ParticleSystemRenderer:
|
||||
m_MeshWeighting2: 1
|
||||
m_MeshWeighting3: 1
|
||||
m_MaskInteraction: 0
|
||||
--- !u!114 &7789765392435096873
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7893307381764779335}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dded6759b4b430e4283cf015251490b7, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
target: {fileID: 0}
|
||||
Force: 1
|
||||
DistanceRelative: 0
|
||||
--- !u!1 &7893317824759632779
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -16396,6 +16396,11 @@ PrefabInstance:
|
||||
propertyPath: m_Layer
|
||||
value: 5
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1385765897516864307, guid: 851e8e61247888340bdec90fc8aa37f5,
|
||||
type: 3}
|
||||
propertyPath: openCloseWindow
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1494204689157949844, guid: 851e8e61247888340bdec90fc8aa37f5,
|
||||
type: 3}
|
||||
propertyPath: m_Layer
|
||||
@@ -17420,7 +17425,17 @@ PrefabInstance:
|
||||
- target: {fileID: 4704300330561169846, guid: 851e8e61247888340bdec90fc8aa37f5,
|
||||
type: 3}
|
||||
propertyPath: strafeRollLeftCorrectionAngle
|
||||
value: 70.6
|
||||
value: -20
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4704300330561169846, guid: 851e8e61247888340bdec90fc8aa37f5,
|
||||
type: 3}
|
||||
propertyPath: strafeRollRightCorrectionAngle
|
||||
value: -10
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4704300330561169846, guid: 851e8e61247888340bdec90fc8aa37f5,
|
||||
type: 3}
|
||||
propertyPath: strafeRollBackwardCorrectionAngle
|
||||
value: 180
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4704300330561169846, guid: 851e8e61247888340bdec90fc8aa37f5,
|
||||
type: 3}
|
||||
@@ -18565,12 +18580,12 @@ PrefabInstance:
|
||||
- target: {fileID: 5657452459766331955, guid: 851e8e61247888340bdec90fc8aa37f5,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMax.x
|
||||
value: 1
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5657452459766331955, guid: 851e8e61247888340bdec90fc8aa37f5,
|
||||
type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
value: 1
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5671630659928648966, guid: 851e8e61247888340bdec90fc8aa37f5,
|
||||
type: 3}
|
||||
|
||||
@@ -81,8 +81,11 @@ namespace Beyond
|
||||
private PlayerAttribute brightnessAttribute;
|
||||
private PlayerAttribute maturityAttribute;
|
||||
private MagicAttacks m_magicAttacks;
|
||||
private bMeleeCombatInput m_meleeCombatInput;
|
||||
|
||||
public MagicAttacks Magic => m_magicAttacks;
|
||||
public bMeleeCombatInput MeleeCombatInput => m_meleeCombatInput;
|
||||
|
||||
public PlayerAttribute MaturityAttribute
|
||||
{
|
||||
get
|
||||
@@ -186,6 +189,7 @@ namespace Beyond
|
||||
m_meleeManager = GetComponent<vMeleeManager>();
|
||||
m_magicAttacks = GetComponent<MagicAttacks>();
|
||||
m_autoTargetting = GetComponent<AutoTargetting>();
|
||||
m_meleeCombatInput = GetComponent<bMeleeCombatInput>();
|
||||
}
|
||||
|
||||
|
||||
@@ -867,10 +871,10 @@ namespace Beyond
|
||||
|
||||
public void PlaySingleSound(AudioClip clipToPlay, bool destroyAfterPlaying = true)
|
||||
{
|
||||
// Opcjonalne opóŸnienie na starcie poziomu, aby unikn¹æ "spamowania" dŸwiêkami
|
||||
// Opcjonalne op<EFBFBD>nienie na starcie poziomu, aby unikn<EFBFBD><EFBFBD> "spamowania" d<EFBFBD>wi<EFBFBD>kami
|
||||
if (Time.timeSinceLevelLoad < 0.5f && clipToPlay != null)
|
||||
{
|
||||
// Mo¿esz chcieæ to odkomentowaæ, jeœli dŸwiêki na starcie s¹ problemem
|
||||
// Mo<EFBFBD>esz chcie<EFBFBD> to odkomentowa<EFBFBD>, je<EFBFBD>li d<EFBFBD>wi<EFBFBD>ki na starcie s<EFBFBD> problemem
|
||||
// return;
|
||||
}
|
||||
|
||||
@@ -885,28 +889,28 @@ namespace Beyond
|
||||
return;
|
||||
}
|
||||
|
||||
// Instancjonowanie prefabu dŸwiêkowego
|
||||
// Upewnij siê, ¿e prefab 'audioSource' ma komponent AudioSource
|
||||
// Instancjonowanie prefabu d<EFBFBD>wi<EFBFBD>kowego
|
||||
// Upewnij si<EFBFBD>, <EFBFBD>e prefab 'audioSource' ma komponent AudioSource
|
||||
GameObject audioObjectInstance = Instantiate(this.audioSource, transform.position, transform.rotation);
|
||||
AudioSource sourceComponent = audioObjectInstance.GetComponent<AudioSource>();
|
||||
|
||||
if (sourceComponent != null)
|
||||
{
|
||||
// PlayOneShot jest dobre dla efektów, nie przerywa innych dŸwiêków na tym samym source,
|
||||
// jeœli s¹ one odtwarzane przez .Play() i nie u¿ywaj¹ tego samego kana³u.
|
||||
// PlayOneShot jest dobre dla efekt<EFBFBD>w, nie przerywa innych d<EFBFBD>wi<EFBFBD>k<EFBFBD>w na tym samym source,
|
||||
// je<EFBFBD>li s<EFBFBD> one odtwarzane przez .Play() i nie u<EFBFBD>ywaj<EFBFBD> tego samego kana<EFBFBD>u.
|
||||
sourceComponent.PlayOneShot(clipToPlay);
|
||||
|
||||
if (destroyAfterPlaying)
|
||||
{
|
||||
// Niszczymy obiekt GameObject zawieraj¹cy AudioSource po zakoñczeniu odtwarzania klipu.
|
||||
// Dodajemy ma³y bufor czasowy, aby upewniæ siê, ¿e dŸwiêk zd¹¿y siê odtworzyæ w ca³oœci.
|
||||
// Niszczymy obiekt GameObject zawieraj<EFBFBD>cy AudioSource po zako<EFBFBD>czeniu odtwarzania klipu.
|
||||
// Dodajemy ma<EFBFBD>y bufor czasowy, aby upewni<EFBFBD> si<EFBFBD>, <EFBFBD>e d<EFBFBD>wi<EFBFBD>k zd<EFBFBD><EFBFBD>y si<EFBFBD> odtworzy<EFBFBD> w ca<EFBFBD>o<EFBFBD>ci.
|
||||
Destroy(audioObjectInstance, clipToPlay.length + 0.1f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("The instantiated 'audioSource' prefab (from Player.cs) does not have an AudioSource component. Destroying instance.");
|
||||
Destroy(audioObjectInstance); // Posprz¹taj, jeœli coœ posz³o nie tak
|
||||
Destroy(audioObjectInstance); // Posprz<EFBFBD>taj, je<EFBFBD>li co<EFBFBD> posz<EFBFBD>o nie tak
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace Invector.vMelee
|
||||
|
||||
public class bMeleeAttackControl : StateMachineBehaviour
|
||||
{
|
||||
// --- MODIFICATION: Static variable to track the currently active attack state ---
|
||||
private static int activeAttackInstanceId = 0;
|
||||
private int myAttackInstanceId;
|
||||
// --- END MODIFICATION ---
|
||||
|
||||
[Header("Damage Window")]
|
||||
[Tooltip("NormalizedTime of Active Damage")]
|
||||
public float startDamage = 0.05f;
|
||||
@@ -37,10 +42,8 @@ namespace Invector.vMelee
|
||||
public float senselessTime;
|
||||
|
||||
[Header("Attack Flow")]
|
||||
[Tooltip("Check true in the last attack of your combo to reset the FSM attack triggers.")]
|
||||
public bool resetAttackTrigger;
|
||||
[Tooltip("Normalized time point to reset attack triggers. (Used only if Combo Timing Window is disabled)")]
|
||||
public float resetTriggerBeforeTime = 0.5f;
|
||||
[Tooltip("Normalized time point to start allowing the next attack input.")]
|
||||
public float blockInputBeforeTime = 0.5f;
|
||||
|
||||
[Header("Combo & Movement")]
|
||||
[Tooltip("Normalized time to unlock rotation, allowing the player to aim the next attack in a combo. Set to 1 to disable.")]
|
||||
@@ -62,7 +65,6 @@ namespace Invector.vMelee
|
||||
[Tooltip("How close the character should get to the target.")]
|
||||
public float stoppingDistance = 1.2f;
|
||||
|
||||
// --- MODIFIED: Switched to a real-time duration model ---
|
||||
[Header("Combo Timing Window")]
|
||||
[Tooltip("Enable a special timing window at the end of the attack to chain the next combo hit.")]
|
||||
public bool useComboTimingWindow = false;
|
||||
@@ -76,7 +78,6 @@ namespace Invector.vMelee
|
||||
|
||||
[Tooltip("The time scale to use during the combo window for a slow-motion effect.")]
|
||||
public float comboWindowTimeScale = 0.1f;
|
||||
// --- END MODIFICATION ---
|
||||
|
||||
[Header("Slow Motion Settings")]
|
||||
[Tooltip("Enable slow motion effect during this attack based on conditions below.")]
|
||||
@@ -104,25 +105,30 @@ namespace Invector.vMelee
|
||||
|
||||
private bThirdPersonController _characterController;
|
||||
private bool _isRotationLockedByThis;
|
||||
private bool _comboWindowEffectTriggered; // --- NEW ---: Tracks if the slow-mo effect has been fired.
|
||||
private bool _comboWindowEffectTriggered;
|
||||
private Animator _animator;
|
||||
|
||||
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
|
||||
{
|
||||
if (_animator == null) _animator = animator;
|
||||
if (_animator == null) _animator = animator;
|
||||
|
||||
// --- MODIFICATION: Assign a unique ID to this state instance ---
|
||||
myAttackInstanceId = ++activeAttackInstanceId;
|
||||
// --- END MODIFICATION ---
|
||||
|
||||
mFighter = animator.GetComponent<vIAttackListener>();
|
||||
_characterController = animator.GetComponent<bThirdPersonController>();
|
||||
|
||||
if (Player.Instance != null)
|
||||
_autoTargettingInstance = Player.Instance.AutoTarget;
|
||||
|
||||
|
||||
if (_autoTargettingInstance == null && debug)
|
||||
Debug.LogWarning($"({damageType}) AutoTargetting instance not found. Rotation/Target features limited.");
|
||||
|
||||
isAttacking = true;
|
||||
isActive = false;
|
||||
m_hasScaledTime = false;
|
||||
_comboWindowEffectTriggered = false; // --- NEW ---: Reset the flag on enter.
|
||||
_comboWindowEffectTriggered = false;
|
||||
|
||||
if (_characterController != null)
|
||||
{
|
||||
@@ -134,26 +140,54 @@ namespace Invector.vMelee
|
||||
mFighter.OnEnableAttack();
|
||||
|
||||
if (debug)
|
||||
Debug.Log($"({damageType}) OnStateEnter. The trigger that started this state has been consumed by the Animator.");
|
||||
Debug.Log($"({damageType}, ID: {myAttackInstanceId}) OnStateEnter. Now the authoritative state.");
|
||||
|
||||
// --- MODIFICATION: Immediately block input on enter ---
|
||||
// This ensures the new state takes control right away.
|
||||
BlockAttack(true);
|
||||
// --- END MODIFICATION ---
|
||||
|
||||
if (attackTimeScaleStart < 0f) attackTimeScaleStart = startDamage;
|
||||
if (attackTimeScaleEnd < 0f) attackTimeScaleEnd = endDamage;
|
||||
}
|
||||
|
||||
void BlockAttack(bool block)
|
||||
{
|
||||
// --- MODIFICATION: Only allow the authoritative state to change the lock ---
|
||||
if (myAttackInstanceId != activeAttackInstanceId)
|
||||
{
|
||||
if(debug) Debug.Log($"({damageType}, ID: {myAttackInstanceId}) Tried to change block but I am not the active instance ({activeAttackInstanceId}). Ignoring.");
|
||||
return;
|
||||
}
|
||||
// --- END MODIFICATION ---
|
||||
|
||||
if (Player.Instance != null)
|
||||
{
|
||||
var meleeInput = Player.Instance.MeleeCombatInput;
|
||||
if (meleeInput != null)
|
||||
{
|
||||
if (meleeInput.BlockAttack != block) // Only log/change if there is a change
|
||||
{
|
||||
if(debug) Debug.Log($"({damageType}, ID: {myAttackInstanceId}) Setting BlockAttack to: {block}");
|
||||
meleeInput.BlockAttack = block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
|
||||
{
|
||||
if (Player.Instance.ActiveWeaponTrail)
|
||||
Player.Instance.ActiveWeaponTrail.m_colorMultiplier = Color.white + Color.red * damageMultiplier;
|
||||
|
||||
|
||||
float currentNormalizedTime = stateInfo.normalizedTime % 1;
|
||||
if (currentNormalizedTime == 0 && stateInfo.normalizedTime > 0.5f) currentNormalizedTime = 1f;
|
||||
|
||||
// --- NEW: Centralized combo logic management ---
|
||||
|
||||
ManageComboLogic(currentNormalizedTime);
|
||||
|
||||
|
||||
if (_characterController != null && _characterController.lockRotation)
|
||||
AttemptRotationTowardsAutoTarget(animator);
|
||||
|
||||
AttemptRotationTowardsAutoTarget(animator);
|
||||
|
||||
AttemptPositionLerp(animator);
|
||||
UpdateRotationLock(currentNormalizedTime);
|
||||
|
||||
@@ -173,16 +207,16 @@ namespace Invector.vMelee
|
||||
ActiveDamage(animator, false);
|
||||
}
|
||||
|
||||
if (isAttacking && currentNormalizedTime > endDamage)
|
||||
if (isAttacking && currentNormalizedTime > endDamage)
|
||||
{
|
||||
if (mFighter != null) mFighter.OnDisableAttack();
|
||||
isAttacking = false;
|
||||
isAttacking = false;
|
||||
}
|
||||
}
|
||||
|
||||
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
|
||||
{
|
||||
if (debug) Debug.Log($"({damageType}) OnStateExit.");
|
||||
if (debug) Debug.Log($"({damageType}, ID: {myAttackInstanceId}) OnStateExit.");
|
||||
|
||||
if (isActive)
|
||||
{
|
||||
@@ -195,68 +229,53 @@ namespace Invector.vMelee
|
||||
|
||||
isAttacking = false;
|
||||
m_hasScaledTime = false;
|
||||
|
||||
// The TimeController now reliably handles resetting the time scale via its own coroutine.
|
||||
// A manual reset here is no longer necessary and could cause conflicts.
|
||||
/*
|
||||
if (mFighter != null && resetAttackTrigger)
|
||||
{
|
||||
mFighter.ResetAttackTriggers();
|
||||
if (debug) Debug.Log($"({damageType}) Final trigger reset on exit due to 'Reset Attack Trigger' flag.");
|
||||
}
|
||||
*/
|
||||
|
||||
if (_comboWindowEffectTriggered && TimeController.Instance != null)
|
||||
{
|
||||
_comboWindowEffectTriggered = false;
|
||||
TimeController.Instance.Reset();
|
||||
TimeController.Instance.Reset();
|
||||
}
|
||||
|
||||
if (_characterController != null && _isRotationLockedByThis)
|
||||
{
|
||||
_characterController.lockRotation = false;
|
||||
_isRotationLockedByThis = false;
|
||||
}
|
||||
|
||||
// --- MODIFICATION: When exiting, ensure the attack is unblocked. ---
|
||||
// This is a safety net. If this was the last attack in a combo,
|
||||
// we need to make sure the input is unlocked for future actions.
|
||||
BlockAttack(false);
|
||||
// --- END MODIFICATION ---
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manages the combo logic, including input window and time scale effects.
|
||||
/// </summary>
|
||||
private void ManageComboLogic(float currentNormalizedTime)
|
||||
{
|
||||
if (!useComboTimingWindow)
|
||||
if (blockInputBeforeTime > 0f)
|
||||
{
|
||||
// Fallback to old logic if new system is disabled for this state
|
||||
if (resetAttackTrigger && currentNormalizedTime >= resetTriggerBeforeTime)
|
||||
if (currentNormalizedTime >= blockInputBeforeTime)
|
||||
{
|
||||
if (mFighter != null)
|
||||
mFighter.ResetAttackTriggers();
|
||||
BlockAttack(false); // Unlock input
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockAttack(true); // Block input
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!useComboTimingWindow) return;
|
||||
|
||||
// --- FIX 2: Corrected window logic ---
|
||||
bool isInsideWindow = currentNormalizedTime >= comboWindowStartTime;
|
||||
|
||||
if (isInsideWindow)
|
||||
{
|
||||
// --- We are INSIDE the combo window ---
|
||||
// We STOP resetting the trigger to allow the player's input to register.
|
||||
|
||||
if (!_comboWindowEffectTriggered && TimeController.Instance != null)
|
||||
{
|
||||
_comboWindowEffectTriggered = true;
|
||||
|
||||
TimeController.Instance.SetTimeScaleForRealTimeSec(comboWindowTimeScale, comboWindowDuration, false);
|
||||
|
||||
if (debug) Debug.Log($"({damageType}) COMBO WINDOW OPEN. Accepting input. Animator mode set to UnscaledTime.");
|
||||
if (debug) Debug.Log($"({damageType}) COMBO WINDOW OPEN. Accepting input.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// --- We are OUTSIDE the combo window ---
|
||||
// We continuously reset the trigger to consume any premature/late input.
|
||||
if (mFighter != null)
|
||||
mFighter.ResetAttackTriggers();
|
||||
}
|
||||
}
|
||||
|
||||
// --- Other methods remain unchanged ---
|
||||
|
||||
@@ -4,6 +4,7 @@ using Invector.vEventSystems;
|
||||
using Invector.vMelee;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEngine.Android;
|
||||
|
||||
namespace Beyond
|
||||
{
|
||||
@@ -23,6 +24,8 @@ namespace Beyond
|
||||
internal vMeleeManager meleeManager;
|
||||
protected bool _isAttacking;
|
||||
|
||||
public bool BlockAttack { get; set; }
|
||||
|
||||
public bool isAttacking
|
||||
{
|
||||
get => _isAttacking || (cc != null && cc.IsAnimatorTag("Attack"));
|
||||
@@ -87,16 +90,17 @@ namespace Beyond
|
||||
autoTargeting = GetComponent<AutoTargetting>();
|
||||
if (autoTargeting == null && Player.Instance != null && Player.Instance.gameObject == this.gameObject)
|
||||
{
|
||||
autoTargeting = Player.Instance.GetComponent<AutoTargetting>();
|
||||
autoTargeting = Player.Instance.GetComponent<AutoTargetting>();
|
||||
}
|
||||
if (autoTargeting == null && cc != null && cc.transform.root != null)
|
||||
{
|
||||
autoTargeting = cc.transform.root.GetComponentInChildren<AutoTargetting>(true);
|
||||
autoTargeting = cc.transform.root.GetComponentInChildren<AutoTargetting>(true);
|
||||
}
|
||||
if (autoTargeting == null)
|
||||
{
|
||||
Debug.LogWarning("bMeleeCombatInput: AutoTargetting component not found. Dash towards target will require manual aiming.");
|
||||
}
|
||||
BlockAttack = false;
|
||||
}
|
||||
|
||||
protected override void LateUpdate()
|
||||
@@ -241,7 +245,7 @@ namespace Beyond
|
||||
public virtual bool MeleeAttackConditions()
|
||||
{
|
||||
if (meleeManager == null) meleeManager = GetComponent<vMeleeManager>();
|
||||
return meleeManager != null && cc != null && cc.isGrounded && !cc.customAction && !cc.IsAnimatorTag("special") &&
|
||||
return !BlockAttack && meleeManager != null && cc != null && cc.isGrounded && !cc.customAction && !cc.IsAnimatorTag("special") &&
|
||||
!cc.isJumping && !cc.isCrouching && !cc.isRolling && !isEquipping &&
|
||||
(cc.animator != null && !cc.animator.IsInTransition(cc.baseLayer)) && !isRotatingAndDashing;
|
||||
}
|
||||
|
||||
@@ -18,10 +18,6 @@ namespace Beyond
|
||||
public bool useAnimationBasedRotation = false;
|
||||
|
||||
[Header("Beyond's Strafe Combat Settings")]
|
||||
[Tooltip("The minimum horizontal input value to trigger a side roll instead of a forward/backward one.")]
|
||||
[Range(0.1f, 1.0f)]
|
||||
public float strafeRollInputThreshold = 0.3f;
|
||||
|
||||
[Tooltip("The name of the animation state to play when rolling forward while strafing. (This is now disabled)")]
|
||||
public string strafeRollForwardAnim = "Roll_Forward"; // Kept for reference, but won't be used
|
||||
[Tooltip("The name of the animation state to play when rolling backward while strafing.")]
|
||||
@@ -31,15 +27,19 @@ namespace Beyond
|
||||
[Tooltip("The name of the animation state to play when rolling right while strafing.")]
|
||||
public string strafeRollRightAnim = "Roll_Right";
|
||||
|
||||
// --- UPDATED FIELDS FOR INDEPENDENT CONTROL ---
|
||||
// --- UPDATED FIELDS FOR FINER CONTROL ---
|
||||
[Header("Beyond's Strafe Roll Correction")]
|
||||
[Tooltip("The fixed angle to rotate the character before a LEFT strafe roll.")]
|
||||
[Range(0f, 90f)]
|
||||
public float strafeRollLeftCorrectionAngle = 45f;
|
||||
[Tooltip("An additional angle to apply for a LEFT strafe roll.")]
|
||||
[Range(-90f, 90f)]
|
||||
public float strafeRollLeftCorrectionAngle = -45f;
|
||||
|
||||
[Tooltip("The fixed angle to rotate the character before a RIGHT strafe roll.")]
|
||||
[Range(0f, 90f)]
|
||||
public float strafeRollRightCorrectionAngle = 70f;
|
||||
[Tooltip("An additional angle to apply for a RIGHT strafe roll.")]
|
||||
[Range(-90f, 90f)]
|
||||
public float strafeRollRightCorrectionAngle = 45f;
|
||||
|
||||
[Tooltip("An additional angle to apply for a BACKWARD strafe roll. Use 0 for a standard 180-degree roll.")]
|
||||
[Range(-180f, 180f)]
|
||||
public float strafeRollBackwardCorrectionAngle = 0f;
|
||||
// --- END OF UPDATED FIELDS ---
|
||||
|
||||
public bool GodMode
|
||||
@@ -64,27 +64,21 @@ namespace Beyond
|
||||
|
||||
protected override void RollBehavior()
|
||||
{
|
||||
// If we are not strafing, use the default Invector roll behavior.
|
||||
if (!isStrafing)
|
||||
{
|
||||
base.RollBehavior();
|
||||
return;
|
||||
}
|
||||
|
||||
// Custom Strafe Roll with Root Motion (no rotation logic needed here anymore)
|
||||
if (!isRolling)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 deltaPosition = new Vector3(animator.deltaPosition.x, 0f, animator.deltaPosition.z);
|
||||
Vector3 v = (deltaPosition / Time.deltaTime) * (1f - stopMoveWeight);
|
||||
|
||||
if (rollUseGravity && animator.GetNormalizedTime(baseLayer) >= rollUseGravityTime)
|
||||
{
|
||||
v.y = _rigidbody.linearVelocity.y;
|
||||
}
|
||||
|
||||
_rigidbody.linearVelocity = v;
|
||||
}
|
||||
|
||||
@@ -120,7 +114,12 @@ namespace Beyond
|
||||
}
|
||||
}
|
||||
|
||||
// --- MODIFIED METHOD WITH TWO-ANGLE LOGIC ---
|
||||
// --- FINAL ROBUST METHOD ---
|
||||
// This logic now handles all specified cases:
|
||||
// 1. Sets a base rotation facing the camera to ensure consistency.
|
||||
// 2. Defaults to a backward roll if input is near-zero (fixing the lingering roll issue).
|
||||
// 3. Never uses the forward roll; it triggers a backward roll instead.
|
||||
// 4. Applies a unique correction angle for backward rolls as well as side rolls.
|
||||
private void TriggerStrafeRoll(string forwardAnim, string backwardAnim, string leftAnim, string rightAnim)
|
||||
{
|
||||
OnRoll.Invoke();
|
||||
@@ -129,42 +128,59 @@ namespace Beyond
|
||||
currentStaminaRecoveryDelay = 2f;
|
||||
|
||||
string animToPlay;
|
||||
float correctionAngle = 0f;
|
||||
|
||||
// Prioritize side rolls based on horizontal input.
|
||||
if (Mathf.Abs(horizontalSpeed) > strafeRollInputThreshold)
|
||||
// Determine the base "forward" direction from the camera, ignoring vertical tilt.
|
||||
Vector3 baseForward = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized;
|
||||
if (baseForward == Vector3.zero) baseForward = transform.forward; // Fallback
|
||||
|
||||
// Set the character's rotation to this base direction. This provides a clean slate.
|
||||
transform.rotation = Quaternion.LookRotation(baseForward);
|
||||
|
||||
// Check if input is negligible (joystick is centered).
|
||||
// input.sqrMagnitude is more efficient than input.magnitude. 0.1*0.1=0.01.
|
||||
if (input.sqrMagnitude < 0.01f)
|
||||
{
|
||||
float correction = 0f;
|
||||
|
||||
// Check if rolling right (positive horizontal speed)
|
||||
if (horizontalSpeed > 0)
|
||||
{
|
||||
animToPlay = rightAnim;
|
||||
// For a right roll, we apply a negative rotation (turn left) to angle the trajectory forward.
|
||||
correction = -strafeRollRightCorrectionAngle;
|
||||
}
|
||||
// Otherwise, rolling left
|
||||
else
|
||||
{
|
||||
animToPlay = leftAnim;
|
||||
// For a left roll, we apply a positive rotation (turn right) to angle the trajectory forward.
|
||||
correction = strafeRollLeftCorrectionAngle;
|
||||
}
|
||||
|
||||
// Apply the calculated rotation instantly around the Y-axis.
|
||||
if (correction != 0)
|
||||
{
|
||||
transform.Rotate(0, correction, 0);
|
||||
}
|
||||
// If no input, always perform a backward roll.
|
||||
animToPlay = backwardAnim;
|
||||
correctionAngle = strafeRollBackwardCorrectionAngle;
|
||||
}
|
||||
// If horizontal input is not met, default to the backward roll.
|
||||
else
|
||||
{
|
||||
animToPlay = backwardAnim;
|
||||
// If there IS input, determine the dominant direction.
|
||||
if (Mathf.Abs(verticalSpeed) >= Mathf.Abs(horizontalSpeed))
|
||||
{
|
||||
// Vertical input is dominant.
|
||||
// ALWAYS use the backward roll, regardless of forward or backward input.
|
||||
animToPlay = backwardAnim;
|
||||
correctionAngle = strafeRollBackwardCorrectionAngle;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Horizontal input is dominant.
|
||||
if (horizontalSpeed > 0)
|
||||
{
|
||||
animToPlay = rightAnim;
|
||||
correctionAngle = strafeRollRightCorrectionAngle;
|
||||
}
|
||||
else
|
||||
{
|
||||
animToPlay = leftAnim;
|
||||
correctionAngle = strafeRollLeftCorrectionAngle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Apply the chosen correction angle if it's not zero.
|
||||
if (correctionAngle != 0f)
|
||||
{
|
||||
transform.Rotate(0, correctionAngle, 0);
|
||||
}
|
||||
|
||||
// Play the selected animation.
|
||||
animator.CrossFadeInFixedTime(animToPlay, rollTransition, baseLayer);
|
||||
}
|
||||
// --- END OF MODIFIED METHOD ---
|
||||
// --- END OF FINAL METHOD ---
|
||||
|
||||
public void OnEvadeStart() { if (!m_GodMode) isImmortal = true; }
|
||||
public void OnEvadeEnd() { if (!m_GodMode) isImmortal = false; }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user