Determine if the enemy is attacking from the front or the back

Hello everyone; I hope you are doing fantastic; I’m just using the lessons from Unity 3rd Person Combat & Traversal as starter points to get my game going.

I have had a fantastic experience adding new features so far.

I was looking for a solution to determine whether the enemy is attacking from the front or the back so if the player is blocking and in a vulnerable position is going to receive damage and transition to the Impact state and so on.

So I wanted to share with you the code I used to achieve that.

Not completely sure If creating two variants from one state, for example, as I did for PlayerBlockingState and PlayerTargetingBlockingState is the right approach to handle this, but in my case worked like a charm, and I can still figure out what it is doing at first glance.

My PlayerBlockingState Looks like this:

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

public class PlayerBlockingState : PlayerBaseState
{
    private readonly int BlockHash = Animator.StringToHash("Block");

    private const float CrossFadeDuration = 0.1f;
    private const float blockCoverageAngle = 20f;
    public PlayerBlockingState(PlayerStateMachine stateMachine) : base(stateMachine) { }

    public override void Enter()
    {
        stateMachine.Health.SetInvulnerable(true);
        stateMachine.Animator.CrossFadeInFixedTime(BlockHash, CrossFadeDuration);
    }

    private bool AttackComingFromFront(Transform otherTransform)
    {
        if (!stateMachine.EnemyTransform)
        {
            return false;
        }
        // Get the angle between the enemy and the player
        // playerDirection is pointing from the player's position to the position of the enemy.
        Vector3 playerDirection = stateMachine.EnemyTransform.position - stateMachine.transform.position;
        playerDirection.y = 0f;

        float angle = Quaternion.Angle(
            Quaternion.LookRotation(stateMachine.transform.forward),
            Quaternion.LookRotation(playerDirection));

        // Debug.Log("Angle between enemy and player: " + angle);
        // Debug.Log("Block coverage angle: " + blockCoverageAngle);
        // Debug.Log(otherTransform.name + " is attacking from the front: " + (angle > blockCoverageAngle));
        return angle <= blockCoverageAngle;
    }

    public override void Tick(float deltaTime)
    {
        Move(deltaTime);

        Move(deltaTime);

        if (!stateMachine.InputReader.IsBlocking)
        {
            stateMachine.SwitchState(new PlayerFreeLookState(stateMachine));
            return;
        }

        // Check if the enemy is attacking from the back
        bool attackFromBack = !AttackComingFromFront(stateMachine.EnemyTransform);
        if (attackFromBack)
        {
            // Set invulnerability to false if the enemy is attacking from the back
            stateMachine.Health.SetInvulnerable(false);
        }


    }

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

Also, since I wanted to block without the need to be in the targeting state
that way, I could block in the PlayerFreeLookState

I created a new state: PlayerTargetingBlockingState

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

public class PlayerTargetingBlockingState : PlayerBaseState
{
    private readonly int BlockHash = Animator.StringToHash("Block");

    private const float CrossFadeDuration = 0.1f;

    public PlayerTargetingBlockingState(PlayerStateMachine stateMachine) : base(stateMachine) { }

    public override void Enter()
    {
    
        stateMachine.Health.SetInvulnerable(true);
        stateMachine.Animator.CrossFadeInFixedTime(BlockHash, CrossFadeDuration);
    }

    public override void Tick(float deltaTime)
    {
        Move(deltaTime);

        if (!stateMachine.InputReader.IsBlocking)
        {   stateMachine.SwitchState(new PlayerTargetingState(stateMachine));
            return;
        } 
    }

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

Nicely done!

1 Like

This is awesome and I hope you don’t mind if I implement this in my game.

Two questions: 1) Where did you get the EnemyTransform from? I can’t find where we reference that. 2) Is there an easy way using this code to change the angle? Was thinking I could give my player a 90-120 degree angle in front of them.

UPDATE: Look like I had to add this to my PlayerStateMachine to get rid of the error messages. Hope that was the right thing to do.

public Transform EnemyTransform{get; private set;}

After I put your code into my Blocking State (the stuff involving the angles) I find I’m not able to block at all- the invincibility and knockback don’t happen, but my blocking animation still holds. When I was targeting I could still still block like before, including from behind. When I made the TargetingBlock state look more like the BlockingState to match the angle stuff, I managed to somehow disable the function of blocking completely. Not sure how that happened (again, the animation still plays and the player unable to move).

