using UnityEngine; using System.Collections.Generic; using System.Linq; /// /// Manages map exploration using a pre-generated large map with fog of war /// public class ExplorationManager { private MapMaker2 mapMaker; private MapData fullMapData; // The complete pre-generated map private bool[,] exploredMask; // Tracks which areas have been revealed private float lastExplorationTime = 0f; // Cooldown tracking // Performance settings for large maps private bool performanceMode = false; // Enable for maps larger than 200x200 private int lodLevel = 1; // Level of Detail: 1 = full detail, 2 = half detail, 4 = quarter detail // Exploration Settings - Public properties for MapMaker2 to set public int fullMapWidth { get; set; } = 300; public int fullMapHeight { get; set; } = 300; public int initialVisibleSize { get; set; } = 80; // Starting visible area public int explorationChunkSize { get; set; } = 40; // Size of chunks to reveal public float explorationDistance { get; set; } = 10f; // Distance from edge to trigger exploration (reduced from 20f) public float explorationCooldown { get; set; } = 3f; // Cooldown between explorations public ExplorationManager(MapMaker2 mapMaker) { this.mapMaker = mapMaker; } /// /// Initialize the exploration system with a large pre-generated map /// public void InitializeExploration() { Debug.Log("🗺️ Initializing Exploration System..."); // Check if we need performance mode for large maps if (fullMapWidth > 200 || fullMapHeight > 200) { performanceMode = true; lodLevel = CalculateOptimalLOD(fullMapWidth, fullMapHeight); Debug.Log($"⚡ Performance mode enabled with LOD level {lodLevel} for large map"); } // Generate the full large map GenerateFullMap(); // Initialize exploration mask exploredMask = new bool[fullMapWidth, fullMapHeight]; Debug.Log($"🔍 Created exploration mask: {fullMapWidth}x{fullMapHeight}"); // Reveal initial area around the center RevealInitialArea(); // Update the visible map data UpdateVisibleMap(); Debug.Log($"✅ Exploration System initialized - Full map: {fullMapWidth}x{fullMapHeight}, Initial visible: {initialVisibleSize}x{initialVisibleSize}"); } /// /// Calculate optimal Level of Detail for given map size /// private int CalculateOptimalLOD(int width, int height) { int totalTiles = width * height; if (totalTiles > 250000) // 500x500+ return 4; // Quarter detail else if (totalTiles > 100000) // 316x316+ return 2; // Half detail else return 1; // Full detail } /// /// DEBUG: Show the entire 300x300 map for testing purposes /// public void ShowFullMap() { if (fullMapData == null) { Debug.LogError("❌ Full map data not available!"); return; } Debug.Log("🌍 Loading full 300x300 map for debugging..."); // Get the current position in full map coordinates BEFORE switching to full map Vector2Int currentFullMapPosition = GetCurrentTeamPositionInFullMapImproved(); Debug.Log($"🎯 Team position before full map: Full map coordinates ({currentFullMapPosition})"); // Mark entire map as explored for (int x = 0; x < fullMapWidth; x++) { for (int y = 0; y < fullMapHeight; y++) { exploredMask[x, y] = true; } } // Update the visible map to show everything UpdateVisibleMap(); // Restore team marker to the correct full map position RestoreTeamMarkerToFullMapPosition(currentFullMapPosition); Debug.Log($"✅ Full map is now visible!"); } /// /// TEST: Debug coordinate conversion to find the issue /// public void TestCoordinateConversion() { SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) { Debug.LogError("❌ SimpleTeamPlacement not found!"); return; } GameObject teamMarker = GameObject.Find("TeamMarker"); if (teamMarker == null) { Debug.LogError("❌ TeamMarker not found!"); return; } // Get current state Vector3 worldPos = teamMarker.transform.position; Vector2Int storedPos = teamPlacement.GetCurrentTeamPosition(); Rect exploredBounds = GetExploredBounds(); bool isShowingFullMap = exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5; Debug.Log("=== COORDINATE CONVERSION TEST ==="); Debug.Log($"Team Marker World Position: ({worldPos.x:F1}, {worldPos.y:F1})"); Debug.Log($"Team Placement Stored Position: ({storedPos.x}, {storedPos.y})"); Debug.Log($"Explored Bounds: {exploredBounds}"); Debug.Log($"Is Showing Full Map: {isShowingFullMap}"); Debug.Log($"Full Map Size: {fullMapWidth}x{fullMapHeight}"); // Test the conversion Vector2Int convertedPos = GetCurrentTeamPositionInFullMapImproved(); Debug.Log($"Converted Full Map Position: ({convertedPos.x}, {convertedPos.y})"); // Expected position for center of map Vector2Int expectedCenter = new Vector2Int(fullMapWidth / 2, fullMapHeight / 2); Debug.Log($"Expected Map Center: ({expectedCenter.x}, {expectedCenter.y})"); // Check if the stored position makes sense if (!isShowingFullMap) { Vector2Int expectedFullMapPos = new Vector2Int( (int)exploredBounds.x + storedPos.x, (int)exploredBounds.y + storedPos.y ); Debug.Log($"Expected Full Map Pos from Stored: Bounds({exploredBounds.x}, {exploredBounds.y}) + Stored({storedPos.x}, {storedPos.y}) = ({expectedFullMapPos.x}, {expectedFullMapPos.y})"); } Debug.Log("====================================="); } /// /// TEST: Simple coordinate conversion test /// public void TestSimpleCoordinateConversion() { SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) { Debug.LogError("❌ SimpleTeamPlacement not found!"); return; } Vector2Int storedPos = teamPlacement.GetCurrentTeamPosition(); Rect exploredBounds = GetExploredBounds(); Debug.Log("=== SIMPLE COORDINATE TEST ==="); Debug.Log($"Stored team position: ({storedPos.x}, {storedPos.y})"); Debug.Log($"Explored bounds: {exploredBounds}"); // Expected full map position Vector2Int expectedFullMapPos = new Vector2Int( (int)exploredBounds.x + storedPos.x, (int)exploredBounds.y + storedPos.y ); Debug.Log($"Expected full map position: ({expectedFullMapPos.x}, {expectedFullMapPos.y})"); Debug.Log($"Map center: ({fullMapWidth / 2}, {fullMapHeight / 2})"); bool isNearCenter = Vector2Int.Distance(expectedFullMapPos, new Vector2Int(fullMapWidth / 2, fullMapHeight / 2)) < 10; Debug.Log($"Is near map center: {(isNearCenter ? "✅ YES" : "❌ NO")}"); Debug.Log("==============================="); } /// /// DEBUG: Test positioning after camera and tile fixes /// public void TestPositioningAfterFix() { SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) { Debug.LogError("❌ SimpleTeamPlacement not found!"); return; } GameObject teamMarker = GameObject.Find("TeamMarker"); if (teamMarker == null) { Debug.LogError("❌ TeamMarker not found!"); return; } Vector2Int storedPos = teamPlacement.GetCurrentTeamPosition(); Rect exploredBounds = GetExploredBounds(); Vector3 teamMarkerWorldPos = teamMarker.transform.position; Debug.Log("=== POSITIONING TEST AFTER FIX ==="); Debug.Log($"📍 Team Marker World Position: ({teamMarkerWorldPos.x:F1}, {teamMarkerWorldPos.y:F1})"); Debug.Log($"🗂️ Stored Team Position: ({storedPos.x}, {storedPos.y})"); Debug.Log($"🗺️ Explored Bounds: {exploredBounds}"); // Calculate expected world position for the center tile Vector3 expectedCenterTileWorldPos = new Vector3( (exploredBounds.x + exploredBounds.width / 2f), (exploredBounds.y + exploredBounds.height / 2f), 0 ); Debug.Log($"🎯 Expected Center Tile World Position: ({expectedCenterTileWorldPos.x:F1}, {expectedCenterTileWorldPos.y:F1})"); // Check camera position Camera mainCam = Camera.main; if (mainCam != null) { Debug.Log($"📹 Camera Position: ({mainCam.transform.position.x:F1}, {mainCam.transform.position.y:F1})"); Debug.Log($"📹 Camera Size: {mainCam.orthographicSize:F1}"); } // Check if team marker should be visible float distanceFromExpectedCenter = Vector3.Distance(teamMarkerWorldPos, expectedCenterTileWorldPos); Debug.Log($"📏 Distance from expected center: {distanceFromExpectedCenter:F1}"); bool shouldBeVisible = distanceFromExpectedCenter < 40f; // Within 40 units of center Debug.Log($"👁️ Should be visible: {(shouldBeVisible ? "✅ YES" : "❌ NO")}"); Debug.Log("==================================="); } /// /// DEBUG: Test full map tile coverage to find missing quadrants /// public void TestFullMapTileCoverage() { Debug.Log("=== FULL MAP TILE COVERAGE TEST ==="); // Get current map data from MapMaker2 var currentMapData = mapMaker?.GetMapData(); if (currentMapData == null) { Debug.LogError("❌ No current map data available!"); return; } Debug.Log($"📊 Current Map Data Size: {currentMapData.Width}x{currentMapData.Height}"); // Check if we're showing full map Rect exploredBounds = GetExploredBounds(); bool isShowingFullMap = exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5; Debug.Log($"🗺️ Is Showing Full Map: {isShowingFullMap}"); Debug.Log($"🗺️ Explored Bounds: {exploredBounds}"); Debug.Log($"🗺️ Full Map Size: {fullMapWidth}x{fullMapHeight}"); if (isShowingFullMap) { // Test if we have tiles in each quadrant int centerX = currentMapData.Width / 2; int centerY = currentMapData.Height / 2; // Test each quadrant Vector2Int[] testPoints = { new Vector2Int(centerX / 2, centerY / 2), // Lower-left new Vector2Int(centerX + centerX / 2, centerY / 2), // Lower-right new Vector2Int(centerX / 2, centerY + centerY / 2), // Upper-left new Vector2Int(centerX + centerX / 2, centerY + centerY / 2) // Upper-right }; string[] quadrantNames = { "Lower-Left", "Lower-Right", "Upper-Left", "Upper-Right" }; for (int i = 0; i < testPoints.Length; i++) { var testPoint = testPoints[i]; var tile = currentMapData.GetTile(testPoint.x, testPoint.y); bool hasValidTile = tile != null; Debug.Log($"🔍 {quadrantNames[i]} Quadrant ({testPoint.x}, {testPoint.y}): {(hasValidTile ? "✅ HAS TILE" : "❌ NO TILE")}"); if (hasValidTile) { Debug.Log($" Terrain: {tile.terrainType}, Feature: {tile.featureType}"); } } // Test specific areas that might be missing Debug.Log("🔍 Testing specific problematic areas:"); Vector2Int[] problematicPoints = { new Vector2Int(0, 0), // Bottom-left corner new Vector2Int(currentMapData.Width-1, 0), // Bottom-right corner new Vector2Int(0, currentMapData.Height-1), // Top-left corner new Vector2Int(currentMapData.Width-1, currentMapData.Height-1) // Top-right corner }; for (int i = 0; i < problematicPoints.Length; i++) { var testPoint = problematicPoints[i]; var tile = currentMapData.GetTile(testPoint.x, testPoint.y); bool hasValidTile = tile != null; Debug.Log($"🔍 Corner ({testPoint.x}, {testPoint.y}): {(hasValidTile ? "✅ HAS TILE" : "❌ NO TILE")}"); } } else { Debug.Log("⚠️ Not currently showing full map - switch to full map first to test coverage"); } Debug.Log("====================================="); } /// /// DEBUG: Test visual tile rendering to find missing areas /// public void TestVisualTileRendering() { Debug.Log("=== VISUAL TILE RENDERING TEST ==="); // Check if we're showing full map Rect exploredBounds = GetExploredBounds(); bool isShowingFullMap = exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5; Debug.Log($"🗺️ Is Showing Full Map: {isShowingFullMap}"); Debug.Log($"🗺️ Explored Bounds: {exploredBounds}"); if (isShowingFullMap) { // Check for actual GameObjects in each quadrant string[] quadrantNames = { "Lower-Left", "Lower-Right", "Upper-Left", "Upper-Right" }; Vector2Int[] testPoints = { new Vector2Int(75, 75), // Lower-left new Vector2Int(225, 75), // Lower-right new Vector2Int(75, 225), // Upper-left new Vector2Int(225, 225) // Upper-right }; for (int i = 0; i < testPoints.Length; i++) { var testPoint = testPoints[i]; // Look for actual tile GameObjects at these world positions string terrainTileName = $"TerrainTile_{testPoint.x}_{testPoint.y}"; GameObject terrainTile = GameObject.Find(terrainTileName); string featureTileName = $"FeatureTile_{testPoint.x}_{testPoint.y}"; GameObject featureTile = GameObject.Find(featureTileName); Debug.Log($"🎮 {quadrantNames[i]} Quadrant ({testPoint.x}, {testPoint.y}):"); Debug.Log($" Terrain GameObject: {(terrainTile != null ? "✅ EXISTS" : "❌ MISSING")}"); Debug.Log($" Feature GameObject: {(featureTile != null ? "✅ EXISTS" : "❌ MISSING")}"); if (terrainTile != null) { Debug.Log($" Terrain Position: ({terrainTile.transform.position.x:F1}, {terrainTile.transform.position.y:F1})"); Debug.Log($" Terrain Active: {terrainTile.activeInHierarchy}"); } } // Check corner tiles specifically Debug.Log("🔍 Testing corner tile GameObjects:"); Vector2Int[] corners = { new Vector2Int(0, 0), // Bottom-left corner new Vector2Int(299, 0), // Bottom-right corner new Vector2Int(0, 299), // Top-left corner new Vector2Int(299, 299) // Top-right corner }; string[] cornerNames = { "Bottom-Left", "Bottom-Right", "Top-Left", "Top-Right" }; for (int i = 0; i < corners.Length; i++) { var corner = corners[i]; string tileName = $"TerrainTile_{corner.x}_{corner.y}"; GameObject tile = GameObject.Find(tileName); Debug.Log($"🎮 {cornerNames[i]} Corner ({corner.x}, {corner.y}): {(tile != null ? "✅ EXISTS" : "❌ MISSING")}"); if (tile != null) { Debug.Log($" Position: ({tile.transform.position.x:F1}, {tile.transform.position.y:F1})"); Debug.Log($" Active: {tile.activeInHierarchy}"); } } // Count total rendered tiles var allObjects = Object.FindObjectsByType(FindObjectsSortMode.None); var terrainTiles = allObjects.Where(go => go.name.StartsWith("TerrainTile_")).ToArray(); Debug.Log($"📊 Total rendered terrain tiles: {terrainTiles.Length}"); Debug.Log($"📊 Expected tiles for 300x300: {300 * 300}"); if (terrainTiles.Length < 300 * 300) { Debug.Log($"⚠️ Missing {(300 * 300) - terrainTiles.Length} tiles!"); // Sample some missing tile names for (int y = 0; y < 10; y++) { for (int x = 0; x < 10; x++) { string tileName = $"TerrainTile_{x}_{y}"; if (GameObject.Find(tileName) == null) { Debug.Log($" Missing: {tileName}"); } } } } } else { Debug.Log("⚠️ Not currently showing full map - switch to full map first"); } Debug.Log("==================================="); } /// /// Restore team marker to correct position in full map coordinates /// private void RestoreTeamMarkerToFullMapPosition(Vector2Int fullMapPosition) { SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) return; // In full map mode, full map coordinates = visible coordinates Debug.Log($"🔧 Restoring team marker to full map position: ({fullMapPosition})"); // Update team marker position teamPlacement.UpdateMarkerAfterMapChange(fullMapPosition); } /// /// Get current team marker position in full map coordinates (improved version) /// private Vector2Int GetCurrentTeamPositionInFullMapImproved() { SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) return new Vector2Int(fullMapWidth / 2, fullMapHeight / 2); // Instead of reading world position, use the stored position and convert it properly Vector2Int storedPosition = teamPlacement.GetCurrentTeamPosition(); // Check if we're currently showing the full map or a partial exploration view Rect exploredBounds = GetExploredBounds(); bool isShowingFullMap = exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5; Vector2Int fullMapPos; if (isShowingFullMap) { // If already showing full map, stored position = full map coordinates fullMapPos = storedPosition; Debug.Log($"🎯 Current team position (Full Map): Stored({storedPosition}) = FullMap({fullMapPos})"); } else { // If showing partial exploration view, convert exploration coordinates to full map coordinates fullMapPos = new Vector2Int( (int)exploredBounds.x + storedPosition.x, (int)exploredBounds.y + storedPosition.y ); Debug.Log($"🎯 Current team position (Exploration): Stored({storedPosition}) + Bounds({exploredBounds.x}, {exploredBounds.y}) → FullMap({fullMapPos})"); Debug.Log($"🔍 DEBUG: ExploredBounds = {exploredBounds}, IsFullMap = {isShowingFullMap}"); } return fullMapPos; } /// /// Restore team marker to correct position after map view changes /// private void RestoreTeamMarkerPosition(Vector2Int fullMapPosition) { SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) return; // Check if we're currently showing the full map Rect exploredBounds = GetExploredBounds(); bool isShowingFullMap = exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5; Vector2Int visiblePosition; if (isShowingFullMap) { // If showing full map, full map coordinates = visible coordinates visiblePosition = fullMapPosition; Debug.Log($"🔧 Restored team marker (Full Map): FullMap({fullMapPosition}) → Visible({visiblePosition})"); } else if (performanceMode) { // Account for LOD scaling in exploration mode visiblePosition = new Vector2Int( (fullMapPosition.x - (int)exploredBounds.x) / lodLevel, (fullMapPosition.y - (int)exploredBounds.y) / lodLevel ); int visibleWidth = (int)exploredBounds.width / lodLevel; int visibleHeight = (int)exploredBounds.height / lodLevel; visiblePosition.x = Mathf.Clamp(visiblePosition.x, 0, visibleWidth - 1); visiblePosition.y = Mathf.Clamp(visiblePosition.y, 0, visibleHeight - 1); Debug.Log($"🔧 Restored team marker (Exploration LOD): FullMap({fullMapPosition}) → Visible({visiblePosition}) [LOD:{lodLevel}]"); } else { // Standard coordinate conversion for exploration mode visiblePosition = new Vector2Int( fullMapPosition.x - (int)exploredBounds.x, fullMapPosition.y - (int)exploredBounds.y ); int visibleWidth = (int)exploredBounds.width; int visibleHeight = (int)exploredBounds.height; visiblePosition.x = Mathf.Clamp(visiblePosition.x, 0, visibleWidth - 1); visiblePosition.y = Mathf.Clamp(visiblePosition.y, 0, visibleHeight - 1); Debug.Log($"🔧 Restored team marker (Exploration): FullMap({fullMapPosition}) → Visible({visiblePosition})"); } // Update team marker position teamPlacement.UpdateMarkerAfterMapChange(visiblePosition); } /// /// Toggle performance mode for testing different map sizes /// public void TogglePerformanceMode() { performanceMode = !performanceMode; if (performanceMode) { lodLevel = CalculateOptimalLOD(fullMapWidth, fullMapHeight); Debug.Log($"⚡ Performance mode enabled with LOD {lodLevel}"); } else { lodLevel = 1; Debug.Log("🎯 Performance mode disabled - using full detail"); } // Refresh the visible map UpdateVisibleMap(); } /// /// Set custom map size for scalability testing /// public void SetMapSize(int width, int height) { fullMapWidth = width; fullMapHeight = height; // Auto-enable performance mode for large maps if (width > 200 || height > 200) { performanceMode = true; lodLevel = CalculateOptimalLOD(width, height); Debug.Log($"⚡ Auto-enabled performance mode for {width}x{height} map (LOD {lodLevel})"); } else { performanceMode = false; lodLevel = 1; Debug.Log($"🎯 Standard mode for {width}x{height} map"); } } /// /// Convert world coordinates to exploration-system-aware tile coordinates /// This handles the coordinate system differences between journey and exploration systems /// public Vector2Int ConvertWorldToExplorationCoordinates(Vector3 worldPosition) { // Convert world position to base tile coordinates Vector2Int baseTilePos = new Vector2Int( Mathf.RoundToInt(worldPosition.x), Mathf.RoundToInt(worldPosition.y) ); // Get current exploration bounds to determine coordinate system Rect exploredBounds = GetExploredBounds(); // Check if we're showing the full map (when bounds = full map size) bool isShowingFullMap = (exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5); if (isShowingFullMap) { // When showing full map, world coordinates ARE the exploration coordinates // Just apply LOD scaling if needed Vector2Int explorationCoords = baseTilePos; if (performanceMode && lodLevel > 1) { explorationCoords.x = explorationCoords.x / lodLevel; explorationCoords.y = explorationCoords.y / lodLevel; // Clamp to LOD-scaled bounds int lodWidth = (int)exploredBounds.width / lodLevel; int lodHeight = (int)exploredBounds.height / lodLevel; explorationCoords.x = Mathf.Clamp(explorationCoords.x, 0, lodWidth - 1); explorationCoords.y = Mathf.Clamp(explorationCoords.y, 0, lodHeight - 1); } else { // Clamp to full map bounds explorationCoords.x = Mathf.Clamp(explorationCoords.x, 0, (int)exploredBounds.width - 1); explorationCoords.y = Mathf.Clamp(explorationCoords.y, 0, (int)exploredBounds.height - 1); } Debug.Log($"🌍 FULL MAP: World({worldPosition.x:F1}, {worldPosition.y:F1}) → Exploration({explorationCoords}) [LOD:{lodLevel}]"); return explorationCoords; } else { // Normal exploration mode - convert to relative coordinates within visible area Vector2Int explorationCoords = new Vector2Int( baseTilePos.x - (int)exploredBounds.x, baseTilePos.y - (int)exploredBounds.y ); if (performanceMode && lodLevel > 1) { // Apply LOD scaling explorationCoords.x = explorationCoords.x / lodLevel; explorationCoords.y = explorationCoords.y / lodLevel; int visibleWidth = (int)exploredBounds.width / lodLevel; int visibleHeight = (int)exploredBounds.height / lodLevel; explorationCoords.x = Mathf.Clamp(explorationCoords.x, 0, visibleWidth - 1); explorationCoords.y = Mathf.Clamp(explorationCoords.y, 0, visibleHeight - 1); } else { explorationCoords.x = Mathf.Clamp(explorationCoords.x, 0, (int)exploredBounds.width - 1); explorationCoords.y = Mathf.Clamp(explorationCoords.y, 0, (int)exploredBounds.height - 1); } Debug.Log($"🔄 PARTIAL: World({worldPosition.x:F1}, {worldPosition.y:F1}) → Base({baseTilePos}) → Exploration({explorationCoords}) [LOD:{lodLevel}]"); return explorationCoords; } } /// /// Convert exploration coordinates back to world coordinates /// public Vector3 ConvertExplorationToWorldCoordinates(Vector2Int explorationCoords) { Rect exploredBounds = GetExploredBounds(); // Check if we're showing the full map bool isShowingFullMap = (exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5); Vector2Int fullMapCoords; if (isShowingFullMap) { // When showing full map, exploration coordinates ARE the world coordinates (with LOD scaling) if (performanceMode && lodLevel > 1) { // Scale up from LOD coordinates fullMapCoords = new Vector2Int( explorationCoords.x * lodLevel, explorationCoords.y * lodLevel ); } else { // Direct mapping fullMapCoords = explorationCoords; } } else { // Normal exploration mode - add bounds offset if (performanceMode && lodLevel > 1) { // Scale up coordinates and add bounds offset fullMapCoords = new Vector2Int( (explorationCoords.x * lodLevel) + (int)exploredBounds.x, (explorationCoords.y * lodLevel) + (int)exploredBounds.y ); } else { // Direct conversion with bounds offset fullMapCoords = new Vector2Int( explorationCoords.x + (int)exploredBounds.x, explorationCoords.y + (int)exploredBounds.y ); } } Vector3 worldPos = new Vector3(fullMapCoords.x, fullMapCoords.y, 0); Debug.Log($"🔄 Exploration({explorationCoords}) → FullMap({fullMapCoords}) → World({worldPos.x:F1}, {worldPos.y:F1}) [LOD:{lodLevel}, FullMap:{isShowingFullMap}]"); return worldPos; } /// /// Synchronize team marker position between coordinate systems /// Call this method when switching between journey and exploration systems /// public void SynchronizeTeamMarkerPosition() { SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) return; GameObject teamMarker = GameObject.Find("TeamMarker"); if (teamMarker == null) return; // Get current world position from the marker Vector3 currentWorldPos = teamMarker.transform.position; // Convert to proper exploration coordinates Vector2Int correctExplorationCoords = ConvertWorldToExplorationCoordinates(currentWorldPos); // Get the current stored position in team placement Vector2Int storedPosition = teamPlacement.GetCurrentTeamPosition(); // Check if there's a mismatch that needs fixing if (storedPosition != correctExplorationCoords) { Debug.Log($"🔧 Coordinate mismatch detected: Stored({storedPosition}) ≠ Calculated({correctExplorationCoords})"); Debug.Log($" World position: ({currentWorldPos.x:F1}, {currentWorldPos.y:F1})"); // Fix the mismatch by updating the stored position to match the world position // This preserves the actual visual location of the marker teamPlacement.UpdateMarkerAfterMapChange(correctExplorationCoords); Debug.Log($"✅ Fixed coordinate mismatch: Updated stored position to ({correctExplorationCoords})"); } else { Debug.Log($"✅ Coordinates are synchronized: World({currentWorldPos.x:F1}, {currentWorldPos.y:F1}) → Exploration({correctExplorationCoords})"); } } /// /// Debug method to show current coordinate state /// public void DebugCoordinateState() { SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) return; GameObject teamMarker = GameObject.Find("TeamMarker"); if (teamMarker == null) return; Vector3 worldPos = teamMarker.transform.position; Vector2Int storedPos = teamPlacement.GetCurrentTeamPosition(); Vector2Int calculatedPos = ConvertWorldToExplorationCoordinates(worldPos); Rect exploredBounds = GetExploredBounds(); bool isShowingFullMap = (exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5); Debug.Log("=== COORDINATE DEBUG ==="); Debug.Log($"World Position: ({worldPos.x:F1}, {worldPos.y:F1})"); Debug.Log($"Stored Position: ({storedPos.x}, {storedPos.y})"); Debug.Log($"Calculated Position: ({calculatedPos.x}, {calculatedPos.y})"); Debug.Log($"Explored Bounds: {exploredBounds}"); Debug.Log($"Showing Full Map: {isShowingFullMap}"); Debug.Log($"Performance Mode: {performanceMode}, LOD Level: {lodLevel}"); Debug.Log($"Coordinate Match: {(storedPos == calculatedPos ? "✅ YES" : "❌ NO")}"); if (storedPos != calculatedPos) { Debug.Log($"🔧 MISMATCH DETECTED! Use 'FIX: Force Coordinate Sync' to fix this."); } Debug.Log("========================"); } /// /// Force coordinate synchronization regardless of current state /// public void ForceCoordinateSync() { SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) return; GameObject teamMarker = GameObject.Find("TeamMarker"); if (teamMarker == null) return; // Get current world position from the marker Vector3 currentWorldPos = teamMarker.transform.position; // Convert to proper exploration coordinates Vector2Int correctExplorationCoords = ConvertWorldToExplorationCoordinates(currentWorldPos); // Force update the stored position teamPlacement.UpdateMarkerAfterMapChange(correctExplorationCoords); Debug.Log($"🔧 FORCED coordinate sync: World({currentWorldPos.x:F1}, {currentWorldPos.y:F1}) → Exploration({correctExplorationCoords})"); Debug.Log($"✅ Team marker position forcibly synchronized"); } /// /// Reset team marker to the center of the map (useful when coordinates get messed up) /// public void ResetTeamMarkerToMapCenter() { SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) return; // Calculate the center of the full map int centerX = fullMapWidth / 2; int centerY = fullMapHeight / 2; Vector2Int mapCenter = new Vector2Int(centerX, centerY); // Check if we're currently showing the full map Rect exploredBounds = GetExploredBounds(); bool isShowingFullMap = exploredBounds.width >= fullMapWidth - 5 && exploredBounds.height >= fullMapHeight - 5; Vector2Int targetPosition; if (isShowingFullMap) { // In full map mode, place at actual center coordinates targetPosition = mapCenter; Debug.Log($"🎯 Resetting team marker to full map center: ({targetPosition})"); } else { // In exploration mode, place at center of visible area targetPosition = new Vector2Int( centerX - (int)exploredBounds.x, centerY - (int)exploredBounds.y ); Debug.Log($"🎯 Resetting team marker to exploration center: Full({mapCenter}) → Visible({targetPosition})"); } // Update team marker position teamPlacement.UpdateMarkerAfterMapChange(targetPosition); Debug.Log($"✅ Team marker reset to map center"); } /// /// Generate the complete large map using existing MapMaker2 systems /// private void GenerateFullMap() { Debug.Log($"🌍 Generating full map of size {fullMapWidth}x{fullMapHeight}..."); // Temporarily modify MapMaker2 settings for large map generation int originalWidth = mapMaker.mapWidth; int originalHeight = mapMaker.mapHeight; int originalSeed = mapMaker.seed; mapMaker.mapWidth = fullMapWidth; mapMaker.mapHeight = fullMapHeight; // Use the same seed for consistency, but initialize it properly Random.InitState(originalSeed); UnityEngine.Random.InitState(originalSeed); // Generate the full map fullMapData = new MapData(fullMapWidth, fullMapHeight); Debug.Log($"📊 Created MapData with size: {fullMapData.Width}x{fullMapData.Height}"); // Generate the complete map using MapMaker2's generation system mapMaker.GenerateCompleteMap(fullMapData); // Ensure roads and features connect properly across the entire map PostProcessMapConnectivity(); // Restore original settings mapMaker.mapWidth = originalWidth; mapMaker.mapHeight = originalHeight; // Debug settlement count in full map int townCount = fullMapData.GetTowns().Count; int villageCount = fullMapData.GetVillages().Count; Debug.Log($"🏘️ Generated full map with {townCount} towns and {villageCount} villages"); Debug.Log("✅ Full map generation complete"); } /// /// Post-process the map to ensure better connectivity of roads and features /// private void PostProcessMapConnectivity() { Debug.Log("🔧 Post-processing map for better connectivity..."); // Ensure all settlements are connected by roads ConnectSettlementsWithRoads(); // Smooth terrain transitions to prevent harsh breaks SmoothTerrainTransitions(); // Validate water bodies and rivers for continuity ValidateWaterFeatures(); Debug.Log("✅ Map connectivity post-processing complete"); } /// /// Connect all settlements with roads for better navigation /// private void ConnectSettlementsWithRoads() { var allSettlements = new List(); allSettlements.AddRange(fullMapData.GetTowns()); allSettlements.AddRange(fullMapData.GetVillages()); Debug.Log($"🛣️ Connecting {allSettlements.Count} settlements with roads..."); for (int i = 0; i < allSettlements.Count - 1; i++) { for (int j = i + 1; j < allSettlements.Count; j++) { Settlement from = allSettlements[i]; Settlement to = allSettlements[j]; // Only connect nearby settlements (within reasonable distance) float distance = Vector2.Distance(from.position, to.position); if (distance < 50f) // Adjust distance threshold as needed { CreateRoadBetweenPoints(from.position, to.position); } } } } /// /// Create a road between two points /// private void CreateRoadBetweenPoints(Vector2Int start, Vector2Int end) { // Simple pathfinding - create L-shaped or direct path List roadPath = new List(); // Direct line approach (can be enhanced with A* pathfinding later) Vector2Int current = start; Vector2Int diff = end - start; // Horizontal movement first int stepX = diff.x > 0 ? 1 : -1; while (current.x != end.x) { roadPath.Add(current); current.x += stepX; } // Vertical movement int stepY = diff.y > 0 ? 1 : -1; while (current.y != end.y) { roadPath.Add(current); current.y += stepY; } roadPath.Add(end); // Place road tiles foreach (var point in roadPath) { if (IsValidExplorationPosition(point.x, point.y)) { MapTile tile = fullMapData.GetTile(point.x, point.y); if (tile != null && !tile.IsWater()) { // Set road feature (assuming FeatureType.Road exists) tile.featureType = FeatureType.Road; } } } } /// /// Smooth terrain transitions to prevent harsh breaks /// private void SmoothTerrainTransitions() { Debug.Log("🌄 Smoothing terrain transitions..."); // Apply smoothing filter to height values for (int x = 1; x < fullMapWidth - 1; x++) { for (int y = 1; y < fullMapHeight - 1; y++) { MapTile center = fullMapData.GetTile(x, y); if (center == null) continue; // Get surrounding tiles List neighbors = new List(); for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { if (dx == 0 && dy == 0) continue; MapTile neighbor = fullMapData.GetTile(x + dx, y + dy); if (neighbor != null) neighbors.Add(neighbor); } } if (neighbors.Count > 0) { // Average the height with neighbors for smoother transitions float avgHeight = neighbors.Average(t => t.height); center.height = (center.height + avgHeight) * 0.5f; } } } } /// /// Validate and fix water features for better continuity /// private void ValidateWaterFeatures() { Debug.Log("🌊 Validating water features..."); // Ensure water tiles form connected bodies // This is a simplified version - can be enhanced for better water flow for (int x = 0; x < fullMapWidth; x++) { for (int y = 0; y < fullMapHeight; y++) { MapTile tile = fullMapData.GetTile(x, y); if (tile != null && tile.IsWater()) { // Ensure isolated water tiles have proper connections EnsureWaterConnection(x, y); } } } } /// /// Ensure water tile has proper connections to other water /// private void EnsureWaterConnection(int x, int y) { // Count water neighbors int waterNeighbors = 0; for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { if (dx == 0 && dy == 0) continue; if (IsValidExplorationPosition(x + dx, y + dy)) { MapTile neighbor = fullMapData.GetTile(x + dx, y + dy); if (neighbor != null && neighbor.IsWater()) { waterNeighbors++; } } } } // If isolated water tile, convert to land or extend water if (waterNeighbors == 0) { MapTile tile = fullMapData.GetTile(x, y); if (tile != null) { // Convert single water tiles to plains to prevent isolated lakes tile.terrainType = TerrainType.Plains; } } } /// /// Reveal the initial area around the map center /// private void RevealInitialArea() { int centerX = fullMapWidth / 2; int centerY = fullMapHeight / 2; int halfSize = initialVisibleSize / 2; for (int x = centerX - halfSize; x < centerX + halfSize; x++) { for (int y = centerY - halfSize; y < centerY + halfSize; y++) { if (IsValidExplorationPosition(x, y)) { exploredMask[x, y] = true; } } } // Ensure we have at least one settlement in the initial area EnsureSettlementsInInitialArea(centerX, centerY, halfSize); Debug.Log($"🔍 Initial area revealed: {initialVisibleSize}x{initialVisibleSize} around center ({centerX}, {centerY})"); } /// /// Get the correct initial team position in visible map coordinates /// public Vector2Int GetInitialTeamPosition() { // The team should be placed at the center of the visible map // Since we start with the full map center revealed, and the visible map shows just the explored area Rect exploredBounds = GetExploredBounds(); int centerX = fullMapWidth / 2; int centerY = fullMapHeight / 2; // Convert full map center to visible map coordinates Vector2Int visiblePosition = new Vector2Int( centerX - (int)exploredBounds.x, centerY - (int)exploredBounds.y ); Debug.Log($"🎯 Initial team position: Full({centerX}, {centerY}) → Visible({visiblePosition.x}, {visiblePosition.y})"); return visiblePosition; } /// /// Ensure there are settlements in the initial revealed area /// private void EnsureSettlementsInInitialArea(int centerX, int centerY, int halfSize) { // Check if there are already settlements in the initial area bool hasSettlements = false; var allSettlements = new List(); allSettlements.AddRange(fullMapData.GetTowns()); allSettlements.AddRange(fullMapData.GetVillages()); foreach (var settlement in allSettlements) { if (settlement.position.x >= centerX - halfSize && settlement.position.x < centerX + halfSize && settlement.position.y >= centerY - halfSize && settlement.position.y < centerY + halfSize) { hasSettlements = true; break; } } // If no settlements in initial area, place one near the center if (!hasSettlements) { Debug.Log("⚠️ No settlements in initial area, creating one..."); // Find a good spot for a settlement near the center Vector2Int settlementPos = FindSuitableSettlementPosition(centerX, centerY, halfSize - 5); if (settlementPos != Vector2Int.zero) { Settlement newSettlement = new Settlement("Starting Village", SettlementType.Village, settlementPos); fullMapData.AddSettlement(newSettlement); Debug.Log($"🏘️ Created starting settlement at ({settlementPos.x}, {settlementPos.y})"); } } } /// /// Find a suitable position for a settlement within the given area /// private Vector2Int FindSuitableSettlementPosition(int centerX, int centerY, int searchRadius) { for (int radius = 5; radius <= searchRadius; radius += 5) { for (int angle = 0; angle < 360; angle += 45) { float radians = angle * Mathf.Deg2Rad; int x = centerX + (int)(radius * Mathf.Cos(radians)); int y = centerY + (int)(radius * Mathf.Sin(radians)); if (IsValidExplorationPosition(x, y)) { MapTile tile = fullMapData.GetTile(x, y); if (tile != null && !tile.IsWater()) { return new Vector2Int(x, y); } } } } // If no suitable position found, use center as fallback return new Vector2Int(centerX, centerY); } /// /// Check if exploration should be triggered based on player position /// public bool ShouldExplore(Vector2 playerPosition, MapData currentMapData) { // Check cooldown first if (Time.time - lastExplorationTime < explorationCooldown) { return false; } // Convert player position to full map coordinates Vector2Int playerFullMapPos = GetPlayerPositionInFullMap(playerPosition, currentMapData); // Check distance to unexplored edges bool shouldExplore = IsNearUnexploredEdge(playerFullMapPos); if (shouldExplore) { Debug.Log($"✅ Exploration triggered! Player at {playerFullMapPos} near unexplored edge"); } return shouldExplore; } /// /// Reveal new areas around the player position /// public void ExploreNewAreas(Vector2 playerPosition, MapData currentMapData) { // Set exploration cooldown lastExplorationTime = Time.time; Vector2Int playerFullMapPos = GetPlayerPositionInFullMap(playerPosition, currentMapData); Debug.Log($"🔍 Exploring new areas around player position {playerFullMapPos}"); // Determine which direction to explore ExplorationDirection direction = GetExplorationDirection(playerFullMapPos); // Reveal new chunk in that direction RevealChunk(playerFullMapPos, direction); // Update the visible map UpdateVisibleMap(); } /// /// Convert player position from current map to full map coordinates /// private Vector2Int GetPlayerPositionInFullMap(Vector2 playerPosition, MapData currentMapData) { // Find the offset of the current visible area within the full map Vector2Int visibleOffset = GetCurrentVisibleOffset(currentMapData); // Ensure player position is valid within current map bounds int clampedX = Mathf.Clamp((int)playerPosition.x, 0, currentMapData.Width - 1); int clampedY = Mathf.Clamp((int)playerPosition.y, 0, currentMapData.Height - 1); Vector2Int fullMapPos = new Vector2Int( visibleOffset.x + clampedX, visibleOffset.y + clampedY ); return fullMapPos; } /// /// Get the offset of the current visible area within the full map /// private Vector2Int GetCurrentVisibleOffset(MapData currentMapData) { // Find the bounds of the explored area Rect exploredBounds = GetExploredBounds(); Vector2Int offset = new Vector2Int((int)exploredBounds.x, (int)exploredBounds.y); return offset; } /// /// Check if player is near an unexplored edge /// private bool IsNearUnexploredEdge(Vector2Int playerPos) { // Validate player position is within full map bounds if (!IsValidExplorationPosition(playerPos.x, playerPos.y)) { Debug.LogWarning($"⚠️ Player position {playerPos} is outside full map bounds!"); return false; } // First check: Is player near the edge of the currently explored area? Rect exploredBounds = GetExploredBounds(); // Calculate distances to each edge of explored area float distToLeft = playerPos.x - exploredBounds.x; float distToRight = (exploredBounds.x + exploredBounds.width - 1) - playerPos.x; float distToBottom = playerPos.y - exploredBounds.y; float distToTop = (exploredBounds.y + exploredBounds.height - 1) - playerPos.y; float minDistToExploredEdge = Mathf.Min(distToLeft, distToRight, distToBottom, distToTop); if (minDistToExploredEdge <= explorationDistance) { Debug.Log($"🎯 Player at {playerPos} is {minDistToExploredEdge} tiles from explored edge - triggering exploration!"); return true; } // Second check: Look for unexplored areas within exploration distance for (int dx = -(int)explorationDistance; dx <= explorationDistance; dx++) { for (int dy = -(int)explorationDistance; dy <= explorationDistance; dy++) { int checkX = playerPos.x + dx; int checkY = playerPos.y + dy; if (IsValidExplorationPosition(checkX, checkY) && !exploredMask[checkX, checkY]) { Debug.Log($"🎯 Found unexplored area at ({checkX}, {checkY}) near player {playerPos}"); return true; } } } return false; } /// /// Determine which direction to explore based on player position /// private ExplorationDirection GetExplorationDirection(Vector2Int playerPos) { // Find the closest unexplored edge float minDistance = float.MaxValue; ExplorationDirection closestDirection = ExplorationDirection.North; // Check each direction float northDist = CheckDirectionDistance(playerPos, ExplorationDirection.North); float southDist = CheckDirectionDistance(playerPos, ExplorationDirection.South); float eastDist = CheckDirectionDistance(playerPos, ExplorationDirection.East); float westDist = CheckDirectionDistance(playerPos, ExplorationDirection.West); // Find the minimum distance if (northDist <= minDistance) { minDistance = northDist; closestDirection = ExplorationDirection.North; } if (southDist <= minDistance) { minDistance = southDist; closestDirection = ExplorationDirection.South; } if (eastDist <= minDistance) { minDistance = eastDist; closestDirection = ExplorationDirection.East; } if (westDist <= minDistance) { minDistance = westDist; closestDirection = ExplorationDirection.West; } Debug.Log($"🧭 Exploration direction: {closestDirection} (N:{northDist:F0}, S:{southDist:F0}, E:{eastDist:F0}, W:{westDist:F0})"); return closestDirection; } private float CheckDirectionDistance(Vector2Int playerPos, ExplorationDirection direction) { Vector2Int checkPos = playerPos; float distance = 0; // Move in the specified direction until we hit unexplored area Vector2Int dirVector = GetDirectionVector(direction); while (IsValidExplorationPosition(checkPos.x, checkPos.y) && exploredMask[checkPos.x, checkPos.y]) { checkPos += dirVector; distance++; // Safety check to prevent infinite loops if (distance > 100) { Debug.LogWarning($"⚠️ Direction check exceeded 100 steps for {direction}, breaking"); break; } } return distance; } private Vector2Int GetDirectionVector(ExplorationDirection direction) { switch (direction) { case ExplorationDirection.North: return new Vector2Int(0, 1); case ExplorationDirection.South: return new Vector2Int(0, -1); case ExplorationDirection.East: return new Vector2Int(1, 0); case ExplorationDirection.West: return new Vector2Int(-1, 0); default: return Vector2Int.zero; } } /// /// Reveal a chunk of the map in the specified direction /// private void RevealChunk(Vector2Int playerPos, ExplorationDirection direction) { Vector2Int chunkCenter = GetChunkCenterForDirection(playerPos, direction); int halfChunk = explorationChunkSize / 2; for (int x = chunkCenter.x - halfChunk; x < chunkCenter.x + halfChunk; x++) { for (int y = chunkCenter.y - halfChunk; y < chunkCenter.y + halfChunk; y++) { if (IsValidExplorationPosition(x, y)) { exploredMask[x, y] = true; } } } Debug.Log($"✅ Revealed {explorationChunkSize}x{explorationChunkSize} chunk at {chunkCenter} in direction {direction}"); } private Vector2Int GetChunkCenterForDirection(Vector2Int playerPos, ExplorationDirection direction) { switch (direction) { case ExplorationDirection.North: return new Vector2Int(playerPos.x, playerPos.y + explorationChunkSize); case ExplorationDirection.South: return new Vector2Int(playerPos.x, playerPos.y - explorationChunkSize); case ExplorationDirection.East: return new Vector2Int(playerPos.x + explorationChunkSize, playerPos.y); case ExplorationDirection.West: return new Vector2Int(playerPos.x - explorationChunkSize, playerPos.y); default: return playerPos; } } /// /// Update the visible map data based on explored areas /// private void UpdateVisibleMap() { if (performanceMode) { UpdateVisibleMapOptimized(); } else { UpdateVisibleMapStandard(); } } /// /// Standard map update for smaller maps /// private void UpdateVisibleMapStandard() { // Find the bounds of the explored area Rect exploredBounds = GetExploredBounds(); // Create new map data for the visible area int visibleWidth = (int)exploredBounds.width; int visibleHeight = (int)exploredBounds.height; MapData newVisibleMap = new MapData(visibleWidth, visibleHeight); // Copy explored tiles to the visible map for (int x = 0; x < visibleWidth; x++) { for (int y = 0; y < visibleHeight; y++) { int fullMapX = (int)exploredBounds.x + x; int fullMapY = (int)exploredBounds.y + y; if (IsValidExplorationPosition(fullMapX, fullMapY) && exploredMask[fullMapX, fullMapY]) { MapTile sourceTile = fullMapData.GetTile(fullMapX, fullMapY); MapTile destTile = newVisibleMap.GetTile(x, y); if (sourceTile != null && destTile != null) { CopyTileData(sourceTile, destTile); } } } } // Copy settlements from the full map to the visible map (adjusted coordinates) CopySettlementsToVisibleMap(newVisibleMap, exploredBounds); // Update the map maker's current map data mapMaker.SetMapData(newVisibleMap); // Fix team marker position after map bounds change FixTeamMarkerPosition(exploredBounds); Debug.Log($"🗺️ Updated visible map: {visibleWidth}x{visibleHeight}"); // Debug settlement count int townCount = newVisibleMap.GetTowns().Count; int villageCount = newVisibleMap.GetVillages().Count; Debug.Log($"🏘️ Visible settlements: {townCount} towns, {villageCount} villages"); } /// /// Optimized map update for large maps using Level of Detail /// private void UpdateVisibleMapOptimized() { Debug.Log($"⚡ Using optimized map update with LOD level {lodLevel}..."); // Find the bounds of the explored area Rect exploredBounds = GetExploredBounds(); // Calculate downsampled dimensions int visibleWidth = (int)exploredBounds.width / lodLevel; int visibleHeight = (int)exploredBounds.height / lodLevel; // Ensure minimum size visibleWidth = Mathf.Max(visibleWidth, 50); visibleHeight = Mathf.Max(visibleHeight, 50); MapData newVisibleMap = new MapData(visibleWidth, visibleHeight); // Copy tiles with Level of Detail sampling for (int x = 0; x < visibleWidth; x++) { for (int y = 0; y < visibleHeight; y++) { // Sample from the full map using LOD int fullMapX = (int)exploredBounds.x + (x * lodLevel); int fullMapY = (int)exploredBounds.y + (y * lodLevel); if (IsValidExplorationPosition(fullMapX, fullMapY) && exploredMask[fullMapX, fullMapY]) { // Average surrounding tiles for better representation MapTile sampledTile = SampleTileWithLOD(fullMapX, fullMapY, lodLevel); MapTile destTile = newVisibleMap.GetTile(x, y); if (sampledTile != null && destTile != null) { CopyTileData(sampledTile, destTile); } } } } // Copy settlements with adjusted coordinates for LOD CopySettlementsToVisibleMapLOD(newVisibleMap, exploredBounds, lodLevel); // Update the map maker's current map data mapMaker.SetMapData(newVisibleMap); // Fix team marker position with LOD adjustment FixTeamMarkerPositionLOD(exploredBounds, lodLevel); Debug.Log($"⚡ Optimized visible map updated: {visibleWidth}x{visibleHeight} (LOD {lodLevel})"); } /// /// Sample a tile from the full map using Level of Detail /// private MapTile SampleTileWithLOD(int centerX, int centerY, int sampleSize) { List sampleTiles = new List(); // Collect tiles in the sample area for (int dx = 0; dx < sampleSize && dx + centerX < fullMapWidth; dx++) { for (int dy = 0; dy < sampleSize && dy + centerY < fullMapHeight; dy++) { MapTile tile = fullMapData.GetTile(centerX + dx, centerY + dy); if (tile != null && exploredMask[centerX + dx, centerY + dy]) { sampleTiles.Add(tile); } } } if (sampleTiles.Count == 0) return fullMapData.GetTile(centerX, centerY); // Return the most common terrain type in the sample var terrainGroups = sampleTiles.GroupBy(t => t.terrainType); var mostCommonTerrain = terrainGroups.OrderByDescending(g => g.Count()).First().Key; // Create a representative tile MapTile representativeTile = fullMapData.GetTile(centerX, centerY); if (representativeTile != null) { representativeTile.terrainType = mostCommonTerrain; representativeTile.height = sampleTiles.Average(t => t.height); } return representativeTile; } /// /// Copy settlements to visible map with LOD adjustment /// private void CopySettlementsToVisibleMapLOD(MapData visibleMap, Rect exploredBounds, int lod) { var fullTowns = fullMapData.GetTowns(); var fullVillages = fullMapData.GetVillages(); foreach (var town in fullTowns) { if (town.position.x >= exploredBounds.x && town.position.x < exploredBounds.x + exploredBounds.width && town.position.y >= exploredBounds.y && town.position.y < exploredBounds.y + exploredBounds.height) { Vector2Int adjustedPos = new Vector2Int( (town.position.x - (int)exploredBounds.x) / lod, (town.position.y - (int)exploredBounds.y) / lod ); Settlement adjustedTown = new Settlement(town.name, town.Type, adjustedPos); visibleMap.AddSettlement(adjustedTown); } } foreach (var village in fullVillages) { if (village.position.x >= exploredBounds.x && village.position.x < exploredBounds.x + exploredBounds.width && village.position.y >= exploredBounds.y && village.position.y < exploredBounds.y + exploredBounds.height) { Vector2Int adjustedPos = new Vector2Int( (village.position.x - (int)exploredBounds.x) / lod, (village.position.y - (int)exploredBounds.y) / lod ); Settlement adjustedVillage = new Settlement(village.name, village.Type, adjustedPos); visibleMap.AddSettlement(adjustedVillage); } } } /// /// Fix team marker position with LOD adjustment /// private void FixTeamMarkerPositionLOD(Rect exploredBounds, int lod) { SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) return; GameObject teamMarker = GameObject.Find("TeamMarker"); if (teamMarker == null) return; Vector3 currentWorldPos = teamMarker.transform.position; // Convert to LOD-adjusted coordinates Vector2Int newTilePos = new Vector2Int( Mathf.RoundToInt(currentWorldPos.x) / lod, Mathf.RoundToInt(currentWorldPos.y) / lod ); int visibleWidth = (int)exploredBounds.width / lod; int visibleHeight = (int)exploredBounds.height / lod; newTilePos.x = Mathf.Clamp(newTilePos.x, 0, visibleWidth - 1); newTilePos.y = Mathf.Clamp(newTilePos.y, 0, visibleHeight - 1); teamPlacement.UpdateMarkerAfterMapChange(newTilePos); Debug.Log($"⚡ Fixed team marker with LOD {lod}: World({currentWorldPos.x:F1}, {currentWorldPos.y:F1}) → Tile({newTilePos.x}, {newTilePos.y})"); } /// /// Fix team marker position after map bounds change /// private void FixTeamMarkerPosition(Rect exploredBounds) { SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) return; // Get the team marker GameObject to preserve world position GameObject teamMarker = GameObject.Find("TeamMarker"); if (teamMarker == null) return; // Get current world position Vector3 currentWorldPos = teamMarker.transform.position; // Convert world position to new tile coordinates // Assuming 1 unit = 1 tile (adjust if your tile scale is different) Vector2Int newTilePos = new Vector2Int( Mathf.RoundToInt(currentWorldPos.x), Mathf.RoundToInt(currentWorldPos.y) ); // Ensure the position is within the new visible map bounds int visibleWidth = (int)exploredBounds.width; int visibleHeight = (int)exploredBounds.height; newTilePos.x = Mathf.Clamp(newTilePos.x, 0, visibleWidth - 1); newTilePos.y = Mathf.Clamp(newTilePos.y, 0, visibleHeight - 1); // Update the team placement with the corrected position teamPlacement.UpdateMarkerAfterMapChange(newTilePos); Debug.Log($"🔧 Fixed team marker: World({currentWorldPos.x:F1}, {currentWorldPos.y:F1}) → Tile({newTilePos.x}, {newTilePos.y})"); } /// /// Copy settlements from full map to visible map, adjusting coordinates /// private void CopySettlementsToVisibleMap(MapData visibleMap, Rect exploredBounds) { // Get settlements from full map var fullTowns = fullMapData.GetTowns(); var fullVillages = fullMapData.GetVillages(); foreach (var town in fullTowns) { // Check if settlement is within explored bounds if (town.position.x >= exploredBounds.x && town.position.x < exploredBounds.x + exploredBounds.width && town.position.y >= exploredBounds.y && town.position.y < exploredBounds.y + exploredBounds.height) { // Adjust coordinates to visible map Vector2Int adjustedPos = new Vector2Int( town.position.x - (int)exploredBounds.x, town.position.y - (int)exploredBounds.y ); // Create new settlement with adjusted position Settlement adjustedTown = new Settlement(town.name, town.Type, adjustedPos); visibleMap.AddSettlement(adjustedTown); } } foreach (var village in fullVillages) { // Check if settlement is within explored bounds if (village.position.x >= exploredBounds.x && village.position.x < exploredBounds.x + exploredBounds.width && village.position.y >= exploredBounds.y && village.position.y < exploredBounds.y + exploredBounds.height) { // Adjust coordinates to visible map Vector2Int adjustedPos = new Vector2Int( village.position.x - (int)exploredBounds.x, village.position.y - (int)exploredBounds.y ); // Create new settlement with adjusted position Settlement adjustedVillage = new Settlement(village.name, village.Type, adjustedPos); visibleMap.AddSettlement(adjustedVillage); } } } private Rect GetExploredBounds() { int minX = fullMapWidth, maxX = 0; int minY = fullMapHeight, maxY = 0; for (int x = 0; x < fullMapWidth; x++) { for (int y = 0; y < fullMapHeight; y++) { if (exploredMask[x, y]) { minX = Mathf.Min(minX, x); maxX = Mathf.Max(maxX, x); minY = Mathf.Min(minY, y); maxY = Mathf.Max(maxY, y); } } } return new Rect(minX, minY, maxX - minX + 1, maxY - minY + 1); } /// /// Public method to get explored bounds for camera positioning /// public Rect GetExploredBoundsForCamera() { return GetExploredBounds(); } /// /// Update team marker position to account for new visible map coordinates /// private void UpdateTeamMarkerPosition(Rect exploredBounds) { // Get the SimpleTeamPlacement instance SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) { Debug.LogWarning("⚠️ SimpleTeamPlacement not found - cannot update team marker position"); return; } // Get current team position in full map coordinates Vector2Int currentFullMapPos = GetCurrentTeamPositionInFullMap(); if (currentFullMapPos == Vector2Int.zero) { Debug.LogWarning("⚠️ Could not determine current team position in full map"); return; } // Convert full map position to new visible map coordinates Vector2Int newVisiblePos = new Vector2Int( currentFullMapPos.x - (int)exploredBounds.x, currentFullMapPos.y - (int)exploredBounds.y ); // Validate the new position is within visible bounds if (newVisiblePos.x >= 0 && newVisiblePos.x < exploredBounds.width && newVisiblePos.y >= 0 && newVisiblePos.y < exploredBounds.height) { // Update the team marker position teamPlacement.UpdateMarkerAfterMapChange(newVisiblePos); Debug.Log($"🎯 Updated team marker from full map pos {currentFullMapPos} to visible pos {newVisiblePos}"); } else { Debug.LogWarning($"⚠️ Calculated team position {newVisiblePos} is outside visible bounds {exploredBounds}"); } } /// /// Get current team position in full map coordinates /// private Vector2Int GetCurrentTeamPositionInFullMap() { // Try to get team position from SimpleTeamPlacement SimpleTeamPlacement teamPlacement = Object.FindFirstObjectByType(); if (teamPlacement == null) return Vector2Int.zero; // Get current visible map position Vector2Int currentVisiblePos = teamPlacement.GetCurrentTeamPosition(); if (currentVisiblePos == Vector2Int.zero) return Vector2Int.zero; // Convert to full map coordinates Vector2Int visibleOffset = GetCurrentVisibleOffset(mapMaker.GetMapData()); Vector2Int fullMapPos = new Vector2Int( visibleOffset.x + currentVisiblePos.x, visibleOffset.y + currentVisiblePos.y ); return fullMapPos; } /// /// Copy tile data from source to destination /// private void CopyTileData(MapTile source, MapTile destination) { destination.terrainType = source.terrainType; destination.height = source.height; destination.isWalkable = source.isWalkable; destination.featureType = source.featureType; destination.name = source.name; // Copy any other tile properties as needed } private bool IsValidExplorationPosition(int x, int y) { return x >= 0 && x < fullMapWidth && y >= 0 && y < fullMapHeight; } /// /// Get exploration progress information /// public ExplorationInfo GetExplorationInfo() { int exploredTiles = 0; for (int x = 0; x < fullMapWidth; x++) { for (int y = 0; y < fullMapHeight; y++) { if (exploredMask[x, y]) exploredTiles++; } } int totalTiles = fullMapWidth * fullMapHeight; float explorationPercentage = (float)exploredTiles / totalTiles * 100f; return new ExplorationInfo { exploredTiles = exploredTiles, totalTiles = totalTiles, explorationPercentage = explorationPercentage, fullMapSize = new Vector2Int(fullMapWidth, fullMapHeight) }; } /// /// DEBUG: Get detailed exploration info for debugging /// public void DebugExplorationState(Vector2 playerPos, MapData currentMapData) { Vector2Int playerFullMapPos = GetPlayerPositionInFullMap(playerPos, currentMapData); Rect exploredBounds = GetExploredBounds(); Debug.Log("=== EXPLORATION DEBUG ==="); Debug.Log($"Player Visible Pos: {playerPos}"); Debug.Log($"Player Full Map Pos: {playerFullMapPos}"); Debug.Log($"Explored Bounds: {exploredBounds}"); Debug.Log($"Current Map Size: {currentMapData.Width}x{currentMapData.Height}"); Debug.Log($"Full Map Size: {fullMapWidth}x{fullMapHeight}"); // Check distances to edges float distToLeft = playerFullMapPos.x - exploredBounds.x; float distToRight = (exploredBounds.x + exploredBounds.width - 1) - playerFullMapPos.x; float distToBottom = playerFullMapPos.y - exploredBounds.y; float distToTop = (exploredBounds.y + exploredBounds.height - 1) - playerFullMapPos.y; Debug.Log($"Distance to edges - Left: {distToLeft}, Right: {distToRight}, Bottom: {distToBottom}, Top: {distToTop}"); Debug.Log($"Exploration Distance Threshold: {explorationDistance}"); Debug.Log($"Should Explore: {IsNearUnexploredEdge(playerFullMapPos)}"); Debug.Log($"Last Exploration Time: {lastExplorationTime}, Current Time: {Time.time}, Cooldown: {explorationCooldown}"); Debug.Log("========================"); } public enum ExplorationDirection { North, South, East, West } } /// /// Information about exploration progress /// public struct ExplorationInfo { public int exploredTiles; public int totalTiles; public float explorationPercentage; public Vector2Int fullMapSize; }