using UnityEngine; /// /// Handles bite attacks, damage, and health for the T-Rex. /// Attach to any character that can attack or take damage. /// public class CombatSystem : MonoBehaviour { [Header("Health")] [Tooltip("Maximum health points")] public float maxHealth = 100f; [Tooltip("Current health")] public float currentHealth; [Tooltip("Time before regenerating health (seconds)")] public float regenDelay = 3f; [Tooltip("Health regenerated per second")] public float regenRate = 5f; [Header("Attack")] [Tooltip("Damage dealt per bite")] public float biteDamage = 25f; [Tooltip("Range of the bite attack")] public float biteRange = 3f; [Tooltip("Arc angle of the bite (degrees)")] public float biteAngle = 60f; [Tooltip("Cooldown between bites (seconds)")] public float biteCooldown = 0.5f; [Tooltip("Push force applied to victims")] public float knockbackForce = 10f; [Header("References")] [Tooltip("Animator for attack animations")] public Animator animator; [Tooltip("Sound effect for biting")] public AudioClip biteSound; [Tooltip("Audio source for playing sounds")] public AudioSource audioSource; [Tooltip("Visual effect for bite impact")] public GameObject biteEffect; [Tooltip("Health bar UI to update")] public RectTransform healthBarFill; // Private private float nextBiteTime; private float lastDamageTime; private HealthBarController healthBarUI; public float HealthPercent => currentHealth / maxHealth; void Start() { currentHealth = maxHealth; lastDamageTime = Time.time; // Setup audio source if needed if (audioSource == null) { audioSource = GetComponent(); if (audioSource == null) { audioSource = gameObject.AddComponent(); } } // Find health bar in UI if (healthBarFill == null) { healthBarUI = FindAnyObjectByType(); } Debug.Log($"⚔️ {gameObject.name} combat initialized - Max HP: {maxHealth}, Bite: {biteDamage}"); } void Update() { HandleRegeneration(); HandleAttack(); UpdateHealthBar(); } void HandleRegeneration() { float timeSinceDamage = Time.time - lastDamageTime; if (timeSinceDamage >= regenDelay && currentHealth < maxHealth) { currentHealth = Mathf.Min(currentHealth + regenRate * Time.deltaTime, maxHealth); } else { } } void HandleAttack() { // Left mouse button or Space for bite attack if (Input.GetButtonDown("Fire1") && Time.time >= nextBiteTime) { PerformBite(); nextBiteTime = Time.time + biteCooldown; } } /// /// Perform a bite attack. Called by player input or AI. /// public void PerformBite() { // Play animation if (animator != null) { animator.SetTrigger("Attack"); } // Play sound if (biteSound != null) { audioSource.PlayOneShot(biteSound); } // Spawn visual effect if (biteEffect != null) { Vector3 effectPos = transform.position + transform.forward * biteRange * 0.5f; Instantiate(biteEffect, effectPos, Quaternion.identity); } // Find targets in bite range Collider[] hits = Physics.OverlapSphere( transform.position + transform.forward * biteRange * 0.5f, biteRange * 0.5f ); foreach (Collider hit in hits) { // Check if target is in bite arc Vector3 directionToTarget = (hit.transform.position - transform.position).normalized; float angle = Vector3.Angle(transform.forward, directionToTarget); if (angle <= biteAngle * 0.5f) { CombatSystem targetCombat = hit.GetComponent(); if (targetCombat != null && targetCombat != this) { targetCombat.TakeDamage(biteDamage, transform.forward); } // Apply knockback to rigidbodies Rigidbody rb = hit.GetComponent(); if (rb != null) { rb.AddForce(transform.forward * knockbackForce, ForceMode.Impulse); } } } Debug.Log($"🦷 Bite attack! Range: {biteRange}, Damage: {biteDamage}"); } /// /// Take damage from another source. /// public void TakeDamage(float damage, Vector3 knockbackDirection = default) { currentHealth -= damage; lastDamageTime = Time.time; // Flash red or play hurt animation if (animator != null) { animator.SetTrigger("Hurt"); } Debug.Log($"💥 {gameObject.name} took {damage} damage! HP: {currentHealth}/{maxHealth}"); if (currentHealth <= 0) { Die(); } } void Die() { Debug.Log($"💀 {gameObject.name} has been defeated!"); // Play death animation if (animator != null) { animator.SetTrigger("Die"); } // Disable combat and movement enabled = false; // Notify AI system if this is an enemy AIController ai = GetComponent(); if (ai != null) { ai.Die(); } // Disable the controller if this is the player TrexController controller = GetComponent(); if (controller != null) { controller.enabled = false; } // Spawn death effect // TODO: Add particle system for death // Destroy after delay Destroy(gameObject, 3f); } void UpdateHealthBar() { if (healthBarFill != null) { healthBarFill.sizeDelta = new Vector2(healthBarFill.sizeDelta.x * HealthPercent, healthBarFill.sizeDelta.y); } if (healthBarUI != null) { healthBarUI.UpdateHealthBar(HealthPercent); } } void OnDrawGizmosSelected() { // Visualize bite range Gizmos.color = Color.red; Gizmos.DrawWireSphere( transform.position + transform.forward * biteRange * 0.5f, biteRange * 0.5f ); } }