MapVisualizer.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. public class MapVisualizer : MonoBehaviour
  4. {
  5. [Header("Terrain Sprites")]
  6. public Sprite defaultSprite; // Default square sprite
  7. public Sprite plainsSprite;
  8. public Sprite forestSprite;
  9. public Sprite oceanSprite;
  10. public Sprite lakeSprite;
  11. public Sprite shoreSprite;
  12. public Sprite riverSprite;
  13. public Sprite mountainSprite;
  14. public Sprite forestRiverSprite; // New hybrid sprite
  15. [Header("Feature Sprites")]
  16. public Sprite roadSprite;
  17. public Sprite bridgeSprite;
  18. public Sprite tunnelSprite;
  19. public Sprite harbourSprite;
  20. public Sprite townSprite;
  21. public Sprite villageSprite;
  22. [Header("Settings")]
  23. public float tileSize = 1f;
  24. public Transform mapParent;
  25. private Dictionary<Vector2Int, GameObject> terrainTiles = new Dictionary<Vector2Int, GameObject>();
  26. private Dictionary<Vector2Int, GameObject> featureTiles = new Dictionary<Vector2Int, GameObject>();
  27. private Sprite generatedDefaultSprite; // Generated sprite for fallback
  28. void Start()
  29. {
  30. if (mapParent == null)
  31. {
  32. GameObject mapContainer = new GameObject("MapContainer");
  33. mapParent = mapContainer.transform;
  34. }
  35. // Create a default white square sprite if none exist
  36. CreateDefaultSprite();
  37. }
  38. private void CreateDefaultSprite()
  39. {
  40. // Create a simple white square texture if defaultSprite is not assigned
  41. if (generatedDefaultSprite == null)
  42. {
  43. Texture2D texture = new Texture2D(32, 32);
  44. Color[] pixels = new Color[32 * 32];
  45. for (int i = 0; i < pixels.Length; i++)
  46. {
  47. pixels[i] = Color.white;
  48. }
  49. texture.SetPixels(pixels);
  50. texture.Apply();
  51. // Use 32 pixels per unit instead of 100 to make tiles bigger
  52. generatedDefaultSprite = Sprite.Create(texture, new Rect(0, 0, 32, 32), new Vector2(0.5f, 0.5f), 32f);
  53. }
  54. }
  55. public void VisualizeMap(MapData mapData)
  56. {
  57. // Clear existing tiles that are out of bounds
  58. ClearOutOfBoundsTiles(mapData);
  59. // Generate visual tiles for the map
  60. for (int x = 0; x < mapData.Width; x++)
  61. {
  62. for (int y = 0; y < mapData.Height; y++)
  63. {
  64. Vector2Int pos = new Vector2Int(x, y);
  65. MapTile tile = mapData.GetTile(x, y);
  66. // Create or update terrain tile
  67. CreateOrUpdateTerrainTile(pos, tile);
  68. // Create or update feature tile
  69. CreateOrUpdateFeatureTile(pos, tile);
  70. }
  71. }
  72. // Position camera to see the map
  73. PositionCameraToMap(mapData);
  74. }
  75. private void PositionCameraToMap(MapData mapData)
  76. {
  77. Camera mainCam = Camera.main;
  78. if (mainCam != null)
  79. {
  80. // Check if we're in exploration mode and need to account for world coordinate offset
  81. Vector3 mapCenter;
  82. // Try to get exploration manager from MapMaker2 to determine proper camera positioning
  83. MapMaker2 mapMaker = Object.FindFirstObjectByType<MapMaker2>();
  84. if (mapMaker != null && mapMaker.useExplorationSystem)
  85. {
  86. var explorationManager = mapMaker.GetExplorationManager();
  87. if (explorationManager != null)
  88. {
  89. // Get the explored bounds to find the actual world coordinate center
  90. var bounds = explorationManager.GetExploredBoundsForCamera();
  91. // Center camera on the actual world coordinates of the explored area
  92. mapCenter = new Vector3(
  93. (bounds.x + bounds.width / 2f) * tileSize,
  94. (bounds.y + bounds.height / 2f) * tileSize,
  95. mainCam.transform.position.z
  96. );
  97. Debug.Log($"🎥 Camera positioned for exploration: bounds({bounds.x}, {bounds.y}, {bounds.width}, {bounds.height}) → center({mapCenter.x:F1}, {mapCenter.y:F1})");
  98. }
  99. else
  100. {
  101. // Fallback to standard positioning
  102. mapCenter = new Vector3(
  103. (mapData.Width * tileSize) / 2f,
  104. (mapData.Height * tileSize) / 2f,
  105. mainCam.transform.position.z
  106. );
  107. }
  108. }
  109. else
  110. {
  111. // Standard positioning for non-exploration mode
  112. mapCenter = new Vector3(
  113. (mapData.Width * tileSize) / 2f,
  114. (mapData.Height * tileSize) / 2f,
  115. mainCam.transform.position.z
  116. );
  117. }
  118. mainCam.transform.position = mapCenter;
  119. // Adjust orthographic size to fit map - make it bigger so you can zoom out more
  120. if (mainCam.orthographic)
  121. {
  122. float mapHeight = mapData.Height * tileSize;
  123. float mapWidth = mapData.Width * tileSize;
  124. float aspectRatio = (float)Screen.width / Screen.height;
  125. float requiredHeight = mapHeight / 2f;
  126. float requiredWidth = mapWidth / (2f * aspectRatio);
  127. // Increased the padding and base size for better zoom out capability
  128. mainCam.orthographicSize = Mathf.Max(requiredHeight, requiredWidth, 80f) + 20f;
  129. }
  130. }
  131. }
  132. /// <summary>
  133. /// Calculate world position for a tile, accounting for exploration bounds offset
  134. /// </summary>
  135. private Vector3 CalculateWorldPosition(Vector2Int visiblePos)
  136. {
  137. // Try to get exploration manager to determine world coordinate offset
  138. MapMaker2 mapMaker = Object.FindFirstObjectByType<MapMaker2>();
  139. if (mapMaker != null && mapMaker.useExplorationSystem)
  140. {
  141. var explorationManager = mapMaker.GetExplorationManager();
  142. if (explorationManager != null)
  143. {
  144. // Get the explored bounds to find the world coordinate offset
  145. var bounds = explorationManager.GetExploredBoundsForCamera();
  146. // Convert visible coordinates to world coordinates
  147. Vector3 worldPos = new Vector3(
  148. (bounds.x + visiblePos.x) * tileSize,
  149. (bounds.y + visiblePos.y) * tileSize,
  150. 0
  151. );
  152. // Debug log for the first few tiles to verify positioning
  153. if (visiblePos.x < 3 && visiblePos.y < 3)
  154. {
  155. Debug.Log($"🔧 Tile positioning: visible({visiblePos.x}, {visiblePos.y}) + bounds({bounds.x}, {bounds.y}) → world({worldPos.x:F1}, {worldPos.y:F1})");
  156. }
  157. return worldPos;
  158. }
  159. }
  160. // Fallback to direct positioning for non-exploration mode
  161. return new Vector3(visiblePos.x * tileSize, visiblePos.y * tileSize, 0);
  162. }
  163. private void ClearOutOfBoundsTiles(MapData mapData)
  164. {
  165. List<Vector2Int> tilesToRemove = new List<Vector2Int>();
  166. // Check terrain tiles
  167. foreach (var kvp in terrainTiles)
  168. {
  169. if (kvp.Key.x >= mapData.Width || kvp.Key.y >= mapData.Height ||
  170. kvp.Key.x < 0 || kvp.Key.y < 0)
  171. {
  172. tilesToRemove.Add(kvp.Key);
  173. }
  174. }
  175. foreach (var pos in tilesToRemove)
  176. {
  177. if (terrainTiles[pos] != null)
  178. DestroyImmediate(terrainTiles[pos]);
  179. terrainTiles.Remove(pos);
  180. }
  181. tilesToRemove.Clear();
  182. // Check feature tiles
  183. foreach (var kvp in featureTiles)
  184. {
  185. if (kvp.Key.x >= mapData.Width || kvp.Key.y >= mapData.Height ||
  186. kvp.Key.x < 0 || kvp.Key.y < 0)
  187. {
  188. tilesToRemove.Add(kvp.Key);
  189. }
  190. }
  191. foreach (var pos in tilesToRemove)
  192. {
  193. if (featureTiles[pos] != null)
  194. DestroyImmediate(featureTiles[pos]);
  195. featureTiles.Remove(pos);
  196. }
  197. }
  198. private void CreateOrUpdateTerrainTile(Vector2Int pos, MapTile tile)
  199. {
  200. GameObject tileObject;
  201. if (!terrainTiles.ContainsKey(pos))
  202. {
  203. // Create new tile
  204. tileObject = new GameObject($"Terrain_{pos.x}_{pos.y}");
  205. tileObject.transform.parent = mapParent;
  206. // Calculate world position accounting for exploration bounds offset
  207. Vector3 worldPosition = CalculateWorldPosition(pos);
  208. tileObject.transform.position = worldPosition;
  209. SpriteRenderer sr = tileObject.AddComponent<SpriteRenderer>();
  210. sr.sortingOrder = 0;
  211. // Scale the tile to make it visible
  212. tileObject.transform.localScale = Vector3.one * tileSize;
  213. terrainTiles[pos] = tileObject;
  214. }
  215. else
  216. {
  217. tileObject = terrainTiles[pos];
  218. }
  219. // Update sprite and color based on terrain type
  220. SpriteRenderer spriteRenderer = tileObject.GetComponent<SpriteRenderer>();
  221. // Use assigned sprite or fallback to default sprite
  222. Sprite terrainSprite = GetTerrainSprite(tile.terrainType);
  223. spriteRenderer.sprite = terrainSprite != null ? terrainSprite : (defaultSprite != null ? defaultSprite : generatedDefaultSprite);
  224. spriteRenderer.color = GetTerrainColor(tile.terrainType);
  225. // For ForestRiver tiles, add a simple river overlay if no custom sprite is provided
  226. if (tile.terrainType == TerrainType.ForestRiver && forestRiverSprite == null)
  227. {
  228. CreateSimpleForestRiverEffect(tileObject);
  229. }
  230. }
  231. private void CreateOrUpdateFeatureTile(Vector2Int pos, MapTile tile)
  232. {
  233. if (tile.featureType == FeatureType.None)
  234. {
  235. // Remove feature tile if it exists
  236. if (featureTiles.ContainsKey(pos))
  237. {
  238. if (featureTiles[pos] != null)
  239. DestroyImmediate(featureTiles[pos]);
  240. featureTiles.Remove(pos);
  241. }
  242. return;
  243. }
  244. GameObject featureObject;
  245. if (!featureTiles.ContainsKey(pos))
  246. {
  247. // Create new feature tile
  248. featureObject = new GameObject($"Feature_{pos.x}_{pos.y}_{tile.featureType}");
  249. featureObject.transform.parent = mapParent;
  250. // Calculate world position accounting for exploration bounds offset
  251. Vector3 worldPosition = CalculateWorldPosition(pos);
  252. featureObject.transform.position = worldPosition;
  253. SpriteRenderer sr = featureObject.AddComponent<SpriteRenderer>();
  254. sr.sortingOrder = 1; // Above terrain
  255. // Scale the tile to make it visible
  256. featureObject.transform.localScale = Vector3.one * tileSize;
  257. featureTiles[pos] = featureObject;
  258. }
  259. else
  260. {
  261. featureObject = featureTiles[pos];
  262. }
  263. // Update sprite and color based on feature type
  264. SpriteRenderer spriteRenderer = featureObject.GetComponent<SpriteRenderer>();
  265. // Use assigned sprite or fallback sprite
  266. Sprite featureSprite = GetFeatureSprite(tile.featureType);
  267. spriteRenderer.sprite = featureSprite != null ? featureSprite : (defaultSprite != null ? defaultSprite : generatedDefaultSprite);
  268. spriteRenderer.color = GetFeatureColor(tile.featureType);
  269. }
  270. private Sprite GetTerrainSprite(TerrainType terrainType)
  271. {
  272. return terrainType switch
  273. {
  274. TerrainType.Plains => plainsSprite,
  275. TerrainType.Forest => forestSprite,
  276. TerrainType.Ocean => oceanSprite,
  277. TerrainType.Lake => lakeSprite,
  278. TerrainType.Shore => shoreSprite,
  279. TerrainType.River => riverSprite,
  280. TerrainType.Mountain => mountainSprite,
  281. TerrainType.ForestRiver => forestRiverSprite != null ? forestRiverSprite : riverSprite,
  282. _ => null
  283. };
  284. }
  285. private Sprite GetFeatureSprite(FeatureType featureType)
  286. {
  287. return featureType switch
  288. {
  289. FeatureType.Road => roadSprite,
  290. FeatureType.Bridge => bridgeSprite,
  291. FeatureType.Tunnel => tunnelSprite,
  292. FeatureType.Harbour => harbourSprite,
  293. FeatureType.Ferry => roadSprite, // Use road sprite for ferry routes (will be colored differently)
  294. FeatureType.Town => townSprite,
  295. FeatureType.Village => villageSprite,
  296. _ => null
  297. };
  298. }
  299. private Color GetTerrainColor(TerrainType terrainType)
  300. {
  301. return terrainType switch
  302. {
  303. TerrainType.Plains => new Color(0.6f, 0.8f, 0.4f), // Light green
  304. TerrainType.Forest => new Color(0.2f, 0.6f, 0.2f), // Dark green
  305. TerrainType.Ocean => new Color(0.2f, 0.4f, 0.8f), // Blue
  306. TerrainType.Lake => new Color(0.3f, 0.5f, 0.9f), // Light blue
  307. TerrainType.Shore => new Color(0.8f, 0.7f, 0.5f), // Sandy
  308. TerrainType.River => new Color(0.4f, 0.6f, 1f), // River blue
  309. TerrainType.Mountain => new Color(0.5f, 0.5f, 0.5f), // Gray
  310. TerrainType.ForestRiver => new Color(0.3f, 0.5f, 0.7f), // Blue-green mix
  311. _ => Color.white
  312. };
  313. }
  314. private Color GetFeatureColor(FeatureType featureType)
  315. {
  316. return featureType switch
  317. {
  318. FeatureType.Road => new Color(0.6f, 0.4f, 0.2f), // Brown
  319. FeatureType.Bridge => new Color(0.9f, 0.8f, 0.6f), // Light tan/wood color
  320. FeatureType.Tunnel => new Color(0.3f, 0.3f, 0.3f), // Dark gray
  321. FeatureType.Harbour => new Color(0.4f, 0.3f, 0.2f), // Dark brown
  322. FeatureType.Ferry => new Color(0.7f, 0.9f, 1.0f), // Light blue/cyan for water routes
  323. FeatureType.Town => new Color(0.8f, 0.2f, 0.2f), // Red
  324. FeatureType.Village => new Color(0.9f, 0.7f, 0.3f), // Yellow
  325. _ => Color.white
  326. };
  327. }
  328. public void ClearAllTiles()
  329. {
  330. foreach (var tile in terrainTiles.Values)
  331. {
  332. if (tile != null) DestroyImmediate(tile);
  333. }
  334. foreach (var tile in featureTiles.Values)
  335. {
  336. if (tile != null) DestroyImmediate(tile);
  337. }
  338. terrainTiles.Clear();
  339. featureTiles.Clear();
  340. }
  341. private void CreateSimpleForestRiverEffect(GameObject forestRiverTile)
  342. {
  343. // Create a simple blue overlay to indicate river flowing through forest
  344. GameObject riverEffect = new GameObject("RiverEffect");
  345. riverEffect.transform.parent = forestRiverTile.transform;
  346. riverEffect.transform.localPosition = Vector3.zero;
  347. riverEffect.transform.localScale = new Vector3(0.6f, 0.6f, 1f); // Smaller than the base tile
  348. SpriteRenderer effectRenderer = riverEffect.AddComponent<SpriteRenderer>();
  349. effectRenderer.sprite = defaultSprite != null ? defaultSprite : generatedDefaultSprite;
  350. effectRenderer.sortingOrder = 1; // Above the forest base
  351. effectRenderer.color = new Color(0.4f, 0.6f, 1f, 0.7f); // Semi-transparent river blue
  352. }
  353. }