블로그 이미지
Every unexpected event is a path to learning for you.

카테고리

분류 전체보기 (2737)
Unity3D (817)
Programming (474)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (58)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (53)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday
04-23 13:34


[링크] http://m.blog.daum.net/zevie/21

반응형
Posted by blueasa
, |



[링크] http://ijemin.com/blog/5385

반응형
Posted by blueasa
, |

프로그래밍을 할 때 있어서 모든 일이 처음 설계한대로 흘러간다면 얼마나 좋을까? 하지만 Hello World를 출럭하는 프로그램이 아닌 이상에야 그런 일은 있을 수 없다.


확장성을 위해, 재사용성을 위해, 더 나은 구조를 위해 코드와 설계는 변하기 마련이다. 그 와중에 많은 함수나 변수, 클래스가 추가되고 삭제된다. 물론 혼자서만 하는 작업이라면 코드를 바꾸고 바꾼 코드를 바로 적용하면 되지만, 코드 베이스를 만드는 사람과 그 베이스를 이용해서 작업하는 사람이 따로 있는 상황이라면 이야기가 조금 달라진다. 


만약 베이스를 작업하는 사람이 몇몇의 함수를 삭제하고 다른 이름의 함수로 대체했다면 그 베이스를 응용하는 사람 역시 그에 대한 사실을 알아야 한다. 물론 일반적인 상식으로 베이스 작업자가 베이스를 변경했다면 다른 작업자에게 바로 알려주고 다른 작업자는 바로 변경하는게 맞는 이야기지만, 사람과 사람 사이의 의사소통이라는게 말처럼 쉽기만 하던가. 베이스 작업자가 변경사항을 몇 개는 빠뜨리고 알려줄 수도 있고, 다른 작업자는 이야기를 들었지만 까먹을 수도 있는 일이다. 여튼 의사소통 과정에서 문제가 발생했다면 다른 작업자는 뜬금없이 바뀐 베이스 코드에 당황을 금치 못할 것이다.


그런 상황을 맞이한 다른 작업자는 당연히 문제를 해결하기 위해서 베이스 작업자에게 어떻게 변경된 것인지 물어보던지, 코드를 뒤져서 바뀐 함수를 적용하던지 하는 노력을 하겠지만 아무래도 이런 방식은 해결 속도도 느릴 뿐더러 효율적이지 못하다.


그렇기 때문에 나온 해결책이 바로 [Obsolete] 라는 어트리뷰트이다. 


class TestClass
{
    [Obsolete]
    public void Function1()
    {
    }
}


더 이상 사용하지 않거나 그럴 예정인 클래스나 함수, 변수의 앞에 [Obsolete] 어트리뷰트를 붙여주면 된다. 그렇게 하면 해당 함수를 호출할 때 초록색 밑줄과 함께 더 이상 사용하지 않는 함수라는 경고가 뜬다.



그리고 툴팁에서는 함수 앞에 [deprecated]가 붙게 된다.


이 [Obsolete]는 세 가지 방식의 오버로딩을 지원한다.


class TestClass
{

    [Obsolete]
    public void Function1()
    {

    }

    [Obsolete("Not use anymore.")]
    public void Function2()
    {

    }

    [Obsolete("Not use anymore.", true)]
    public void Function3()
    {

    }
}


[Obsolete] :: 더 이상 사용하지 않는 코드라는 경고만 출력한다.


[Obsolete(string message)] :: 더 이상 사용하지 않는다는 경고에 추가적인 메시지를 남길 수 있다. 이 메시지를 통해 더 이상 사용하지 않는 코드 대신에 사용할 코드를 사용자에게 알릴 수 있다.


[Obsolete(string message, bool error)] :: 추가적인 로그와 함께 이 코드를 사용할 경우에 컴파일 에러를 띄울지를 결정한다. true를 넣어주면 컴파일 에러를 띄워서 이 코드를 사용하면 컴파일을 할 수 없게 된다.



이런 식으로 [Obsolete]를 적절하게 사용하면 베이스 작업자는 코드 작업만으로 다른 작업자에게 코드가 변경되었음을 알림과 동시에 그에 대한 해결책도 전해줄 수 있다. 베이스 작업자가 코드를 변경하고 다른 작업자에게 변경사항을 일일이 알리는 것보다 훨씬 빠르고 효율적인 해결책이다.



출처: http://wergia.tistory.com/23 [베르의 프로그래밍 노트]



참조 : http://answers.unity3d.com/questions/559529/how-to-mark-a-method-obsolete.html

반응형

'Programming > C#' 카테고리의 다른 글

ODBC/OleDB로 Excel 읽어서 처리할 때, 255자로 짤리는 경우  (0) 2018.04.13
Dictionary for Loop in C#  (0) 2017.12.05
[펌] string을 byte[] 배열로 변환?  (0) 2017.01.10
[펌] 반복문 유틸  (0) 2016.12.07
[펌] Loop Dictionary  (0) 2016.12.07
Posted by blueasa
, |

UnityWebRequest를 이용해서 원격 서버에서 받아온 에셋 번들을 로컬 저장소에 저장하는 방법

유니티 5.6 문서에서는 알려주지 않는 로컬 저장소 저장 방법

유니티 5.6 문서에서는 웹 서버에서 에셋 번들을 받아올 때 WWW.LoadFromCacheOrDownload 대신에 UnityWebRequest와 DownloadHandlerAssetBundle을 사용할 것을 권장하고 있다. 아래의 코드가 유니티 5.6 문서에서 보여주는 웹 서버에서 에셋 번들을 받아와서 메모리에 로드하는 예제이다.

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class UnityWebRequestExample : MonoBehaviour
{
IEnumerator InstantiateObject()
{
string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;
UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
yield return request.Send();

AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);

GameObject cube = bundle.LoadAsset<GameObject>("Cube");
GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");

Instantiate(cube);
Instantiate(sprite);
}
}


출처: http://wergia.tistory.com/32 [베르의 프로그래밍 노트]
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class UnityWebRequestExample : MonoBehaviour
{
IEnumerator InstantiateObject()
{
string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;
UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
yield return request.Send();

AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);

GameObject cube = bundle.LoadAsset<GameObject>("Cube");
GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");

Instantiate(cube);
Instantiate(sprite);
}
}


출처: http://wergia.tistory.com/32 [베르의 프로그래밍 노트]
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class UnityWebRequestExample : MonoBehaviour
{
IEnumerator InstantiateObject()
{
string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;
UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
yield return request.Send();

AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);

GameObject cube = bundle.LoadAsset<GameObject>("Cube");
GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");

Instantiate(cube);
Instantiate(sprite);
}
}


출처: http://wergia.tistory.com/32 [베르의 프로그래밍 노트]
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class UnityWebRequestExample : MonoBehaviour
{
IEnumerator InstantiateObject()
{
string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;
UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
yield return request.Send();

AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);

GameObject cube = bundle.LoadAsset<GameObject>("Cube");
GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");

Instantiate(cube);
Instantiate(sprite);
}
}


출처: http://wergia.tistory.com/32 [베르의 프로그래밍 노트]
using UnityEngine;
using UnityEngine.Networking;

public class UnityWebRequestExample : MonoBehaviour
{
IEnumerator InstantiateObject()
{
string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;
UnityWebRequest request = UnityWebRequest.GetAssetBundle(uri, 0);
yield return request.Send();

AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);

GameObject cube = bundle.LoadAsset<GameObject>("Cube");
GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");

Instantiate(cube);
Instantiate(sprite);
}
}
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class UnityWebRequestExample : MonoBehaviour
{
IEnumerator InstantiateObject()
{
string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;
UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
yield return request.Send();

AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);

GameObject cube = bundle.LoadAsset<GameObject>("Cube");
GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");

Instantiate(cube);
Instantiate(sprite);
}
}


출처: http://wergia.tistory.com/32 [베르의 프로그래밍 노트]

서버에서 받아온 에셋 번들을 메모리에 넣어두고 사용하고자 하는 목적이 아니라 받아온 에셋 번들을 클라이언트의 로컬 저장소에 저장하고 패치하는 시스템을 만들고자할 때에는 부적절한 예제이며, 로컬 저장소에 저장하는 방법은 유니티 5.6의 문서에서는 알려주지 않는다.



에셋 번들을 로컬 저장소에 저장하는 방법

서버에서 받아온 에셋 번들을 로컬 저장소에 저장하려면 받아온 데이터를 파일 입출력을 해야했는데, 그러기 위해서는 우선 받아온 에셋 번들의 데이터, byte[] data를 찾아내고 거기에 엑세스할 수 있어야 했다. 그래서 첫 번째로 시도한 방법이 위의 예제에서 UnitWebRequest.GetAssetBundle()로 받아온  UnityWebRequest request에서 request.downloadHandler.data를 통해서 접근하는 것이었다.

using System.IO;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class AssetLoader : MonoBehaviour
{
public string[] assetBundleNames;

IEnumerator AccessFailMethod()
{

string uri = "http://127.0.0.1/character";


UnityWebRequest request = UnityWebRequest.GetAssetBundle(uri);

yield return request.Send();
string assetBundleDirectory = "Assets/AssetBundles";

if (!Directory.Exists(assetBundleDirectory))
{
Directory.CreateDirectory(assetBundleDirectory);
}

FileStream fs = new FileStream(assetBundleDirectory + "/" + "character.unity3d", System.IO.FileMode.Create);
fs.Write(request.downloadHandler.data, 0, (int)request.downloadedBytes);
fs.Close();
}
}

하지만 위의 방법은 에셋 번들에 대한 원시 데이터 접근은 지원하지 않는다는 예외를 발생시키고 실패한다. 즉, GetAssetBundle로 웹 서버에서 불러온 데이터는 데이터에 대한 직접 접근을 허용하지 않으니 파일 입출력을 통해서 로컬 저장소에 저장할 수 없다는 것이다.


그렇기 때문에 로컬 저장소에 저장하기 위해서는 웹 서버에서 에셋 번들을 받아올 때 다른 방법을 취해야 했다. 아래의 예제가 다른 방식으로 웹 서버에서 에셋 번들을 받아와서 로컬 저장소에 저장하는 예제이다 :

using System.IO;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class AssetLoader : MonoBehaviour
{

// 서버에서 받아오고자 하는 에셋 번들의 이름 목록

// 지금은 간단한 배열 형태를 사용하고 있지만 이후에는

// xml이나 json을 사용하여 현재 가지고 있는 에셋 번들의 버전을 함께 넣어주고

// 서버의 에셋 번들 버전 정보를 비교해서 받아오는 것이 좋다.
public string[] assetBundleNames;

IEnumerator SaveAssetBundleOnDisk()
{

// 에셋 번들을 받아오고자하는 서버의 주소

// 지금은 주소와 에셋 번들 이름을 함께 묶어 두었지만

// 주소 + 에셋 번들 이름 형태를 띄는 것이 좋다.
string uri = "http://127.0.0.1/character";


// 웹 서버에 요청을 생성한다.
UnityWebRequest request = UnityWebRequest.Get(uri);
yield return request.Send();


// 에셋 번들을 저장할 경로

string assetBundleDirectory = "Assets/AssetBundles";
// 에셋 번들을 저장할 경로의 폴더가 존재하지 않는다면 생성시킨다.
if (!Directory.Exists(assetBundleDirectory))
{
Directory.CreateDirectory(assetBundleDirectory);
}


// 파일 입출력을 통해 받아온 에셋을 저장하는 과정
FileStream fs = new FileStream(assetBundleDirectory + "/" + "character.unity3d", System.IO.FileMode.Create);
fs.Write(request.downloadHandler.data, 0, (int)request.downloadedBytes);
fs.Close();
}
}

위 예제에서 보다시피 UnityWebRequest.Get() API를 사용했을 경우 받아온 에셋 번들의 원시 데이터에 대한 접근이 가능해진다. 이로 인해서 파일 입출력을 통한 원격 서버에서 받아온 에셋 번들의 로컬 저장소 저장에 성공하게 되었다.



파일 입출력을 통한 저장 방법

받아온 에셋 번들을 파일 입출력을 통해 로컬 저장소에 저장하는 방법은 여러가지가 있다. 적당하다고 생각되는 방법을 골라서 사용하면 될 것이다.

// 파일 저장 방법 1
FileStream fs = new FileStream(assetBundleDirectory + "/" + "character.unity3d", System.IO.FileMode.Create);
fs.Write(request.downloadHandler.data, 0, (int)request.downloadedBytes);
fs.Close();

// 파일 저장 방법 2
File.WriteAllBytes(assetBundleDirectory + "/" + "character.unity3d", request.downloadHandler.data);
 

// 파일 저장 방법 3
for (ulong i = 0; i < request.downloadedBytes; i++)
{
fs.WriteByte(request.downloadHandler.data[i]);
// 저장 진척도 표시

}



로컬 저장소에 저장한 에셋 번들을 불러와서 사용하는 방법

위의 과정을 통해 원격 서버에서 받아온 에셋 번들을 로컬 저장소에 저장하는데 성공했다. 이 다음에 해야할 작업은 저장한 에셋 번들을 불러와서 사용하는 것이다. 그 작업은 유니티 5.6 문서에 나오는 기본 예제를 구현하는 것으로 충분히 가능하다.

using System.IO;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class AssetLoader : MonoBehaviour
{
IEnumerator LoadAssetFromLocalDisk()
{
string assetBundleDirectory = "Assets/AssetBundles";
// 저장한 에셋 번들로부터 에셋 불러오기
var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(assetBundleDirectory + "/", "character.unity3d"));
if (myLoadedAssetBundle == null)
{
Debug.Log("Failed to load AssetBundle!");
yield break;
}
else
Debug.Log("Successed to load AssetBundle!");

var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("P_C0001");
Instantiate(prefab, Vector3.zero, Quaternion.identity);
}
}



출처: http://wergia.tistory.com/36 [베르의 프로그래밍 노트]

반응형
Posted by blueasa
, |

아이폰 처음 사용자라면 아이폰에 MP3 같은 음악 넣기가 상당히 어렵게 느껴질 겁니다. 특히 아이폰은 안드로이드 휴대폰과 다르게 아이튠즈 어플을 이용하여 컴퓨터와 파일을 주고 받기 때문에 아직 아이폰 사용법 조차 익숙하지 않은 분들에게는 더욱 더 그럴 겁니다.


아이폰 음악 넣기 방법은 보관함을 이용하여 동기화 시키는 방법과 수동으로 사용자가 직접 음악을 추가하는 방법이 있습니다.


각각 장단점이 있는데 여기서는 좀 더 직관적으로 느껴질 수 있는 수동으로 관리하기로 음악 넣기 방법을 설명 드리겠습니다.



먼저, 아이튠즈 어플을 설치한 다음 USB 케이블로 아이폰을 컴퓨터에 연결 합니다. 아이튠즈는 애플 홈페이지에서 무료로 다운로드 받을 수 있습니다.



휴대폰 모양의 아이콘을 클릭하면 아래의 화면처럼 요약 화면이 보이며 옵션 항목에서 "수동으로 음악 및 비디오 관리"를 체크 합니다.




컴퓨터에 저장된 MP3 음악 파일을 마우스로 끌어다 놓으면 아이폰으로 자동 복사되어 전송 됩니다. 정말 간단하고 쉬운 방법이죠? ^^ 컨트롤 + 클릭으로 한번에 여러 개의 MP3 파일을 끌어다 놓으면 일괄 전송 됩니다.


이렇게 아이폰에 음악 넣기를 한 다음 아이폰에 기본으로 설치되어 있는 음악 플레이어인 "음악" 아이콘을 탭하여 실행해보면 조금 전에 전송한 음악들이 보관함에 들어 있는 것을 확인할 수 있을 겁니다.



수동 관리가 아닌 보관함을 이용한 방법은 동기화를 시킬 수 있어 음악 전송이 좀 더 편리하지만 동기화 옵션을 잘못 건드리면 아이폰에 저장된 모든 음악 파일이 삭제되어 한방에 사라질 수 있습니다. 물론 이런 일이 드문 경우이고 파일 제거 전에 경고 창이 뜨지만 아이폰 초보 사용자 분들이라면 한번 쯤 겪게 될 수도 있습니다 저 또한 그런 경험을 해봤고요 ㅎㅎㅎ -끝-



출처: http://hyozin.com/50 [이효진의 블로그]

반응형
Posted by blueasa
, |