Ability transition - KnockedDown > Downed >? MyRevive

zoicelols

Member
Link from where I came from before this. https://opsive.com/forum/index.php?...-knocked-down-to-laying-down.4185/#post-21015

Trying to implement within
Ability - Downed : the only way to exit downed is by MyRevive(ButtonPress), pressing Specific attack abilities, or by being attacked (which results in KnockedDown -> Downed)



What route would you recommend to transition between Downed(laying on the ground) to MyRevive(Standing up)?

My animator keeps getting stuck which I'm sure is because I haven't scripted the proper rules into Downed and also haven't properly come up with a proper transition built into one of the abilities. One of the issues I am facing is within MyRevive.cs CanStartAbility I turn off the Downed ability, then that animator gets stuck. I keep trying new things and I can't quite figure out a fix.
 
You could have a state preset that's active during downed, which disables abilities you don't want the player to have access to during that state.
 
Okay setting the states worked well, but I am still getting stuck on my Downed ability.

If I press MyRevive button then it will transition to the MyRevive animation and shut off the Downed ability as intended in the script.

If I wait like 2 seconds after transitioning to Downed and then try to use MyRevive button, it will not work to break it out of Downed. The character is stuck in Downed animation with Downed ability active until being hit again pushing the character back into knocked down --- Downed again.
I'm not sure what waiting a couple seconds does to mess this up.
Also I hadn't added any code to my Downed ability. I'm not sure what I would need to add to the ability to fix this, or maybe I need to add something to MyRevive?

1606885105002.png

Here are my ability scripts:

Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Opsive.UltimateCharacterController.Character.Abilities;
using Opsive.UltimateCharacterController.Character;
using Opsive.Shared.Events;
using Opsive.UltimateCharacterController.Utility;


[CODE=csharp]public class MyDamageVisualization : DamageVisualization

{



    private enum TakeDamageIndex

    {

        FrontLeft,  // Play an animation based upon a damage position on the front left.

        FrontRight, // Play an animation based upon a damage position on the front right.

        BackLeft,   // Play an animation based upon a damage position on the back left.

        BackRight,   // Play an animation based upon a damage position on the back right.



        HeavyFrontLeft,

        HeavyFrontRight,

        HeavyBackLeft,

        HeavyBackRight,



        HeavyAboveFront,

        HeavyAboveBack,

        HeavyBelowFront,

        HeavyBelowBack



    }







    /// <summary>

    /// Returns the value that the AbilityIntData parameter should be set to.

    /// </summary>

    /// <param name="amount">The amount of damage taken.</param>

    /// <param name="position">The position of the damage.</param>

    /// <param name="force">The amount of force applied to the character.</param>

    /// <param name="attacker">The GameObject that damaged the character.</param>

    /// <returns>The value that the AbilityIntData parameter should be set to. A value of -1 will prevent the ability from starting.</returns>







    protected override void AbilityStarted()

    {

        var characterLocomotion = m_GameObject.GetComponent<UltimateCharacterLocomotion>();

    

    }







    protected override int GetDamageTypeIndex(float amount, Vector3 position, Vector3 force, GameObject attacker)

    {



        if (amount <= 14)

        {



            var direction = m_Transform.InverseTransformPoint(position);

            if (direction.z > 0)

            {

                if (direction.x > 0)

                {

                    return (int)TakeDamageIndex.FrontRight;

                }

                return (int)TakeDamageIndex.FrontLeft;

            }

            else if (direction.z < 0)

            {

                if (direction.x > 0)

                {

                    return (int)TakeDamageIndex.BackRight;

                }

                return (int)TakeDamageIndex.BackLeft;

            }

        }



        if (amount >= 15)

        {







            var direction = m_Transform.InverseTransformPoint(position);



            if (direction.y < 0)

            {

                if (direction.z < 0)

                {

                    return (int)TakeDamageIndex.HeavyAboveFront;

                }

            }









            if (direction.z > 0)

            {

                if (direction.x > 0)

                {

                    return (int)TakeDamageIndex.HeavyFrontRight;

                }

                return (int)TakeDamageIndex.HeavyFrontLeft;

            }

            else if (direction.z < 0)

            {

                if (direction.x > 0)

                {

                    return (int)TakeDamageIndex.HeavyBackRight;

                }

                return (int)TakeDamageIndex.HeavyBackLeft;

            }

        }





        return -1;

    

    }









    protected override void AbilityStopped(bool force)

    {



    

        base.AbilityStopped(force);



        var characterLocomotion = m_GameObject.GetComponent<UltimateCharacterLocomotion>();

        var downedAbility = characterLocomotion.GetAbility<Downed>();



        characterLocomotion.TryStartAbility(downedAbility);



    

    }







}
[/CODE]