Here are my scripts in case one of you geniuses can spot something I failed to catch. If it would help to send some of my other scripts, I’ll gladly do that. Been stuck on this for awhile now.

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

public class PlayerBlockingState : PlayerBaseState
{
    private readonly int BlockHash = Animator.StringToHash("Block");

    private const float CrossFadeDuration = 0.1f;
    private const float blockCoverageAngle = 20f;
    public PlayerBlockingState(PlayerStateMachine stateMachine) : base(stateMachine){}

    public override void Enter()
    {
        stateMachine.Health.SetInvulnerable(true);
        stateMachine.Animator.CrossFadeInFixedTime(BlockHash, CrossFadeDuration);
    }
    
    private bool AttackComingFromFront(Transform otherTransform)
    {
        if (!stateMachine.EnemyTransform)
        {
            return false;
        }
        //Gets the angle between enemy and player.
        //playerDirection is pointing from the player's position to the position of the enemy.

        Vector3 playerDirection = stateMachine.EnemyTransform.position - stateMachine.transform.position;
        playerDirection.y = 0f;

        float angle = Quaternion.Angle(
            Quaternion.LookRotation(stateMachine.transform.forward), 
            Quaternion.LookRotation(playerDirection));

        //Debug.Log(+ angle);
        //Debug.Log(+ blockCoverageAngle);
        //Debug.Log(otherTransform.name + (angle > blockCoverageAngle));

        return angle <= blockCoverageAngle;
    }
    public override void Tick(float deltaTime)
    {
        Move(deltaTime);

        Move(deltaTime);

        if(!stateMachine.InputReader.IsBlocking)
        {
            stateMachine.SwitchState(new PlayerFreeLookState(stateMachine));
            return;
        }

        bool attackFromBack = !AttackComingFromFront(stateMachine.EnemyTransform);
        if (attackFromBack)
        {
            //sets invulnerability to false if the enemy is attacking from the back.
            stateMachine.Health.SetInvulnerable(false);
        }
    }
    public override void Exit()
    {
        stateMachine.Health.SetInvulnerable(false);
    }
}

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

public class PlayerTargetingBlockingState : PlayerBaseState
{
    private readonly int BlockHash = Animator.StringToHash("Block");
    private const float CrossFadeDuration = 0.1f;
    private const float blockCoverageAngle = 20f;
    public PlayerTargetingBlockingState(PlayerStateMachine stateMachine) : base(stateMachine) {}

    public override void Enter()
    {
        stateMachine.Health.SetInvulnerable(true);
        stateMachine.Animator.CrossFadeInFixedTime(BlockHash, CrossFadeDuration);
    }

    public override void Tick(float deltaTime)
    {
        Move(deltaTime);

        Move(deltaTime);

        if (!stateMachine.InputReader.IsBlocking)
        {
            stateMachine.SwitchState(new PlayerTargetingState(stateMachine));
        }

        bool attackFromBack = !AttackComingFromFront(stateMachine.EnemyTransform);
        if (attackFromBack)
        {
            //sets invulnerability to false if the enemy is attacking from the back.
            stateMachine.Health.SetInvulnerable(false);
        }
    }

    private bool AttackComingFromFront(Transform otherTransform)
    {
        if (!stateMachine.EnemyTransform)
        {
            return false;
        }
        //Gets the angle between enemy and player.
        //playerDirection is pointing from the player's position to the position of the enemy.

        Vector3 playerDirection = stateMachine.EnemyTransform.position - stateMachine.transform.position;
        playerDirection.y = 0f;

        float angle = Quaternion.Angle(
            Quaternion.LookRotation(stateMachine.transform.forward), 
            Quaternion.LookRotation(playerDirection));

        //Debug.Log(+ angle);
        //Debug.Log(+ blockCoverageAngle);
        //Debug.Log(otherTransform.name + (angle > blockCoverageAngle));

        return angle <= blockCoverageAngle;
    }

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

Hey, Mat thank you for your reply. Actually, the solution I posted Is not efficient and is giving weird issues on the relative player rotation, so if the enemy turns out to be on the opposite side of the z-axis the player is going to receive damage anyway, so I already got it working with different code:

I ended up changing the function name and a couple of fixes, so I ended up implementing a function, a bool method called AttackComingFromBack, and I put it on the Player Base state so I could quickly call on whichever state I wanted,

add the method to the player base state:

