본문 바로가기

Unity

[Unity] 유니티에서 네이버 지도 API 사용하기

반응형

1. 개요 및 목표 설정

안녕하세요, 이번 가이드에서는 유니티(Unity)에서 네이버 클라우드 플랫폼의 맵 API를 사용하여 지도를 표시하고 드래그를 통해 지도를 이동하는 방법에 대해 알아보겠습니다. 이 튜토리얼은 유니티를 처음 사용하는 분들부터 이미 경험이 있는 분들까지 모두 따라할 수 있도록 구성되었습니다. 시작하기 전에 필요한 도구들을 확인해보겠습니다.

필요한 도구:

  • Unity: 최신 버전을 권장합니다. 유니티는 2D 및 3D 게임을 개발할 수 있는 강력한 엔진입니다. Android 플랫폼으로 진행합니다.
  • Naver Cloud Platform API Key: 네이버 클라우드 플랫폼에서 발급받을 수 있습니다.
  • Visual Studio: 유니티에서 스크립트를 작성할 때 주로 사용하는 코드 편집기입니다. vscode 등의 다른 코드 편집기를 사용해도 무방합니다.

2. 유니티 프로젝트 생성 및 Android 플랫폼 설정

유니티에서 새 프로젝트를 생성하고 Android 플랫폼으로 설정하는 방법을 알아보겠습니다.

2.1 유니티 실행 및 새 프로젝트 생성

  1. 유니티 허브(Unity Hub)를 실행하고 '새 프로젝트(New Project)' 버튼을 클릭합니다.
  2. 프로젝트 이름을 입력하고 저장 경로를 설정합니다.
  3. 템플릿으로 2D 또는 3D 중 원하는 것을 선택합니다. 이번 예제에서는 3D 템플릿을 선택하겠습니다.
  4. '생성(Create)' 버튼을 클릭하여 새 프로젝트를 만듭니다. 프로젝트가 생성되면 유니티 에디터가 열립니다.

2.2 Android 플랫폼으로 전환

  1. 유니티 에디터 상단 메뉴에서 'File'을 클릭한 후 'Build Settings...'를 선택합니다.
  2. 'Platform' 목록에서 'Android'를 선택하고, 'Switch Platform' 버튼을 클릭합니다.
  3. 필요한 경우, Android SDK 및 NDK 경로를 설정합니다. 설정 방법은 유니티 공식 문서에서 자세히 확인할 수 있습니다.

이제 유니티 프로젝트가 Android 플랫폼으로 설정되었습니다. 다음으로 네이버 클라우드 플랫폼에서 API 키를 발급받아보겠습니다.

3. 네이버 클라우드 플랫폼에서 API 키 발급받기

먼저 네이버 클라우드 플랫폼에서 API 키를 발급받아야 합니다. 이는 유니티 프로젝트에서 네이버 맵 API를 사용할 수 있게 해줍니다. 아래 단계를 따라 진행해보세요.

3.1 네이버 클라우드 플랫폼 접속 및 로그인

  1. 네이버 클라우드 플랫폼에 접속합니다.
  2. 네이버 계정으로 로그인합니다. 계정이 없으신 경우, 회원가입을 진행해주세요.

NAVER CLOUD PLATFORM

cloud computing services for corporations, IaaS, PaaS, SaaS, with Global region and Security Technology Certification

