character's animator stuck while doing combo attack

I've stripped the attack down to a very simple 2 step combo, using AnimatorAudio Sequence and the problem still appears. Requiring a CharacterAttribute was not the cause. I've also used different timings for the OnAnimatorItemUse and OnAnimatorItemUseComplete events, I've even tried it without sending events but using fixed timings.

In all cases, the root cause seems to be that the states are not being reset properly.

@Justin I did some digging but I cannot pinpoint the correct place in the MeleeWeapon / UsableItem code where SlotItemStateIndex and SlotItemSubstateIndex are being set. Could you point me in the right direction and maybe shed some light on how/when the states should be reset finally?

Somehow it seems that they are overwritten after being set, I assume because I have set the Reset Delay to .5 instead of -1. How else can I reset the combo after the attack is done?
 
Last edited:
Undo combos this page explains the process for the parameters being reset:
https://opsive.com/support/document...controller/items/actions/usable/melee-weapon/

Really though for your situation I recommend creating a new animator controller so you can customize it to fit your game. I go into the details for how the parameters work in this video:

https://opsive.com/support/document...oller/animation/animator/animator-controller/

Of course, if you can reproduce the combos getting stuck within the demo scene of a fresh project we can take a closer look. The animator controller is setup to use combos in a certain way so if you change that then you'll also need to change the animator controller.

With that said, if you use the Reset Delay it wasn't correctly being reset. If you update Sequence.cs with the following then it will correctly reset the combo after the specified amount of time.


Code:
    public class Sequence : AnimatorAudioStateSelector
{
[Tooltip("Resets the index back to the start after the specified delay. Set to -1 to never reset.")]
[SerializeField] protected float m_ResetDelay = -1;

public float ResetDelay { get { return m_ResetDelay; } set { m_ResetDelay = value; } }

private int m_CurrentIndex = -1;
private float m_LastUsedTime = -1;

/// <summary>
/// Starts or stops the state selection.
/// </summary>
/// <param name="start">Is the object starting?</param>
public override void StartStopStateSelection(bool start)
{
base.StartStopStateSelection(start);

// The Sequence task can reset which index is returned if the next state is selected too slowly.
if (start && m_ResetDelay != -1 && m_LastUsedTime != -1 && m_LastUsedTime + m_ResetDelay < Time.time) {
m_CurrentIndex = -1;
}
}

/// <summary>
/// Returns the current state index. -1 indicates this index is not set by the class.
/// </summary>
/// <returns>The current state index.</returns>
public override int GetStateIndex()
{
return m_CurrentIndex;
}

/// <summary>
/// Moves to the next state.
/// </summary>
/// <returns>Was the state changed successfully?</returns>
public override bool NextState()
{
m_LastUsedTime = Time.time;
var count = 0;
var size = m_States.Length;
if (size == 0) {
return false;
}
do {
m_CurrentIndex = (m_CurrentIndex + 1) % size;
count++;
} while ((!IsStateValid(m_CurrentIndex) || !m_States[m_CurrentIndex].Enabled) && count <= size);
return count <= size;
}
    }

This will be included in version 2.2.5 which will be going out soon.
 
I was able to prevent any combo with a ResetDelay other than -1 from getting stuck by finding the right combination of Use Rate, Reset Delay and firing the Animation events. It even worked with the original Sequence.cs selector (without the change from above).

In my example a Use Rate of .5, Reset Delay of .7 and the Use and UseComplete events firing anywhere around .5 and.7 worked well. Looks like a use rate that is too low can lead to the ability re-triggering (states being set before the transition happens) which gets it stuck.


Since my attacks alyso require a character attribute, I also slightly changed the Item Use Ability to make sure that the item is not being used when there is not enough of that resource. But I don't think that has any effect on the core problem.

 
Hi @Tzirrit, I was able to reproduce the attack getting stuck and you're right it is when he's moving and stopping a lot. This happens for all melee weapons that have moving and in place attacks.

The tricky part is having the fully body layer aware of what state the character is in even when he's moving, where only the upper body layer in active. I think I have a fix now. I converted the attack states on the full body layer to be blendtrees based on speed. When the character is moving (speed > .1) the blendtree will stay in an empty state, when the character is standing still it will go to the full body attack. This will be in the next update coming out in a couple days.

I have removed that attack idle state now since these blendtrees take care of that. I thought of doing a transition to the attack idle whenever the character is attacking and moving but then whenever you stopped moving it would basically replay the active attack state.

I hope this helps!
 
I know this thread is over a year old, but I don't want to create a duplicate thread: (note: some of my line numbers may be off because I inserted and deleted a couple of Debug.Log statements)
I know that my animator properties are getting stuck because at ~ line 810 in the Use script, m_WaitForUseCompleteEvent[0] is false, so the UseCompleteItem method gets aborted before it can call StopAbility. 1630038199165.png
My problem is that I can't figure out why it is set to false when I use the second or third hit in a combo, but is fine when I only do the first attack.
It looks like it stops calling ScheduleCompleteEvent method from LateUpdate because CanUseItem (Use.cs Line 651) is returning false somehow. 1630039169732.png

What I can't find is why CanUseItem is returning false when that should basically be impossible.

Edit: I found where CanUseItem is returning false. It looks like I overrode it so I was looking in the wrong place. It seems I've misunderstood what the method is used for. Where can I override that only if the player presses a button, does the use script check if there is a followup AudioAnimator state?
 
Last edited:
Top