C#:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Opsive.UltimateCharacterController.Character.Abilities;
using Opsive.UltimateCharacterController.Camera;
using Opsive.UltimateCharacterController.Character;
using Opsive.Shared.Events;
using Opsive.Shared.Game;

public class MyRevive : Revive
{



    public enum Direction
    {
        Left,       // Left dodge.
        Forward,    // Forward dodge.
        Right,      // Right dodge.
        Backward,   // Backward dodge.
        None        // No dodge.
    }

    [SerializeField] protected Direction m_NoVelocityDirection = Direction.None;

    public Direction NoVelocityDirection { get { return m_NoVelocityDirection; } set { m_NoVelocityDirection = value; } }

    private Direction m_Direction;

    public override int AbilityIntData { get { return (int)m_Direction; } }

    private AimAssist m_AimAssist;

    public override void Awake()
    {
        base.Awake();


        EventHandler.RegisterEvent<ILookSource>(m_GameObject, "OnCharacterAttachLookSource", OnAttachLookSource);
    

    }



    /// <summary>
    /// A new ILookSource object has been attached to the character.
    /// </summary>
    /// <param name="lookSource">The ILookSource object attached to the character.</param>
    private void OnAttachLookSource(ILookSource lookSource)
    {
        if (lookSource != null)
        {
            m_AimAssist = lookSource.GameObject.GetCachedComponent<AimAssist>();
        }
        else
        {
            m_AimAssist = null;
        }
    }


    /// <summary>
    /// Can the ability be started?
    /// </summary>
    /// <returns>True if the ability can be started.</returns>
    public override bool CanStartAbility()
    {

        var characterLocomotion = m_GameObject.GetComponent<UltimateCharacterLocomotion>();
        var downedAbility = characterLocomotion.GetAbility<Downed>();
  
        var myDamageVisualizationAbility = characterLocomotion.GetAbility<MyDamageVisualization>();
        // Tries to start the downed ability. There are many cases where the ability may not start,
        // such as if it doesn't have a high enough priority or if CanStartAbility returns false.
  
  
        // Stop the ability if it is active.

        // An attribute may prevent the ability from starting.
        if (!base.CanStartAbility())
        {
            return false;
        }

        if (!downedAbility.IsActive)
        {
            return false;
        }

  

        if (!m_CharacterLocomotion.Grounded)
        {
            return false;
        }

        var localVelocity = m_CharacterLocomotion.LocalLocomotionVelocity;
        var localVelocity2 = m_CharacterLocomotion.LocalLocomotionVelocity;
        localVelocity.y = 0;
        localVelocity2.x = 0;
    
        if (m_NoVelocityDirection == Direction.None && localVelocity.sqrMagnitude == 0 && localVelocity2.sqrMagnitude == 0)
        {
            return false;
        }

    

  

        return true;
    }


    /// <summary>
    /// The ability has started.
    /// </summary>
    protected override void AbilityStarted()
    {
        base.AbilityStarted();

        var characterLocomotion = m_GameObject.GetComponent<UltimateCharacterLocomotion>();
        var myDownedAbility = characterLocomotion.GetAbility<Downed>();
        characterLocomotion.TryStopAbility(myDownedAbility);
    
        var localLocomotionVelocity = m_CharacterLocomotion.LocalLocomotionVelocity;
        if (localLocomotionVelocity.sqrMagnitude == 0)
        {
            m_Direction = m_NoVelocityDirection;
        }
        else
        {
            var inputVector = m_CharacterLocomotion.ActiveMovementType.UseIndependentLook(true) ? m_CharacterLocomotion.InputVector : m_CharacterLocomotion.RawInputVector;
            // Horizontal revive has priority over forward/back.
            var horizontalRevive = Mathf.Abs(inputVector.x) >= Mathf.Abs(inputVector.y);
            if (horizontalRevive)
            {
                if (inputVector.x < 0)
                {
                    m_Direction = Direction.Left;
                }
                else
                {
                    m_Direction = Direction.Right;
                }
            }
            else
            {
                if (inputVector.y > 0)
                {
                    m_Direction = Direction.Forward;
                }
                else
                {
                    m_Direction = Direction.Backward;
                }
            }
        }
    }









}
 
Last edited:
It's tough to say without actually playing through and setting breakpoints.

Generally for transition problems I take things in two stages:
- First I determine if the animator parameters are correct. If they are not correct then something is wrong with the code and I start to debug the code.
- If the animator parameters are correct then it's a problem with the animator. For this I then look at the transitions and make sure the correct conditions are setup.
 
Top