3.2 프로젝트 생성

  1. 로그인 후 상단 메뉴에 있는 서비스 탭을 클릭합니다.

  1. 'Application Service' 메뉴에서 'Maps' 서비스를 선택합니다.
  2. 처음 회원 가입 후 진행하신 경우, 결제 수단을 등록하셔야 합니다. 사용하실 결제 수단을 등록하신 후, 다음 단계를 진행해 주시면 감사하겠습니다.

  1. 이용 신청하기를 클릭합니다

  1. Application 등록 버튼을 클릭합니다.

  1. Maps Services에서 필요한 API를 선택해 주세요. 저희는 'Static Map', 'Geocoding' API를 사용할 예정이므로, 해당 API를 반드시 체크해 주시기 바랍니다. 저 또한 추후 사용을 위해 다른 API도 모두 체크해 두었으니, 본인에게 필요한 다른 API가 있다면 추가로 체크해 주시면 되겠습니다.
  2. 서비스 환경 등록에서, Web Dynamic Map을 선택하신 분은 자신의 웹사이트 URL을 넣어주시면 됩니다.
  3. Mobile Dynamic Map을 선택하신 분은 Android 앱 패키지 이름 또는 iOS Bundle ID를 추가해주시면 됩니다.
  4. 우리는 Static MapGeocoding을 사용하고, Unity에서 진행할 것이기 때문에 Android 앱 패키지 이름에 정보를 추가하겠습니다.
  5. Edit > Project Settings > Player > Other Settings > Identification > Package Name의 위치에서 자신의 앱 패키지 이름을 확인할 수 있습니다.

3.3 API 키 발급

  1. 'Static Map'과 'Geocoding' API 활성화 후, '인증 정보'에서 'Client ID'와 'Client Secret'을 확인합니다.
  2. 확인 클라이언트 ID와 클라이언트 시크릿을 메모해둡니다. 이 정보는 유니티 프로젝트에서 API 요청 시 필요합니다.

4. 네이버 맵 API와 연동하기

유니티 프로젝트에서 네이버 맵 API를 사용하여 지도를 표시하는 스크립트를 작성해보겠습니다. 각각의 전체 코드를 먼저 확인하고, 세부 내용을 확인해보겠습니다.

4.1 API 싱글톤 스크립트 생성

먼저 네이버 맵 API를 받아올 스크립트를 생성하겠습니다. 저는 Assets/Scripts/API/NaverMapAPI.cs 경로로 생성하였습니다.

using UnityEngine;

public class NaverMapAPI : MonoBehaviour
{
    // 싱글톤 인스턴스를 위한 정적 프로퍼티
    public static NaverMapAPI Instance { get; private set; }

    // 네이버 지도 API의 지오코드 요청 URL    
    [HideInInspector] public string geocodeApiUrl = "https://naveropenapi.apigw.ntruss.com/map-geocode/v2/geocode";
    // 네이버 지도 API의 정적 지도 요청 URL
    [HideInInspector] public string mapStaticApiUrl = "https://naveropenapi.apigw.ntruss.com/map-static/v2/raster";
    // 네이버 클라우드 플랫폼에서 발급받은 클라이언트 아이디
    [HideInInspector] public string clientID = "YOUR_CLIENT_ID";
    // 네이버 클라우드 플랫폼에서 발급받은 클라이언트 시크릿
    [HideInInspector] public string clientSecret = "YOUR_CLIENT_SECRET";

    // Awake 메서드는 유니티 라이프 사이클 중 객체가 처음 생성될 때 호출됨
    private void Awake()
    {
        // 싱글톤 인스턴스 설정
        if (Instance == null)
        {
            // 현재 인스턴스를 설정하고 다른 씬 로드 시 파괴되지 않도록 설정
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            // 이미 인스턴스가 존재하면 현재 객체를 파괴
            Destroy(gameObject);
        }
    }
}
 

이 코드는 Unity에서 네이버 지도 API를 사용하기 위한 클래스입니다. 주요 내용은 다음과 같습니다:

싱글톤 패턴 구현:

  • public static NaverMapAPI Instance { get; private set; }: 정적 인스턴스 프로퍼티로 다른 클래스에서 이 클래스의 인스턴스에 접근할 수 있도록 합니다.
  • private void Awake(): Unity의 생명 주기 함수 중 하나로, 오브젝트가 생성될 때 호출됩니다. 이 함수에서 싱글톤 패턴을 구현하여 인스턴스가 하나만 존재하도록 합니다. Instance가 설정되지 않은 경우 현재 인스턴스를 설정하고, 씬 전환 시 파괴되지 않도록 DontDestroyOnLoad 메서드를 호출합니다. 이미 인스턴스가 존재하면 현재 오브젝트를 파괴합니다.

