| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- 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();
- }
- // Helper method to get WeaponItem from CombatDataTransfer if available
- WeaponItem GetEnhancedWeaponItem(string characterName, bool isPlayer)
- {
- Debug.Log($"🔍 GetEnhancedWeaponItem called for '{characterName}', isPlayer: {isPlayer}");
- if (!CombatDataTransfer.HasValidSession())
- {
- Debug.Log($"🔍 No valid CombatDataTransfer session");
- return null;
- }
- var session = CombatDataTransfer.GetCurrentSession();
- if (session == null)
- {
- Debug.Log($"🔍 CombatDataTransfer session is null");
- return null;
- }
- Debug.Log($"🔍 Session has {session.playerTeam.Count} players and {session.enemies.Count} enemies");
- if (isPlayer)
- {
- // Debug: List all available player characters
- Debug.Log($"🔍 Available players in session:");
- foreach (var player in session.playerTeam)
- {
- Debug.Log($" - Player: '{player.characterName}', Weapon: {(player.equippedWeaponItem != null ? player.equippedWeaponItem.name : "NULL")}");
- }
- // Find player character in enhanced data (match by base name, ignoring suffixes)
- foreach (var player in session.playerTeam)
- {
- if (player.characterName == characterName && player.equippedWeaponItem != null)
- {
- Debug.Log($"🎯 Found enhanced WeaponItem for player {characterName}: {player.equippedWeaponItem.name}");
- return player.equippedWeaponItem;
- }
- // Also try matching without the numbered suffix (e.g., "Player 1" vs "Player")
- if (characterName.StartsWith(player.characterName) && player.equippedWeaponItem != null)
- {
- Debug.Log($"🎯 Found enhanced WeaponItem for player {characterName} (matched base name {player.characterName}): {player.equippedWeaponItem.name}");
- return player.equippedWeaponItem;
- }
- }
- Debug.Log($"🔍 No matching player found for '{characterName}'");
- }
- else
- {
- // Find enemy character in enhanced data (match by base name, ignoring suffixes)
- foreach (var enemy in session.enemies)
- {
- if (enemy.enemyName == characterName && enemy.preferredWeaponItem != null)
- {
- Debug.Log($"🎯 Found enhanced WeaponItem for enemy {characterName}: {enemy.preferredWeaponItem.name}");
- return enemy.preferredWeaponItem;
- }
- // Also try matching the base name (e.g., "Skeleton Warrior_1" vs "Skeleton Warrior")
- if (characterName.StartsWith(enemy.enemyType) && enemy.preferredWeaponItem != null)
- {
- Debug.Log($"🎯 Found enhanced WeaponItem for enemy {characterName} (matched base type {enemy.enemyType}): {enemy.preferredWeaponItem.name}");
- return enemy.preferredWeaponItem;
- }
- }
- }
- return null;
- }
- // Enhanced weapon equipping with WeaponItem support
- void EquipWeapon(Character character, WeaponItem weaponItem)
- {
- Debug.Log($"🔧 EquipWeapon called for {character.CharacterName} with WeaponItem: {(weaponItem != null ? weaponItem.name : "null")}");
- Weapon weapon = null;
- if (weaponItem != null)
- {
- Debug.Log($"🔧 Using WeaponItem.CreateWeaponInstance() for {weaponItem.name}");
- // Use the WeaponItem's CreateWeaponInstance method to preserve all attributes
- weapon = weaponItem.CreateWeaponInstance(character.transform);
- if (weapon != null)
- {
- weapon.SetWielder(character);
- Debug.Log($"✅ Successfully created weapon from WeaponItem: {weapon.weaponName}");
- }
- else
- {
- Debug.LogWarning($"⚠️ WeaponItem.CreateWeaponInstance() returned null for {weaponItem.name}. Falling back to string-based creation.");
- // Fallback to string-based weapon creation
- EquipWeapon(character, weaponItem.weaponType.ToString());
- return;
- }
- }
- else
- {
- Debug.LogWarning($"No WeaponItem provided for {character.CharacterName}. Equipping with fists as fallback.");
- EquipWeapon(character, "Fists");
- return;
- }
- if (weapon != null)
- {
- // Attach weapon to the character
- 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);
- Debug.Log($"✅ Successfully equipped {weapon.weaponName} to {character.CharacterName}");
- }
- else
- {
- Debug.LogError($"❌ Failed to create weapon for {character.CharacterName}");
- }
- }
- // Fallback weapon equipping using string types (for backward compatibility)
- void EquipWeapon(Character character, string weaponType)
- {
- Debug.Log($"🔧 EquipWeapon called for {character.CharacterName} with weaponType: '{weaponType}'");
- Weapon weapon = null;
- // Handle null or empty weapon types
- if (string.IsNullOrEmpty(weaponType))
- {
- Debug.LogWarning($"No weapon type specified for {character.CharacterName}. Equipping with fists as fallback.");
- weaponType = "Fists";
- }
- Debug.Log($"🔧 Processing weapon type: '{weaponType}' for {character.CharacterName}");
- if (weaponType == "Sword")
- {
- Debug.Log($"⚔️ Creating Sword for {character.CharacterName}");
- var weaponObj = Instantiate(SwordPrefab, character.transform);
- weapon = weaponObj.GetComponent<Weapon>();
- }
- else if (weaponType == "Bow")
- {
- Debug.Log($"🏹 Creating Bow for {character.CharacterName}");
- var weaponObj = Instantiate(BowPrefab, character.transform);
- weapon = weaponObj.GetComponent<Weapon>();
- }
- else if (weaponType == "Fists")
- {
- Debug.Log($"👊 Creating Fists for {character.CharacterName}");
- // Create a fists weapon directly using SimpleSword as base
- GameObject fistsObj = new GameObject("Fists");
- fistsObj.transform.SetParent(character.transform, false);
- SimpleSword fistsWeapon = fistsObj.AddComponent<SimpleSword>();
- // Override the sword's properties to make it act like fists
- fistsWeapon.weaponName = "Fists";
- fistsWeapon.description = "Bare fists - a basic unarmed attack.";
- fistsWeapon.attackSpeed = 1.0f;
- weapon = fistsWeapon;
- }
- else
- {
- Debug.LogWarning($"❓ Unknown weapon type: '{weaponType}' for {character.CharacterName}. Equipping with fists as fallback.");
- // Create a fists weapon as fallback using SimpleSword as base
- GameObject fistsObj = new GameObject("Fists");
- fistsObj.transform.SetParent(character.transform, false);
- SimpleSword fistsWeapon = fistsObj.AddComponent<SimpleSword>();
- // Override the sword's properties to make it act like fists
- fistsWeapon.weaponName = "Fists";
- fistsWeapon.description = "Bare fists - a basic unarmed attack.";
- fistsWeapon.attackSpeed = 1.0f;
- weapon = fistsWeapon;
- }
- 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);
- Debug.Log($"✅ Successfully equipped {weapon.weaponName} to {character.CharacterName}");
- }
- else
- {
- Debug.LogError($"❌ Failed to create weapon for {character.CharacterName}");
- }
- }
- 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)
- {
- Debug.Log($"🔍 SpawnNextPlayerCharacterForPlacement: Character '{selection.characterName}' with weapon '{selection.weaponType}'");
- // Try to get enhanced weapon data first
- WeaponItem enhancedWeapon = GetEnhancedWeaponItem(selection.characterName, true);
- Debug.Log($"🔍 Enhanced weapon lookup for '{selection.characterName}': {(enhancedWeapon != null ? enhancedWeapon.name : "NULL")}");
- if (enhancedWeapon != null)
- {
- Debug.Log($"🎯 Using enhanced weapon: {enhancedWeapon.name}");
- EquipWeapon(character, enhancedWeapon);
- }
- else
- {
- Debug.Log($"🔍 No enhanced weapon found, falling back to selection.weaponType: '{selection.weaponType}'");
- 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)
- {
- // Try to get enhanced weapon data first
- WeaponItem enhancedWeapon = GetEnhancedWeaponItem(selection.characterName, false);
- if (enhancedWeapon != null)
- {
- EquipWeapon(character, enhancedWeapon);
- }
- else
- {
- EquipWeapon(character, selection.weaponType);
- }
- character.CharacterName = selection.characterName + "_" + (i + 1);
- }
- AdjustCharacterOnGround(placedEnemy); // Adjust the enemy to the ground
- placedEnemyCharacters.Add(placedEnemy);
- }
- }
- }
|