using UnityEngine; using UnityEngine.Events; using TMPro; using System; using UnityUtils; using System.Collections; public class HealthComponent : MonoBehaviour, ISquezeDamageReceiver { public bool bloodRegen = false; public float regen = 1000; [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 OnHealthChangeAtPos; public UnityEvent OnHealthZero; public UnityEvent OnHealthChange; [Header("Squeze Damage")] [SerializeField] float minThreshold = 1f; [SerializeField] float squezeDamageScalor = 1f; bool alreadyReachedZero = false; void Awake() { currentHealth = maxHealth; OnHealthChange.AddListener((prev, nex) => showRedTint = nex(); while (true) { if (!showRedTint) { 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); sr.color = Color.red; yield return new WaitForSecondsRealtime(0.1f); sr.color = Color.white; yield return new WaitForSecondsRealtime(0.1f); sr.color = Color.red; yield return new WaitForSecondsRealtime(0.1f); sr.color = Color.white; yield return new WaitForSecondsRealtime(0.1f); sr.color = Color.red; yield return new WaitForSecondsRealtime(0.1f); sr.color = Color.white; yield return new WaitForSecondsRealtime(0.1f); sr.color = Color.red; yield return new WaitForSecondsRealtime(0.1f); sr.color = Color.white; yield return new WaitForSecondsRealtime(0.1f); sr.color = Color.red; yield return new WaitForSecondsRealtime(0.1f); sr.color = Color.white; yield return new WaitForSecondsRealtime(0.1f); showRedTint = false; } } void Update() { // blod regen if (bloodRegen) { PlayerInput playerInput = GetComponent(); float bloodAccumalted = playerInput.PlayerNum == 0 ? BloodComputeShader.Instance.mop1Clean : BloodComputeShader.Instance.mop2Clean; TakeDamage(-bloodAccumalted / regen); } 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) { if (damage == 0f) return; currentHealth -= damage; currentHealth = Mathf.Clamp(currentHealth, 0f, getMaxHealth()); 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); } }