네이버 지도 API 설정:

  • public string geocodeApiUrl: 지오코드 API의 요청 URL입니다. 이 URL을 사용하여 주소를 좌표로 변환할 수 있습니다.
  • public string mapStaticApiUrl: 정적 지도 API의 요청 URL입니다. 이 URL을 사용하여 정적 지도를 이미지로 요청할 수 있습니다.
  • public string clientID 및 public string clientSecret: 네이버 클라우드 플랫폼에서 발급받은 클라이언트 아이디와 시크릿입니다. API 요청 시 인증을 위해 사용됩니다.
  • 이 변수들은 [HideInInspector] 속성으로 인스펙터에 노출되지 않도록 설정되어 있습니다. 싱글톤을 통해 다른 스크립트에서 접근이 가능해야 하나. 굳이 인스펙터에서 건드릴 이유가 있는 항목이 아니기 때문에 숨김 처리를 진행하였습니다.

4.2 GeocodeManager 스크립트 생성

주소를 사용하여 Geocode(위도, 경도 등의 지리 정보)를 받아올 스크립트를 만들겠습니다. 저는 Assets/Scripts/Managers/GeocodeManager.cs 경로로 생성하였습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using Newtonsoft.Json;

public class GeocodeManager : MonoBehaviour
{
    // 싱글톤 인스턴스를 위한 정적 프로퍼티
    public static GeocodeManager Instance { get; private set; }

    private void Awake()
    {
        // 싱글톤 인스턴스 설정
        if (Instance == null)
        {
            // 현재 인스턴스를 설정하고 다른 씬 로드 시 파괴되지 않도록 설정
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            // 이미 인스턴스가 존재하면 현재 객체를 파괴
            Destroy(gameObject);
        }
    }

    // 주소를 지오코딩하여 좌표 정보를 가져오는 코루틴
    public IEnumerator GetGeocode(string query, System.Action<List<Address>> callback)
    {
        // 지오코드 API URL 생성 (query 매개변수를 URL 인코딩)
        string url = $"{NaverMapAPI.Instance.geocodeApiUrl}?query={UnityWebRequest.EscapeURL(query)}";

        // UnityWebRequest 객체를 사용하여 GET 요청 생성
        UnityWebRequest request = UnityWebRequest.Get(url);
        // 요청 헤더에 클라이언트 ID와 시크릿 설정
        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)
        {
            // 오류 메시지를 출력하고 콜백으로 null 전달
            Debug.LogError(request.error);
            callback(null);
        }
        else
        {
            // 응답이 성공적인 경우 응답 본문을 문자열로 가져옴
            string jsonResponse = request.downloadHandler.text;
            // 응답 문자열을 파싱하여 주소 리스트로 변환
            List<Address> addresses = ParseGeocodeResponse(jsonResponse);
            // 콜백 함수 호출하여 주소 리스트 전달
            callback(addresses);
        }
    }

    // JSON 응답 문자열을 Address 객체 리스트로 변환하는 메서드
    private List<Address> ParseGeocodeResponse(string jsonResponse)
    {
        // JSON 문자열을 GeocodeResponse 객체로 디시리얼라이즈
        GeocodeResponse geocodeResponse = JsonConvert.DeserializeObject<GeocodeResponse>(jsonResponse);
        // GeocodeResponse 객체에서 주소 리스트를 반환
        return geocodeResponse.addresses;
    }
}

// Geocode API 응답 구조체
public class GeocodeResponse
{
    // JSON 응답에서 addresses 필드를 매핑
    public List<Address> addresses { get; set; }
}

// 주소 정보를 담는 클래스
public class Address
{
    // 도로명 주소
    public string roadAddress { get; set; }
    // 지번 주소
    public string jibunAddress { get; set; }
    // 영어 주소
    public string englishAddress { get; set; }
    // 경도
    public string x { get; set; }
    // 위도
    public string y { get; set; }
}

