| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.AI;
- public class BattleSetup : MonoBehaviour
- {
- List<GameObject> unplacedEnemyCharacters = new List<GameObject>();
- List<GameObject> placedPlayerCharacters = new List<GameObject>();
- List<GameObject> placedEnemyCharacters = new List<GameObject>();
- private List<GameObject> playerCharacters = new List<GameObject>();
- private List<GameObject> enemyCharacters = new List<GameObject>();
- private List<CharacterSelection> playerSelections = new List<CharacterSelection>();
- private List<CharacterSelection> enemySelections = new List<CharacterSelection>();
- [Tooltip("Select the layer(s) that represent the ground for raycasting.")]
- public LayerMask groundLayerMask;
- public GameObject playerPrefab; // Assign in the inspector or through GameManager
- public GameObject enemyPrefab; // Assign in the inspector or through GameManager
- public GameObject SwordPrefab; // Assign in the inspector or through GameManager
- public GameObject BowPrefab; // Assign in the inspector or through GameManager
- GameObject playerSpawnArea;
- GameObject enemySpawnArea;
- Bounds playerSpawnBounds;
- private Camera mainCamera;
- private GameObject currentPlacingCharacterInstance;
- private int nextPlayerCharacterPrefabIndex = 0;
- private bool isPlacingPlayerCharacters = false;
- void Awake()
- {
- mainCamera = Camera.main;
- if (mainCamera == null)
- {
- Debug.LogError("Main camera not found. Please ensure there is a camera tagged as 'MainCamera' in the scene.");
- enabled = false;
- return;
- }
- playerCharacters.Clear();
- enemyCharacters.Clear();
- // Store the selections for use during placement
- playerSelections = new List<CharacterSelection>(BattleSetupData.playerSelections);
- enemySelections = new List<CharacterSelection>(BattleSetupData.enemySelections);
- // Initialize the lists with characters from the game manager or other sources
- playerSpawnArea = GameObject.Find("PlayerSpawnArea");
- enemySpawnArea = GameObject.Find("EnemySpawnArea");
- if (playerSpawnArea == null)
- {
- Debug.LogError("PlayerSpawnArea GameObject not found in scene. Please ensure there is a GameObject named 'PlayerSpawnArea' in the scene.");
- enabled = false;
- return;
- }
- Collider playerSpawnAreaCollider = playerSpawnArea.GetComponent<Collider>();
- if (playerSpawnAreaCollider == null)
- {
- Debug.LogError("PlayerSpawnArea does not have a collider component.");
- enabled = false;
- return;
- }
- playerSpawnBounds = playerSpawnAreaCollider.bounds;
- if (enemySpawnArea == null)
- {
- // Enemy placement might still work if unplacedEnemyCharacters is empty
- Debug.LogWarning("EnemySpawnArea GameObject not found in the scene. Enemy placement might be affected.");
- }
- // Call the setup methods to place characters
- PlaceEnemyCharacters();
- InitiatePlayerCharacterPlacement();
- }
- void EquipWeapon(Character character, string weaponType)
- {
- Weapon weapon = null;
- if (weaponType == "Sword")
- {
- var weaponObj = Instantiate(SwordPrefab, character.transform);
- weapon = weaponObj.GetComponent<Weapon>();
- }
- else if (weaponType == "Bow")
- {
- var weaponObj = Instantiate(BowPrefab, character.transform);
- weapon = weaponObj.GetComponent<Weapon>();
- }
- else
- {
- Debug.LogWarning($"Unknown weapon type: {weaponType}. No weapon equipped.");
- }
- if (weapon != null)
- {
- Transform attachPoint = character.transform.Find("WeaponAttachPoint");
- if (attachPoint != null)
- {
- weapon.transform.SetParent(attachPoint, false);
- weapon.transform.localPosition = Vector3.zero;
- weapon.transform.localRotation = Quaternion.identity;
- }
- else
- {
- weapon.transform.SetParent(character.transform, false);
- weapon.transform.localPosition = new Vector3(0.5f, 0, 0);
- }
- character.Weapon = weapon;
- weapon.SetWielder(character);
- }
- }
- void Update()
- {
- if (!isPlacingPlayerCharacters || currentPlacingCharacterInstance == null)
- {
- return;
- }
- HandleCharacterPlacement();
- }
- private void InitiatePlayerCharacterPlacement()
- {
- if (playerSelections.Count == 0)
- {
- return;
- }
- isPlacingPlayerCharacters = true;
- nextPlayerCharacterPrefabIndex = 0;
- SpawnNextPlayerCharacterForPlacement();
- }
- private void SpawnNextPlayerCharacterForPlacement()
- {
- if (currentPlacingCharacterInstance != null)
- {
- // This case should ideally not happen if logic flows correctly,
- // but as a safeguard if a previous instance wasn't cleaned up.
- Destroy(currentPlacingCharacterInstance);
- currentPlacingCharacterInstance = null;
- }
- if (nextPlayerCharacterPrefabIndex < playerSelections.Count)
- {
- var selection = playerSelections[nextPlayerCharacterPrefabIndex];
- currentPlacingCharacterInstance = Instantiate(playerPrefab);
- currentPlacingCharacterInstance.name = selection.characterName;
- var character = currentPlacingCharacterInstance.GetComponent<Character>();
- if (character != null)
- {
- EquipWeapon(character, selection.weaponType);
- character.CharacterName = selection.characterName + " " + (nextPlayerCharacterPrefabIndex + 1);
- }
- currentPlacingCharacterInstance.GetComponent<NavMeshAgent>().enabled = false;
- // Optionally disable AI or other components that might interfere with placement
- // e.g., currentPlacingCharacterInstance.GetComponent<AIController>()?.enabled = false;
- }
- else
- {
- FinalizePlayerPlacement();
- }
- }
- private void HandleCharacterPlacement()
- {
- Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
- Debug.DrawRay(ray.origin, ray.direction * 200f, Color.yellow); // Visualize the ray
- if (Physics.Raycast(ray, out RaycastHit hit, 200f, groundLayerMask))
- {
- Vector3 targetPosition = hit.point;
- // Clamp position to playerSpawnArea bound (X and Z axis)
- targetPosition.x = Mathf.Clamp(targetPosition.x, playerSpawnBounds.min.x, playerSpawnBounds.max.x);
- targetPosition.z = Mathf.Clamp(targetPosition.z, playerSpawnBounds.min.z, playerSpawnBounds.max.z);
- // Y is determined by the raycast hit on the ground
- // --- Direct Y Position Calculation for Mouse-Following Character ---
- // This approach was found to be more stable than repeatedly calling AdjustCharacterOnGround.
- // It assumes a standard Unity CapsuleCollider where the pivot is at the center.
- Vector3 finalCharacterPosition = targetPosition; // targetPosition.y is from the ground hit (hit.point.y)
- CapsuleCollider capCollider = currentPlacingCharacterInstance.GetComponent<CapsuleCollider>();
- if (capCollider != null)
- {
- // For a capsule, its pivot is typically at its center.
- // To place its bottom on targetPosition.y (ground level),
- // its center (pivot) needs to be at targetPosition.y + (height / 2).
- // We also account for the character's local scale.
- finalCharacterPosition.y = targetPosition.y + (capCollider.height * currentPlacingCharacterInstance.transform.localScale.y / 2f);
- }
- else
- {
- // Fallback if not a capsule or if a different pivot is used.
- // This might need adjustment based on your character's actual pivot and collider.
- Debug.LogWarning($"'{currentPlacingCharacterInstance.name}' does not have a CapsuleCollider. Using default Y offset for placement. Adjust if incorrect.");
- finalCharacterPosition.y = targetPosition.y + 0.5f; // Example offset, adjust as needed
- }
- currentPlacingCharacterInstance.transform.position = finalCharacterPosition;
- // AdjustCharacterOnGround(currentPlacingCharacterInstance); // No longer called every frame for mouse-follow
- }
- else
- {
- }
- // Else mouse is not over valid ground, character stays at last valid position or initial spawn
- if (Input.GetMouseButtonDown(0))
- { // Left-click to place character
- // Check if the current position is valid (within bounds and not overlapping)
- // The position is already clamped and on ground due to the logic above.
- // We primarily need to check for overlaps.
- if (!IsOverlappingOtherCharacters(currentPlacingCharacterInstance))
- {
- PlaceCurrentCharacter();
- }
- else
- {
- Debug.LogWarning("Cannot place character: Overlapping with another character.");
- // Optionally, you could provide feedback to the player about the overlap (e.g. change color?).
- }
- }
- if (Input.GetMouseButtonDown(1))
- { // Right-click to cancel placement
- if (placedPlayerCharacters.Count > 0)
- {
- FinalizePlayerPlacement();
- }
- else
- {
- }
- }
- }
- private void PlaceCurrentCharacter()
- {
- placedPlayerCharacters.Add(currentPlacingCharacterInstance);
- currentPlacingCharacterInstance = null;
- nextPlayerCharacterPrefabIndex++;
- SpawnNextPlayerCharacterForPlacement(); // Spawn next character for placement
- }
- private void AdjustCharacterOnGround(GameObject character)
- {
- if (character == null)
- {
- return;
- }
- Collider charCollider = character.GetComponent<Collider>();
- if (charCollider != null)
- {
- // This ensured the lowest point of the collider is at character.transform.position.y
- // (which should be the ground hit point)
- // currentY is the Y-coordinate of the character's pivot.
- // We want the character's collider bottom (feet) to be at this Y-level.
- float currentY = character.transform.position.y;
- float colliderMinYWorld = charCollider.bounds.min.y;
- float verticalOffset = currentY - colliderMinYWorld;
- const float tolerance = 0.001f; // Small tolerance to avoid floating point issues
- if (Mathf.Abs(verticalOffset) > tolerance)
- {
- character.transform.position += Vector3.up * verticalOffset;
- }
- }
- else
- {
- Debug.LogWarning($"Character: {character.name} has no collider. Cannot accurately adjust to ground.");
- }
- }
- private bool IsOverlappingOtherCharacters(GameObject character)
- {
- Collider newCharCollider = character.GetComponent<Collider>();
- if (newCharCollider == null)
- {
- Debug.LogWarning($"Character: {character.name} has no collider. Cannot check for overlaps.");
- return false; // Or true to precent placement if no collider
- }
- Bounds newCharBounds = newCharCollider.bounds;
- foreach (GameObject placedCharacter in placedPlayerCharacters)
- {
- Collider otherCollider = placedCharacter.GetComponent<Collider>();
- if (otherCollider != null && newCharBounds.Intersects(otherCollider.bounds))
- {
- return true;
- }
- }
- foreach (GameObject placedEnemy in placedEnemyCharacters)
- {
- Collider otherCollider = placedEnemy.GetComponent<Collider>();
- if (otherCollider != null && newCharBounds.Intersects(otherCollider.bounds))
- {
- return true;
- }
- }
- return false;
- }
- private void FinalizePlayerPlacement()
- {
- isPlacingPlayerCharacters = false;
- if (currentPlacingCharacterInstance != null)
- {
- Destroy(currentPlacingCharacterInstance); // Destroy the preview instance if it wasn't placed
- currentPlacingCharacterInstance = null;
- }
- EndPlacementPhase();
- // Here you might want to trigger the next phase of your game, e.g., start the battle.
- GameManager.Instance.StartBattle(placedPlayerCharacters, placedEnemyCharacters);
- Destroy(playerSpawnArea);
- Destroy(enemySpawnArea);
- playerSpawnArea = null;
- enemySpawnArea = null;
- }
- private void EndPlacementPhase()
- {
- // This method can be used to clean up or finalize the placement phase.
- // For example, you might want to enable AI, re-enable NavMeshAgents, etc.
- foreach (GameObject character in placedPlayerCharacters)
- {
- NavMeshAgent agent = character.GetComponent<NavMeshAgent>();
- if (agent != null)
- {
- agent.enabled = true; // Re-enable NavMeshAgent
- }
- // Enable AI or other components as needed
- // e.g., character.GetComponent<AIController>()?.enabled = true;
- }
- foreach (GameObject character in enemyCharacters)
- {
- NavMeshAgent agent = character.GetComponent<NavMeshAgent>();
- if (agent != null)
- {
- agent.enabled = true; // Re-enable NavMeshAgent
- }
- // Enable AI or other components as needed
- // e.g., character.GetComponent<AIController>()?.enabled = true;
- }
- }
- private void PlaceEnemyCharacters()
- {
- Collider spawnAreaCollider = enemySpawnArea.GetComponent<Collider>();
- if (spawnAreaCollider == null)
- {
- Debug.LogError("Enemy spawn area does not have a collider component.");
- return;
- }
- Bounds spawnBounds = spawnAreaCollider.bounds;
- for (int i = enemySelections.Count - 1; i >= 0; i--)
- {
- var selection = enemySelections[i];
- float randomX = UnityEngine.Random.Range(spawnBounds.min.x, spawnBounds.max.x);
- float randomZ = UnityEngine.Random.Range(spawnBounds.min.z, spawnBounds.max.z);
- Vector3 rayOrigin = new Vector3(randomX, enemySpawnArea.transform.position.y + 10f, randomZ);
- Vector3 spawnPosition = new Vector3(randomX, enemySpawnArea.transform.position.y, randomZ);
- // Raycast to find the ground
- if (Physics.Raycast(rayOrigin, Vector3.down, out RaycastHit hit, 200f, groundLayerMask))
- {
- spawnPosition = hit.point;
- }
- else
- {
- Debug.LogWarning($"Raycast did not hit ground below ({randomX}, {randomZ}). Placing enemy at spawn area Y level.");
- }
- GameObject placedEnemy = Instantiate(enemyPrefab, spawnPosition, Quaternion.identity);
- Character character = placedEnemy.GetComponent<Character>();
- if (character != null)
- {
- EquipWeapon(character, selection.weaponType);
- character.CharacterName = selection.characterName + "_" + (i + 1);
- }
- AdjustCharacterOnGround(placedEnemy); // Adjust the enemy to the ground
- placedEnemyCharacters.Add(placedEnemy);
- }
- }
- }
|