
Unity를 사용한 지도 확대/축소 기능 구현하기
안녕하세요, 여러분! 오늘은 이전 포스트에 이어 PC에서는 에디터 테스트를 위한 기능을, Android에서는 실제 기능을 통해 네이버 지도를 확대/축소하는 방법을 알아보겠습니다. 이 기능은 두 플랫폼 모두에서 지도를 보다 직관적으로 탐색할 수 있게 해줍니다.
개요
우리는 PC에서는 마우스 휠을 이용한 에디터 테스트 기능을, Android에서는 터치 제스처를 이용한 실제 기능을 구현할 것입니다. 이를 위해 다음과 같은 단계를 거쳐 구현됩니다:
- Singleton 패턴을 이용한 ZoomController 클래스 생성
- PC 에디터 테스트용 마우스 휠 이벤트 처리
- Android 실제 기능용 터치 제스처 이벤트 처리
- 확대/축소 함수 작성
- 이벤트와 함수 연결
- NaverMapController 클래스에 기능 연결
ZoomController.cs
using UnityEngine;
public class ZoomController
{
// ZoomController 인스턴스를 위한 정적 속성
public static ZoomController Instance { get; private set; }
// 이전 두 터치 포인트 간의 거리
private float previousDistance;
// 줌 중인지 여부를 나타내는 플래그
private bool isZooming = false;
// 줌 속도 상수
private const float zoomSpeed = 0.1f;
// 생성자를 private으로 설정하여 외부에서 인스턴스 생성을 막음
private ZoomController() { }
// ZoomController의 인스턴스를 초기화하는 메서드
public static void Initialize()
{
// Instance가 아직 초기화되지 않은 경우
if (Instance == null)
{
// 새 ZoomController 인스턴스를 생성하여 Instance에 할당
Instance = new ZoomController();
}
}
// 줌 동작을 처리하는 메서드
public void HandleZoom()
{
#if UNITY_EDITOR
// 유니티 에디터에서 마우스 줌 동작을 처리
HandleMouseZoom();
#endif
#if UNITY_ANDROID
// 안드로이드에서 터치 줌 동작을 처리
HandleTouchZoom();
#endif
}
// 마우스를 이용한 줌 동작을 처리하는 메서드
private void HandleMouseZoom()
{
// 마우스 휠 입력을 받아옴
float scroll = Input.GetAxis("Mouse ScrollWheel");
// 스크롤 값이 0이 아닌 경우
if (scroll != 0.0f)
{
// NaverMapController의 줌 값을 업데이트하고 제한 범위 내로 클램프
NaverMapController.Instance.zoom = Mathf.Clamp(NaverMapController.Instance.zoom + (scroll > 0 ? 1 : -1), 1, 20);
// 업데이트된 줌 값으로 맵 타일을 다시 불러옴
NaverMapController.Instance.StartCoroutine(NaverMapController.Instance.GetMapTile(NaverMapController.Instance.latitude, NaverMapController.Instance.longitude, NaverMapController.Instance.zoom));
}
}
// 터치를 이용한 줌 동작을 처리하는 메서드
private void HandleTouchZoom()
{
// 두 개의 터치 포인트가 감지된 경우
if (Input.touchCount == 2)
{
// 첫 번째 터치 포인트
Touch touch1 = Input.GetTouch(0);
// 두 번째 터치 포인트
Touch touch2 = Input.GetTouch(1);
// 터치가 처음 시작된 경우
if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
{
// 두 터치 포인트 간의 초기 거리를 저장
previousDistance = Vector2.Distance(touch1.position, touch2.position);
// 줌 중임을 표시
isZooming = true;
}
// 터치 포인트가 이동한 경우
else if (touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved)
{
// 현재 두 터치 포인트 간의 거리를 계산
float currentDistance = Vector2.Distance(touch1.position, touch2.position);
// 현재 거리와 이전 거리의 차이가 일정 값 이상인 경우
if (Mathf.Abs(currentDistance - previousDistance) > 0.01f)
{
// NaverMapController의 줌 값을 업데이트하고 제한 범위 내로 클램프
NaverMapController.Instance.zoom = Mathf.Clamp(NaverMapController.Instance.zoom + (currentDistance > previousDistance ? 1 : -1), 1, 20);
// 업데이트된 줌 값으로 맵 타일을 다시 불러옴
NaverMapController.Instance.StartCoroutine(NaverMapController.Instance.GetMapTile(NaverMapController.Instance.latitude, NaverMapController.Instance.longitude, NaverMapController.Instance.zoom));
// 이전 거리를 현재 거리로 업데이트
previousDistance = currentDistance;
}
}
// 터치가 종료된 경우
else if (touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended)
{
// 줌 중이 아님을 표시
isZooming = false;
}
}
}
}
이 코드는 유니티 게임 엔진에서 줌 동작을 처리하는 ZoomController 클래스입니다. 아래에 각 부분을 설명하겠습니다.
싱글톤 패턴
ZoomController 클래스는 Singleton 패턴을 사용하여 인스턴스를 하나만 생성할 수 있게 합니다. Instance 프로퍼티와 Initialize 메서드를 통해 인스턴스를 관리합니다.
public static ZoomController Instance { get; private set; }
private ZoomController() { }
public static void Initialize()
{
if (Instance == null)
{
Instance = new ZoomController();
}
}
- Instance는 ZoomController의 유일한 인스턴스를 저장합니다.
- private 생성자를 사용하여 외부에서 직접 인스턴스를 생성할 수 없게 합니다.
- Initialize 메서드는 인스턴스가 없을 때만 새 인스턴스를 생성합니다.
줌 동작 처리
HandleZoom 메서드는 전처리기 지시문(UNITY_EDITOR 및 UNITY_ANDROID)을 사용하여 PC 에디터와 Android 환경에서 각각 적절한 확대/축소 이벤트를 처리하도록 합니다.
public void HandleZoom()
{
#if UNITY_EDITOR
HandleMouseZoom();
#endif
#if UNITY_ANDROID
HandleTouchZoom();
#endif
}
마우스 줌 처리
HandleMouseZoom 함수는 PC 에디터 테스트용으로 마우스 휠 이벤트를 처리하여 확대/축소를 수행합니다. Input.GetAxis("Mouse ScrollWheel")를 통해 마우스 휠의 스크롤 값을 가져오고, 이를 이용해 NaverMapController의 zoom 값을 조정합니다. Mathf.Clamp를 사용하여 확대/축소 범위를 제한합니다.
private void HandleMouseZoom()
{
float scroll = Input.GetAxis("Mouse ScrollWheel");
if (scroll != 0.0f)
{
NaverMapController.Instance.zoom = Mathf.Clamp(NaverMapController.Instance.zoom + (scroll > 0 ? 1 : -1), 1, 20);
NaverMapController.Instance.StartCoroutine(NaverMapController.Instance.GetMapTile(NaverMapController.Instance.latitude, NaverMapController.Instance.longitude, NaverMapController.Instance.zoom));
}
}
- 마우스 휠 입력을 받아줌(scroll 값)을 감지합니다.
- 줌 값을 업데이트하고 일정 범위(1~20) 내로 제한합니다.
- 업데이트된 줌 값으로 맵 타일을 다시 불러옵니다.
터치 줌 처리
HandleTouchZoom 함수는 Android 실제 기능용으로 두 손가락 터치 제스처를 처리하여 확대/축소를 수행합니다. 두 손가락 터치의 이전 위치와 현재 위치 간의 거리를 계산하여 확대/축소 비율을 결정합니다. 이 값을 이용해 NaverMapController의 zoom 값을 조정하고, 마찬가지로 Mathf.Clamp를 사용하여 확대/축소 범위를 제한합니다.
private void HandleTouchZoom()
{
if (Input.touchCount == 2)
{
Touch touch1 = Input.GetTouch(0);
Touch touch2 = Input.GetTouch(1);
if (touch1.phase == TouchPhase.Began || touch2.phase == TouchPhase.Began)
{
previousDistance = Vector2.Distance(touch1.position, touch2.position);
isZooming = true;
}
else if (touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved)
{
float currentDistance = Vector2.Distance(touch1.position, touch2.position);
if (Mathf.Abs(currentDistance - previousDistance) > 0.01f)
{
NaverMapController.Instance.zoom = Mathf.Clamp(NaverMapController.Instance.zoom + (currentDistance > previousDistance ? 1 : -1), 1, 20);
NaverMapController.Instance.StartCoroutine(NaverMapController.Instance.GetMapTile(NaverMapController.Instance.latitude, NaverMapController.Instance.longitude, NaverMapController.Instance.zoom));
previousDistance = currentDistance;
}
}
else if (touch1.phase == TouchPhase.Ended || touch2.phase == TouchPhase.Ended)
{
isZooming = false;
}
}
}
- 두 손가락 터치를 감지합니다.
- 터치가 시작되면 두 손가락 사이의 거리를 저장하고 줌 동작을 시작합니다.
- 터치가 이동하면 현재 거리를 계산하고 이전 거리와 비교하여 줌 값을 업데이트합니다.
- 터치가 종료되면 줌 동작을 종료합니다.
NaverMapController.cs
NaverMapController 클래스는 지도 이동 및 검색 기능을 포함하여 전체적인 맵 조작을 담당합니다. 따라서 ZoomController에서 함수화한 기능들을 본 스크립트에 연결하는 작업을 수행하겠습니다.
전체적인 코드는 같으며, 추가된 스니펫(코드 조각)을 기준으로 설명드리겠습니다.
NaverMapController 클래스에서 줌 동작 호출
// ...
void Update()
{
ZoomController.Instance.HandleZoom();
}
// ...
- Update 메서드에서 ZoomController.Instance.HandleZoom()을 호출하여 매 프레임마다 줌 입력을 처리합니다.
맵 타일을 요청하는 부분
// ...
public IEnumerator GetMapTile(float latitude, float longitude, int zoom)
{
string apiUrl = $"{NaverMapAPI.Instance.mapStaticApiUrl}?w=500&h=500¢er={longitude},{latitude}&level={zoom}&pos:{longitude} {latitude}";
UnityWebRequest request = UnityWebRequestTexture.GetTexture(apiUrl);
request.SetRequestHeader("X-NCP-APIGW-API-KEY-ID", NaverMapAPI.Instance.clientID);
request.SetRequestHeader("X-NCP-APIGW-API-KEY", NaverMapAPI.Instance.clientSecret);
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError(request.error);
}
else
{
Texture2D texture = DownloadHandlerTexture.GetContent(request);
mapImage.texture = texture;
mapImage.SetNativeSize();
mapImage.rectTransform.anchoredPosition = Vector2.zero;
mapImage.transform.localScale = Vector3.one * 3;
}
}
// ...
- GetMapTile 코루틴: 새로운 맵 타일을 요청하여 받아오고, 이를 mapImage에 설정합니다. 이때, int zoom 매개변수가 추가되어 줌 레벨을 API 요청에 포함합니다. API URL 또한 줌 레벨을 포함하도록 변경되었습니다.
마무리
이번 포스트에서는 유니티에서 네이버 지도 API를 사용하여 PC와 Android 플랫폼 모두에서 직관적인 지도 확대/축소 기능을 구현하는 방법을 알아보았습니다. 싱글톤 패턴을 사용한 ZoomController 클래스 생성부터, PC에서는 마우스 휠 이벤트를, Android에서는 터치 제스처를 통해 각각의 줌 동작을 처리하는 방법을 상세히 설명했습니다. 또한, NaverMapController 클래스와의 연결을 통해 실시간으로 지도 타일을 갱신하는 기능을 구현하였습니다.
이 과정을 통해 여러분은 유니티에서의 네이버 지도 API 활용과 플랫폼별 입력 처리를 배우게 되셨을 것입니다. 유니티 프로젝트에서 이러한 기능을 적용함으로써 사용자 경험을 향상시키고, 다양한 환경에서 지도를 손쉽게 탐색할 수 있는 애플리케이션을 개발할 수 있게 됩니다. 앞으로도 유니티와 다양한 API를 활용한 프로젝트를 통해 더 많은 기능을 구현해보시길 바랍니다. 감사합니다.
'Unity' 카테고리의 다른 글
| [Unity] 유니티 레이캐스트(Raycast) 기초 : 이해 및 활용 (0) | 2025.06.08 |
|---|---|
| [Unity] 유니티 연습 개발 환경 기본 세팅 (2) | 2025.06.08 |
| [Unity] 캐릭터를 추적하는 카메라가 떨리는 문제 해결 방법 (1) | 2025.06.08 |
| [Unity] 유니티에서 네이버 지도 API 사용하기 (2) | 2025.06.08 |
| [Unity] 유니티에서 TextMesh Pro(TMP) 한글 폰트 문제 해결하기 (0) | 2025.06.08 |