123 lines
3.3 KiB
C#
123 lines
3.3 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using TMPro;
|
|
using System;
|
|
using UnityUtils;
|
|
using System.Collections;
|
|
|
|
public class HealthComponent : MonoBehaviour, ISquezeDamageReceiver
|
|
{
|
|
[SerializeField] private bool onlyCallZeroHealthOnce = true;
|
|
[SerializeField] float maxHealth = 100;
|
|
|
|
[SerializeField] float damageTickDelay = 0.25f;
|
|
private float currentDamageTick = 0f;
|
|
private float accumulatedDamageInTick = 0f;
|
|
|
|
public float currentHealth { get; private set; }
|
|
|
|
public static event Action<Vector3, float> OnHealthChangeAtPos;
|
|
|
|
public UnityEvent OnHealthZero;
|
|
public UnityEvent<float, float> OnHealthChange;
|
|
|
|
[Header("Squeze Damage")]
|
|
[SerializeField]
|
|
float minThreshold = 1f;
|
|
|
|
[SerializeField]
|
|
float squezeDamageScalor = 1f;
|
|
|
|
bool alreadyReachedZero = false;
|
|
|
|
void Awake()
|
|
{
|
|
currentHealth = maxHealth;
|
|
OnHealthChange.AddListener((_, _) => showRedTint = 1);
|
|
StartCoroutine(RedTintLoop());
|
|
}
|
|
|
|
float showRedTint = 0;
|
|
private IEnumerator RedTintLoop()
|
|
{
|
|
SpriteRenderer sr = GetComponentInChildren<SpriteRenderer>();
|
|
while (true)
|
|
{
|
|
if (showRedTint < 0.1f)
|
|
{
|
|
yield return new WaitForSecondsRealtime(0.1f);
|
|
continue;
|
|
}
|
|
|
|
sr.color = Color.red;
|
|
yield return new WaitForSecondsRealtime(0.1f);
|
|
sr.color = Color.white;
|
|
yield return new WaitForSecondsRealtime(0.1f);
|
|
}
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (currentDamageTick < Time.time)
|
|
{
|
|
if (accumulatedDamageInTick < 1f) return;
|
|
|
|
OnHealthChangeAtPos?.Invoke(transform.position.Add(y: 2f), accumulatedDamageInTick);
|
|
currentDamageTick = Time.time + damageTickDelay;
|
|
accumulatedDamageInTick = 0f;
|
|
}
|
|
}
|
|
|
|
public float getMaxHealth() {
|
|
return maxHealth;
|
|
}
|
|
|
|
public void setMaxHealth(float amount, bool heal = false) {
|
|
maxHealth = amount;
|
|
|
|
if (heal)
|
|
currentHealth = amount;
|
|
}
|
|
|
|
public void TakeDamage(float damage)
|
|
{
|
|
currentHealth -= damage;
|
|
OnHealthChange?.Invoke(currentHealth + damage, currentHealth);
|
|
|
|
accumulatedDamageInTick += damage;
|
|
|
|
if (currentHealth <= 0) {
|
|
if (alreadyReachedZero && onlyCallZeroHealthOnce) return;
|
|
|
|
alreadyReachedZero = true;
|
|
// Make sure to flush accumulated when dying
|
|
if (accumulatedDamageInTick > 1f)
|
|
OnHealthChangeAtPos?.Invoke(transform.position.Add(y: 2f), accumulatedDamageInTick);
|
|
|
|
OnHealthZero?.Invoke();
|
|
|
|
if (BloodComputeShader.Instance != null)
|
|
{
|
|
int blood = (int)(maxHealth * 100.0f * BloodComputeShader.Instance.scoreMult);
|
|
float power = 10.0f + (maxHealth / 25.0f);
|
|
|
|
BloodComputeShader.Instance.createBlood(transform.position, blood / 2, power);
|
|
BloodComputeShader.Instance.createBlood(transform.position, blood / 2, power);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void TakeSquezeDamage(float squezeDamage)
|
|
{
|
|
if (squezeDamage < minThreshold) return;
|
|
|
|
TakeDamage((int) Mathf.Round(squezeDamage * squezeDamageScalor));
|
|
}
|
|
|
|
public void EnemyKill()
|
|
{
|
|
|
|
Destroy(gameObject);
|
|
}
|
|
}
|