Hello,
so I have a kind of weird problem where my input for attacking doesn’t register correctly, but only the first time I ever attack. After that it works perfectly fine. Leads me to think I’ve made some kind of mistake in a Start() method but I seem unable to find it.
Relevant code:
Weapon script, sitting on the weapon GameObject
[RequireComponent(typeof(BoxCollider2D))]
public class Weapon2D : MonoBehaviour
{
[SerializeField]
private DamageParameters m_DamageParams = null;
[SerializeField]
private float m_HeavyAttackModifier = 1.5f;
[SerializeField][Range(0.0f, float.MaxValue)]
private float m_AttackTime = 1.0f;
[SerializeField][Range(0.0f, float.MaxValue)]
private float m_AttackTimeHeavy = 1.0f;
[SerializeField][Range(0.0f, float.MaxValue)]
private float m_Cooldown = 0.25f;
public delegate void AttackEvent(GameObject weapon);
public delegate void AttackHitEvent(GameObject weapon, GameObject hit, float damage);
public event AttackEvent OnBeginAttack;
public event AttackEvent OnAttack;
public event AttackEvent OnEndAttack;
public event AttackHitEvent OnTargetHit;
private BoxCollider2D m_Collider;
private float m_NextAttackTime;
private bool m_IsHeavyAttack;
private bool m_IsAttackPrepared;
public bool IsHeavyAttack
{
get { return m_IsHeavyAttack; }
}
void Start()
{
m_Collider = GetComponent<BoxCollider2D>();
if (!m_Collider.isTrigger)
Debug.LogError($"Collider on weapon {transform.name} not set as trigger");
m_Collider.enabled = false;
m_NextAttackTime = 0.0f;
m_IsHeavyAttack = false;
m_IsAttackPrepared = false;
}
void OnTriggerEnter2D(Collider2D other)
{
// Damage handling and knockback call happens here
}
private void ApplyKnockback(CharacterHealth2D target)
{
// Knockback handling happens here
}
private void EndAttack()
{
m_IsAttackPrepared = false;
m_Collider.enabled = false;
OnEndAttack?.Invoke(gameObject);
}
private IEnumerator DoAttack(float time)
{
yield return new WaitForSeconds(time);
EndAttack();
}
public void BeginAttack(bool heavy = false)
{
if (m_NextAttackTime > Time.time || m_IsAttackPrepared)
return;
m_IsHeavyAttack = heavy;
m_IsAttackPrepared = true;
OnBeginAttack?.Invoke(gameObject);
}
public void Attack()
{
if (!m_IsAttackPrepared)
return;
OnAttack?.Invoke(gameObject);
m_Collider.enabled = true;
StartCoroutine(DoAttack(m_IsHeavyAttack ? m_AttackTimeHeavy : m_AttackTime));
m_NextAttackTime = Time.time + m_Cooldown;
}
Animation controller for the weapon, also sitting on the weapon GameObject:
[RequireComponent(typeof(Animator), typeof(Weapon2D))]
public class WeaponAnimationController : MonoBehaviour
{
private Weapon2D m_Weapon;
private Animator m_Animator;
void Awake()
{
m_Weapon = GetComponent<Weapon2D>();
m_Animator = GetComponent<Animator>();
}
void Start()
{
m_Weapon.OnAttack += OnWeaponAttack;
m_Weapon.OnBeginAttack += OnWeaponPrepare;
m_Weapon.OnEndAttack += OnWeaponAttackEnd;
m_Weapon.gameObject.SetActive(false);
}
private void OnWeaponPrepare(GameObject weapon)
{
weapon.SetActive(true);
m_Animator.SetBool(AnimationStrings.BOOL_ATK_HEAVY, m_Weapon.IsHeavyAttack ? true : false);
}
private void OnWeaponAttack(GameObject weapon)
{
m_Animator.SetTrigger(AnimationStrings.TRIGGER_ATTACK);
}
private void OnWeaponAttackEnd(GameObject weapon)
{
weapon.SetActive(false);
}
And the player weapon controller, sitting on the player GameObject
public class PlayerWeaponController : MonoBehaviour
{
// TODO: Multiple Weapons
[SerializeField]
private Weapon2D m_Weapon = null;
void Update()
{
if (Input.GetKeyDown(GlobalInput.VK_ATTACK))
{
m_Weapon.BeginAttack(false);
}
else if (Input.GetKeyDown(GlobalInput.VK_ATTACK_HEAVY))
{
m_Weapon.BeginAttack(true);
}
else if (Input.GetKeyUp(GlobalInput.VK_ATTACK) || Input.GetKeyUp(GlobalInput.VK_ATTACK_HEAVY))
{
m_Weapon.Attack();
}
}
}
The weapon GameObject is a child of the player GameObject. The classes GlobalInput and AnimationStrings are just classes that hold the constants for keys and strings respectively.
The attack handling itself is done by just using OnTriggerEnter and moving the weapon using an animator. Damage application works perfectly fine, the only real issue is that the first time I ever try to attack the player will in fact hold the sword (so the BeginAttack events do actually get called), but after releasing the respective button the Attack event just won’t fire at all. If I press any attack button again it works and from then on it always works as expected.
Would be nice if someone could help me out here.