using SanAndreasUnity.Behaviours.Vehicles; using SanAndreasUnity.Importing.Conversion; using SanAndreasUnity.Utilities; using System; using System.Collections; using System.IO; using UnityEngine; using UnityEngine.UI; using Object = UnityEngine.Object; namespace SanAndreasUnity.Behaviours { public class MiniMap : MonoBehaviour { public const int tileEdge = 12; // width/height of map in tiles public const int tileCount = tileEdge * tileEdge; // number of tiles public const int mapEdge = 6000; // width/height of map in world coordinates public const int texSize = 128; // width/height of single tile in px public const int mapSize = tileEdge * texSize; // width/height of whole map in px public const int uiSize = 256, uiOffset = 10; public static bool toggleMap; public Image northImage, outlineImage, maskImage, mapImage; public RawImage playerImage; public RectTransform mapTransform, maskTransform, mapContainer; public Text zoneNameLabel; private Canvas _canvas; public float zoom = 1.3f; private const float scaleConst = 1f; public const float maxVelocity = 300f; public static float[] zooms = new float[10] { .5f, .75f, 1f, 1.2f, 1.4f, 1.6f, 2f, 2.5f, 3f, 5f }; // Why? [HideInInspector] [Obsolete] public float calibrator = 2.34f; public float zoomDuration = 1, mapZoomScaler = 1, mapMovement = 5; public Vector3 FocusPos { get; set; } = Vector3.zero; public bool IsMinimapVisible => _canvas.enabled && this.gameObject.activeInHierarchy; public bool debugActive = true; public static MiniMap Instance { get; private set; } private float realZoom { get { return zoom * scaleConst; } set { zoom = value / scaleConst; } } private float _timeWhenRetrievedZoneName = 0f; private string _lastZoneName = ""; private string ZoneName { get { if (Time.time - _timeWhenRetrievedZoneName > 2f) { _timeWhenRetrievedZoneName = Time.time; _lastZoneName = Zone.GetZoneName(this.FocusPos); } return _lastZoneName; } } public Texture2D NorthBlip { get { return this.northBlip; } } public Texture2D PlayerBlip { get { return this.playerBlip; } } public Texture2D WaypointTexture { get { return this.waypointTexture; } } public Texture2D VehicleTexture => this.vehicleTexture; public Texture2D GreenHouseTexture { get; private set; } public Texture2D MapTexture { get { return this.mapTexture; } } public Texture2D BlackPixel { get { return this.blackPixel; } } public Texture2D SeaPixel { get { return this.seaPixel; } } private Ped m_ped => Ped.Instance; private PlayerController m_playerController => PlayerController.Instance; private TextureDictionary huds; private Texture2D northBlip, playerBlip, waypointTexture, vehicleTexture, mapTexture; private Sprite mapSprite; public RectTransform northPivot; // Zoom vars public float curZoomPercentage; private float lastZoom; private int zoomSelector = 2; private Coroutine zoomCoroutine; // GUI Elements private Texture2D blackPixel, seaPixel; private float fAlpha = 1; private bool showZoomPanel; private float curZoom = 1; public void Load() { LoadGameTextures(); blackPixel = new Texture2D(1, 1); blackPixel.SetPixel(0, 0, new Color(0, 0, 0, .5f)); blackPixel.Apply(); seaPixel = new Texture2D(1, 1); seaPixel.SetPixel(0, 0, new Color(.45f, .54f, .678f)); seaPixel.Apply(); } private void LoadGameTextures() { mapTexture = new Texture2D(mapSize, mapSize, TextureFormat.ARGB32, false, true); TextureLoadParams textureLoadParams = new TextureLoadParams() { makeNoLongerReadable = false }; for (int i = 0; i < tileCount; i++) { // Offset int y = ((i / tileEdge) + 1) * texSize, x = (i % tileEdge) * texSize; string name = "radar" + ((i < 10) ? "0" : "") + i; var texDict = TextureDictionary.Load(name); Texture2D tex = texDict.GetDiffuse(name, textureLoadParams).Texture; for (int ii = 0; ii < texSize; ++ii) for (int jj = 0; jj < texSize; ++jj) mapTexture.SetPixel(x + ii, texSize - (y + jj) - 1, tex.GetPixel(ii, jj)); // unload the texture (don't destroy it, because it can be a dummy texture) } mapTexture.Apply(false, true); huds = TextureDictionary.Load("hud"); northBlip = huds.GetDiffuse("radar_north").Texture; playerBlip = huds.GetDiffuse("radar_centre").Texture; waypointTexture = huds.GetDiffuse("radar_waypoint").Texture; vehicleTexture = huds.GetDiffuse("radar_impound").Texture; GreenHouseTexture = huds.GetDiffuse("radar_propertyG").Texture; northImage.sprite = Sprite.Create(northBlip, new Rect(0, 0, northBlip.width, northBlip.height), new Vector2(northBlip.width, northBlip.height) / 2); playerImage.texture = this.PlayerBlip; mapSprite = Sprite.Create(mapTexture, new Rect(0, 0, mapTexture.width, mapTexture.height), new Vector2(mapTexture.width, mapTexture.height) / 2); mapImage.sprite = mapSprite; } private void Awake() { Instance = this; _canvas = this.GetComponentInParent(); curZoomPercentage = zooms[zoomSelector]; } private void ReadInput() { bool zoomIn = Input.GetKeyDown(KeyCode.N); bool zoomOut = Input.GetKeyDown(KeyCode.B); if (zoomIn) ++zoomSelector; else if (zoomOut) --zoomSelector; if (zoomIn || zoomOut) { if (zoomCoroutine != null) StopCoroutine(zoomCoroutine); zoomCoroutine = StartCoroutine(ChangeZoom(zoomIn)); } } public static Vector2 WorldPosToMapPos(Vector3 worldPos) { // map center is at (0,0) world coordinates // this, for example, means that the left edge of the world is at: -mapEdge / 2.0f // adjust world position, so that (0,0) world coordinates are mapped to (0,0) map coordinates worldPos += new Vector3(mapEdge / 2.0f, 0, mapEdge / 2.0f); float mul = mapSize / (float)mapEdge; return new Vector2(worldPos.x * mul, worldPos.z * mul); } public static Vector3 MapPosToWorldPos(Vector2 mapPos) { // adjust map position, so that (0,0) map coordinated are mapped to (0,0) world coordinates mapPos -= Vector2.one * (mapSize * 0.5f); float mul = mapEdge / (float)mapSize; return new Vector3(mapPos.x * mul, 0.0f, mapPos.y * mul); } private void LateUpdate() { if (!this.IsMinimapVisible) return; // update focus position var ped = m_ped; if (ped != null) this.FocusPos = ped.transform.position; else if (Camera.main != null) this.FocusPos = Camera.main.transform.position; // update zoom based on ped's velocity var playerController = m_playerController; if (playerController != null) realZoom = Mathf.Lerp(.9f * scaleConst, 1.3f * scaleConst, 1 - Mathf.Clamp(playerController.CurVelocity, 0, maxVelocity) / maxVelocity) * curZoomPercentage; // read input if (GameManager.CanPlayerReadInput()) { this.ReadInput(); } // update position of UI int worldSize = mapSize * 4; Vector3 mapPos = - new Vector3(this.FocusPos.x, this.FocusPos.z, 0f) * mapSize / (float)worldSize; mapImage.rectTransform.localPosition = mapPos; // update rotation of UI float relAngle = Camera.main != null ? Camera.main.transform.eulerAngles.y : 0f; //mapContainer.pivot = new Vector2(mapPos.x, mapPos.y); mapContainer.localRotation = Quaternion.Euler(0, 0, relAngle); mapContainer.localScale = new Vector3(realZoom, realZoom, 1); lastZoom = realZoom; if (northPivot != null) northPivot.localRotation = Quaternion.Euler(0, 0, relAngle); if (playerImage != null && m_ped != null) playerImage.rectTransform.localRotation = Quaternion.Euler(0, 0, relAngle - (m_ped.transform.eulerAngles.y + 180)); // update zone name label string currentZoneName = this.ZoneName; if (currentZoneName != this.zoneNameLabel.text) this.zoneNameLabel.text = currentZoneName; } private IEnumerator ChangeZoom(bool isIncreasing) { showZoomPanel = true; fAlpha = 1; zoomSelector = GetClampedZoomSelector(zoomSelector); float curZoom = zooms[zoomSelector % zooms.Length], lastZoom = zooms[GetClampedZoomSelector(zoomSelector - 1 * (isIncreasing ? 1 : -1)) % zooms.Length]; float t = 0; while (t < zoomDuration) { curZoomPercentage = Mathf.Lerp(lastZoom, curZoom, t / zoomDuration); yield return new WaitForFixedUpdate(); t += Time.fixedDeltaTime; fAlpha -= Time.fixedDeltaTime / zoomDuration; } showZoomPanel = false; zoomCoroutine = null; } private int GetClampedZoomSelector(int? val = null) { int zoomVal = val == null ? zoomSelector : val.Value; if (zoomVal < 0) zoomVal = zooms.Length - 1; return zoomVal; } } }