이 코드는 Unity에서 네이버 지도 API를 사용하여 주소를 지오코딩하는 기능을 제공합니다. 주요 내용은 다음과 같습니다:

싱글톤 패턴 구현:

  • public static GeocodeManager Instance { get; private set; }: 정적 인스턴스 프로퍼티로 다른 클래스에서 이 클래스의 인스턴스에 접근할 수 있도록 합니다.
  • private void Awake(): Unity의 생명 주기 함수 중 하나로, 오브젝트가 생성될 때 호출됩니다. 이 함수에서 싱글톤 패턴을 구현하여 인스턴스가 하나만 존재하도록 합니다. Instance가 설정되지 않은 경우 현재 인스턴스를 설정하고, 씬 전환 시 파괴되지 않도록 DontDestroyOnLoad 메서드를 호출합니다. 이미 인스턴스가 존재하면 현재 오브젝트를 파괴합니다.

주소 지오코딩 기능:

  • public IEnumerator GetGeocode(string query, System.Action<List<Address>> callback): 입력된 주소 문자열을 네이버 지도 API를 통해 지오코딩하여 좌표 정보를 가져오는 코루틴입니다.
    • UnityWebRequest 객체를 사용하여 네이버 지도 API에 GET 요청을 보냅니다.
    • 요청 헤더에 클라이언트 ID와 시크릿을 설정하여 인증을 수행합니다.
    • 요청 응답을 대기한 후, 네트워크 오류나 프로토콜 오류가 발생한 경우 오류 메시지를 출력하고 콜백 함수에 null을 전달합니다.
    • 응답이 성공적인 경우 응답 본문을 문자열로 가져와 파싱하여 주소 리스트를 생성하고 콜백 함수에 전달합니다.

JSON 응답 파싱:

  • private List<Address> ParseGeocodeResponse(string jsonResponse): JSON 응답 문자열을 GeocodeResponse 객체로 변환하고, 이 객체에서 주소 리스트를 추출하여 반환합니다.

데이터 구조 정의:

  • public class GeocodeResponse: 네이버 지도 API의 지오코드 응답을 매핑하기 위한 클래스입니다. addresses 필드를 통해 주소 리스트를 포함합니다.
  • public class Address: 각 주소 정보를 담는 클래스입니다. 도로명 주소, 지번 주소, 영어 주소, 경도, 위도 등의 필드를 포함합니다.

4.3 NaverMapController 스크립트 생성

실제로 네이버 지도를 불러오고, 드래그를 통해 이동하는 기능을 가진 스크립트를 생성하겠습니다. 저는 Assets/Scripts/Controllers/NaverMapController.cs 경로로 생성하였습니다.

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using TMPro;
using System.Collections.Generic;
using UnityEngine.Networking;

public class NaverMapController : MonoBehaviour
{
    // 지도 이미지를 표시할 RawImage 컴포넌트
    public RawImage mapImage;
    // 주소 입력 필드와 검색 버튼
    public TMP_InputField addressInput;
    public Button searchButton;
    // 초기 줌 레벨
    public int zoom = 15;
    // 초기 지도 중심 좌표 (서울)
    private float latitude = 37.5665f;
    private float longitude = 126.9780f;

    // 드래그 시작 위치와 마지막 드래그 위치
    private Vector2 pointerDownPosition;
    private Vector2 lastDragPosition;
    // 드래그 동안의 총 이동 거리
    private Vector2 dragDeltaTotal;
    // 드래그 중인지 여부를 나타내는 플래그
    private bool isDragging = false;
    // 클릭으로 간주할 최대 이동 거리
    private const float clickThreshold = 10f;
    // 드래그 감도 조절
    public float dragFactor = 0.00001f;

    void Start()
    {
        // 이벤트 트리거 설정
        SetupEventTrigger();
        // 초기 지도를 불러옵니다.
        StartCoroutine(GetMapTile(latitude, longitude, zoom));

        // 검색 버튼 클릭 이벤트 추가
        searchButton.onClick.AddListener(OnSearchButtonClick);
    }