    protected bool AttackComingFromBack(Transform otherTransform)
    {
        // Get the angle between the enemy and the player
        Vector3 playerDirection = otherTransform.transform.position - stateMachine.transform.position;
        playerDirection.y = 0f;

        float angle = Vector3.Angle(stateMachine.transform.forward, playerDirection);
        if (angle > 180) angle = 360 - angle;
        bool attackFromBack = angle > blockCoverageAngle;

        if (attackFromBack)
        {
            // If the enemy is attacking from behind, set invulnerability to false
            stateMachine.Health.SetInvulnerable(false);
        }

        return !attackFromBack;

    }

The function calculates the angle between the enemy and the player using the positions of the “otherTransform” and the stateMachine’s transform. It then checks if the angle is greater than 180 degrees, if so it sets the angle to 360 minus itself. The function then compares this angle with a variable “blockCoverageAngle” and returns whether the angle is greater than blockCoverageAngle or not. If the angle is greater than blockCoverageAngle, which means the enemy is attacking from behind, it sets the invulnerability of the stateMachine’s health to false. The function returns the opposite of the attackFromBack variable.

Ending up the implementation like this:

PlayerTargetingBlockingState.cs


using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class PlayerTargetingBlockingState : PlayerBaseState

{

    private readonly int BlockHash = Animator.StringToHash("Block");

    private const float CrossFadeDuration = 0.1f;

    public PlayerTargetingBlockingState(PlayerStateMachine stateMachine) : base(stateMachine) { }

    public override void Enter()

    {

        stateMachine.Health.SetInvulnerable(true);

        stateMachine.Animator.CrossFadeInFixedTime(BlockHash, CrossFadeDuration);

    }

    public override void Tick(float deltaTime)

    {

        Move(Vector3.zero, deltaTime);

        if (!stateMachine.InputReader.IsBlocking)

        {

            stateMachine.SwitchState(new PlayerTargetingState(stateMachine));

            return;

        }

        foreach (Target enemy in stateMachine.Enemies)

        {

            AttackComingFromBack(enemy.transform);

        }

    }

    public override void Exit()

    {

        stateMachine.Health.SetInvulnerable(false);

    }

}

PlayerBlockingState.cs

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

public class PlayerBlockingState : PlayerBaseState
{
    private readonly int BlockHash = Animator.StringToHash("Block");

    private const float CrossFadeDuration = 0.1f;
    public PlayerBlockingState(PlayerStateMachine stateMachine) : base(stateMachine) { }

    public override void Enter()
    {
        stateMachine.Health.SetInvulnerable(true);
        stateMachine.Animator.CrossFadeInFixedTime(BlockHash, CrossFadeDuration);
    }

    public override void Tick(float deltaTime)
    {
        Move(Vector3.zero, deltaTime);

        if (!stateMachine.InputReader.IsBlocking)
        {
            stateMachine.SwitchState(new PlayerFreeLookState(stateMachine));
            return;
        }

        if (stateMachine.Targeter.CurrentTarget != null)
        {
            stateMachine.SwitchState(new PlayerTargetingBlockingState(stateMachine));
            return;
        }
        // Iterate through all enemies and check if they are attacking from behind
        foreach (Target enemy in stateMachine.Enemies)
        {
            AttackComingFromBack(enemy.transform);
        }
    }

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




and Finally in my PlayerTargetingState.cs


