PlayerDecisionController .cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. using System.Collections.Generic;
  2. using Unity.VisualScripting;
  3. using UnityEngine;
  4. public class PlayerDecisionController : MonoBehaviour
  5. {
  6. [Header("References")]
  7. public LayerMask enemyLayerMask = 1 << 10; // Enemies are on layer 10
  8. public LayerMask playerLayerMask = 1 << 9; // Players are on layer 9
  9. [Header("Settings")]
  10. public float enemySnapDistance = 1f;
  11. private List<Character> playerCharacters = new List<Character>();
  12. private Character selectedCharacter;
  13. private TargetingLine targetingLine;
  14. private Camera mainCamera;
  15. private bool isDragging = false;
  16. private Vector3 dragStartPosition;
  17. private bool isEnabled = true;
  18. private List<TargetingLine> activeActionLines = new List<TargetingLine>();
  19. void Awake()
  20. {
  21. mainCamera = Camera.main;
  22. targetingLine = GetComponent<TargetingLine>();
  23. if (targetingLine == null)
  24. {
  25. targetingLine = gameObject.AddComponent<TargetingLine>();
  26. }
  27. }
  28. void Start()
  29. {
  30. InitializePlayerCharacters();
  31. }
  32. void Update()
  33. {
  34. HandleInput();
  35. }
  36. private void InitializePlayerCharacters()
  37. {
  38. // Get player characters from GameManager if available
  39. if (GameManager.Instance != null)
  40. {
  41. playerCharacters.Clear();
  42. foreach (GameObject playerGO in GameManager.Instance.playerCharacters)
  43. {
  44. Character character = playerGO.GetComponent<Character>();
  45. if (character != null)
  46. {
  47. playerCharacters.Add(character);
  48. }
  49. }
  50. }
  51. else
  52. {
  53. // Fallback: find all characters (for testing without GameManager)
  54. Character[] characters = FindObjectsByType<Character>(FindObjectsSortMode.None);
  55. playerCharacters.AddRange(characters);
  56. }
  57. foreach (Character character in playerCharacters)
  58. {
  59. character.actionData.Reset();
  60. character.SetVisualState(ActionDecisionState.NoAction);
  61. }
  62. }
  63. private void HandleInput()
  64. {
  65. if (!isEnabled) return;
  66. if (Input.GetMouseButtonDown(0)) // Left click
  67. {
  68. HandleLeftClickDown();
  69. }
  70. else if (Input.GetMouseButton(0) && isDragging) // Left drag
  71. {
  72. HandleLeftDrag();
  73. }
  74. else if (Input.GetMouseButtonUp(0)) // Left release
  75. {
  76. HandleLeftClickUp();
  77. }
  78. else if (Input.GetMouseButtonDown(1)) // Right click
  79. {
  80. HandleRightClick();
  81. }
  82. }
  83. private void HandleLeftClickDown()
  84. {
  85. Vector3 mouseWorldPosition = GetMouseWorldPosition();
  86. Character clickedCharacter = GetPlayerCharacterAtPosition(mouseWorldPosition);
  87. if (clickedCharacter != null)
  88. {
  89. selectedCharacter = clickedCharacter;
  90. isDragging = true;
  91. dragStartPosition = clickedCharacter.transform.position;
  92. // Clear any existing action lines before starting new targeting
  93. ClearActionLineForCharacter(clickedCharacter);
  94. targetingLine.StartTargeting(dragStartPosition);
  95. // CinemachineCameraController.Instance.FocusOnCharacter(clickedCharacter.transform);
  96. }
  97. }
  98. private void HandleLeftDrag()
  99. {
  100. if (selectedCharacter == null) return;
  101. Vector3 mouseWorldPos = GetMouseWorldPosition();
  102. GameObject enemyAtMouse = GetEnemyAtPosition(mouseWorldPos);
  103. if (enemyAtMouse != null)
  104. {
  105. // Snap to enemy
  106. Vector3 enemyPos = enemyAtMouse.transform.position;
  107. targetingLine.UpdateTargeting(dragStartPosition, enemyPos, true);
  108. }
  109. else
  110. {
  111. // Follow mouse
  112. targetingLine.UpdateTargeting(dragStartPosition, mouseWorldPos, false);
  113. }
  114. }
  115. private void HandleLeftClickUp()
  116. {
  117. if (!isDragging || selectedCharacter == null) return;
  118. Vector3 mouseWorldPos = GetMouseWorldPosition();
  119. GameObject enemyAtMouse = GetEnemyAtPosition(mouseWorldPos);
  120. if (enemyAtMouse != null)
  121. {
  122. // Set attack target
  123. selectedCharacter.actionData.SetAttackTarget(enemyAtMouse);
  124. // Also update enhanced action data if it exists
  125. UpdateEnhancedActionData(selectedCharacter, BattleActionType.Attack, enemyAtMouse, mouseWorldPos);
  126. }
  127. else
  128. {
  129. // Set move target
  130. selectedCharacter.actionData.SetMoveTarget(mouseWorldPos);
  131. // Also update enhanced action data if it exists
  132. UpdateEnhancedActionData(selectedCharacter, BattleActionType.Move, null, mouseWorldPos);
  133. }
  134. selectedCharacter.SetVisualState(selectedCharacter.actionData.state);
  135. // Cleanup
  136. targetingLine.StopTargeting();
  137. selectedCharacter = null;
  138. isDragging = false;
  139. }
  140. private void HandleRightClick()
  141. {
  142. if (isDragging && selectedCharacter != null)
  143. {
  144. // Cancel current action
  145. selectedCharacter.actionData.Reset();
  146. selectedCharacter.SetVisualState(ActionDecisionState.NoAction);
  147. targetingLine.StopTargeting();
  148. selectedCharacter = null;
  149. isDragging = false;
  150. }
  151. else
  152. {
  153. // Right click on character to reset their action
  154. Vector3 mouseWorldPos = GetMouseWorldPosition();
  155. Character clickedCharacter = GetPlayerCharacterAtPosition(mouseWorldPos);
  156. if (clickedCharacter != null)
  157. {
  158. clickedCharacter.actionData.Reset();
  159. clickedCharacter.SetVisualState(ActionDecisionState.NoAction);
  160. }
  161. }
  162. }
  163. private Vector3 GetMouseWorldPosition()
  164. {
  165. Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
  166. RaycastHit hit;
  167. // Raycast against a ground plane or existing colliders
  168. if (Physics.Raycast(ray, out hit, 200f))
  169. {
  170. return hit.point;
  171. }
  172. // Fallback: project onto a horizontal plane at y=0
  173. Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
  174. if (groundPlane.Raycast(ray, out float distance))
  175. {
  176. return ray.GetPoint(distance);
  177. }
  178. return Vector3.zero;
  179. }
  180. private Character GetPlayerCharacterAtPosition(Vector3 worldPosition)
  181. {
  182. Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
  183. RaycastHit hit;
  184. if (Physics.Raycast(ray, out hit, 200f, playerLayerMask))
  185. {
  186. return hit.collider.GetComponent<Character>();
  187. }
  188. // Try raycast without layer mask to see what we're hitting
  189. if (Physics.Raycast(ray, out hit, 200f))
  190. {
  191. }
  192. else
  193. {
  194. }
  195. return null;
  196. }
  197. private GameObject GetEnemyAtPosition(Vector3 worldPosition)
  198. {
  199. Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
  200. RaycastHit hit;
  201. if (Physics.Raycast(ray, out hit, 200f, enemyLayerMask))
  202. {
  203. return hit.collider.gameObject;
  204. }
  205. return null;
  206. }
  207. public bool AllCharactersHaveActions()
  208. {
  209. foreach (var character in playerCharacters)
  210. {
  211. // Characters need actions if they have no action set
  212. if (character.actionData.state == ActionDecisionState.NoAction)
  213. return false;
  214. }
  215. return true;
  216. }
  217. public void ResetAllCharacterActions()
  218. {
  219. foreach (var character in playerCharacters)
  220. {
  221. character.actionData.Reset();
  222. character.SetVisualState(ActionDecisionState.NoAction);
  223. }
  224. }
  225. public void UpdateVisualStates()
  226. {
  227. foreach (var character in playerCharacters)
  228. {
  229. // Update visual states based on current action status
  230. if (character.actionData.state == ActionDecisionState.NoAction)
  231. {
  232. character.SetVisualState(ActionDecisionState.NoAction); // Pink
  233. }
  234. else if (character.HasActionSelected())
  235. {
  236. character.SetVisualState(ActionDecisionState.ActionSelected); // Green
  237. }
  238. }
  239. }
  240. public void RefreshPlayerCharacters()
  241. {
  242. InitializePlayerCharacters();
  243. }
  244. public void SetEnabled(bool enabled)
  245. {
  246. isEnabled = enabled;
  247. if (!enabled)
  248. {
  249. if (isDragging)
  250. {
  251. // Cancel any current dragging operation
  252. targetingLine.StopTargeting();
  253. selectedCharacter = null;
  254. isDragging = false;
  255. }
  256. // Don't automatically hide action lines when disabling - let caller decide
  257. }
  258. }
  259. public void ShowActiveActionLines()
  260. {
  261. HideActiveActionLines(); // Clear any existing lines first
  262. foreach (var character in playerCharacters)
  263. {
  264. if (character.HasActionSelected() && !character.IsActionComplete())
  265. {
  266. GameObject lineObject = new GameObject($"ActionLine_{character.name}");
  267. TargetingLine line = lineObject.AddComponent<TargetingLine>();
  268. activeActionLines.Add(line);
  269. Vector3 startPos = character.transform.position + Vector3.up * 0.5f;
  270. if (character.actionData.targetEnemy != null)
  271. {
  272. Vector3 endPos = character.actionData.targetEnemy.transform.position + Vector3.up * 0.5f;
  273. line.StartTargeting(startPos);
  274. line.UpdateTargeting(startPos, endPos, true); // true for enemy target (red line)
  275. }
  276. else if (character.actionData.targetPosition != Vector3.zero)
  277. {
  278. line.StartTargeting(startPos);
  279. line.UpdateTargeting(startPos, character.actionData.targetPosition, false); // false for movement (blue line)
  280. }
  281. }
  282. }
  283. }
  284. public void HideActiveActionLines()
  285. {
  286. foreach (var line in activeActionLines)
  287. {
  288. if (line != null)
  289. {
  290. line.StopTargeting();
  291. Destroy(line.gameObject);
  292. }
  293. }
  294. activeActionLines.Clear();
  295. }
  296. public void ClearActionLineForCharacter(Character character)
  297. {
  298. for (int i = activeActionLines.Count - 1; i >= 0; i--)
  299. {
  300. var line = activeActionLines[i];
  301. if (line != null && line.gameObject.name == $"ActionLine_{character.name}")
  302. {
  303. line.StopTargeting();
  304. Destroy(line.gameObject);
  305. activeActionLines.RemoveAt(i);
  306. break;
  307. }
  308. }
  309. }
  310. private void UpdateEnhancedActionData(Character character, BattleActionType actionType, GameObject targetEnemy, Vector3 targetPosition)
  311. {
  312. // Check if character has enhanced action data
  313. var enhancedData = character.GetEnhancedActionData<EnhancedCharacterActionData>();
  314. if (enhancedData != null)
  315. {
  316. Debug.Log($"🔄 Updating enhanced action data for {character.CharacterName}: {actionType}");
  317. // Update the enhanced action data to match the targeting result
  318. enhancedData.actionType = actionType;
  319. enhancedData.state = ActionDecisionState.ActionSelected;
  320. if (actionType == BattleActionType.Attack && targetEnemy != null)
  321. {
  322. enhancedData.targetEnemy = targetEnemy;
  323. enhancedData.targetPosition = Vector3.zero;
  324. Debug.Log($"🗡️ Enhanced data updated for attack on {targetEnemy.name}");
  325. }
  326. else if (actionType == BattleActionType.Move)
  327. {
  328. enhancedData.targetPosition = targetPosition;
  329. enhancedData.targetEnemy = null;
  330. Debug.Log($"👟 Enhanced data updated for move to {targetPosition}");
  331. }
  332. }
  333. else
  334. {
  335. Debug.Log($"ℹ️ No enhanced action data found for {character.CharacterName}");
  336. }
  337. }
  338. /// <summary>
  339. /// Manually start targeting mode for a specific character and action type
  340. /// Called by the action wheel system
  341. /// </summary>
  342. public void StartTargetingForCharacter(Character character, BattleActionType actionType)
  343. {
  344. Debug.Log($"🎯 StartTargetingForCharacter called: {character.CharacterName} -> {actionType}");
  345. selectedCharacter = character;
  346. isDragging = true;
  347. dragStartPosition = character.transform.position;
  348. // Store the action type for later reference
  349. var enhancedData = character.GetEnhancedActionData<EnhancedCharacterActionData>();
  350. if (enhancedData == null)
  351. {
  352. enhancedData = new EnhancedCharacterActionData();
  353. character.SetEnhancedActionData(enhancedData);
  354. }
  355. enhancedData.actionType = actionType;
  356. // Clear any existing action lines before starting new targeting
  357. ClearActionLineForCharacter(character);
  358. // Start the targeting line
  359. targetingLine.StartTargeting(dragStartPosition);
  360. Debug.Log($"✅ Targeting mode activated for {character.CharacterName}");
  361. }
  362. /// <summary>
  363. /// Cancel current targeting operation
  364. /// </summary>
  365. public void CancelTargeting()
  366. {
  367. if (isDragging && selectedCharacter != null)
  368. {
  369. selectedCharacter.actionData.Reset();
  370. selectedCharacter.SetVisualState(ActionDecisionState.NoAction);
  371. targetingLine.StopTargeting();
  372. selectedCharacter = null;
  373. isDragging = false;
  374. Debug.Log("❌ Targeting cancelled");
  375. }
  376. }
  377. }