Third Person Combat Course Issues, Part 2/3

Here is my second problem:

  1. Any target I have, miraculously, instantiates an “Impact” effect after my player performs a combo attack on that target (somehow, I got an impact strike back from a static cube (after a combo attack), let alone my AI enemies)

This one is as direct as the name says, and I will post my ‘PlayerImpactState.cs’, as I believe it can be a potential suspect script:

using UnityEngine;

public class PlayerImpactState : PlayerBaseState
{

    private readonly int ImpactHash = Animator.StringToHash("Impact");
    private readonly float CrossFadeDuration = 0.3f;
    private float duration = 1.0f;

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

    public override void Enter()
    {
        stateMachine.Animator.CrossFadeInFixedTime(ImpactHash, CrossFadeDuration);
    }

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

        // Impact duration:
        duration -= deltaTime;
        // If the impact duration is over, return the player to locomotion (which takes care of him, be it if he's in FreeLook or Targeting State):
        if (duration <= 0) {
            ReturnToLocomotion();
        }

    }

    public override void Exit() {}

}
1 Like

I’m afraid I don’t understand the question…

Are you saying that when the player hits the target, the player is knocked back (instead of surging a bit forward)?

Does this happen when you swing the sword and don’t hit? (Then we need to see the PlayerAttackingState.cs)

Does this happen only when you damage the target? (Then we need to see WeaponDamage.cs)

Am I completely misunderstanding the question? (Then a more descriptive walk through of the problem is needed)

1 Like

Not really, no. What happens is, at the end of my 3-way combo attack, assuming he gets it done, my player takes an impact from any target he just attacked. To prove how horrendous this is, I put a cube for him to attack, and somehow, even a static cube forced my player to an Impact state, where he got hit back by a cube (through visual animations), but it dealt no damage

I think so, yes. Here is the script:

using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;

public class WeaponDamage : MonoBehaviour
{

    [SerializeField] private Collider myCollider;

    private List<Collider> alreadyCollidedWith = new List<Collider>();

    private int damage;
    private float knockback;

    private void OnEnable() {
        alreadyCollidedWith.Clear();
    }

    private void OnTriggerEnter(Collider other) {
        
        if (other == myCollider) return;

        if (alreadyCollidedWith.Contains(other)) return;
        alreadyCollidedWith.Add(other);

        if (other.TryGetComponent<Health>(out Health health)) {
            health.DealDamage(damage);
        }

        if (other.TryGetComponent<ForceReceiver>(out ForceReceiver forceReceiver)) {
            Vector3 direction = (other.transform.position - myCollider.transform.position).normalized;
            Vector3 force = direction * knockback;
            forceReceiver.AddForce(force);
        }

    }

    public void SetAttack(int damage, float knockback) {
        this.damage = damage;
        this.knockback = knockback;
    }

}

But since it also happens at the end of the shield attack, which is not exactly working right now (I responded to this Udemy question regarding that), then I think my ‘ShieldDamage.cs’ script will be necessary as well. Here it is:

using System.Collections.Generic;
using UnityEngine;

public class ShieldDamage : MonoBehaviour
{

    [SerializeField] private Collider myCollider;

    private List<Collider> alreadyCollidedWith = new List<Collider>();

    private int damage;
    private float knockback;

    private void OnEnable()
    {
        alreadyCollidedWith.Clear();
    }

    private void OnTriggerEnter(Collider other)
    {

        if (other == myCollider) return;

        if (alreadyCollidedWith.Contains(other)) return;
        alreadyCollidedWith.Add(other);

        if (other.TryGetComponent<Health>(out Health health))
        {
            health.DealDamage(damage);
        }

        if (other.TryGetComponent<ForceReceiver>(out ForceReceiver forceReceiver))
        {
            Vector3 direction = (other.transform.position - myCollider.transform.position).normalized;
            Vector3 force = direction * knockback;
            forceReceiver.AddForce(force);
        }

    }

    public void SetAttack(int damage, float knockback) {
        this.damage = damage;
        this.knockback = knockback;
    }

}
1 Like

Try adding the above Debug.Log to both the ShieldDamage and WeaponDamage…

OK so since we both know the shield Damage is currently not working, this makes debugging a little easier, until I figure out how to access these values…

To get these values, I froze the attack animation of my enemy, so my player can get a proper chance to attack him, but he still managed to sway his sword to my player (now I understand why animating the collisions is essential), hence the first line of the debugger (the one with the (-10.50, 1.97, -16.91) values).

