
Where Am I?오늘 구현한 것은 크게 미니맵과 인벤토리 및 상자 보관, 제작 시스템, 오브젝트 랜덤 생성 로직이다. 슬슬 기능 구현은 다되어가지만, 미니맵 구현에서 예상보다 시간이 소요되어 예정이 조금 밀리게됐다.
이번 포스트에서는 구현한 미니맵 로직을 분석하고 소개하려한다. 간단히 맵과 연동되어 플레이어의 탐색에 따라 밝혀지는 POE의 맵핑과 같은 시스템을 구현했다.
MinimapData실제 생성되는 맵과 연동시키기 위해 맵의 데이터를 바탕으로 미니맵 데이터를 저장한다.
public class MinimapData : MonoBehaviour
{
[Header("Drag&Drop")]
[SerializeField] private MapData _mapData;
private int _mapSize;
public int MapSize => _mapSize;
private int[,] _map;
public int[,] Map => _map;
private int _offset;
private void Start()
{
Init();
Initialize();
}
private void Initialize()
{
// 미니맵 생성
_map = new int[_mapSize, _mapSize];
// 맵 크기 보정
for (int x = 0; x < _mapSize; x++)
{
for (int y = 0; y < _mapSize; y++)
{
_map[x, y] = _mapData.Map[x * _offset, y * _offset];
}
}
}
private void Init()
{
_mapSize = _mapData.MapSize;
_offset = _mapData.Offset;
}
}
MinimapCampublic class MinimapCam : MonoBehaviour
{
[Header("Drag&Drop")]
[SerializeField] private Transform _player;
[Header("InputNumber")]
[SerializeField] private float _zoomSpeed;
[SerializeField] private float _minY;
[SerializeField] private float _maxY;
private void LateUpdate()
{
transform.position = new Vector3(_player.position.x / 5, transform.position.y, _player.position.z / 5);
if (!ItemManager.Instance.HasCompass)
{
transform.rotation = Quaternion.Euler(90,_player.rotation.eulerAngles.y,0);
}
float scroll = Input.GetAxis("Mouse ScrollWheel");
transform.position += Vector3.up * (scroll * _zoomSpeed);
float clampY = Mathf.Clamp(transform.position.y, _minY, _maxY);
transform.position = new Vector3(transform.position.x, clampY, transform.position.z);
}
}
Minimappublic class Minimap : MonoBehaviour
{
[Header("Drag&Drop")]
[SerializeField] private Transform _player;
[SerializeField] private GameObject _playerPrefab;
private GameObject _playerObject;
private bool _isTurnOn;
private Camera _minicam;
private void Awake()
{
Init();
}
private void Start()
{
Vector3 startPos = new Vector3(_player.position.x / 5, -1, _player.position.z / 5);
_playerObject = Instantiate(_playerPrefab, startPos, Quaternion.identity);
}
private void Update()
{
_playerObject.transform.position = new Vector3(_player.position.x / 5, -1, _player.position.z / 5);
if (Input.GetKeyDown(KeyCode.Tab))
{
_isTurnOn = !_isTurnOn;
if (_isTurnOn != _minicam.gameObject.activeSelf)
{
_minicam.gameObject.SetActive(_isTurnOn);
}
}
}
private void Init()
{
_minicam = GetComponentInChildren<Camera>();
_minicam.rect = new Rect(0.35f, 0.35f, 0.3f, 0.3f);
_isTurnOn = false;
_minicam.gameObject.SetActive(_isTurnOn);
}
}
MinimapGeneratorpublic class MinimapGenerator : MonoBehaviour
{
[Header("Drag&Drop")]
[SerializeField] private MinimapData _data;
[SerializeField] private GameObject _wallPrefab;
[SerializeField] private GameObject _tilePrefab;
private int[,] _map;
private int _mapSize;
private void Start()
{
Init();
GenerateMap();
}
private void GenerateMap()
{
for (int z = 0; z < _mapSize; z++)
{
for (int x = 0; x < _mapSize; x++)
{
Vector3 pos = new Vector3(x, -1, z);
if (_map[z, x] == 1)
{
Instantiate(_wallPrefab, pos, Quaternion.identity,transform);
}
else
{
Instantiate(_tilePrefab, pos, Quaternion.identity,transform);
}
}
}
}
private void Init()
{
_map = _data.Map;
_mapSize = _data.MapSize;
}
}
MinimapRevealpublic class MinimapReveal : MonoBehaviour
{
[Header("Drag&Drop")]
[SerializeField] private Transform _player;
[Header("InputNumber")]
[SerializeField] private float _revealRange;
private List<GameObject> _tiles;
private void Start()
{
Init();
}
private void Update()
{
foreach (var tile in _tiles)
{
Vector3 targetPos = new Vector3(_player.position.x / 5, -1, _player.position.z / 5);
if (Vector3.Distance(tile.transform.position, targetPos) < _revealRange)
{
tile.SetActive(true);
}
}
}
private void Init()
{
_tiles = new List<GameObject>();
foreach (var tile in GetComponentsInChildren<MeshFilter>())
{
tile.gameObject.SetActive(false);
_tiles.Add(tile.gameObject);
}
}
}