블로그

  • 코루틴 결과값 리턴받기

    코루틴을 사용한 리소스 비동기 로딩 구현 도중 특정 코루틴의 결과값을 리턴받아야 할 일이 생겼습니다.

    public Coroutine LoadCharacterAsync(CharacterData data)
    {
        return StartCoroutine(LoadCharacterAsyncRoutine(data));
    }
      
    IEnumerator LoadCharacterAsyncRoutine(CharacterData data)
    {
        GameObject characterObject = new GameObject();
        PokoCharacter character = characterObject.AddComponent<PokoCharacter>();
         
        // 캐릭터를 구성하는 각 파츠의 SkinnedMesh를 읽어서 생성
        for(int i = 0; i < 3; ++i)
        {
            GameObject loadedParts = null;
      
            yield return StartCoroutine(LoadCharacterPartsRoutine(data.partsName[i]);
      
            // 위 코루틴의 결과값을 어떻게 받지?!
            character.AddParts(i, loadedParts);
        }
    }
      
    IEnumerator LoadCharacterPartsRoutine(string partsName)
    {
        // Mesh, Texture, Bone, Animation 등등 로딩
    }

    혹시나 이런 게 되나 싶었는데

    IEnumerator LoadCharacterPartsRoutine(string partsName)
    {
        // Mesh, Texture, Bone, Animation 등등 로딩
        return loadedParts;
    }

    될 리가 없죠;; 

    IEnumerator로 선언된 메소드 내에서는 ref, out 같은 키워드도 문법적으로 사용할 수 없습니다. 

    해서 구글링을 해 봤더니 C#의 람다를 콜백으로 사용하는 신박한 방법이 있더라구요. 

    IEnumerator LoadCharacterPartsRoutine(string partsName)
    {
        // Mesh, Texture, Bone, Animation 등등 로딩
        return loadedParts;
    }

  • NGUI <-> World 좌표계 상호 변환

    1. World 좌표계 -> NGUI 좌표계

    • 사용 예시 : RPG 에서 캐릭터 머리 위에 따라다니는 HP Bar 등
    • 참고 : World 좌표계에서 Viewport 좌표계로 중간 변환하고 나서 다시 NGUI 좌표계로 변환한다.

    UICamera.mainCamera.ViewportToWorldPoint (Camera.main.WorldToViewportPoint (worldPosition));

    2. NGUI 좌표계 -> World 좌표계  

    • 사용 예시 : 캐릭터 아이콘 UI 에서 실제 월드상의 캐릭터 3D 모델에게 선을 긋는다.
    • 참고 : 위와 같이 Viewport 좌표계 변환이 한 번 있어야 한다.
    • 가장 중요한 포인트!
    • NGUI 좌표계에서 z값이 0 인데 특정 값을 꼭 넣어야 한다.
    • 그렇지 않으면 항상 카메라 위치가 나오게 되므로 2D->3D 가 애초에 안되니 Ray 를 쏘거나 복잡해지는데
    • z값에 값을 넣게 되면 간단히 해결!
    public static Vector3 NGUIToWorld(Vector3 nguiPosition)
    {
        nguiPosition.z += 5f;
        Vector3 worldPosition = Camera.main.ViewportToWorldPoint(UICamera.mainCamera.WorldToViewportPoint(nguiPosition));
        return worldPosition;
    }

    마우스의 현재 위치를 가져오기 위해 사용하는 Input.mousePosition은 스크린 좌표계를 사용한다.따라서 이 좌표를 월드 좌표로 변환해주기 위해 사용하는 것이 Camera.ScreenToWorldPoint()인데, 한가지 주의해야할 점이 있다.Input.mousePosition의 z값이 항상 0이라는 것이다.따라서 Camera.main.ScreenToWorldPoint(Input.mousePosition)을 하게 되면 그 결과는 카메라의 월드 좌표값이 나오게 된다.그래서 Input.mousePosition을 그대로 사용하면 안되고, z값을 변경해준 뒤에 사용해야 한다.예를들어 아래와 같이 사용할 수 있다.

    Vector3 screenMouse = Input.mousePosition;screenMouse.z = Camera.main.WorldToScreenPoint(Vector3.zero).z;Vector3 worldMouse = Camera.main.ScreenToWorldPoint(screenMouse);

    screenMouse의 z 값에 대입한 값의 정체를 생각해보자.월드 좌표계의 원점(0, 0, 0)을 스크린 좌표계로 변환한 값이다. 이는 카메라의 위치에 따라 다른 값이 될 수 있겠다.어쨌든 이렇게 하면 마우스 클릭이 월드 좌표계의 z값 0인 위치에서의 클릭 지점이 되겠다. 

  • 플랫폼 쉽게 초스피드로 변경하기

    유니티에서 리소스가 많아질수록 플랫폼 변경시에 시간이 많이 소요되는 문제가 있습니다.포코 메르헨의 경우에는 플랫폼 변경에만 30분정도 걸리네요.그래서 좀 찾아봤습니다.

    https://youtu.be/efOr9aWfRyY?feature=shared

    요약하자면 이런거에요.


    1. 기존에 e:/work 프로젝트 폴더가 있고, 이 프로젝트를 android 플랫폼으로 사용 중이라고 가정하겠습니다.
    2. windows 플랫폼을 하나 더 추가하고 싶다면 e:/ work_windows 폴더를 만들고,
    3. 커맨드 라인에서 e:/work_windows 폴더로 이동한 다음
    4. mklink /j Assets ..\work\Assets
    5. mklink /j ProjectSettings ..\work\ProjectSettings
    6. 유니티를 켜고 work_windows 프로젝트를 연 후 플랫폼을  pc, mac & linux standalone으로 변경합니다.

    이렇게 하면 별도의 Library폴더를 가지게 되기 때문에, 코드 및 리소스를 공유를 하고 플랫폼만 다른 두개의 프로젝트를 유지할 수 있습니다.