The second value is my enemies’ health, after my player struck an impact on him at the end of his combo (again, my first 2 attacks of the combo are ineffective, so I can’t impact him then), and the last line is the damage dealt by my player to my enemy, which is practically nothing (AND AGAIN, THAT LAST LINE ONLY SHOWS UP AFTER THE ATTACK COMBO IS DONE, Which highlights my point that… my first two attack combos are ineffective)

If it helps in anyway, here is my ‘Enemy State Machine’ hierarchy inspector:

Enemy State Machine

I’m assuming your enemy health is starting at 100, which means that ZERO damage (slightly less than practically nothing) is being applied on the hit, and ZERO force is being applied on the hit… So somehow the message isn’t getting from the AttackState to the WeaponLogic down to the Weapon. The knockback, at least, on the Enemy is getting through to it’s weapon.

More Debugs… to follow the trail:

    public void SetAttack(int damage, float knockback) {
        this.damage = damage;
        this.knockback = knockback;
        Debug.Log($"Setting {myCollider.gameObject.name}'s Weapon Damage on {name}. Damage={damage}, knockback = {knockback}");
    }

Set a similar Debug in WeaponHandler to log out that you are receiving the Damage and Knockback values as well, and I would go so far as to add a Debug in PlayerAttackState.Enter that logs out the Attack’s index, damage, and Knockback before passing it to the WeaponHandler.

public void SetAttack(int damage, float knockback) {
        this.damage = damage;
        this.knockback = knockback;
        Debug.Log($"Setting {myCollider.gameObject.name}'s Weapon Damage on {name}. Damage={damage}, knockback = {knockback}");
    }

This debug works, and we get the messages as expected

  1. As for this one:

I went to ‘WeaponHandler.cs’ and added this debugger, in ‘EnableWeapon()’:

public void EnableWeapon() {
        weaponLogic.SetActive(true);
        Debug.Log($"Dealing damage {weaponLogic}. Damage {GetComponent<WeaponDamage>().damage}, Knockback {GetComponent<WeaponDamage>().knockback}"); // this is line 16, where the NRE error below is coming from
    }

After making the knockback and attack in ‘WeaponDamage.cs’ public for this one (I’ll reverse them to private soon)

AND… It returns a Null Reference Exception on the ‘WeaponHandler.Enable()’ 's Debug.Log line, as follows:

NullReferenceException: Object reference not set to an instance of an object
WeaponHandler.EnableWeapon () (at Assets/Scripts/WeaponHandler.cs:16)

and this is the line causing the issues:

        Debug.Log($"Dealing damage {weaponLogic}. Damage {GetComponent<WeaponDamage>().damage}, Knockback {GetComponent<WeaponDamage>().knockback}");

  1. And finally, in ‘PlayerAttackState.Enter()’, I entered this debugger to get the index (not sure if it’s the right or wrong way), the damage and knockback, as follows:
    public override void Enter()
    {
        stateMachine.Weapon.SetAttack(attack.Damage, attack.Knockback);
        // stateMachine.ShieldDamage.SetAttack(attack.Damage, attack.Knockback);
        Debug.Log($"Attack Index: {attack}, Weapon damage: {attack.Damage}, Weapon Knockback: {attack.Knockback}");
        stateMachine.Animator.CrossFadeInFixedTime(attack.AnimationName, attack.TransitionDuration);
    }

This one went through fine as well

Here are all 3 in action

I wrote these debugs from work… and forgot that WeaponDamage is disabled by default. Try

        Debug.Log($"Dealing damage {weaponLogic}. Damage {GetComponent<WeaponDamage>(true).damage}, Knockback {GetComponent<WeaponDamage>(true).knockback}");

You might also change that to “Setting damage” because at this point you’re only setting the damage on the WeaponDamage, not actually dealing damage. That could lead to misinterpretation of the results.

In any event, it looks like the attacks are getting through to the linked WeaponDamage, which is odd that when a hit actually happens these values aren’t set… That’s the purpose of the debug in the 3/3… I have a suspicioun

The new ones with the true inside them are giving me compiler errors. I don’t think this one has an input argument to take in (that’s what the compiler says)

Call me tired… change those to GetComponentInChildren

Debugger is giving out the values just fine, everytime the collider gets toggled and my player attempts to deal damage. I think it has something to do with the ‘alreadyCollidedWith’ being empty for some reason

AlreadyCollidedWith having a matching entry blocks damage, not the other way round

Privacy & Terms