        if (stateMachine.InputReader.IsBlocking)
        {
            stateMachine.SwitchState(new PlayerBlockingState(stateMachine));
            return;
        }

let me know if that works for you I’ll be glad to help.

1 Like

Compliment #2 ahead! Spotting an issue and refactoring to fix it. Well done!

We can teach you only so much in the course, it’s when you begin to start playing with the code, finding the problems, and making the needed adjustments that make the transition from student to coder.

1 Like

Very nice.

As an aside, you could use the dot product of two vectors to determine their relation to each other. You would need to determine what the value is you want for your coverage angle because it’s not in degrees or radians, but it’s quite simple to use.

private bool AttackComingFromBehind(Transform other)
{
    var directionToAttacker = (other.position - stateMachine.transform.position).normalized;
    var dotProduct = Vector3.Dot(statemachine.transform.forward, directionToAttacker);
    return dotProduct < 0f;
}

The dot product will return 1 if the attacker is directly in front of the player, -1 if the attacker is directly behind the player, and 0 if the attacker is perpendicular to the player. The code above will only return true if the attacker is behind the player. That is 90° and more. To get a 20° coverage, you can use

var requiredValue = Mathf.Cos(20f * Mathf.Deg2Rad);

So, all together it would be something like

private bool AttackComingFromBehind(Transform other, float coverageAngle)
{
    var requiredValue = Mathf.Cos(coverageAngle * Mathf.Deg2Rad);
    var directionToAttacker = (other.position - stateMachine.transform.position).normalized;
    var dotProduct = Vector3.Dot(statemachine.transform.forward, directionToAttacker);
    return dotProduct < requiredValue;
}

the required value could be precalculated and passed in instead because it’s probably not going to change often. With all of this it’s important to use normalised vectors.

Thought I’d add this because it doesn’t matter which way the player is facing or where the attacker is coming from.

Unity Vector3.Dot

1 Like

Hi! I’m here after trying out these to no success (I must be missing something important).

I copied your protected bool AttackComingFromBack(Transform otherTransform){} and pasted into my PlayerBaseState. I got a swiggly line under blockCoverageAngle; and one of the auto solutions was to add this private readonly float blockCoverageAngle; to the top of my PlayerBaseState. Not sure if that was the right thing to do.

I also copy/pasted the foreach (Target enemy in stateMachine.Enemies) { AttackComingFromBack(enemy.transform); }
in my my Blocking and TargetingBlocking States. I got a swiggly line under Enemies so I added what the system suggested in my PlayerStateMachine public IEnumerable<Target> Enemies { get; internal set; }

This gets rid of the swiggly lines.

The ticks for my Blocking State and TargetingBlockingAtate are these.

Blocking

public override void Tick(float deltaTime)
    {
        Move(deltaTime);
        Vector3 movement = CalculateMovement();
        Move(movement * stateMachine.BlockingMovementSpeed, deltaTime);

        if (!stateMachine.InputReader.IsBlocking) //If the player is not blocking "!" is the equivalent of 'not'
        {
            stateMachine.SwitchState(new PlayerFreeLookState(stateMachine));
            {return;}
        }

        if (stateMachine.InputReader.MovementValue == Vector2.zero) 
        { 
            stateMachine.Animator.SetFloat(FreeLookSpeedHash, 0, AnimatorDampTime, deltaTime);
            return; 
        }

        stateMachine.Animator.SetFloat(FreeLookSpeedHash, stateMachine.InputReader.MovementValue.magnitude, AnimatorDampTime, deltaTime);
        FaceMovementDirection(movement,deltaTime);
        
        foreach (Target enemy in stateMachine.Enemies)
        {
            AttackComingFromBack(enemy.transform);
        }

        if(!stateMachine.Controller.isGrounded)
        {
            stateMachine.SwitchState(new PlayerFallingState(stateMachine));
        }
    }

TargetingBlocking

public override void Tick(float deltaTime)
    {
        Move(deltaTime);

        if (!stateMachine.InputReader.IsBlocking) //If the player is not blocking "!" is the equivalent of 'not'
        {
            stateMachine.SwitchState(new PlayerTargetingState(stateMachine));
            {return;}
        }

        if (stateMachine.Targeter.CurrentTarget == null) //If there is no target, game will do this
        {
            stateMachine.SwitchState(new PlayerBlockingState(stateMachine));
            {return;}
        }

        Vector3 movement = CalculateTargetingMovement(deltaTime);
        Move(movement * stateMachine.TargetingBlockingMovementSpeed, deltaTime);
        UpdateAnimator(deltaTime);
        FaceTarget();
        
        foreach (Target enemy in stateMachine.Enemies)
        {
            AttackComingFromBack(enemy.transform);
        }

        if(!stateMachine.Controller.isGrounded)
        {
            stateMachine.SwitchState(new PlayerFallingState(stateMachine));
        }
    }

When I run the game with these, and both additions to the PlayerBaseState and PlayerStateMachine, I get the NullReferenceException error for every frame I block for.

Not sure what I did wrong. I’m thinking it’s either how I have my Tick methods set up, or if I put the incorrect lines in the other scripts.

You just added variables to get rid of squiggly lines and never assigned anything to them? I would say that’s the problem. From what I can see Enemies would be a list of all the enemies that’s currently attacking you. Not assigning anything to it will give you null reference exceptions

1 Like

Thanks! I knew I was missing something. I tried adding [field: SerializeField] public float blockCoverageAngle { get; private set; } in my PlayerStateMachine, and set that to a bunch fo different numbers like 10, 180, 90, etc.

I also added Enemies = (IEnumerable<Target>)GameObject.FindGameObjectWithTag("Enemy").GetComponent<WeaponDamage>(); to my private void Start, hoping that would do something (the whole thing had a swiggly line until I added the (IENumerable) part.

Nothing changed, still having the same issues.

This will not work. You are trying to put a square (WeaponDamage) in a round hole (Target). You cannot cast WeaponDamage to Target because they are not the same thing.

The Targeter has a list of enemies that are close enough for you to target. I suspect it would be safe to assume they are close enough to be attacking you, too. Unless there are ranged enemies that you cannot target but are attacking you. Then you’d need another solution. Get hold of this list. It’s the type you want, i.e. Target

I feel like I should be getting closer, but still having the same issues. I replaced the old line with this and changed nothing else, but the NullReferenceException errors keep popping up.

Enemies = (IEnumerable<Target>)GetComponent<Targeter>();

Funny enough, the errors pop up only while I’m moving and blocking in freelook, but pop up with I’m stationary and moving in targeting. Not sure why.

Still not the same thing. Targeter is not Target.

You’d want to expose the list in Targeter so you can access it from outside and then assign it

// In Targeter.cs
public IEnumerable<Target> GetTargets()
{
    return targets; // <- this is the list of targets that is constantly being update by the trigger colliders
}

Then assign that

Enemies = Targeter.GetTargets(); // your PlayerStateMachine should already have a reference to Targeter

You should remember that this list is constantly being updated so you may benefit from getting it in each frame rather than caching it

1 Like

Thank you so much! This was a big step forward. Still having some issues though.

You should remember that this list is constantly being updated so you may benefit from getting it in each frame rather than caching it

I made a private void Tick() in my PlayerStateMachine and put Enemies = Targeter.GetTargets();, but I got the same errors as before. Putting that in the Start method gets rid of the error and makes the directional blocking function-ish.

It’s weird. If I set BlockingCoverageAngle to 0, the player cannot block and stay invulnerable (as expected). If I set it to 180, the player can block in all directions (what we had before).

It’s when I set it to 90 where I get inconsistent results. Sometimes the player will block correctly and other times they won’t. Here’s a video of what I mean. Hoping to draw some consistencies in why the blocking sometimes won’t work.

I’m thinking it has something to do with how the player can move while blocking and that messes up with the world space somehow? Doing more tests to figure it out.

Hey Matt, sorry not to include the list of enemies code

Basically what I did to achieve and iterate through them was:

[field: SerializeField] public List<Target> Enemies { get { return Targeter.GetTargets(); } }

can you show me your AttackComingFromBack? yeah I do need to put some refactor to variables like blockCoverageAngle I putted above the PlayerBaseState to get a quickly ramp up, I setted my blockCoverageAngle to 90f my goal for that was no matter what if the enemy is attacking from the front is going to block but in the case that some enemy is chasing and attacking and I’m giving my back is going to transition to the impact state hence receive damage.

also I can see that in your PlayerBlockingState in my case (the freelookstate blocking)
i have the following condition:
maybe in your blocking targeting state is bouncing from the lack of the following condition?

 if (stateMachine.Targeter.CurrentTarget != null)
    {
        stateMachine.SwitchState(new PlayerTargetingBlockingState(stateMachine));
        return;
    }

The covereage angle is inclusive of -blockingCoverageAngle to +blockingCoverageAngle, as the result of this calculation is always a positive number, even if the angle is negative.

This means that a coverageAngle of 180 is really a coverage angle from -180 to 180, or a total of 360 degrees. A coverage angle of 90 would yield -90 to 90 (a half moon in front of the player).

Here’s my slightly altered AttackComingFromBack

protected bool AttackComingFromBack(Transform otherTransform)
    {
        // Get the angle between the enemy and the player
        Vector3 playerDirection = otherTransform.transform.position - stateMachine.transform.position;
        playerDirection.y = 0f;

        float angle = Vector3.Angle(stateMachine.transform.forward, playerDirection);
        if (angle > 180) angle = 360 - angle;
        bool attackFromBack = angle > stateMachine.BlockCoverageAngle;

        if (attackFromBack)
        {
            // If the enemy is attacking from behind, set invulnerability to false
            stateMachine.Health.SetInvulnerable(false);
        }

        return !attackFromBack;
    }

that I have in my BaseState.

I added the condition in the PlayerBlockingState condition, which may or may not have helped It didn’t completely solve the issue, my enemies are still landing hits when they shouldn’t. Here’s another video with the updated scripts.

It’s interesting that for the most part, it works- until it doesn’t.

*I have the listeners for targeting and canceling in my blocking states so I can target/untarget while keeping my shield up

Yeah you’re right is working but suddenly is not working at all;

could you also try to:
stateMachine.Health.SetInvulnerable(false);
in both the exit method in both blocking states,
I was having some weird issues due to the lack of that statement on my exit method.

EDIT: another thing you could try is put the a Debug.Log statement in the AttackComingFromBack method

    Debug.Log("Angle between enemy and player: " + angle);
    Debug.Log("Block coverage angle: " + stateMachine.BlockCoverageAngle);
    Debug.Log(otherTransform.name + " is attacking from the back: " + (angle > stateMachine.BlockCoverageAngle));

So you can see the value of the Angle between the enemy and the player

Where Angle between the enemy and the player is a value that is dynamic based on your blocking
so basically, if the value is more than 90, it is going to receive damage. If my player is on the front, it gives me a value of 30, but If I turn my back, it will have a value of 160, and so on.

Do you have some repo on gitlab or github that I could replicate? I would love to take a look and help you to fix the issue.

This if will never be entered. Vector3.Angle will always return a value between 0 and 180. If you use Vector3.SignedAngle you may get better results

protected bool AttackComingFromBack(Transform otherTransform)
{
    // Get the angle between the enemy and the player
    Vector3 playerDirection = otherTransform.transform.position - stateMachine.transform.position;
    playerDirection.y = 0f;

    // get the angle between -180 and 180
    float angle = Vector3.SignedAngle(stateMachine.transform.forward, playerDirection);
    // use the absolute value of the angle to compare
    bool attackFromBack = Mathf.Abs(angle) > stateMachine.BlockCoverageAngle;

    if (attackFromBack)
    {
        // If the enemy is attacking from behind, set invulnerability to false
        stateMachine.Health.SetInvulnerable(false);
    }

    return !attackFromBack;
}

(Edit actually, it doesn’t matter. The if still won’t get entered, but the return value is already the same value you will get with the absolute value of the Vector3.SignedAngle result.)

My earlier post may also remove some of the issues

private bool AttackComingFromBack(Transform otherTransform)
{
    var requiredValue = Mathf.Cos(stateMachine.BlockCoverageAngle * Mathf.Deg2Rad);
    var directionToAttacker = (otherTransform.position - stateMachine.transform.position).normalized;
    var dotProduct = Vector3.Dot(statemachine.transform.forward, directionToAttacker);
    return dotProduct < requiredValue;
}

Also, this part should really not be in this function. It will work, but the function is to check if the attack is from behind. Here, it also changes the player’s health state. The better option is to take the result of this function when it’s called and using that to set invulnerability

That makes sense, just check if the attack is from behind, I would look to avoid messing up the player’s health there, but for a quick result, I did it that way, and it worked. I was just trying your refactor of the method, but it seems it isn’t working as expected for me:

however, the code that I have right now is now giving me the expected results maybe this is what Matt is looking for however I’m up to refactor whatever is needed.

(I didn’t notice that I had background music sorry)

The problem with this is that some other developer (for teams) or future you want to do something else that need to see if the enemy is attacking from behind. So other dev/you find this nifty function called AttackComingFromBack. Perfect. So other dev/you starts using it. But now the player has become invulnerable (or not) and other dev/you spend hours trying to figure out why.

I have not tested any of it. I would have to update my own project to allow for blocking while not in the targeting state and then implement this. Will get back with an update soon

Privacy & Terms