    // 이벤트 트리거를 설정하는 메서드
    private void SetupEventTrigger()
    {
        // RawImage에 EventTrigger 컴포넌트를 추가합니다.
        EventTrigger trigger = mapImage.gameObject.AddComponent<EventTrigger>();

        // PointerDown 이벤트 트리거 설정
        EventTrigger.Entry entryPointerDown = new EventTrigger.Entry();
        entryPointerDown.eventID = EventTriggerType.PointerDown;
        entryPointerDown.callback.AddListener((data) => { OnPointerDown((PointerEventData)data); });
        trigger.triggers.Add(entryPointerDown);

        // PointerUp 이벤트 트리거 설정
        EventTrigger.Entry entryPointerUp = new EventTrigger.Entry();
        entryPointerUp.eventID = EventTriggerType.PointerUp;
        entryPointerUp.callback.AddListener((data) => { OnPointerUp((PointerEventData)data); });
        trigger.triggers.Add(entryPointerUp);

        // Drag 이벤트 트리거 설정
        EventTrigger.Entry entryDrag = new EventTrigger.Entry();
        entryDrag.eventID = EventTriggerType.Drag;
        entryDrag.callback.AddListener((data) => { OnDrag((PointerEventData)data); });
        trigger.triggers.Add(entryDrag);
    }

    // 포인터가 눌러졌을 때 호출되는 메서드
    private void OnPointerDown(PointerEventData eventData)
    {
        // 포인터 다운 위치를 기록합니다.
        pointerDownPosition = eventData.position;
        lastDragPosition = eventData.position;
        dragDeltaTotal = Vector2.zero;
        isDragging = false;
    }

    // 포인터가 떼어졌을 때 호출되는 메서드
    private void OnPointerUp(PointerEventData eventData)
    {
        // 드래그가 발생하지 않았고 클릭으로 간주할 최대 이동 거리 내에 있다면 클릭으로 처리합니다.
        if (!isDragging && Vector2.Distance(pointerDownPosition, eventData.position) < clickThreshold)
        {
            // 클릭 이벤트 처리 (필요시 추가)
        }
    }

    // 드래그 중일 때 호출되는 메서드
    private void OnDrag(PointerEventData eventData)
    {
        // 현재 드래그 위치를 기록하고 이동 거리를 계산합니다.
        Vector2 currentDragPosition = eventData.position;
        Vector2 dragDelta = currentDragPosition - lastDragPosition;
        lastDragPosition = currentDragPosition;

        // 누적된 드래그 이동 거리에 현재 이동 거리를 더합니다.
        dragDeltaTotal += dragDelta;

        // 드래그 중임을 표시합니다.
        isDragging = true;

        // 드래그 이동에 따라 지도 좌표를 변경합니다.
        latitude -= dragDelta.y * dragFactor; // 위도 이동
        longitude -= dragDelta.x * dragFactor; // 경도 이동 (좌우 반전)

        // 지도 타일을 다시 불러옵니다.
        StartCoroutine(GetMapTile(latitude, longitude, zoom));
    }

    // 주소 검색 버튼 클릭 시 호출되는 메서드
    private void OnSearchButtonClick()
    {
        string address = addressInput.text;
        if (!string.IsNullOrEmpty(address))
        {
            StartCoroutine(GeocodeManager.Instance.GetGeocode(address, OnGeocodeReceived));
        }
    }

    // Geocode API 응답을 처리하는 콜백 메서드
    private void OnGeocodeReceived(List<Address> addresses)
    {
        if (addresses != null && addresses.Count > 0)
        {
            if (float.TryParse(addresses[0].y, out float lat) && float.TryParse(addresses[0].x, out float lon))
            {
                latitude = lat;
                longitude = lon;
                StartCoroutine(GetMapTile(latitude, longitude, zoom));
            }
            else
            {
                Debug.LogError("Invalid coordinates received from the geocode API.");
            }
        }
        else
        {
            Debug.LogError("No coordinates found for the address.");
        }
    }

