using UnityEngine; using System.Collections.Generic; public class MapVisualizer : MonoBehaviour { [Header("Terrain Sprites")] public Sprite defaultSprite; // Default square sprite public Sprite plainsSprite; public Sprite forestSprite; public Sprite oceanSprite; public Sprite lakeSprite; public Sprite shoreSprite; public Sprite riverSprite; public Sprite mountainSprite; public Sprite forestRiverSprite; // New hybrid sprite [Header("Feature Sprites")] public Sprite roadSprite; public Sprite bridgeSprite; public Sprite tunnelSprite; public Sprite harbourSprite; public Sprite townSprite; public Sprite villageSprite; [Header("Settings")] public float tileSize = 1f; public Transform mapParent; private Dictionary terrainTiles = new Dictionary(); private Dictionary featureTiles = new Dictionary(); private Sprite generatedDefaultSprite; // Generated sprite for fallback void Start() { if (mapParent == null) { GameObject mapContainer = new GameObject("MapContainer"); mapParent = mapContainer.transform; } // Create a default white square sprite if none exist CreateDefaultSprite(); } private void CreateDefaultSprite() { // Create a simple white square texture if defaultSprite is not assigned if (generatedDefaultSprite == null) { Texture2D texture = new Texture2D(32, 32); Color[] pixels = new Color[32 * 32]; for (int i = 0; i < pixels.Length; i++) { pixels[i] = Color.white; } texture.SetPixels(pixels); texture.Apply(); // Use 32 pixels per unit instead of 100 to make tiles bigger generatedDefaultSprite = Sprite.Create(texture, new Rect(0, 0, 32, 32), new Vector2(0.5f, 0.5f), 32f); } } public void VisualizeMap(MapData mapData) { // Clear existing tiles that are out of bounds ClearOutOfBoundsTiles(mapData); // Generate visual tiles for the map for (int x = 0; x < mapData.Width; x++) { for (int y = 0; y < mapData.Height; y++) { Vector2Int pos = new Vector2Int(x, y); MapTile tile = mapData.GetTile(x, y); // Create or update terrain tile CreateOrUpdateTerrainTile(pos, tile); // Create or update feature tile CreateOrUpdateFeatureTile(pos, tile); } } // Position camera to see the map PositionCameraToMap(mapData); } private void PositionCameraToMap(MapData mapData) { Camera mainCam = Camera.main; if (mainCam != null) { // Check if we're in exploration mode and need to account for world coordinate offset Vector3 mapCenter; // Try to get exploration manager from MapMaker2 to determine proper camera positioning MapMaker2 mapMaker = Object.FindFirstObjectByType(); if (mapMaker != null && mapMaker.useExplorationSystem) { var explorationManager = mapMaker.GetExplorationManager(); if (explorationManager != null) { // Get the explored bounds to find the actual world coordinate center var bounds = explorationManager.GetExploredBoundsForCamera(); // Center camera on the actual world coordinates of the explored area mapCenter = new Vector3( (bounds.x + bounds.width / 2f) * tileSize, (bounds.y + bounds.height / 2f) * tileSize, mainCam.transform.position.z ); Debug.Log($"🎥 Camera positioned for exploration: bounds({bounds.x}, {bounds.y}, {bounds.width}, {bounds.height}) → center({mapCenter.x:F1}, {mapCenter.y:F1})"); } else { // Fallback to standard positioning mapCenter = new Vector3( (mapData.Width * tileSize) / 2f, (mapData.Height * tileSize) / 2f, mainCam.transform.position.z ); } } else { // Standard positioning for non-exploration mode mapCenter = new Vector3( (mapData.Width * tileSize) / 2f, (mapData.Height * tileSize) / 2f, mainCam.transform.position.z ); } mainCam.transform.position = mapCenter; // Adjust orthographic size to fit map - make it bigger so you can zoom out more if (mainCam.orthographic) { float mapHeight = mapData.Height * tileSize; float mapWidth = mapData.Width * tileSize; float aspectRatio = (float)Screen.width / Screen.height; float requiredHeight = mapHeight / 2f; float requiredWidth = mapWidth / (2f * aspectRatio); // Increased the padding and base size for better zoom out capability mainCam.orthographicSize = Mathf.Max(requiredHeight, requiredWidth, 80f) + 20f; } } } /// /// Calculate world position for a tile, accounting for exploration bounds offset /// private Vector3 CalculateWorldPosition(Vector2Int visiblePos) { // Try to get exploration manager to determine world coordinate offset MapMaker2 mapMaker = Object.FindFirstObjectByType(); if (mapMaker != null && mapMaker.useExplorationSystem) { var explorationManager = mapMaker.GetExplorationManager(); if (explorationManager != null) { // Get the explored bounds to find the world coordinate offset var bounds = explorationManager.GetExploredBoundsForCamera(); // Convert visible coordinates to world coordinates Vector3 worldPos = new Vector3( (bounds.x + visiblePos.x) * tileSize, (bounds.y + visiblePos.y) * tileSize, 0 ); // Debug log for the first few tiles to verify positioning if (visiblePos.x < 3 && visiblePos.y < 3) { Debug.Log($"🔧 Tile positioning: visible({visiblePos.x}, {visiblePos.y}) + bounds({bounds.x}, {bounds.y}) → world({worldPos.x:F1}, {worldPos.y:F1})"); } return worldPos; } } // Fallback to direct positioning for non-exploration mode return new Vector3(visiblePos.x * tileSize, visiblePos.y * tileSize, 0); } private void ClearOutOfBoundsTiles(MapData mapData) { List tilesToRemove = new List(); // Check terrain tiles foreach (var kvp in terrainTiles) { if (kvp.Key.x >= mapData.Width || kvp.Key.y >= mapData.Height || kvp.Key.x < 0 || kvp.Key.y < 0) { tilesToRemove.Add(kvp.Key); } } foreach (var pos in tilesToRemove) { if (terrainTiles[pos] != null) DestroyImmediate(terrainTiles[pos]); terrainTiles.Remove(pos); } tilesToRemove.Clear(); // Check feature tiles foreach (var kvp in featureTiles) { if (kvp.Key.x >= mapData.Width || kvp.Key.y >= mapData.Height || kvp.Key.x < 0 || kvp.Key.y < 0) { tilesToRemove.Add(kvp.Key); } } foreach (var pos in tilesToRemove) { if (featureTiles[pos] != null) DestroyImmediate(featureTiles[pos]); featureTiles.Remove(pos); } } private void CreateOrUpdateTerrainTile(Vector2Int pos, MapTile tile) { GameObject tileObject; if (!terrainTiles.ContainsKey(pos)) { // Create new tile tileObject = new GameObject($"Terrain_{pos.x}_{pos.y}"); tileObject.transform.parent = mapParent; // Calculate world position accounting for exploration bounds offset Vector3 worldPosition = CalculateWorldPosition(pos); tileObject.transform.position = worldPosition; SpriteRenderer sr = tileObject.AddComponent(); sr.sortingOrder = 0; // Scale the tile to make it visible tileObject.transform.localScale = Vector3.one * tileSize; terrainTiles[pos] = tileObject; } else { tileObject = terrainTiles[pos]; } // Update sprite and color based on terrain type SpriteRenderer spriteRenderer = tileObject.GetComponent(); // Use assigned sprite or fallback to default sprite Sprite terrainSprite = GetTerrainSprite(tile.terrainType); spriteRenderer.sprite = terrainSprite != null ? terrainSprite : (defaultSprite != null ? defaultSprite : generatedDefaultSprite); spriteRenderer.color = GetTerrainColor(tile.terrainType); // For ForestRiver tiles, add a simple river overlay if no custom sprite is provided if (tile.terrainType == TerrainType.ForestRiver && forestRiverSprite == null) { CreateSimpleForestRiverEffect(tileObject); } } private void CreateOrUpdateFeatureTile(Vector2Int pos, MapTile tile) { if (tile.featureType == FeatureType.None) { // Remove feature tile if it exists if (featureTiles.ContainsKey(pos)) { if (featureTiles[pos] != null) DestroyImmediate(featureTiles[pos]); featureTiles.Remove(pos); } return; } GameObject featureObject; if (!featureTiles.ContainsKey(pos)) { // Create new feature tile featureObject = new GameObject($"Feature_{pos.x}_{pos.y}_{tile.featureType}"); featureObject.transform.parent = mapParent; // Calculate world position accounting for exploration bounds offset Vector3 worldPosition = CalculateWorldPosition(pos); featureObject.transform.position = worldPosition; SpriteRenderer sr = featureObject.AddComponent(); sr.sortingOrder = 1; // Above terrain // Scale the tile to make it visible featureObject.transform.localScale = Vector3.one * tileSize; featureTiles[pos] = featureObject; } else { featureObject = featureTiles[pos]; } // Update sprite and color based on feature type SpriteRenderer spriteRenderer = featureObject.GetComponent(); // Use assigned sprite or fallback sprite Sprite featureSprite = GetFeatureSprite(tile.featureType); spriteRenderer.sprite = featureSprite != null ? featureSprite : (defaultSprite != null ? defaultSprite : generatedDefaultSprite); spriteRenderer.color = GetFeatureColor(tile.featureType); } private Sprite GetTerrainSprite(TerrainType terrainType) { return terrainType switch { TerrainType.Plains => plainsSprite, TerrainType.Forest => forestSprite, TerrainType.Ocean => oceanSprite, TerrainType.Lake => lakeSprite, TerrainType.Shore => shoreSprite, TerrainType.River => riverSprite, TerrainType.Mountain => mountainSprite, TerrainType.ForestRiver => forestRiverSprite != null ? forestRiverSprite : riverSprite, _ => null }; } private Sprite GetFeatureSprite(FeatureType featureType) { return featureType switch { FeatureType.Road => roadSprite, FeatureType.Bridge => bridgeSprite, FeatureType.Tunnel => tunnelSprite, FeatureType.Harbour => harbourSprite, FeatureType.Ferry => roadSprite, // Use road sprite for ferry routes (will be colored differently) FeatureType.Town => townSprite, FeatureType.Village => villageSprite, _ => null }; } private Color GetTerrainColor(TerrainType terrainType) { return terrainType switch { TerrainType.Plains => new Color(0.6f, 0.8f, 0.4f), // Light green TerrainType.Forest => new Color(0.2f, 0.6f, 0.2f), // Dark green TerrainType.Ocean => new Color(0.2f, 0.4f, 0.8f), // Blue TerrainType.Lake => new Color(0.3f, 0.5f, 0.9f), // Light blue TerrainType.Shore => new Color(0.8f, 0.7f, 0.5f), // Sandy TerrainType.River => new Color(0.4f, 0.6f, 1f), // River blue TerrainType.Mountain => new Color(0.5f, 0.5f, 0.5f), // Gray TerrainType.ForestRiver => new Color(0.3f, 0.5f, 0.7f), // Blue-green mix _ => Color.white }; } private Color GetFeatureColor(FeatureType featureType) { return featureType switch { FeatureType.Road => new Color(0.6f, 0.4f, 0.2f), // Brown FeatureType.Bridge => new Color(0.9f, 0.8f, 0.6f), // Light tan/wood color FeatureType.Tunnel => new Color(0.3f, 0.3f, 0.3f), // Dark gray FeatureType.Harbour => new Color(0.4f, 0.3f, 0.2f), // Dark brown FeatureType.Ferry => new Color(0.7f, 0.9f, 1.0f), // Light blue/cyan for water routes FeatureType.Town => new Color(0.8f, 0.2f, 0.2f), // Red FeatureType.Village => new Color(0.9f, 0.7f, 0.3f), // Yellow _ => Color.white }; } public void ClearAllTiles() { foreach (var tile in terrainTiles.Values) { if (tile != null) DestroyImmediate(tile); } foreach (var tile in featureTiles.Values) { if (tile != null) DestroyImmediate(tile); } terrainTiles.Clear(); featureTiles.Clear(); } private void CreateSimpleForestRiverEffect(GameObject forestRiverTile) { // Create a simple blue overlay to indicate river flowing through forest GameObject riverEffect = new GameObject("RiverEffect"); riverEffect.transform.parent = forestRiverTile.transform; riverEffect.transform.localPosition = Vector3.zero; riverEffect.transform.localScale = new Vector3(0.6f, 0.6f, 1f); // Smaller than the base tile SpriteRenderer effectRenderer = riverEffect.AddComponent(); effectRenderer.sprite = defaultSprite != null ? defaultSprite : generatedDefaultSprite; effectRenderer.sortingOrder = 1; // Above the forest base effectRenderer.color = new Color(0.4f, 0.6f, 1f, 0.7f); // Semi-transparent river blue } }