From 0d2bf453ce538468e6c6d98be603d9ef57d6a95d Mon Sep 17 00:00:00 2001 From: sharedacc520k Date: Fri, 3 Apr 2026 18:04:26 +0900 Subject: [PATCH] =?UTF-8?q?2026-04-03=20=EB=AF=B8=EB=8B=88=EB=A7=B5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/01_Scenes/GameScene.unity | 4 +- .../Managers/Local/MinimapManager.cs | 137 ++++++++++++++++++ .../Managers/Local/MinimapManager.cs.meta | 2 + Assets/02_Scripts/UI/Minimap.meta | 8 + .../02_Scripts/UI/Minimap/MinimapCapture.cs | 40 +++++ .../UI/Minimap/MinimapCapture.cs.meta | 2 + Assets/02_Scripts/UI/Minimap/MinimapMarker.cs | 52 +++++++ .../UI/Minimap/MinimapMarker.cs.meta | 2 + 8 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 Assets/02_Scripts/Managers/Local/MinimapManager.cs create mode 100644 Assets/02_Scripts/Managers/Local/MinimapManager.cs.meta create mode 100644 Assets/02_Scripts/UI/Minimap.meta create mode 100644 Assets/02_Scripts/UI/Minimap/MinimapCapture.cs create mode 100644 Assets/02_Scripts/UI/Minimap/MinimapCapture.cs.meta create mode 100644 Assets/02_Scripts/UI/Minimap/MinimapMarker.cs create mode 100644 Assets/02_Scripts/UI/Minimap/MinimapMarker.cs.meta diff --git a/Assets/01_Scenes/GameScene.unity b/Assets/01_Scenes/GameScene.unity index 761693f..eac71b4 100644 --- a/Assets/01_Scenes/GameScene.unity +++ b/Assets/01_Scenes/GameScene.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:53d63a41c9f19da0b2cefbd7533df4d5289e1796712177873c797020a3f6c62c -size 485087 +oid sha256:dd8fa9f69d6100bb86796ba79124479be760f50e547ef8bbea45d6babd6c0382 +size 496645 diff --git a/Assets/02_Scripts/Managers/Local/MinimapManager.cs b/Assets/02_Scripts/Managers/Local/MinimapManager.cs new file mode 100644 index 0000000..9bfc943 --- /dev/null +++ b/Assets/02_Scripts/Managers/Local/MinimapManager.cs @@ -0,0 +1,137 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +/* + Canvas (기존 InGameUI Canvas) +└── MinimapRoot (빈 오브젝트, MinimapManager 컴포넌트 부착) + ├── MapMask (원형/사각형 마스크, Mask 컴포넌트) + │ ├── MapImage (RawImage) ← _mapImage, _mapRect + │ ├── PlayerIcon (Image) ← _playerIcon + │ └── MarkerContainer (빈 오브젝트) ← _markerContainer + └── MinimapFrame (Image) ← 테두리 장식 (선택) + */ + +public class MinimapManager : MonoBehaviour +{ + [Header("미니맵 UI")] + [SerializeField] private RawImage _mapImage; // 맵 배경 (RenderTexture 또는 프리렌더 이미지) + [SerializeField] private RectTransform _mapRect; // 맵 이미지의 RectTransform + [SerializeField] private RectTransform _playerIcon; // 플레이어 아이콘 + [SerializeField] private RectTransform _markerContainer;// 마커 부모 + + [Header("프리렌더 이미지")] + [SerializeField] private Texture2D _bakedMapImage; + + [Header("월드 범위")] + [SerializeField] private Vector2 _worldMin = new Vector2(-50, -50); + [SerializeField] private Vector2 _worldMax = new Vector2(50, 50); + + [Header("모드")] + [SerializeField] private bool _useRenderTexture = true; // true: 실시간(개발용), false: 프리렌더(출시용) + + //개발용 설정 + //---------------------------------------------------------- + [Header("미니맵 카메라")] + [SerializeField] private Camera _minimapCamera; + [SerializeField] private RenderTexture _renderTexture; + + [Header("카메라 설정")] + [SerializeField] private float _cameraHeight = 50f; + [SerializeField] private float _zoomLevel = 30f; + [SerializeField] private float _minZoom = 15f; + [SerializeField] private float _maxZoom = 80f; + //---------------------------------------------------------- + + private List _markers = new List(); + + private void Start() + { + ApplyMode(); + } + + private void LateUpdate() + { + UpdateCamera(); + UpdatePlayerIcon(); + UpdateMarkers(); + } + + public void ApplyMode() + { + if (_useRenderTexture) + { + _mapImage.texture = _renderTexture; + if (_minimapCamera != null) _minimapCamera.gameObject.SetActive(true); + } + else + { + _mapImage.texture = _bakedMapImage; + if (_minimapCamera != null) _minimapCamera.gameObject.SetActive(false); + } + } + + private void UpdateCamera() + { + if (!_useRenderTexture || _minimapCamera == null) return; + + Vector3 pos = GameManager.Instance.Level.CurrentCharacter.transform.position; + _minimapCamera.transform.position = new Vector3(pos.x, pos.y + _cameraHeight, pos.z); + _minimapCamera.orthographicSize = _zoomLevel; + } + + private void UpdatePlayerIcon() + { + if (_playerIcon == null) return; + + _playerIcon.anchoredPosition = WorldToMapPos(GameManager.Instance.Level.CurrentCharacter.transform.position); + _playerIcon.localRotation = Quaternion.Euler(0, 0, -GameManager.Instance.Level.CurrentCharacter.transform.eulerAngles.y); + } + + private void UpdateMarkers() + { + for (int i = _markers.Count - 1; i >= 0; i--) + { + if (_markers[i] == null) + { + _markers.RemoveAt(i); + continue; + } + + _markers[i].UpdatePosition(this); + } + } + + public Vector2 WorldToMapPos(Vector3 worldPos) + { + float ratioX = (worldPos.x - _worldMin.x) / (_worldMax.x - _worldMin.x); + float ratioY = (worldPos.z - _worldMin.y) / (_worldMax.y - _worldMin.y); + + //sizeDelta는 앵커 영역과 실제 UI 크기의 차이값 + return new Vector2( + ratioX * _mapRect.sizeDelta.x - _mapRect.sizeDelta.x * 0.5f, + ratioY * _mapRect.sizeDelta.y - _mapRect.sizeDelta.y * 0.5f + ); + } + + public RectTransform MarkerContainer => _markerContainer; + + public void RegisterMarker(MinimapMarker marker) + { + if (!_markers.Contains(marker)) + _markers.Add(marker); + } + + public void UnregisterMarker(MinimapMarker marker) + { + _markers.Remove(marker); + } + + public void SetZoom(float zoom) + { + _zoomLevel = Mathf.Clamp(zoom, _minZoom, _maxZoom); + } + + public void ZoomIn(float amount) => SetZoom(_zoomLevel - amount); + public void ZoomOut(float amount) => SetZoom(_zoomLevel + amount); +} diff --git a/Assets/02_Scripts/Managers/Local/MinimapManager.cs.meta b/Assets/02_Scripts/Managers/Local/MinimapManager.cs.meta new file mode 100644 index 0000000..bede67e --- /dev/null +++ b/Assets/02_Scripts/Managers/Local/MinimapManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0298fb5f6cff794429c87fab23351ae8 \ No newline at end of file diff --git a/Assets/02_Scripts/UI/Minimap.meta b/Assets/02_Scripts/UI/Minimap.meta new file mode 100644 index 0000000..6121d59 --- /dev/null +++ b/Assets/02_Scripts/UI/Minimap.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6ac2fd73b3fec65448b65adadd35989f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/02_Scripts/UI/Minimap/MinimapCapture.cs b/Assets/02_Scripts/UI/Minimap/MinimapCapture.cs new file mode 100644 index 0000000..e2b492f --- /dev/null +++ b/Assets/02_Scripts/UI/Minimap/MinimapCapture.cs @@ -0,0 +1,40 @@ +#if UNITY_EDITOR +using UnityEditor; +#endif +using UnityEngine; + +public class MinimapCapture : MonoBehaviour +{ + [SerializeField] private Camera _minimapCamera; + [SerializeField] private int _resolution = 1024; + [SerializeField] private string _savePath = "Assets/08_UI/MinimapImage.png"; + + [ContextMenu("미니맵 이미지 캡처")] + public void CaptureMapImage() + { + RenderTexture rt = new RenderTexture(_resolution, _resolution, 24); + _minimapCamera.targetTexture = rt; + _minimapCamera.Render(); + + RenderTexture.active = rt; + Texture2D tex = new Texture2D(_resolution, _resolution, TextureFormat.RGB24, false); + tex.ReadPixels(new Rect(0, 0, _resolution, _resolution), 0, 0); + tex.Apply(); + + byte[] bytes = tex.EncodeToPNG(); + System.IO.File.WriteAllBytes(_savePath, bytes); + + _minimapCamera.targetTexture = null; + RenderTexture.active = null; + +#if UNITY_EDITOR + DestroyImmediate(rt); + DestroyImmediate(tex); + AssetDatabase.Refresh(); + Debug.Log($"미니맵 이미지 저장 완료: {_savePath}"); +#else + Destroy(rt); + Destroy(tex); +#endif + } +} diff --git a/Assets/02_Scripts/UI/Minimap/MinimapCapture.cs.meta b/Assets/02_Scripts/UI/Minimap/MinimapCapture.cs.meta new file mode 100644 index 0000000..1fc02f3 --- /dev/null +++ b/Assets/02_Scripts/UI/Minimap/MinimapCapture.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d4a6e37a841f8f64bb2142ceb2c29d0e \ No newline at end of file diff --git a/Assets/02_Scripts/UI/Minimap/MinimapMarker.cs b/Assets/02_Scripts/UI/Minimap/MinimapMarker.cs new file mode 100644 index 0000000..e0b6ff7 --- /dev/null +++ b/Assets/02_Scripts/UI/Minimap/MinimapMarker.cs @@ -0,0 +1,52 @@ +using UnityEngine; +using UnityEngine.UI; + +public class MinimapMarker : MonoBehaviour +{ + [SerializeField] private Sprite _iconSprite; + [SerializeField] private Color _iconColor = Color.red; + [SerializeField] private Vector2 _iconSize = new Vector2(10f, 10f); + [SerializeField] private bool _rotateWithTarget = false; + + private RectTransform _iconRect; + private Transform _target; // 추적할 월드 오브젝트 + + private void Awake() + { + _target = transform; + } + + public void Initialize(MinimapManager manager) + { + // 마커 아이콘 UI 생성 + GameObject iconObj = new GameObject($"Marker_{gameObject.name}"); + iconObj.transform.SetParent(manager.MarkerContainer, false); + + Image img = iconObj.AddComponent(); + img.sprite = _iconSprite; + img.color = _iconColor; + + _iconRect = iconObj.GetComponent(); + _iconRect.sizeDelta = _iconSize; + + manager.RegisterMarker(this); + } + + public void UpdatePosition(MinimapManager manager) + { + if (_iconRect == null || _target == null) return; + + _iconRect.anchoredPosition = manager.WorldToMapPos(_target.position); + + if (_rotateWithTarget) + { + _iconRect.localRotation = Quaternion.Euler(0, 0, -_target.eulerAngles.y); + } + } + + private void OnDestroy() + { + if (_iconRect != null) + Destroy(_iconRect.gameObject); + } +} diff --git a/Assets/02_Scripts/UI/Minimap/MinimapMarker.cs.meta b/Assets/02_Scripts/UI/Minimap/MinimapMarker.cs.meta new file mode 100644 index 0000000..775591c --- /dev/null +++ b/Assets/02_Scripts/UI/Minimap/MinimapMarker.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 85b8750f387527d4c8751eefec4c4c47 \ No newline at end of file