/// <summary> /// Describes what happens when colliding with a damageable object /// </summary> /// <param name="health">Health.</param> protected virtual void OnCollideWithDamageable(Health health) { // if what we're colliding with is a CorgiController, we apply a knockback force _colliderCorgiController = health.gameObject.MMGetComponentNoAlloc <CorgiController>(); ApplyDamageCausedKnockback(); OnHitDamageable?.Invoke(); HitDamageableFeedback?.PlayFeedbacks(this.transform.position); if ((FreezeFramesOnHitDuration > 0) && (Time.timeScale > 0)) { MMFreezeFrameEvent.Trigger(Mathf.Abs(FreezeFramesOnHitDuration)); } // we apply the damage to the thing we've collided with _colliderHealth.Damage(DamageCaused, gameObject, InvincibilityDuration, InvincibilityDuration); if (_colliderHealth.CurrentHealth <= 0) { OnKill?.Invoke(); } SelfDamage(DamageTakenEveryTime + DamageTakenDamageable); }
/// <summary> /// Describes what happens when colliding with a non damageable object /// </summary> protected virtual void OnCollideWithNonDamageable() { OnHitNonDamageable?.Invoke(); if (DamageTakenEveryTime + DamageTakenNonDamageable > 0) { HitNonDamageableFeedback?.PlayFeedbacks(this.transform.position); SelfDamage(DamageTakenEveryTime + DamageTakenNonDamageable); } }
protected virtual void Colliding(Collider2D collider) { if (!this.isActiveAndEnabled) { return; } // if the object we're colliding with is part of our ignore list, we do nothing and exit if (_ignoredGameObjects.Contains(collider.gameObject)) { return; } // if what we're colliding with isn't part of the target layers, we do nothing and exit if (!MMLayers.LayerInLayerMask(collider.gameObject.layer, TargetLayerMask)) { return; } _collidingCollider = collider; _colliderHealth = collider.gameObject.MMGetComponentNoAlloc <Health>(); OnHit?.Invoke(); // if what we're colliding with is damageable if (_colliderHealth != null) { if (_colliderHealth.CurrentHealth > 0) { OnCollideWithDamageable(_colliderHealth); } } // if what we're colliding with can't be damaged else { OnCollideWithNonDamageable(); } }
/// <summary> /// Called when the object takes damage /// </summary> /// <param name="damage">The amount of health points that will get lost.</param> /// <param name="instigator">The object that caused the damage.</param> /// <param name="flickerDuration">The time (in seconds) the object should flicker after taking the damage.</param> /// <param name="invincibilityDuration">The duration of the short invincibility following the hit.</param> public virtual void Damage(int damage, GameObject instigator, float flickerDuration, float invincibilityDuration) { if (damage <= 0) { OnHitZero?.Invoke(); return; } // if the object is invulnerable, we do nothing and exit if (TemporaryInvulnerable || Invulnerable) { OnHitZero?.Invoke(); return; } // if we're already below zero, we do nothing and exit if ((CurrentHealth <= 0) && (InitialHealth != 0)) { return; } // we decrease the character's health by the damage float previousHealth = CurrentHealth; CurrentHealth -= damage; OnHit?.Invoke(); if (CurrentHealth < 0) { CurrentHealth = 0; } // we prevent the character from colliding with Projectiles, Player and Enemies if (invincibilityDuration > 0) { DamageDisabled(); StartCoroutine(DamageEnabled(invincibilityDuration)); } // we trigger a damage taken event MMDamageTakenEvent.Trigger(_character, instigator, CurrentHealth, damage, previousHealth); if (_animator != null) { _animator.SetTrigger("Damage"); } // we play the damage feedback DamageFeedbacks?.PlayFeedbacks(); if (FlickerSpriteOnHit) { // We make the character's sprite flicker if (_renderer != null) { StartCoroutine(MMImage.Flicker(_renderer, _initialColor, FlickerColor, 0.05f, flickerDuration)); } } // we update the health bar UpdateHealthBar(true); // if health has reached zero if (CurrentHealth <= 0) { // we set its health to zero (useful for the healthbar) CurrentHealth = 0; if (_character != null) { if (_character.CharacterType == Character.CharacterTypes.Player) { LevelManager.Instance.KillPlayer(_character); return; } } Kill(); } }