    // 지도 타일을 불러오는 코루틴
    IEnumerator GetMapTile(float latitude, float longitude, int zoom)
    {
        // 네이버 지도 API 요청 URL 생성
        string apiUrl = $"{NaverMapAPI.Instance.mapStaticApiUrl}?w=500&h=500&center={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
        {
            // 요청이 성공한 경우, 응답으로 받은 텍스처를 RawImage에 적용합니다.
            Texture2D texture = DownloadHandlerTexture.GetContent(request);
            mapImage.texture = texture;
            mapImage.SetNativeSize();
            mapImage.rectTransform.anchoredPosition = Vector2.zero; // 화면 가운데로 고정
            mapImage.transform.localScale = Vector3.one * 3; // 이미지 크기 조정
        }
    }
}

코드에 대한 설명은 다음과 같습니다.

  1. 필드 선언부:
    • mapImage: 지도 이미지를 표시하는 RawImage 컴포넌트입니다.
    • addressInput: 주소 입력 필드입니다.
    • searchButton: 주소 검색 버튼입니다.
    • zoom: 초기 줌 레벨을 설정하는 변수입니다.
    • latitude, longitude: 초기 지도 중심 좌표를 설정하는 변수입니다.
    • 드래그 관련 변수들: pointerDownPosition, lastDragPosition, dragDeltaTotal, isDragging, clickThreshold, dragFactor.
  2. 초기화:
    • Start(): 이벤트 트리거를 설정하고 초기 지도를 불러옵니다. 검색 버튼 클릭 이벤트를 추가합니다.
  3. 이벤트 트리거 설정:
    • SetupEventTrigger(): mapImage에 EventTrigger를 추가하고, 포인터 다운, 업, 드래그 이벤트를 설정합니다.
  4. 포인터 이벤트 처리:
    • OnPointerDown(PointerEventData eventData): 포인터가 눌러졌을 때 호출됩니다. 포인터 다운 위치를 기록하고 초기화합니다.
    • OnPointerUp(PointerEventData eventData): 포인터가 떼어졌을 때 호출됩니다. 드래그 여부에 따라 클릭 이벤트를 처리할 수 있습니다.
    • OnDrag(PointerEventData eventData): 드래그 중일 때 호출됩니다. 드래그 이동 거리를 계산하고 지도 좌표를 업데이트합니다.
  5. 주소 검색 처리:
    • OnSearchButtonClick(): 검색 버튼 클릭 시 호출되어 입력된 주소를 지오코딩합니다.
    • OnGeocodeReceived(List<Address> addresses): 지오코딩 API 응답을 처리하고 지도를 해당 위치로 이동시킵니다.
  6. 지도 타일 요청:
    • GetMapTile(float latitude, float longitude, int zoom): 지도 타일을 불러오는 코루틴입니다. 네이버 지도 API를 사용하여 지도를 가져옵니다.

네이버 지도 API 요청 URL 설명

IEnumerator GetMapTile(float latitude, float longitude, int zoom) 에서 사용하는 네이버 지도 API 요청 URL의 경우, 다양한 쿼리를 사용하여 필요한 작업을 수행할 수 있습니다. 다음은 주로 사용하는 쿼리 파라미터를 정리한 내용입니다.

