Blocking

When I am Blocking in the target State I don’t receive damage, even when I get out of target state. Wil we be solving this issue in another lecture? i think that if we exit the targeting state or is not blocking then we should receive damage.

Do you have this in your Exit for the PlayerBlockingState?

public override void Exit()
{
    stateMachine.Health.SetInvulnerable(false);
}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class PlayerBlockingState : PlayerBaseState

{

private readonly int BlackHash = Animator.StringToHash("PlayerBlocking");

private const float CrossFadeDuration = 0.1f;

public PlayerBlockingState(PlayerStateMachine stateMachine) : base(stateMachine)

{

}

public override void Enter()

{

    stateMachine.PlayerHealth.SetInvulnerable(true);

    stateMachine.Animator.CrossFadeInFixedTime(BlackHash, CrossFadeDuration);

}

public override void Tick(float deltaTime)

{

    Move2(deltaTime);

    if(!stateMachine.InputReader.IsBlocking)

    {

        stateMachine.SwitchState(new PlayerTargetState(stateMachine));

        return;

    }

    if(stateMachine.Targeter.CurrentTarget == null)

    {

        stateMachine.SwitchState(new PlayerFreeLookState(stateMachine));

        return;

    }

}

public override void Exit()

{

    stateMachine.PlayerHealth.SetInvulnerable(false);

}

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using System;

public class Health : MonoBehaviour

{

[SerializeField] private int maxHealth = 100;

[SerializeField] private int health;

private bool isInvulrnerable = false;

public event Action onTakeDamage;

public event Action onDie;

public bool IsDead => health == 0;



private void Start()

{

    health = maxHealth;

}

public void DealDamage(int damage)

{

    if(health == 0) {return;}

    if(isInvulrnerable){return;}

    health = Mathf.Max(health - damage, 0);

    if(onTakeDamage != null)

    {

      onTakeDamage.Invoke();

    }

    if(onDie != null)

    {

        if(health == 0)

        {

         onDie.Invoke();

        }

    }

   

    Debug.Log(health);

}

public void SetInvulnerable(bool isInvulrnerable)

{

    this.isInvulrnerable = isInvulrnerable;

}

}

I Think I have every thing

some how the EXIT and ENTER in the " PlayerBlockingState" are being Flipped so the EXIT get’s called first then the ENTER.

public override void Enter()

{

    stateMachine.PlayerHealth.SetInvulnerable(true);

    stateMachine.Animator.CrossFadeInFixedTime(BlackHash, CrossFadeDuration);

    Debug.Log("ENTER Blocking");

}


public override void Exit()
{
    stateMachine.PlayerHealth.SetInvulnerable(false);
    Debug.Log("EXIT Blocking");
}

InputReader works correctly.

public void OnBlock(InputAction.CallbackContext context)

{

    if (context.performed)

    {

        IsBlocking  = true;

        Debug.Log("IS Blocking");

    }

    else if (context.canceled)

    {

        IsBlocking  = false;

        Debug.Log("IS NOT Blocking");

    }

}

That seems… well… impossible?

Paste in your StateMachine.cs, to check something

PlayerStateMachine

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

// removing MonoBehaviour as an inharitance then replacing it with (StateMachine)

public class PlayerStateMachine : StateMachine

{

[field: SerializeField] public InputReader InputReader{get; private set;}

[field: SerializeField] public CharacterController Controller{get; private set;}

[field: SerializeField] public float FreeLookMovementSpeed {get; private set;}

[field: SerializeField] public float TargetingMovementSpeed {get; private set;}

[field: SerializeField] public float RotationSmoothSpeed {get; private set;}

[field: SerializeField] public float DodgeDuration {get; private set;}

[field: SerializeField] public float DodgeLength {get; private set;}

[field: SerializeField] public float PreviousDodgeTime {get; private set;} = Mathf.NegativeInfinity;

[field: SerializeField] public float DodgeCooldown {get; private set;}

[field: SerializeField] public Animator Animator {get; private set;}

[field: SerializeField] public Targeter Targeter {get; private set;}

[field: SerializeField] public ForceReciver ForceReciver {get; private set;}

[field: SerializeField] public Attack [] Attacks {get; private set;}

[field: SerializeField] public WeaponDamage Weapon {get; private set;}

[field: SerializeField] public Health PlayerHealth {get; private set;}

[field: SerializeField] public Ragdoll Ragdoll {get; private set;}

public Transform MainCameraTransform {get; private set;}

// Start is called before the first frame update

private void Start()

{

    MainCameraTransform = Camera.main.transform;

    SwitchState(new PlayerFreeLookState(this));

}

    private void OnEnable()

{

    PlayerHealth.onTakeDamage += HandleTakeDamege;

    PlayerHealth.onDie += HandleDie;

}

private void OnDisable()

{

    PlayerHealth.onTakeDamage -= HandleTakeDamege;

    PlayerHealth.onDie -= HandleDie;

}

private void HandleTakeDamege()

{

    SwitchState(new PlayerImpactState(this));

}

    private void HandleDie()

{

    SwitchState(new PlayerDeadState(this));

}

public void SetDodgeTime(float dodgeTime)

{

    PreviousDodgeTime = dodgeTime;

}

}

StateMachine

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class StateMachine : MonoBehaviour
{
    private State currentState;

    // Update is called once per frame
    private void Update()
    {
        if (currentState != null)
        {
            currentState.Tick(Time.deltaTime);
        }    
    }

    public void SwitchState(State newState)
    {
        // I need the first state like this to begin because
        //I'm doing the "IF" statements like this and not like in the tutorial ((currentState?.Exit();))
        currentState = newState; /// < --
        //this is going from one state to another state.
        if(currentState != null)
        {
            currentState.Exit();
            currentState = newState;
            if(currentState != null)
            {
                currentState.Enter();
            }
       }
    }
}

I think I see the problem, and literally ALL of your states are going to run Exit before running Enter the way you have this set up… You’re overwriting the current State and then running Exit on the new state instead of running exit on the old stae.

In SwitchState, the first thing that has to happen is that you need to run Exit on the current state… that’s the

currentState?.Exit();

method. This should only run if there is a current State…
Then you can change the currentState to the newState;
Then you can run the Enter on the new state.

You don’t have to use the null propogation currentState?.Exit if you wish…

Try it this way

public void SwitchState(State newState)
{
    if(currentState!=null) 
    {
         currentState.Exit(); //run exit on existing state
    }
    currentState = newState; //now we work on the new state going forward
    if(currentState!=null)
    {
          currentState.Enter();
    }
}

Thank you.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms