유니티를 사용하다 보면 디버깅을 위해 로그를 찍을때 리스트 뷰에서는 콜스택에 대한 정보를 볼수 없어 귀찮은 경우가 많다. 어셋 스토에서 판매하고 있는 'Console Pro'라는 어셋을 사용하면 편리하긴하지만..

using UnityEngine;


public static class LogHeader

{

    public static string Path

    {

        get

        {

#if UNITY_EDITOR || USE_DEBUGGING

            string callStack = StackTraceUtility.ExtractStackTrace();

            callStack = callStack.Substring(callStack.IndexOf("\n") + 1);

            callStack = callStack.Substring(0, callStack.IndexOf("\n") + 1);

            return callStack;

#else

            return "";

#endif

        }

    }


    public static string Function

    {

        get

        {

#if UNITY_EDITOR || USE_DEBUGGING

            string callStack = StackTraceUtility.ExtractStackTrace();

            callStack = callStack.Substring(callStack.IndexOf("\n") + 1);

            callStack = callStack.Substring(0, callStack.IndexOf("("));

            //callStack = callStack.Substring(0, callStack.IndexOf(" ") + 1);

            return "[" + callStack + "] ";

#else

            return "";

#endif

        }

    }


    // example :

    //     Debug.Log(LogHeader.Function + "any log text will be here");

    // result :

    //    CallStackLogMain:func_2() (at Assets/CallStackLogMain.cs:17)

    //    any log text will be here

}



Posted by kukuta
TAG C#, unity

댓글을 달아 주세요

유니티로 작업하다 보면 데이터를 저장하기 위해 SerializedField와 같은 어트리뷰트를 사용한다. 문제는 개발 도중 이 필드의 이름이 변경되어 기존 저장된 데이터들을 사용하지 못하게 되는 경우가 있다. 이런 경우 FormerlySerializedAs 어트리뷰트를 이용해 기존 버전과의 호환성을 유지해 줄 수 있다.


만일 아래와 같이 m_MyVariable이라는 멤버 변수를 사용하고 있는데 :

class MyClass : MonoBehaviour

{

  [SerializeField]

  private string m_MyVariable;

}


m_MyVariable의 이름이 다른 것으로, 예를 들자면 m_ABetterName와 같이 바뀐다면 기존에 m_MyVariable의 이름으로 저장된 데이터를 읽어 들이지 못하게 된다.

이럴 경우 아래와 같이 작성해주게 된다면 기존  m_MyVariable의 데이터를 m_ABetterName으로 치환해서 읽어 들일수 있다 :


class MyClass : MonoBehaviour

{

  [FormerlySerializedAs("m_MyVariable")]

  [SerializeField]

  private string m_ABetterName;

}


그리고 FormerlySerializedAs 는 여러번 중복해서 사용가능하다. 만일 이름이 여러 번 변경 된다고 하더라도 변경 히스토리에 따라 FormerlySerializedAs 어트리뷰트를 유지해 준다면 여전히 데이터 손실 없이 사용이 가능하다.


class MyClass : MonoBehaviour

{

  [FormerlySerializedAs("m_MyVariable")]

  [FormerlySerializedAs("m_ABetterName")]

  [SerializeField]

  private string m_EvenBetterName;

}


원문 : https://blogs.unity3d.com/2015/02/03/renaming-serialized-fields/

Posted by kukuta

댓글을 달아 주세요

Unity가 편한 개발 엔진이라고 아무런 기본 지식 없이 마냥 닥치는대로 하려다보니 이래저래 어려움이 많다.

이 포스팅에서는 Unity를 사용하기 전에 미리 알면 도움이 되는 기본 지식들에 대해서 다뤄 보자

  • SetParent 
    • 개인적으로 worldPositionStays 파라메터를 자주 잊거나 헷깔림
    • worldPositionStays 가 true일 경우. 자식이 되는 오브젝트의 월드 좌표는 변경되지 않는다(화면상으로 보기엔 그냥 그대로 있는것 같다는 말). 하지만 부모가 변경 되었으므로 로컬 좌표가 변경된다.
      예를 들어 부모가 없는 두 오브젝트(부모가 없다는 것은 월드 포지션과 로컬 포지션이 같다는 의미) A가 (0, 1)에, 오브젝트 B가 (1, 0)에 있는 경우, SetParent 함수 호출시 worldPositionStays를 true로 하면 자식이 되는 오브젝트 B의 월드 포지션은 여전히 (1, 0)이고 부모와의 관계를 나타내는 로컬 포지션은 (1, -1)로 변경 된다(유니티 인스펙터에는 로컬 포지션이 표시된다).
    • worldPositionStatys가 false일 경우. 자식이 되는 오브젝트의 로컬 좌표 값을 새로운 부모와 그대로 유지한다. 오브젝트 B가  오브젝트 A의 자식이 되는 경우 B의 로컬 포지션(1, 0)은 그대로 유지되며 대신 월드 포지션이 변경 된다.
  • LLVM(Low Level Vritual Machine) : 프로그램을 컴파일 타임, 링크 타임, 런타임 상황에서 프로그램의 작성 언어에 상관 없이 최적화를 쉽게 구현할 수 있도록 구성. LLVM으로 언어에 가상 기계를 생성, 가상 기계가 언어에 독립적인 최적화를 실행한다.
  • IL2CPP : https://blogs.unity3d.com/2015/05/06/an-introduction-to-ilcpp-internals/
    • Intermediate Language to CPP
  • 좌표계 : Unity uses a number of 2D coordinate spaces, most of which define X as increasing to the right, and Y increasing upwards. The one exception is in the GUI and GUILayout classes, where Y increases downwards.
  • Resources - http://docs.unity3d.com/ScriptReference/Resources.html
    • Assets 폴더 밑 어느 곳에라도 Resources 폴더를 만들고 asset들을 넣어두면 Resources.Load로 접근 가능
    • 개인적으로 Resources 폴더를 어디에 만들어야 할지 몰라 한참을 고생했었기에 기록에 남긴다.
    • Resources 디렉토리 밑에 스프라이트를 두면 SpritePacker로 아틀라스를 만들지 못한다.
  • GameObject - http://docs.unity3d.com/ScriptReference/GameObject.html
    • Unity scene 안에 있는 모든 것들의 베이스 클래스
  • Transform - http://docs.unity3d.com/ScriptReference/Transform.html
    • scene 안에 있는 모든 객체들이 가지고 있는 위치, 스케일, 회전 정보
    • transform은 부모 transform을 가질 수 있다
    • localPosition은 부모의 transform에 상대적 위치 정
    • GetComponentXXX<T> 함수들을 잘 이용하면 객체들을 찾기가 쉬워진다.
  • RectTransform - http://docs.unity3d.com/ScriptReference/RectTransform.html
    • 주로 UI를 위해 사용 됨(아마도..)
    • 위치, 사이즈, 앵커, 피봇 관련 정보들을 담고 있음
    • sizeDelta : RectTransform의 앵커 기준 상대적 사이즈. 만일 앵커가 붙어 있다면 sizeDelta는 size와 동일하다. 만일 앵커가 부모의 각 네 코너에 맞춰져 있다면 sizeDelta는 부모의 사각형 대비 얼마나 크거나 작은지를 나타낸다.
    • rect : eg. rectTransform.rect.height 으로 RectTransform 객체의 높이를 가져 올 수 있다
  • Gizmo : Gizmos are used to give visual debugging or setup aids in the scene view
  • 애니메이션 종료 여부 알아 내기 - http://kukuta.tistory.com/181
  • svn 
  • Help with access/write files on Android : http://forum.unity3d.com/threads/help-with-access-write-files-on-android.72819/
  • 4.6 UI Text rect does not expand automatically
  • 유니티의 입력 값은 스크린 좌표 값인데 게임월드 상의 오브젝트를 다루려면 월드 좌표를 사용해야 한다. 이를 위해서 유니티에서는 ScreenToWorldPoint(http://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html) 함수를 제공한다.Event.current.mousePosition은 화면의 좌하단이 (0, 0)이다. 터치 입력과 같은 좌표계(화면 좌 상단이 0, 0)를 사용하는 Input.mousePosition(http://docs.unity3d.com/ScriptReference/Input-mousePosition.html)을 사용하자.
  • BoxCollider 를 설정하고 IsTrigger 옵션을 선택하면 OnCollisionXXX 대신 OnTriggerXXX 함수가 호출 된다. IsTrigger 셋팅이 되어있다면 오브젝트간 물리적 상호 작용은 없고 서로 겹칠때 알림만 온다.
  • saving and loading player game data in unity 
    • http://www.sitepoint.com/saving-and-loading-player-game-data-in-unity/
    • http://gamedevelopment.tutsplus.com/tutorials/how-to-save-and-load-your-players-progress-in-unity--cms-20934
  • Dictionary 시리얼라이즈 : http://answers.unity3d.com/questions/460727/how-to-serialize-dictionary-with-unity-serializati.html
  • content size fitter : 부모 객체의 rect를 자식 객체들에 맞춰서 변경 시켜주는 역할. 하지만 자식에 Vertical Layout 혹은 Horizon Layout 같은 Layout이 붙어야 한다. 텍스트 같은 경우는 아마도 예외인것 같다.
  • JsonUtility - http://docs.unity3d.com/ScriptReference/JsonUtility.html
  • 스크립트 직렬화 - http://docs.unity3d.com/kr/current/Manual/script-Serialization.html
  • Application.OpenURL - https://docs.unity3d.com/kr/current/ScriptReference/Application.OpenURL.html
  • AudioListener.volumn - https://docs.unity3d.com/ScriptReference/AudioListener-volume.html


Posted by kukuta
TAG unity

댓글을 달아 주세요

  1. unisushi 2016.10.25 22:00  댓글주소  수정/삭제  댓글쓰기

    감사합니다 굳!

스프라이트 객체를 AssetBundle로 만들고 난뒤 AssetBundle을 통해 스프라이트 객체로 로드를 했는데 로드를 하지 못하고 null을 리턴하는 현상이 발생했습니다. Unity 4.3 버젼에서는 스프라이트는 어셋번들로 만들면서 데이터가 떨어져 나가고 텍스쳐로 로드해서 스프라이트로 변환 해야 한다고하는 군요.


그래서 텍스쳐를 스프라이트로 변경하는 방법에 대해서 살짝 짚고 넘어가보도록 하겠습니다.


Rect rect = new Rect(0, 0, texture.width, texture.height);

sprite.GetComponent<SpriteRenderer>().sprite = Sprite.Create(texture, rect, new Vector2(0.5f, 0.5f)); 


참 쉽죠?ㅋ


추가 : Sprite Packer를 이용해 패킹한 sprite는 asset bundle을 통해서도 정상적으로 로드 되었다.

Posted by kukuta

댓글을 달아 주세요

이번 포스팅에서는 어셋 번들의 기본 개념과 유니티에서 어셋스토어를 통해 제공하고 있는 '어셋번들 매니저'를 이용하여 어셋번들을 만들고 로드하는 과정에 대해 알아 보도록 하겠습니다.

'어셋번들(Asset Bundle)' 이란?
어셋번들(Asset Bundle)은 유니티에서 사용하는 실행 어플리케이션과 별도로 배포/로딩 될 목적으로 저장된 어셋들과 씬들을 집합한 파일로써 필요시에 로컬에서 직접 로딩 혹은 원격 저장소에서 다운로드 받은 후 로딩 할수 있는 기능을 제공합니다. 이를 통해 새로 빌드된 어플리케이션의 자체의 배포 없이 변경 되거나 신규로 추가된 데이터만을 필요시에 동적으로 배포 할수 있도록 해줍니다. 이를 통해 어플리케이션의 데이터가 변경 될때 마다 각 스토어에 검수를 받을 필요 없이 컨텐츠를 업데이트 한다던지, DLC 등을 쉽게 구현 할 수 있습니다. 

좀 더 구체적으로, 어셋번들에 포함 될수 있는 어셋은 스크립트를 제외한 유니티에서 사용하는 거의 모든 것 - 모델, 머트리얼, 텍스쳐, 오디오 클립, 심지어는 커스텀 바이너리 데이터 까지 - 이며 스트리밍 기반의 비동기 로딩을 가능하게 도와 줍니다.

어셋번들의 기본적인 속성은 아래와 같습니다 :
  • 어셋번들은 전체가 다운로드 되고 캐싱 됩니다. 그렇다고 전체를 로드 할 필요는 없다. 번들 내에 필요한 어셋만 구분하여 로드할 수 있습니다.
  • 어셋번들에 포함된 어셋들은 서로 의존성을 가질 수도 있습니다. 그리고 그 의존성을 공유 할 수 있다. 예를 들어 게임 오브젝트 A와 B가 동일한 머트리얼과 텍스쳐 어셋을 공유 할 수 있다는 의미 입니다.
  • 각 어셋 번들은 파일의 사이즈와 관리하는데 기술적 오버헤드를 가진다. 
  • 어셋 번들은 각 타겟 플랫폼에 맞추어 빌드 되어야 한다.

어셋번들의 메니페스트(Manifest)와 의존성 관리
어셋번들에서 어셋의 의존성은 절대 누락되지 않습니다. 여기서 '의존성'이란 아래 그림과 같이 모델이 머트리얼을 참조하고, 머트리얼은 텍스쳐를 참조하는 각 어셋들의 참조 관계를 의미합니다. 

탱크 모델 어셋의 의존성 체인 : 모델 > 머트리얼 > 텍스쳐

서로 의존성을 가지고 있는 어셋은 명시적으로 어셋번들 이름이 지정되어 있지 않다고 하더라도 자동적으로 어셋번들에 포함되어 빌드 됩니다. 이런 방법은 모든 참조 어셋들에 대해 일일이 관리할 필요 없이 모델과 같은 최상위 어셋만 어셋번들을 명시적으로 지정해 주면 된다는 편리함이 있는 반면, 어셋번들에 포함되는 어셋들의 중복을 유발 할 수 있다는 단점이 있습니다. 예를 들어 두개의 모델이 하나의 머트리얼을 공유한다고 가정해 보겠습니다. 그리고 각각의 모델은 다른 어셋번들에 포함되도록 명시적으로 지정되어 있고, 머트리얼에는 명시적으로 어셋번들이 지정 되어 있지 않다고 하겠습니다. 이런 경우 머트리얼은 자동적으로 두 어셋번들에 각각 독립적으로 추가 됩니다. 결국 머트리얼의 공유라는 것이 의미가 없어집니다. 이런것을 방지하기 위해서는 머트리얼은 명시적으로 어셋번들에 할당 되어야 합니다. 


어셋번들의 의존성과 기타 다른 정보들은 메니페스트(Manifest)에 저장됩니다. 메니페스트는 일종의 컨텐츠 테이블 같은 것으로써, 어셋번들이 빌드 되면 유니티는 많은 양의 데이터를 생성하고 해당 데이터들의 상세정보가 메니페스트에 저장됩니다. 메니페스트는 어셋번들의 타겟 빌드마다 따로 만들어지며 이 메니페스트 파일을 통해 모든 어셋번들에 대한 질의와 의존성 참조가 이루어 집니다. 추후 뒤에 나오는 어셋번들의 빌드 과정이후 각 결과 폴더를 살펴 보면 어셋번들 하나당 .manifest라는 확장자를 가진 파일이 만들어 지는 것을 확인 할 수 있습니다.


어셋번들 매니저(Asset Bundle Manager)?
어셋번들을 사용 할때 가장 많은 노력이 필요한 부분은 어셋번들을 빌드하고 정상적으로 로딩 되는지 테스트 하는 부분입니다. 개발 중 어셋번들에 포함 되는 어셋들은 얼마든지 변경되거나 추가, 삭제 될 수 있습니다. 기본적으로  이런 경우 전체 어셋들을 다시 빌드하고, 원격 저장소에 업로드하고, 정상적인 다운로드와 로딩을 테스트 하는 과정을 반복해야 합니다. '어셋번들 매니저'(AssetBundle Manager)는 이와 같은 복잡하고 반복적인 작업을 단순한 클릭과 간단한 스크립트 작업으로 해결할 수 있도록 도와 줍니다.

어셋번들을 만들고 사용하는 과정을 요약하면 대충 아래와 같습니다 :
  1. 유니티 에디터에서 어셋번들에 포함될 어셋들을 지정
  2. 어셋번들 빌드
  3. 외부 저장소에 어셋번들을 업로드
  4. 어플리케이션에서 어셋번들을 다운로드
  5. 어플리케이션에서 어셋번들을 로드

어셋번들 매니저를 이용하면 위 과정중 1번. 어셋번들에 포함될 어셋들을 지정하는 작업외에는 모든 부분을 어셋번들 매니저에게 맡길수 있습니다.


1. 어셋번들에 포함될 어셋들을 지정
어셋들을 어셋번들로 빌드하기 위한 첫번째 과정은 해당 어셋이 어떤 어셋번들에 포함될 것인지, 어셋번들의 이름을 지정해 주는 것입니다. 여러분들은 이것을 위해서 유니티 에디터에서 간단한 설정 몇가지만 해주면 됩니다. 프로젝트(Project) 탭의 어셋을 클릭하면 인스펙터(Inspector)창에 해당 아래와 같은 어셋의 프리뷰를 볼수 있습니다.

어셋을 어셋번들에 포함되게 하기 위해서는 Asset Bundle Name 드롭 다운 메뉴를 이용하여 어셋이 어떤 어셋번들에 포함 될 것인지 지정해 주기만 하면 됩니다.


  1. 드롭 다운 메뉴를 클릭
  2. 포함 될 어셋번들의 이름을 선택.
    새로운 번들을 만들고 싶다면 'New...'를 선택 후 이름을 할당해 주고, 제외하고 싶다면 'None'을 선택
  3. 사용되지 않는 어셋번들을 지우고 싶다면 'Remove Unused Name' 선택

2. 어셋번들 베리언트(Asset Bundle Variant) 사용

어셋번들은 어셋 리소스를 저장하고 로드하는데 마주하는 많은 어려움들을 해결하는데 도움을 줍니다. 특히 이번 장에서 알아볼 어셋번들 베리언트는 타겟 디바이스나 로컬라이징, 유저 설정에 따라 다양한 어셋번들중 특정 버젼을  쉽게 로딩 할수 있도록 도와 줍니다.

예를 들어 어플리케이션이 한국에서 실행 되느냐 미국에서 실행 되느냐에 따라 메뉴가 한글이 될수도 있고 영어가 될수 있습니다. 이런 경우 모든 언어에 대응하는 텍스트 어셋번들을 만들고 배포하는 것이 아니라 한글버젼 어셋번들과 영어버젼 어셋번들을 만들고 어셋번들 베리언트를 이용해 구분하여 필요한 국가의 언어팩만 로드 할 수 있습니다.

어셋번들 베리언트를 이용하기 위해서는 :

  • 'Asset Bundle Name'은 동일해야 합니다
  • 유일하게 달라야 할 부분은 Asset Bundle Variant 부분 입니다.
  • 어셋번들 베리언트를 이용한 어셋번들간에 호환성을 가지려면 어셋번들에 포함 되는 컨텐츠의 폴더와 모든 어셋들은 같은 이름과 같은 계층구조를 가져야 합니다.

Project 탭 


어셋번들 실전에서 사용하기

지금까지 어셋 번들의 기본 개념에 대해서 알아 보았습니다. 이번 장에서는 우리가 어셋 번들과 관련된 작업을 함에 있어서 큰 도움을 줄수 있는 '어셋번들 매니저'(AssetBundleManager)를 이용하여 어셋 번들과 번들에 포함된 어셋들을 로드하는 방법에 대해서 알아보도록 하겠습니다. 


이전 장에서 우리는 어셋 번들을 사용하기 위해서는 빌드를 해야 하고, 원격 저장소 혹은 로컬 저장소에 배포를 해야 하며, 우리의 어플리케이션 내에서 API를 사용하여 로드를 해야 함을 배웠습니다. 만일 어셋 번들에 포함되는 어셋 중 하나라도 변경이 된다면, 변경이 발생할 때 마다 우리는 빌드 -> 배포 -> 테스트와 같은 지루하고 오랜 시간이 걸리는 작업을 반복 해야 합니다. 어셋 번들 매니저는 '시뮬레이션 모드'와 '로컬 어셋 번들' 서버를 제공함으로써 실제 빌드, 배포 과정을 거치지 않고도 정상적으로 어플리케이션이 어셋번들과 연동되는지 테스트 해볼수 있는 기능을 제공합니다.

  1. 시뮬레이션 모드
    시뮬레이션 모드가 활성화 되면 어셋번들 매니저는 프로젝트에 포함된 어셋들을 빌드하는 시뮬레이션을 수행합니다. 단순히 유니티 에디터 메뉴에서 “Assets/AssetBundles/Simulation Mode”를 체크해주면 시뮬레이션 모드가 활성화 됩니다. 시뮬레이션 모드에서는 실제 어셋번들 빌드를 수행하는 것이 아닌 프로젝트 런타임 시점에 빌드과정에 대해 시뮬레이션만 진행하는 것이므로 실제 빌드 보다 훨씬 빠른 속도를 제공합니다. 단, 주의할 점은 어셋번들 베리언트를 사용시 시뮬레이션 모드에서는 동작을 하지 않습니다.
  2. 로컬 어셋 번들 서버
    로컬 어셋 번들 서버는 보다 정확한 어셋 번들 배포 시뮬레이션을 제공합니다. 로컬 어셋 번들 서버를 사용하기 위해서는 유니티 에디터 메뉴에서 “Assets/AssetBundles/Local AssetBundle Server”를 활성화 하고 어셋 번들 빌드을 빌드하고 빌드된 어셋번들을 기본 폴더(프로젝트 최상위 폴더/AssetBundles)에 저장하는 과정이 필요합니다. 로컬 어셋 번들 서버가 활성화 되면 빌드된 어셋번들은 에디터와 모든 로컬 빌드에서 접근이 가능합니다. 로컬 어셋 번들 서버는 어셋 번들 베리언트를 로컬에서 테스트 해볼수 있는 유일한 방법이며 샘플로 제공된 씬을 구동하기 위해서 로컬 어셋 번들을 활성화 시키는 과정이 반드시 필요한 경우도 있습니다.

    어셋 번들 매니저가 제공하는 기능들을 살펴 보았으니 지금 부터는 로드에 필요한 API들에 대해 어셋 번들 매니저 샘플 예제를 통해 살펴 보도록 하겠습니다. 먼저 어셋 번들 매니저가 제공하는 API를 살펴 보도록 하죠 (AssetBundleManager/AssetBundleManager.cs 참고) :

    • Initialize() : 어셋번들 메니페스트(http://docs.unity3d.com/ScriptReference/AssetBundleManifest.html) 객체를 초기화 합니다.
    • LoadAssetAsync() : 어셋번들로 부터 지정된 어셋과 의존성을 가지고 있는 모든 다른 어셋들을 로드 합니다.
    • LoadLevelAsync() : 어셋번들로 부터 지정된 신과 의존성을 가지고 있는 모든 다른 어셋들을 로드 합니다.
    • LoadDependencies() : 지정된 어셋번들이 의존성을 가지고 있는 모든 다른 어셋번들들을 로드 합니다.
    • BaseDownloadingURL : 기본 다운로드 URL 경로를 지정합니다.
    • SimulateAssetBundleInEditor : 유니티 에디터의 시뮬레이션 모드를 활성화 합니다.
    • ActiveVariants : 어셋번들 베리언트를 저장합니다.
    • RemapVariantName() : 어셋번들 베리언트 네임을 이용하여 적합한 어셋번들 이름을 리턴합니다.

    AssetBundleManager 패키지에는 위 API들의 사용 예를 보여주는 샘플 파일들이 AssetBundleSample 폴더에 포함되어 있습니다. 샘플에는 세가지 기본 예제 씬과 세가지 예제들을 종합적으로 보여 주는 예제 씬이 'AssetBundleSample/Scenes'에 있습니다 :

    • AssetLoader : 어셋번들로 부터 일반 어셋을 어떻게 로드하는지 보여 줍니다.
    • SceneLoader : 어셋번들로 부터 씬을 어떻게 로드하는지 보여 줍니다.
    • VariantLoader : 어셋번들 베리언트를 이용하여 어셋을 로드하는 방법을 보여 줍니다.
    • LoadTanks : 위 세가지 예제를 조합하여 보여 줍니다.

    각각의 씬들은 LoadAssets.cs, LoadScenes.cs, LoadVariants.cs, LoadTanks.cs 스크립트에 구현 되어 있습니다.


    예제 1. 어셋 로딩하기

    1. 유니티 에디터 메뉴 "Assets > AssetBundles > Simulation Mode" 에서 시뮬레이션 모드 활성화 합니다.
    2. 프로젝트 탭에서 "AssetBundleSample/Scenes/AssetLoader" 씬을 엽니다. 플레이 모드를 실행하기 전에 씬엔 메인 카메라와 라이트, 로더 게임 오브젝트 외에는 아무것도 없음을 주목해주세요.
    3. 플레이 버튼을 눌러 프로젝트를 실행 합니다. 이때 어셋번들로 부터 큐브를 로딩하여 씬에 보여 줍니다.
    4. 씬과 관련된 스크립트는 'LoadAssets.cs'에서 확인 할 수 있습니다.
    AssetBundleSample/Scripts/LoadAssets.cs
    "AssetBundleSample/Scripts/LoadAssets.cs" 스크립트를 에디터에서 열어 주세요. LoadAssets 클래스에는 두개의 public 변수가 있습니다.
    • public string assetBundleName : 로드 될 어셋 번들의 이름
    • public string assetName : 로드 될 어셋의 이름

    이 스크립트는 Start() 함수와 Start() 함수에 의해 호출 되는 두개의 코루틴으로 구성되어 있습니다. 

    • Initialize() 함수에서는 DontDestroyOnLoad()를 호출 하고 난 후, 어셋 번들의 패스와 어셋 번들 매니페스트를 초기화 합니다. 필요해 보이지 않는 DontDestroyOnLoad()를 굳이 사용하는 이유는, 어셋번들 로딩을 관리하는 이 게임 오브젝트가 씬이 변경된다거나 할 때 지워지는 것을 방지하기 위해서 입니다.
    • InstantiateGameObjectAsync() 함수에서는 어셋과 어셋번들의 이름을 인자로 받아 AssetBundleManager.LoadAssetAsync() 함수를 호출 합니다. 이때 리턴 값이 null이 아닌 경우 해당 객체(프리팹)을 인스턴스 화 합니다.

    여기서 주의 깊게 볼 한가지는 프로젝트 탭 "AssetBundleSample/Assets"에 있는 "MyCube" 어셋은 "MyMaterial"에 의존성을 가지고 있고, "MyMaterial"은 "UnityLogo"에 의존성을 가지고 있는데, 우리가 한 일은 단지 "MyCube"만을 로드 했을 뿐이지만 어셋번들 매니저는 메니페스트를 통해 의존성을 파악하고 관련 모든 어셋들을 정확하게 로드해 준다는 것입니다. 또 한가지는 어떻게 어셋 번들의 패스가 셋팅 되는가 입니다. "LoadeAsset" 클래스의 코드에서는 씬이 로딩 될때 실행 환경이 에디터이거나 개발 버젼 빌드일 경우 어셋번들 위치를 로컬 어셋번들로 셋팅하는 것입니다(보다 정확하고 다양한 정보를 원하신다면 퍼블리싱 빌드 문서를 참고 해주세요).

    시뮬레이션 모드가 활성화 되어 있는 동안 에디터에서 플레이 모드를 실행 시키면 어셋번들은 실제 빌드와 다운로드 과정을 거치지 않고 단지 위과정들을 시뮬레이션만 합니다.


    예제 2. 씬 로딩하기

    1. 유니티 에디터 메뉴 "Assets > AssetBundles > Simulation Mode" 에서 시뮬레이션 모드 활성화 합니다.
    2. 프로젝트 탭에서 "AssetBundleSample/Scenes/SceneLoader" 씬을 엽니다. 플레이 모드를 실행하기 전에 씬엔 메인 카메라와 라이트, 로더 게임 오브젝트 외에는 아무것도 없음을 주목해주세요.
    3. 플레이 버튼을 눌러 프로젝트를 실행 합니다. 이때 어셋번들로 부터 큐브와 펑면을 로딩하여 씬에 보여 줍니다.
    4. 씬과 관련된 스크립트는 'LoadScene.cs'에서 확인 할 수 있습니다.
    AssetBundleSample/Scripts/LoadAssets.cs
    "AssetBundleSample/Scripts/LoadScene.cs" 스크립트를 에디터에서 열어 주세요. LoadScene 클래스에는 두개의 public 변수가 있습니다.
    • public string sceneAssetBundle : 로드 될 어셋 번들의 이름
    • public string sceneName : 로드 될 씬의 이름

    이 스크립트는 Start() 함수와 Start() 함수에 의해 호출 되는 두개의 코루틴으로 구성되어 있습니다. 

    • Initialize() 함수에서는 DontDestroyOnLoad()와 어셋 번들의 패스를 셋팅하고 어셋번들 메니페스트를 초기화 합니다.
    • InitializeLevelAsync() 함수에서는 씬의 이름과 isAdditive 변수를 인자로 받아 AssetBundleManager.LoadAssetAsync() 함수를 호출 합니다. 이때 리턴 되는 씬이 null인 경우 콘솔창에 에러 메시지를 출력하고 코루틴은 종료 됩니다. 
      InitializeLevelAsync()함수는 isAddtive 인자에 따라 내부적으로 Application.LoadLevelAdditiveAsync() 함수 혹은 Application.LoadLevelAsync()함수를 호출합니다. 두 함수 모두 씬 이름을 인자로 받아 씬을 백그라운드에서 비동기 로딩한다는 것은 같지만 LoadLevelAdditiveAsync()함수의 경우는 기존 씬에 로딩 되어 있는 게임 오브젝트들을 삭제하지 않고 추가만 한다는 것에 차이가 있습니다.
      만일 여러분께서 InializeLevelAsync() 함수의 isAdditive 인자를 false로 수정한 후 실행 한다면 Hierarchy 탭에 기존 신에서 로드 되어 있던 카메라와 라이트 오브젝트가 사라지고 큐브와 바닥만 로드 되어 있는 것을 확인 할수 있을겁니다.

    어셋 번들 매니저를 이용한 씬 로딩 역시 예제 1과 동일하게  의존성에 따라 필요한 어셋들을 자동적으로 로드 합니다. 우리가 로드한 것은 "TestScene" 하나지만 "TestScene"에 포함되어 있던 "Cube"와 그외 모든 어셋들이 로드 됩니다.


    예제 3. 어셋번들 베리언트 사용하기

    이번 장은 예제에 대한 본격적인 설명에 들어가기 앞서 약간의 부연 설명이 필요합니다. 어셋번들 베리언트는 시뮬레이션 모드에서는 구동되지 않고 로컬 어셋번들 서버를 사용하거나 실제 원격 저장 공간을 이용해야 합니다. 때문에 필수적으로 어셋번들이 빌드 되어야 합니다. 이전에 언급 되었듯이 어셋번들과 번들에 포함된 베리언트를 빌드하기 위해서는 빌드 대상 어셋들에 어셋번들 이름이 지정되어 있어야 합니다. 물론 베리언트를 사용할 어셋이라면 어셋번들 베리언트 네임 역시 지정되어야 합니다.


    어셋에 어셋번들 이름과 베리언트가 지정되면 에디터 메뉴 "Assets/AssetBundles/BuildAssetBundles"를 통해 어셋번들을 빌드 할 수 있습니다. 기본적으로 어셋번들은 현재 빌드 타겟에 최적화 되어 빌드 된 후 "프로젝트 폴더/AssetBundles" 폴더 아래에 빌드 타겟별로 그룹화(Android/OSX..) 되어 저장됩니다.


    편의성과 새로 빌드된 어셋번들을 배포 과정 없이 테스트 해보기 위해 로컬 어셋 번들 서버가 활성화 되어 있어야 합니다. 에디터 메뉴 "Assets/AssetBundles/Local AssetBundle Server"를 통해 로컬 어셋번들 서버를 활성화 할 수 있습니다. 로컬 어셋 번들 서버 역시 일반 원격 서버와 마찬가지로 접근 권한이라던지 방화벽과 같은 일반 다른 원격 서버와 동일한 제약 사항을 적용 받습니다. 로컬 어셋번들 서버가 정상적으로 활성화 된다면 이제 부터 어셋번들 다운로드를 로컬에서 테스트 해볼수 있습니다.

    1. 에디터 메뉴 "Assets/AssetBundles/Simulation Mode"에서 시뮬레이션 모드를 비활성화 시킵니다.
    2. 에디터 메뉴 "Assets/AssetBundles/Local AssetBundle Server"에서 로컬 어셋번들 서버를 활성화 시킵니다.
    3. 프로젝트 탭의 "AssetBundleSample/Scenes/VariantLoder" 신을 엽니다. 플레이 모드를 실행하기 전에 씬엔 메인 카메라와 라이트, 로더 게임 오브젝트 외에는 아무것도 없음을 주목해주세요.
    4. 플레이 버튼을 눌러 프로젝트를 실행 합니다.
    5. "Load SD"를 선택 합니다. 빨간색 큐브와 저해상도 스프라이트가 로드 된것을 확인합니다.
    6. 플레이 모드를 빠져나온 후 다시 플레이 버튼을 눌러 프로젝트를 실행합니다.
    7. "Load HD"를 선택 합니다. 이번에는 녹색 큐브와 고해상도 스프라이트가 로드 된것을 확인합니다.
      (만일 해당도나 큐브의 색이 바뀌지 않았다면 로컬 어셋번들 서버 활성화 여부, 빌드 여부를 체크해 주세요)
    8. 씬과 관련된 스크립트는 'LoadVariants.cs'에서 확인 할 수 있습니다.

    "AssetBundleSample/Scripts/LoadVariants.cs"

    "AssetBundleSample/Scripts/LoadVariants.cs" 스크립트를 에디터에서 열어 주세요. LoadVariants 클래스에는 두개의 public 변수와 두개의 private 변수를 가지고 있습니다.

    • public string variantSceneAssetBundle : 로드 될 어셋 번들의 이름
    • public string variantSceneName : 로드 될 신의 이름
    • private string[] activeVariants : "Load SD" 혹은 "Load HD" 버튼이 눌러지면 해당 어셋번들 네임을 저장하여 AssetBundleManager.ActiveVariants 변수에 셋팅 됩니다.
    • private bool bundlesLoaded : 버튼 UI의 디스플레이 여부를 판단하는 변수. 어셋번들이 로드 되고 난후 버튼을 숨기는데 사용 됩니다.

    이 스크립트는 BeginExample()과 Start()에 의해 호출되는 두개의 코루틴으로 구성됩니다. BeginExample()함수는 "Load SD" 또는 "Load HD" 버튼을 누름으로써 호출 됩니다.

    • Initialize() 함수에서는 DontDestroyOnLoad()와 어셋 번들의 패스를 셋팅하고 어셋번들 메니페스트를 초기화 합니다.
    • BeginExample() 함수에서 Initialize() 함수와 InitailizeLevelAsync() 함수가 호출되는 가운데 AssetBundleManager.ActiveVariants 변수가 셋팅 됩니다. 여기에서 셋팅 되는 값은 OnGUI()의 "Load SD" 또는 "Load HD" 버튼을 누를때 "sd" 또는 "hd"로 셋팅이 됩니다.

    여기서 우리가 주의 깊게 살펴봐야 하는 부분은 어셋번들에서 베리언트에 따라 어떻게 구분 되어 씬에 로드 될수 있는가 입니다. 어셋번들 베리언트를 지정하게 되면 "."을 구분자로 하여 어셋번들 이름이 메니페스트에 저장 됩니다. 이 예에서는 "AssetBundleSample/SampleAssets/Variants" 하위의 "MyAssets-HD" 폴더와 "MyAssets-SD"  폴더의 하위 어셋들이 어셋 각각 "variants/myassets.hd" 와 "variants/myassets.sd"와 같은 이름을 가집니다. AssetBundleManager는  "."을 구분자로 어셋번들 이름과 AssetBundleManager.ActiveVarintans에 지정된 베리언트 이름이 일치하는 어셋을 로드합니다.


    AssetBundleManager.ActiveVariants는 여러 개의 엔트리를 가지는 것도 가능합니다. 예를 들어 my-material.sd, my-material.hd, my-text.english, my-text.danish, my-text.catalan, my-text.welsh와 같이 어셋번들 베리언트가 지정되었다고 하면, ActiveVariants는 "hd"와 "danish" 혹은 "sd"와 "english"와 같이 다양한 조합을 선택할 수 있습니다. 이와 같은 방법으로 어셋번들 매니저는 hd 혹은 sd의 해상도와 언어 선택을 개별적으로 처리 할 수 있습니다.


    만일 ActiveVariants에 아무런 어셋번들 베리언트 네임이 셋팅되어 있지 않다면 어셋번들 매니저는 베리언트 이름을 무시하고 지정된 이름의 어셋번들 중 가장 첫번째에 검색되는 어셋번들을 로드 합니다. 또한 동일한 어셋번들 네임을 가진 다른 베리언트들이 동시에 지정되어 있다면 - 예를 들어 "sd"와 "hd"가 동시에 지정 - 어셋번들 매니저는 ActiveVariants에 셋팅되어 있는 베리언트 네임 중 가장 앞에 있는 어셋번들을 로드 합니다.


    예제 4. 탱크

    이번 장에서는 이전까지 살펴 보았던 부분들을 되세기며 기본적인 씬과 어셋들을 로드하고 특정 게임 오브젝트에 대해서는 어셋번들 베리언트를 사용하여 해상도와 컨텐츠, 로컬라이징에 따른 언어팩을 선택 할수 있는 통합 예제를 살펴 보도록하겠습니다.

    1. 에디터 메뉴 "Assets/AssetBundles/Simulation Mode"에서 시뮬레이션 모드를 비활성화 시킵니다.
    2. 에디터 메뉴 "Assets/AssetBundles/Local AssetBundle Server"에서 로컬 어셋번들 서버를 활성화 시킵니다.
    3. 프로젝트 탭의 "AssetBundleSample/Scenes/TanksLoder" 신을 엽니다.
      씬엔 메인 카메라와 라이트, "Loader" 게임 오브젝트 외에는 아무것도 없음을 주목해주세요.
    4. 플레이 버튼을 눌러 프로젝트를 실행 합니다.
    5. 해상도와 스타일, 언어를 각각 선택 합니다.
    6. 선택에 따라 각각의 어셋이 로드된것을 확인 합니다. 만일 명시적으로 선택된 옵션이 없는 경우 어셋번들 매니저가 자동으로(예제 3에서 살펴본 룰에 따라) 한가지를 선택, 콘솔창에 경고를 출력하는 것을 확인 합니다.
    7. 씬과 관련된 스크립트는 'LoadTanks.cs'에서 확인 할 수 있습니다.
      "AssetBundleSample/Scripts/LoadTanks.cs" 스크립트를 에디터에서 열어 주세요.

    이 스크립트는 이전 예제의 "LoadScenes.cs", "LoadAssets.cs"와 매우 비슷합니다. 이전 예제에서는 하나의 어셋번들만 로드 했지만 이 예제에서는 씬을 가지고 있는 어셋과 텍스트 어엣을 가지고 있는 어셋번들 두개를 로드 합니다. 이전 예제에서 이미 살펴 보았던 어셋과 씬의 로딩을 통합하여 하나의 클래스에서 호출하는 것 외에는 이전 예제들과 크게 다른 점은 없기 때문에 많은 설명이 필요하진 않습니다.

    • public string sceneAssetBundle : 로드 될 씬 어셋번들의 이름
    • public string sceneName : 로드 될 신의 이름
    • public string textAssetBundle : 로드 될 텍스트 어셋번들의 이름
    • public string textAssetName : 로드 될 텍스트 어셋의 이름
    • private string[] activeVariants : 어셋번들 매니저에게 전달 될 활성화 될 어셋번들 베리언트의 이름 배열
    • private bool bundlesLoaded : 버튼 UI 표시/숨김에 사용될 변수
    • private bool sd, hd, normal, desert, english, danish : ActiveVarinat에 셋팅 될 옵션 선택 여부
    • private string tankAlbedoStyle, tankAlbedoResolution, language : ActiveVarinat에 셋팅 될 옵션 선택 여부

    이 스크립트는 BeginExample() 함수와 Start()에서 호출 되는 세개의 코루틴으로 구성되어 있습니다. BeginExample() 함수는 "Load Scene" 버튼을 클릭 시 호출 됩니다.

    • Initialize() 함수에서는 DontDestroyOnLoad()와 어셋 번들의 패스를 셋팅하고 어셋번들 메니페스트를 초기화 합니다.
    • BeginExample() 함수에서 Initialize() 함수와 InitialzeLeveAsync() 함수 가운데 AssetBundleManager.ActiveVariants 변수가 셋팅 되며 세부 내용은 이전 장에서 살펴 봤던것과 동일 합니다.
    • InitialzeLeveAsync() 함수와 InstantiateGameObjectAsync() 함수를 호출하여 신과 텍스트 어셋을 로드 합니다.


    이상 어셋번들의 기본 개념과 어셋번들의 빌드/배포/로드를 도와 주는 어셋번들 매니저의 사용 방법에 대해 알아 보았습니다. 보다 자세한 정보를 얻고 싶다면 다음 링크를 참고해 주세요.

    원문 : http://unity3d.com/kr/learn/tutorials/topics/scripting/assetbundles-and-assetbundle-manager?playlist=17117


    문제 해결 : 어셋번들 로드 시 쉐이더가 정상적으로 표현 되지 않는 문제 

     - http://forum.unity3d.com/threads/custom-shaders-and-asset-bundles-on-ios.144014/

     - http://baramlife.tistory.com/9


    '진리는어디에' 카테고리의 다른 글

    삼각함수  (0) 2016.06.27
    리팩토링 - Position 클래스  (0) 2016.02.14
    Unity Asset Bundle  (0) 2016.01.29
    Unity Coroutine  (0) 2016.01.22
    브레즌햄(Bresenham) 알고리즘  (0) 2016.01.16
    unity Animator 사용하여 애니메이션 종료까지 기다리기  (0) 2015.12.14
    Posted by kukuta

    댓글을 달아 주세요

    애니메이션이 플레이 중인지 종료가 되었는지는 다음과 같은 체크 코드를 사용하면 간단하게 알아 볼수 있다.

    animator.GetCurrentAnimatorStateInfo(0).IsName("YourAnimationName")


    "YourAnimationName" : 메카님 스테이트의 이름(Animator 윈도우를 보면 여러 상태가 있는데 체크하고 싶은 애니메이션이 플레이되는 상태의 이름을 적어주면 된다).


    IEnumerator WaitForAnimation(Animator animator)

    {

    while (true == animator.GetCurrentAnimatorStateInfo(0).IsName("<UserAnimationStateName>")) {

    yield return new WaitForEndOfFrame();

    }

    GameObject.Destroy (animator.gameObject);

    }


    위 함수를 작성하고 StartCoroutine() 함수를 이용해 호출 해주면 애니메이션 재생이 끝나면 해당 오브젝트가 삭제 된다.


    출처 : http://answers.unity3d.com/questions/362629/how-can-i-check-if-an-animation-is-being-played-or.html


    위의 방식이 정상 동작하지 않았다. 그래서 아래와 같이 IsInTransition함수를 이용하여 애니메이션 종료 여부를 알아 내도록 한다.

    IEnumerator WaitForAnimation(Animator animator)
    {
        //while (true == animator.GetCurrentAnimatorStateInfo(0).IsName(name)) {
        while(false == animator.IsInTransition(0)) {
            yield return new WaitForEndOfFrame();
        }
        GameObject.Destroy (animator.gameObject);

    }

    단 위와 같은 방법을 사용하기 위해서는 메카님에서 상태 변화(Transition)를 시켜 줘야한다.


    Posted by kukuta

    댓글을 달아 주세요

    현상 : GameObject의 AddComponent를 호출 했는데, 맥에서는 아무런 문제 없이 동작했지만 윈도우에서 작업 할 때는 null을 리턴 한다.


    원인 : MonoBehaviour 를 상속 받은 아주 작은 역할을 하는 클래스를(이하 A 클래스) 새로운 파일을 만들지 않고 기존 클래스의(이하 B 클래스) 내부에 작성하였는데 이런 경우 윈도우에서는 AddComponent 시 null을 리턴한다.


    해결 : A 클래스와 이름이 같은 신규 파일을 생성


    참조 : http://forum.unity3d.com/threads/gameobject-addcomponent-is-returning-null.68201/


    사족 : 유니티에서 MonoBehaviour를 상속받은 클래스는 new 로 생성할 수 없고 GameObject에 AddComponent를 통해서만 생성 할 수 있단다. 



    Posted by kukuta
    TAG unity

    댓글을 달아 주세요

    이번 포스팅은 Facebook Unity SDK(https://developers.facebook.com/)를 이용하여 Unity와 facebook을 연동하는 방법에 대해서 다룹니다. 예제 코드는 facebook sdk 패키지를 import하면 만들어지는 Examples/InteractiveConsole이 깔끔하고 쉽게 나와있으므로 그것을 보시는 것이 좋습니다. 


    본 포스팅에서는 InteractiveConsole 예제를 실행하면서 겪었던 환경 셋팅 문제를 주로 다룹니다. 현재 안드로이드 버젼마 다루고 있으며 ios의 경우에는 해당 작업을 하게 되면 추가하도록 하겠습니다.


    준비 작업 :

    • Java SDK(ver 1.7) : : facebook 앱 인증에 필요한 key hash를 생성하는데 사용됩니다.
    • OpenSSL(dowload) : facebook key hash를 생성과 안드로이드 빌드 위해 필요 합니다.
      • Java SDK와 OpenSSL의 경우에는 설치를 하고 환경 변수 PATH에 bin 디렉토리의 경로를 등록합니다.
    • Unity 3D(ver. 4.3.4f) : http://unity3d.com/ 에서 다운 받으시면 됩니다. 자세한 설명은 생략합니다.
    • Facebook Unity SDK(ver 4.3.6) : https://developers.facebook.com/docs/unity/downloads/ 에서 다운 받으시면 됩니라. 링크가 변경 되었더라도 충분히 검색을 통해 찾으실수 있으리라 믿습니다.
    • 혹시나 몰라 버젼을 기록해 두었습니다. 뭔가 이상하게 돌아간다면 버젼을 확인해보시고 버젼이 상이하고 이 문서가 더 이상 도움이 되지 않는다고 생각 되시면 kukuta@gmail.com으로 메일 주십시오.

    Overview : 

      우리가 하게 될 작업에 대해 간단하게 알아 보겠습니다.

    1. 일단 Unity가 설치되어 있어야 합니다.
    2. Facebook Unity SDK를 Unity 프로젝트에 import 합니다. 
    3. Facebook app을 만듭니다.
    4. Unity에서 Build Setting과 Facebook 연동.
    5. 빌드해서 스마트 폰에 올려 봅니다.
    6. 테스트 합니다.
    7. 문제를 발견 합니다..고칩니다..빌드해서 스마트 폰에 올려 봅니다..테스트 합니다..문제르..쿨럭..

    step 1. Unity 설치

    • 알아서들 설치 합니다. 이 포스트를 볼 정도면 Unity 설치가 문제가 아니라고 생각 됩니다.

    step 2. Facebook Unity SDK Download & Import

    • https://developers.facebook.com/docs/unity/downloads/ 에서 SDK를 다운 받습니다.
    • 페이지가 깨지거나 링크가 달라지더라도 검색을 통해 알아서 다운 받으실수 있다고 믿습니다.
    • 다운로드 받고 custom import 하는 부분에 대해서도 설명을 생략합니다.
    • SDK가 import 되고 나면 Unity 메뉴에 'Facebook'이 추가 됩니다.
    • https://developers.facebook.com/docs/unity/getting-started/canvas 참조

    step 3. Facebook 앱 만들기

    • Facebook 앱 생성에 대한 설명 역시 생략합니다.
    • 설정에 필요한 Package Name, Class Name, Key Hashes 항목은 Unity 셋팅을 통해 생성됩니다. 
    • 본 포스팅 마지막 과정에서 위 세개 값을 Unity로 부터 생성하여 복사해서 넣도록 하겠습니다.

    step 4. Unity와 Facebook 연동

    1) App Name, App Id - "Invalid App Id"

    • Unity 프로젝트 생성, Scene 생성 등에 대한 설명은 생략합니다.
    • 'Facebook > Edit Settings' 메뉴를 클릭하면 Facebook Settings Inspector가 뜹니다.
    • 'Facebook 앱'에서 App Name과 App Id 복사해 붙여 넣습니다.

    2) 플랫폼 안드로이드로 변경

    • 'File > Build Settings' 메뉴를 클릭, Platform=Android 변경, Switch Platform을 클릭하여 플랫폼을 변경합니다.

    3) Package Name 지정

    • 'Facebook > Edit Settings'에 보면 기본 Package Name이 (com.Company.ProductName) 셋팅 되어 있습니다.
    • 'File > Build Settings > Player Settings 클릭 > Inspector 창 > Other Settings 메뉴 > Bundle Identifier'를 수정
    4) Class Name
    • 'com.facebook.unity.FBUnityDeepLinkingActivity'
    • 지정되어 있는대로 내비둡니다. 나중에 이걸 복사해서 facebook 엡에 붙여 넣을 겁니다.

    5) Key Hash 생성

    • 조심하십시오. 가장 많은 삽질이 여기서 일어납니다!!!
    • "your android debug keystorefile is missing! you can create new one by creating and build empty android project in eclipse" 가 디스플레이 되고 있다면 아직은 정상입니다. 
    • key hash를 먼저 생성해 주어야 합니다. 그러기 위해서는 Java SDK 에 들어 있는 keytool과 OpenSSL이 필요 합니다. (혹시 아직 설치하지 않았다면 Java SDK와  OpenSSL을 설치하시고 환경 변수(PATH)에 bin 디렉토리를 등록하신 다음 여기로 돌아 오시기 바랍니다)
    • 커맨드 창을 열어 다음과 같이 입력 합니다 :

    keytool -genkey -alias androiddebugkey -keystore D:\Project\FacebookLogin\Facebook\debug.keystore| "openssl.exe" sha1 -binary | "openssl.exe" base64

      • '-genkey' : 키를 생성하라는 옵션입니다.
        Facebook 가이드 문서를 보면 -exportcert 옵션을 사용하는데, 이 옵션의 경우 파일이 없는 경우 새로 생성 해내지 않습니다. 하지만 우리는 대부분 처음 작업하는 사람인지라 기존 파일이 없겠지요.
      • '-alias' : 뭔지 잘 모르겠습니다. 그냥 androiddebugkey라고 적어 줍니다.
      • '-keystore' : key가 저장될 위치와 이름을 지정합니다.
        상대 경로도 가능한지 모르겠습니다. 지정된 디렉토리가 없는 경우 새로 생성하지 않고 실패 합니다. 디렉토리는 미리 생성 되어 있어야 합니다.
      • 나머지는 그냥 그대로 따라 쓰면 됩니다.
    • 정상적인 상황이라면 패스워드를 물어 옵니다. "android" 를 입력 합니다. 그 외에 질문하는 것들은 모두 엔터로 넘겨 버리고 맨 마지막 질문에 "yes(한글 버젼이면 예)"를 타이핑합니다. 이렇게 되면 key hash 생성에 성공 입니다.(따옴표는 입력하지 않습니다. 만일 패스워드를 묻지 않는다면 뭔가 잘못 된 것입니다.)

    6) 'File > Build Settings > Player Settings 클릭 > Inspector 창 > Publishing Settings

    • Use Existing Keystore 체크
    • Browse Keystore클릭 하고 이전에 생성해놓은 debug.keystore 위치를 찾아 선택
    • Keystore password에 "android" 입력
    • Alias 에서 androiddebukey 선택
    • Password "android" 

    • 위와 같이 셋팅하고 다시 'Facebook > Edit Settings' 메뉴로 돌아가면 Package Name, Class Name, Debug Android Key Hash가 모두 반영 되어있습니다.
    • ..라고 하고 싶지만 여전히 "your android debug keystorefile is missing! you can create new one by creating and build empty android project in eclipse" 메시지가 나오고 있을 겁니다.
    • Facebook SDK의 윈도우쪽 버그로써 아래 Trouble Shooting에서 다루겠습니다.

    7) Unity로 부터 Package Name, Class Name, Key Hash를 복사 & 붙여 넣기를 하고 저장

    • 'Facebook > Edit Settings'
    • Package Name, Class Name, Key Hash를 페이스 북에 복사 & 붙여 넣기
    • 로그인 테스트를 하는데 개발자만 로그인이 되고 다른 사람들이 로그인 되지 않는 경우는 아래 Trouble Shooting 항목을 참고 하세요.

    step 5. Build & Run on Device

    • Facebook SDK 4.3버젼에서는 PC에서 로그인 테스트를 하는 경우 무조건 성공을 떨어뜨리는 버그가 있다. 제대로된 테스트를 위해서는 꼭 장치에 올려서 테스트 해보도록 한다.

    step 6. Trouble Shooting :

    • "your android debug keystorefile is missing! you can create new one by creating and build empty android project in eclipse"
      • key hash 파일이 생성되지 않았거나, 지정된 위치에 없으면 발생하는 에러 메시지 입니다.
      • key hash 파일을 생성했고, 해당 파일이 지정된 디렉토리에 있는데도 불구하고 위 메시지가 발생 되는 경우원인은 Facebook Unity SDK 의 버그로써 SDK에서는 key hash 파일을 특정 위치에만 놓고 사용하도록 코드가 만들어져 있습니다(윈도우의 경우에는 "C:/Users/<계정>/.android/debug.keystore", 리눅스 or 맥의 경우에는 ~/.android/debug.keystore). 그런데 윈도우의 경우에는 앞에 "C:/" 부분이 빠져 있기 때문에 SDK 코드를 직접 수정해야만 합니다(http://answers.unity3d.com/questions/596752/android-debug-keystore-file-is-missing.html) :

      • 저 같은 경우 Unity 프로젝트 내에 Facebook이라는 디렉토리를 만들고 그 안에 debug.keystore 파일을 저장했습니다만..각자 편한대로 수정해서 사용하시면 될듯 합니다.
    • "openssl not found. make sure that openssl is installed and that it is in your path"
      • open ssl이 PATH 환경 변수에 제대로 등록 되지 않은 것입니다. 등록하시고 unity를 재시작 합니다.
    • 개발자만 로그인이 되고 다른 사람 계정은 로그인이 되지 않아요!
      • Facebook 앱을 공개로 변경하지 않으면 앱 개발자만 로그인 할수 있습니다. Status & Review 설정에서 앱을 공개로 변경하거나 테스트 사용자를 등록하여 로그인하셔야 합니다.


    Posted by kukuta

    댓글을 달아 주세요

    1. Favicon of http://QuainTree.tistory.com BlogIcon SOVOT 2014.04.03 10:00  댓글주소  수정/삭제  댓글쓰기

      좋은 글 감사합니다 여러 모로 많은 도움이 되었습니다~ 궁금한 점이 있는데요 페이스북 설정에서 key hash 값은 유니티 페이스북 세팅에서 보여지는 Debug Android Key Hash 값을 계속 사용하면 되는건가요?

    2. ItsMe 2014.07.24 00:12  댓글주소  수정/삭제  댓글쓰기

      좋은 정보 진심으로 감사드립니다.
      좋은 하루되세요~ ^^

    3. BlogIcon 데코 2014.08.28 18:15  댓글주소  수정/삭제  댓글쓰기

      좋은글 감사합니다 트러블슈팅이 아주 도움이 되었습니다.

    4. 다른사람도 보여주고싶은데 ㅠㅠ 2014.10.31 16:38  댓글주소  수정/삭제  댓글쓰기

      아래 설명해 주셨지만 경로좀 알수 있을까요 ...?

    5. 스타키 2014.11.16 00:24  댓글주소  수정/삭제  댓글쓰기

      잘 보고 갑니다!

    6. mgk 2014.12.08 22:06  댓글주소  수정/삭제  댓글쓰기

      좋은글 감사드립니다.
      설정이 제대로 된것 같은데 정작 apk 파일 만들어서 폰에서 실행시키면
      FB.Login 함수 호출되는 타이밍에 애플리케이션이 비정상 종료되네요..
      조언부탁드립니다.

    7. 토고망고 2015.03.09 07:42  댓글주소  수정/삭제  댓글쓰기

      개인 개발자입니다. 능력자님 덕분에 막혔던 부분을 해결하고 갑니다. 고맙습니다~!

    8. 초식식물 2017.01.04 11:14  댓글주소  수정/삭제  댓글쓰기

      감사합니다 :) 덕분에 해결됬네여