주요 쿼리 파라미터

  1. 크기 조절:
    • w (Width): 지도의 너비를 지정합니다. 단위는 픽셀입니다. 예: w=500
    • h (Height): 지도의 높이를 지정합니다. 단위는 픽셀입니다. 예: h=500
  2. 중심 좌표 및 줌 레벨:
    • center: 지도의 중심 좌표를 지정합니다. 경도,위도 형식으로 입력합니다. 예: center=126.9780,37.5665
    • level: 줌 레벨을 지정합니다. 숫자가 클수록 더 자세한 지도를 보여줍니다. 예: level=15
  3. 마커:
    • markers: 지도에 표시할 마커를 지정합니다. 여러 마커를 표시할 수 있습니다.
      • type: 마커의 유형을 지정합니다. 기본값은 t입니다.
      • size: 마커의 크기를 지정합니다. 가능한 값은 tiny, mid, small입니다.
      • color: 마커의 색상을 지정합니다. 예: color:red
      • pos: 마커의 위치를 지정합니다. 경도 위도 형식으로 입력합니다. 여러 개의 마커를 |로 구분하여 입력할 수 있습니다. 예: pos:126.9780 37.5665
  4. 경로:
    • paths: 지도에 경로를 그립니다. 경로의 스타일과 좌표를 지정할 수 있습니다.
      • strokeWeight: 경로의 두께를 지정합니다.
      • strokeColor: 경로의 색상을 지정합니다.
      • strokeOpacity: 경로의 투명도를 지정합니다. 0.0 ~ 1.0 사이의 값을 사용합니다.
      • pos: 경로의 좌표를 지정합니다. 경도 위도 형식으로 여러 개의 좌표를 |로 구분하여 입력합니다. 예: pos:126.9780 37.5665|126.9790 37.5670
  5. 다각형:
    • polygons: 지도에 다각형을 그립니다. 다각형의 스타일과 좌표를 지정할 수 있습니다.
      • fillColor: 다각형 내부의 색상을 지정합니다.
      • fillOpacity: 다각형 내부의 투명도를 지정합니다.
      • strokeWeight: 다각형 외곽선의 두께를 지정합니다.
      • strokeColor: 다각형 외곽선의 색상을 지정합니다.
      • strokeOpacity: 다각형 외곽선의 투명도를 지정합니다.
      • pos: 다각형의 좌표를 지정합니다. 경도 위도 형식으로 여러 개의 좌표를 |로 구분하여 입력합니다. 예: pos:126.9780 37.5665|126.9790 37.5670|126.9800 37.5665

예시 URL

아래는 다양한 쿼리 파라미터를 사용하여 생성된 예시 URL입니다.

string apiUrl = $"{NaverMapAPI.Instance.mapStaticApiUrl}?w=600&h=400&center=126.9780,37.5665&level=16&markers=type:t|size:mid|color:blue|pos:126.9780 37.5665&paths=strokeWeight:5|strokeColor:blue|strokeOpacity:0.7|pos:126.9770 37.5655|126.9790 37.5670&polygons=fillColor:yellow|fillOpacity:0.4|strokeWeight:2|strokeColor:green|strokeOpacity:0.9|pos:126.9780 37.5665|126.9790 37.5670|126.9785 37.5655";

이 URL은 다음과 같은 지도를 생성합니다:

  • 크기: 600x400 픽셀
  • 중심 좌표: 경도 126.9780, 위도 37.5665
  • 줌 레벨: 16
  • 마커: 중심 좌표에 파란색 중간 크기 마커
  • 경로: 좌표 (126.9770, 37.5655)에서 (126.9790, 37.5670)까지 파란색, 두께 5, 투명도 0.7의 경로
  • 다각형: 좌표 (126.9780, 37.5665), (126.9790, 37.5670), (126.9785, 37.5655)로 이루어진 노란색 내부, 투명도 0.4, 녹색 외곽선, 두께 2, 투명도 0.9의 다각형

이와 같은 다양한 쿼리 파라미터를 활용하여 원하는 지도를 생성할 수 있습니다.

5. Unity에서 지도 표시하기

이제 스크립트를 유니티 씬(Scene)에 적용하여 지도를 표시해보겠습니다.

5.1 관리 객체 생성

위에서 생성한 스크립트를 사용하려면 해당 스크립트를 씬(Scene)에 등록해야 합니다. 이를 위해 먼저 각 스크립트를 부착할 관리 객체를 생성해 보겠습니다.

저는 차후 생성할 스크립트를 각각 관리하기 위하여 Management Group 객체를 먼저 생성하고, 그 하위에 Third party API Script를 관리할 APIs, Manager Script를 관리할 Managers, Controller Script를 관리할 Controllers 객체를 생성하였습니다.

5.2 Canvas UI 설정

  1. Game View 해상도는 4K에 맞춰서 진행하겠습니다. Free Aspect를 눌러 맨 하단의 +를 누르고, 3840 * 2160 해상도를 설정해주시면 됩니다.

  1. 단순히 바로 Map부터 만들어도 되지만, Game View에서 뒤의 Skybox가 신경쓰이신다면 Main Camera의 Clear Flags를 Solid Color로 변경하고, Background Color를 검정색으로 바꿔주시면 됩니다.

  1. Map을 그릴 Raw Image를 생성해줍니다.

  1. Raw Image의 이름을 Map으로 바꾸고, Transfrom을 다음 사진과 같이 설정해줍니다.

  1. 다음은 주소를 입력할 Input Field를 만들어보겠습니다.

  1. 프로젝트에서 TextMeshPro를 처음 사용하게 되면 TextMeshPro를 Import하라는 창이 뜨는데, 위의 것만 설치하셔도 되고, 필요하시다면 밑의 것까지 설치하시면 됩니다.
  2. TextMeshPro를 초기 설정 그대로 사용할 경우, 기본 폰트가 한글을 지원하지 않아 한글 입력이 □으로 표시됩니다. 한글을 사용하려면 폰트를 변경해야 합니다. 해결 방법은 다음 포스트를 참고해 주세요.
  3. 한글 입력이 가능한 폰트를 생성했다면, 생성한 InputField (TMP)의 TextMeshPro - Input Field Component의 Input Field Settings > Font Asset을 한글 입력이 가능한 폰트로 바꿔줍니다.

  1. 다음은 주소 입력 후 이벤트를 처리할 버튼을 만들어 줍니다.

  1. 만든 UI들을 위에서 미리 생성했던 NaverMapController Script에 부착해줍시다.

6. 지도 실행 및 주소 검색 기능 확인

이제 Unity Play 버튼을 누르면 서울특별시청을 중심으로 하는 초기 지도가 나타납니다.

지도를 드래그하여 이동이 가능하며,

우측 Input Field를 통해 주소를 입력하면 해당 주소로 지도가 점프합니다.

지도를 한번 그려낼 때 static map api가 한번 사용되는 것이고, 현재 코드는 드래그 시 드래그한 만큼 이동하면서 그려지는 static map을 모두 그리고 있습니다. 이 api의 사용량은 네이버 클라우드 플랫폼의 application에서 볼 수 있습니다.

application

결론

이번 가이드에서는 유니티와 네이버 클라우드 플랫폼의 맵 API를 활용하여 지도를 표시하고 드래그를 통해 지도를 이동하는 방법을 알아보았습니다. 이를 통해 우리는 다음과 같은 내용을 학습했습니다:

  1. 유니티 프로젝트 생성 및 Android 플랫폼 설정: 유니티에서 새 프로젝트를 생성하고 Android 플랫폼으로 설정하는 방법을 배웠습니다.
  2. 네이버 클라우드 플랫폼에서 API 키 발급: 네이버 클라우드 플랫폼에서 API 키를 발급받아 유니티 프로젝트에서 사용할 수 있도록 설정했습니다.
  3. 네이버 맵 API와 연동: 유니티에서 네이버 맵 API를 사용하여 지도를 표시하고, 주소 검색 및 지도 이동 기능을 구현했습니다.
  4. 지도 표시 및 드래그 기능 구현: 네이버 맵 API를 사용하여 지도를 불러오고, 드래그 이벤트를 통해 지도를 이동하는 기능을 구현했습니다.

이번 프로젝트를 통해 유니티와 외부 API를 연동하여 다양한 기능을 구현하는 방법을 배웠습니다. 이러한 기술은 게임 개발뿐만 아니라 다양한 애플리케이션 개발에도 유용하게 사용할 수 있습니다. 앞으로도 유니티와 다양한 API를 활용하여 더 많은 프로젝트를 시도해보시기 바랍니다

반응형