| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- 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<Vector2Int, GameObject> terrainTiles = new Dictionary<Vector2Int, GameObject>();
- private Dictionary<Vector2Int, GameObject> featureTiles = new Dictionary<Vector2Int, GameObject>();
- 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<MapMaker2>();
- 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);
- // Calculate required size but don't override if camera is already zoomed out further
- float suggestedSize = Mathf.Max(requiredHeight, requiredWidth) + 20f;
- // Only set the camera size if it's smaller than what we need
- // This preserves user's zoom level while ensuring the map is initially visible
- if (mainCam.orthographicSize < suggestedSize)
- {
- mainCam.orthographicSize = suggestedSize;
- Debug.Log($"🎥 Camera zoom adjusted to fit map: {suggestedSize:F1}");
- }
- else
- {
- Debug.Log($"🎥 Camera zoom preserved: {mainCam.orthographicSize:F1} (suggested: {suggestedSize:F1})");
- }
- }
- }
- }
- /// <summary>
- /// Calculate world position for a tile, accounting for exploration bounds offset
- /// </summary>
- private Vector3 CalculateWorldPosition(Vector2Int visiblePos)
- {
- // Try to get exploration manager to determine world coordinate offset
- MapMaker2 mapMaker = Object.FindFirstObjectByType<MapMaker2>();
- 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,
- 0,
- (bounds.y + visiblePos.y) * tileSize
- );
- // 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.z:F1})");
- }
- return worldPos;
- }
- }
- // Fallback to direct positioning for non-exploration mode
- return new Vector3(visiblePos.x * tileSize, 0, visiblePos.y * tileSize);
- }
- private void ClearOutOfBoundsTiles(MapData mapData)
- {
- List<Vector2Int> tilesToRemove = new List<Vector2Int>();
- // 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<SpriteRenderer>();
- sr.sortingOrder = 0;
- // Scale the tile to make it visible
- tileObject.transform.localScale = Vector3.one * tileSize;
- // Rotate sprite to be flat on the ground for top-down view
- tileObject.transform.rotation = Quaternion.Euler(90f, 0f, 0f);
- terrainTiles[pos] = tileObject;
- }
- else
- {
- tileObject = terrainTiles[pos];
- }
- // Update sprite and color based on terrain type
- SpriteRenderer spriteRenderer = tileObject.GetComponent<SpriteRenderer>();
- // 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<SpriteRenderer>();
- sr.sortingOrder = 1; // Above terrain
- // Scale the tile to make it visible
- featureObject.transform.localScale = Vector3.one * tileSize;
- // Rotate sprite to be flat on the ground for top-down view
- featureObject.transform.rotation = Quaternion.Euler(90f, 0f, 0f);
- featureTiles[pos] = featureObject;
- }
- else
- {
- featureObject = featureTiles[pos];
- }
- // Update sprite and color based on feature type
- SpriteRenderer spriteRenderer = featureObject.GetComponent<SpriteRenderer>();
- // 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<SpriteRenderer>();
- 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
- }
- }
|