FirstPersonWeapon.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. public class FirstPersonWeapon : MonoBehaviour
  5. {
  6. private Animator animator;
  7. public GameObject weaponVisual;
  8. public float animationDuration = 1.2f;
  9. public int damageAmount = 10;
  10. public GameObject damagePopupPrefab;
  11. public FirstPersonWeapon assignedWeapon;
  12. [Header("Attack Range Settings")]
  13. public float attackRange = 3f; // Maximum distance to hit
  14. public float attackAngle = 60f; // Cone angle in front of player (60 degrees = 30 each side)
  15. private void Start()
  16. {
  17. animator = GetComponent<Animator>();
  18. if (weaponVisual != null)
  19. weaponVisual.SetActive(false);
  20. }
  21. public void TriggerAttack()
  22. {
  23. if (animator == null || weaponVisual == null) return;
  24. StopAllCoroutines();
  25. StartCoroutine(AttackRoutine());
  26. }
  27. IEnumerator AttackRoutine()
  28. {
  29. weaponVisual.SetActive(true);
  30. animator.SetTrigger("Attack");
  31. yield return new WaitForSeconds(0.2f);
  32. TryHitMonster();
  33. yield return new WaitForSeconds(animationDuration - 0.2f);
  34. weaponVisual.SetActive(false);
  35. }
  36. void TryHitMonster()
  37. {
  38. GameObject player = GameObject.FindWithTag("Player");
  39. if (player == null)
  40. {
  41. Debug.LogWarning("[Combat] Player not found!");
  42. return;
  43. }
  44. Vector3 playerPos = player.transform.position;
  45. Vector3 playerForward = player.transform.forward;
  46. // Find all monsters that are in range and in front of player
  47. List<MonsterController> validTargets = new List<MonsterController>();
  48. var monsterGroups = FindObjectsByType<MonsterFormationGroup>(FindObjectsSortMode.None);
  49. foreach (var group in monsterGroups)
  50. {
  51. // Check both front and back row
  52. var allMonsters = new List<MonsterController>();
  53. allMonsters.AddRange(group.frontRow);
  54. allMonsters.AddRange(group.backRow);
  55. foreach (var monster in allMonsters)
  56. {
  57. if (monster == null) continue;
  58. Vector3 monsterPos = monster.transform.position;
  59. float distance = Vector3.Distance(playerPos, monsterPos);
  60. // Check if monster is within attack range
  61. if (distance <= attackRange)
  62. {
  63. // Check if monster is in front of player
  64. Vector3 directionToMonster = (monsterPos - playerPos).normalized;
  65. float angle = Vector3.Angle(playerForward, directionToMonster);
  66. if (angle <= attackAngle / 2f)
  67. {
  68. validTargets.Add(monster);
  69. Debug.Log($"[Combat] Valid target found: {monster.name} at {distance:F2}m, angle {angle:F1}°");
  70. }
  71. else
  72. {
  73. Debug.Log($"[Combat] {monster.name} is out of angle: {angle:F1}° (max {attackAngle / 2f}°)");
  74. }
  75. }
  76. else
  77. {
  78. Debug.Log($"[Combat] {monster.name} is too far: {distance:F2}m (max {attackRange}m)");
  79. }
  80. }
  81. }
  82. // Attack the closest valid target
  83. if (validTargets.Count > 0)
  84. {
  85. // Sort by distance and hit the closest one
  86. validTargets.Sort((a, b) =>
  87. {
  88. float distA = Vector3.Distance(playerPos, a.transform.position);
  89. float distB = Vector3.Distance(playerPos, b.transform.position);
  90. return distA.CompareTo(distB);
  91. });
  92. MonsterController target = validTargets[0];
  93. target.TakeDamage(damageAmount);
  94. Debug.Log($"[Combat] Hit {target.name}! Damage: {damageAmount}");
  95. ShowDamagePopup(target.transform.position + Vector3.up * 2f, damageAmount);
  96. }
  97. else
  98. {
  99. Debug.Log("[Combat] No valid targets in range and in front of player!");
  100. }
  101. }
  102. void ShowDamagePopup(Vector3 position, int amount)
  103. {
  104. if (damagePopupPrefab == null) return;
  105. GameObject popup = Instantiate(damagePopupPrefab, position, Quaternion.identity);
  106. var text = popup.GetComponentInChildren<TMPro.TextMeshPro>();
  107. if (text != null)
  108. text.text = "-" + amount.ToString();
  109. // Facultatif : orienter vers la caméra
  110. popup.transform.LookAt(Camera.main.transform);
  111. popup.transform.Rotate(0, 180, 0); // pour qu'il soit bien lisible
  112. }
  113. // Visualize attack range in editor
  114. private void OnDrawGizmosSelected()
  115. {
  116. GameObject player = GameObject.FindWithTag("Player");
  117. if (player == null) return;
  118. Vector3 playerPos = player.transform.position;
  119. Vector3 playerForward = player.transform.forward;
  120. // Draw attack range sphere
  121. Gizmos.color = new Color(1f, 0f, 0f, 0.2f);
  122. Gizmos.DrawWireSphere(playerPos, attackRange);
  123. // Draw attack cone
  124. Gizmos.color = Color.red;
  125. Vector3 leftBoundary = Quaternion.Euler(0, -attackAngle / 2f, 0) * playerForward * attackRange;
  126. Vector3 rightBoundary = Quaternion.Euler(0, attackAngle / 2f, 0) * playerForward * attackRange;
  127. Gizmos.DrawLine(playerPos, playerPos + leftBoundary);
  128. Gizmos.DrawLine(playerPos, playerPos + rightBoundary);
  129. Gizmos.DrawLine(playerPos, playerPos + playerForward * attackRange);
  130. // Draw arc
  131. Vector3 previousPoint = playerPos + leftBoundary;
  132. for (int i = 1; i <= 20; i++)
  133. {
  134. float angle = Mathf.Lerp(-attackAngle / 2f, attackAngle / 2f, i / 20f);
  135. Vector3 direction = Quaternion.Euler(0, angle, 0) * playerForward;
  136. Vector3 point = playerPos + direction * attackRange;
  137. Gizmos.DrawLine(previousPoint, point);
  138. previousPoint = point;
  139. }
  140. }
  141. }