GameForFun

블로그 이미지
by PforPepsi

TAG CLOUD

  • Total hit
  • Today hit
  • Yesterday hit

'[Unity3D]'에 해당되는 글 39건

  1. 2013.12.13
    [NGUI] 입문기.
  2. 2013.06.26
    [UNITY3D] AssetBundle에 스크립트 포함시 문제점.
  3. 2013.05.31
    [Unity3D] IOS에서 Compressed된 Asset 사용하기.
  4. 2013.05.29
    [UNITY3D] 위치의 중요성...?
  5. 2013.04.30
    [UNITY 3D] Eclipse 연동.
  6. 2013.04.29
    WWW관련 장애. 1
  7. 2013.03.17
    [Unity3d] Memory Leak 총 정리. 3
  8. 2013.03.15
    [Unity3d} Profiler의 Static Collider.Create, Move 등의 오류.
  9. 2013.03.11
    [Unity3d] Mesh Leaking 해결 방법 2
  10. 2013.03.11
    [Unity3d] Singleton 사용시 주의사항

이제 시대에 뒤떨어진 EZGUI를 뒤로 버리고

Next Generation UI인 NGUI를 익히고자 이 글을 쓴다.


먼저 NGUI를 얼추 만지고 나서의 느낌은 [간편] 하다의 느낌이 강했다.

EZGUI에서는 여러가지의 옵션설정으로 인해 Inspector창이 지저분했고, 애니메이션 시스템도 복잡하여 사실상 애니메이션은 따로 스크립트를 통해 진행했었는데,  NGUI의 경우 대부분의 기능들이 아주 기본적인 요소은 UISprite를 재활용하여 진행하는 방식이라 간단하면서도 한편으로는 조합을 통해 더욱 다양하게 UI를 원하는데로 조작할 수 있음을 느꼈다.

UISprite의 재활용이라 함은,  가령 체력바와 같은 ProgressBar의 경우 뒷판인 Background, 앞에 게이지가 찰 ForeImage를 각각의 UISprite로 배치한뒤, ForeImage 내부인자인 FillAmount를 조절하여 ProgressBar를 구현하는데, 이는 UNITY3D의 기능과 유사하게 레고를 조립하는 느낌으로 만들어 진것 같다.


NGUI에서 Atlas의 관리법은 다음처럼 이루어진다.

Atlas를 생성할 오브젝트를 만들고 -> UIAtlas라는 Component를 추가 -> 여기에 원하는 Material을 설정한 뒤, 원하는 이미지들을 추가해주면 Atlas 오브젝트가 생성되는데, 추가된 이미지들은  해당 Atlas 데이터에서 이름으로 검색이 가능하다.

Atlas 자체를 GameObject형태로 관리하는것에서의 장점은 외부로부터 생성된 Atlas를 언제나 동적으로 사용 가능하다는 것에 있는것 같다.

기존에 EZGUI는 Atlas가 생성이되면 그 Atlas에 대한 설정은 우리가 맘대로 볼 수 없는 형태였는데 NGUI같은 경우에는 특정 Atlas에 들어있는 이미지는 해당 이미지 이름으로 값을 얻어 올수 있는 구조이기 때문에,  언제든지 외부에서 새로운 Atlas를 Asset형태로 불러올 수 있고, 해당 Atlas에 속해있는 이미지의 이름만 알면 언제든지 그 이미지를 사용할 수 있다.

여기에 잠시 Atlas를 asset형태로 만들고 외부에서 새로운 atlas를 불러오는 기능을 만들어보자면 다음과 같다.

먼저 assetbundle을 만들 코드를 생성하자.


using UnityEditor;
using UnityEngine;
using System.Collections;

public class ImageBundleCreator : Editor {

//메뉴에 AssetBundleCreate이라는 항목 아래 CreateImageAsset버튼이 생기는 명령어.
	[MenuItem("AssetBundleCreate/Create Image Asset")]
	public static void CreateImageBundle()
	{
		string path = EditorUtility.SaveFilePanel("Save ImageBundle","","ImageBundleAsset","");

		Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);

		foreach(Object o in selection)
		{
			Debug.Log(o);
		}

		BuildPipeline.BuildAssetBundle(null,
			selection,
	       path,
	       BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets | BuildAssetBundleOptions.UncompressedAssetBundle,
	       BuildTarget.Android);

		Debug.Log("IMAGE BUNDLE CREATED");
	}
}

위의 스크립트를 생성하고, Atlas오브젝트를 Asset으로 만든뒤 해당 Asset을 클릭한 상태에서 Createa Image Asset을 눌러주자.

그 뒤 외부에서 Atlas AssetBundle을 읽어올 Manager스크립트를 다음과 같이 작성.




using UnityEngine;
using System.Collections;

public class ImageBundlemanager : MonoBehaviour {

	public string path ;

	public UISprite m_Sprite;

	public AssetBundle m_AssetBundle;
	public UIAtlas m_Atlas;
	public string m_SpriteSpriteName;
	// Use this for initialization
	void Start () {
		path = Application.dataPath + "/../Documents/ImageBundleAsset.zip";
		//m_AssetBundle = AssetBundle.CreateFromFile(path);
		LoadCostumeBundle();
		//m_Atlas = (UIAtlas)m_AssetBundle.Load("ImageBundle");
	}
	
	// Update is called once per frame
	void Update () {
		if(Input.GetKeyDown(KeyCode.A))
		{
			m_Sprite.atlas = m_Atlas;
		}

		if(Input.GetKeyDown(KeyCode.Space))
		{
			m_Sprite.spriteName = m_SpriteSpriteName;
		}
	}


	public void LoadCostumeBundle()
	{
		StartCoroutine(ELoadCostumeBundle());
	}
	
	public IEnumerator ELoadCostumeBundle()
	{		
		//while(!m_WeaponBundleDone)
		//{
		//	yield return new WaitForFixedUpdate();	
		//}
		WWW url = new WWW("file://"+path);
		int framecount = 0;
		while(url.progress != 1)
		{
			framecount++;
			yield return new WaitForSeconds(0.5f);	
		}	
		yield return new WaitForSeconds(0.5f);
		yield return url;
		m_AssetBundle = url.assetBundle;
		if((m_AssetBundle == null || url.bytes.Length == 0 || url.error != null))
		{
		}else
		{
			url.Dispose();
			url = null;
		}

		Object o = m_AssetBundle.Load("ImageBundleObject");
		Debug.Log(m_AssetBundle.Contains("ImageBundleObject"));

		m_Atlas = ((GameObject)o).GetComponent();

		Debug.Log("ImageBundle Set");
		yield break;
	}
}

이제 Manager를 만들어주고 m_SpriteSpriteName을 설정한 뒤 Space를 눌러주면 외부에서 불러온 Atlas의 m_SpriteSpriteName이 m_Sprite의 이미지로 설정이 된다.

AND

현재 하는 작업중 특정 오브젝트들(가령 무기)를 외부에서 다운받아서 언제든지 새로운 무기가 추가될 수 있도록 구조가 만들어져있다.

 여기서 문제는 실제 클라이언트에 포함되어있는 Script(ScriptA라고 하자)의 내용과, Assetbundle에 포함되어있는 Script의 내용이 달라질 경우에 생기는 문제가 생긴다.

여기서 문제는, ScriptA의 내용을 직접 수정하지 않아도 현재 클라이언트와는 다르다는 경고를 띄워준다는 것인데, 이는 ScriptA를 참조하는 ScriptB의 Serialization이 달라지면서 에러가 생기는것인데. 보완책은 

1. 더이상의 public변수를 설정하지 않는것이다.

-> public으로 선언시에 editor를 업데이트하기위해 새로운 serialization 클래스를 만들어서 뭔가 링크가 변경되는것 같고,

2. GetSet을 사용하지 않는것이 좋다. 

'[Unity3D]' 카테고리의 다른 글

[NGUI] 입문기.  (0) 2013.12.13
[Unity3D] IOS에서 Compressed된 Asset 사용하기.  (0) 2013.05.31
[UNITY3D] 위치의 중요성...?  (0) 2013.05.29
[UNITY 3D] Eclipse 연동.  (0) 2013.04.30
WWW관련 장애.  (1) 2013.04.29
AND

WWW를 이용하고, "file://"path + filename,version)로 경로를 사용. 

이 방식을 안하고  AssetBundle.CreateFromFile(path)를 하면 다음과 같은 에러 발생  "expect UnityRaw, got UnityWeb"이라는 에러를 뱉어냄...

'[Unity3D]' 카테고리의 다른 글

[NGUI] 입문기.  (0) 2013.12.13
[UNITY3D] AssetBundle에 스크립트 포함시 문제점.  (0) 2013.06.26
[UNITY3D] 위치의 중요성...?  (0) 2013.05.29
[UNITY 3D] Eclipse 연동.  (0) 2013.04.30
WWW관련 장애.  (1) 2013.04.29
AND

일단 너무 큰 범위에서 애들이 돌아다니면 가령(-10000,10000,10000)등....

float계산이 잘 안된다고 경고창이 뜨는데.. 이를 무시하고 그 좌표계에서 놀다보면 

1. skin된 메쉬가 뒤틀릴수도 있고.

2. 오브젝트의 떨림현상이 발생할 수 있음으로

float부분의 계산이 잘 돌아갈 수 있도록 좌표를 적당히 잡도록 하자....

AND
AND

http://answers.unity3d.com/questions/212877/does-the-wwwisdone-function-actually-work.html


직면한 문제.. isDone을 써서 WWW가 로딩된 후 load하려니까 이놈이 다 안됬다면서 에러를 내뱉는다....WTF!?

언틋 들은 얘기로는 두 1f == 1f를 했을때 false가 나오는 현상이 있다고하는데.. 이러한 현상중 하나일까나..?

해결법은 완료됬다고 구라를 치는순간 yield로 1초를 더 기다려주고 get해보도록

AND

1. Static(전역) 에 의한 메모리 누수
- C#에서 흔히 Singleton을 사용하여, 아무곳에서나 접근가능한 클래스를 만드는 경우가 존재하는데 이때, 메모리 누수에 주의해야 한다. static이기 때문에 Scene이 넘어가도 해당 클래스는 누군가가 참조하기 때문에 GC(Garbagecollector)는 해당 메모리를 회수하지 않고 메모리에 지속적으로 올려놓는다..

따라서 static instance를 할당했다면 스크립트가 파괴되어야 할 시점, OnDestroy()에서 instance = null을해서 GC가 메모리를 해제할 수 있도록 해줘야 한다.

2. Mesh에 의한 메모리 누수
- Unity는 새롭게 생성된 Mesh를 해당 객체가 Destroy 된다고 해서 메쉬데이터를 지워주진 않는다. 따라서 해당 객체가 파괴될때  즉, OnDestroy()에서 메쉬 정보를 지워주면 된다. 

3. Asset에 의한 누수
- 이건 좀 특별한 경우인데, 다음 경우를 살펴보자.
Scene 1과 2가 있다 치고, Scene1에 처음으로 입장했을때, 메모리 사용량이 10MB였다면, Scene2를 갔다가 다시 Scene1로 넘어올때 메모리 사용량이 10MB보다 크게 나오는 경우가 존재한다.
이럴때 의심해 볼 수 있는것이 Scene2에 사용된 Asset이 메모리에 올라가 있다고 예상 해볼 수 있다. 
해결법은 Scene2에서 링크방식으로 지정된 Asset들을 모두 파괴시에 null로 만들어주면 된다. 
가령

class dada:monobehaviour {

 public Texture2D hellotexture;

void OnDestroy()
{
    hellotexture = null;
}

위와 같이 해주도록 하자.  AudioClip, Texture2D, Object, GameObject 모든것에 의심을 해볼 가치가 있다.

4.Material에 의한 누수
- 이 경우는 MAterial의 instance가 지속적으로 생길댸 발생하는 현상인데... 아직 해결법을 못찾고 있다.... Destory를 해줬는데도 증가하는것을 보면....(다른쪽에 남아있을지도?) 
혹시 모르니 해당 객체가 파괴될때 Destroy 를 해주도록 하자.


아래 코드는 Editor 하위 폴더에 넣어주면 Menu에 새로운 탭이 생겨서 사용할 수 있다.
기능은 현재 Scene에서 로드된 모든 오브젝트들을 보는 것이다.

3번에서 설명했던것과 같이 Scene2에서 1으로 넘어올때 어떤것들이 해제 안됬나를 보려면, 먼저 Scene1에서 사용후, Scene2를 방문했다가 다시 Scene1에 와서 사용해주면, 새롭게 추가된 Object들의 이름이 Console창에 뜬다.

 static DIctionary<string, int> tempdicts = new Dictionary<string,int>();
[MenuItem("MemoryDetector/Print Item Names")]
publicstatic void PrintObjectName()
{
    Dictionary<string, int> tempdicts = new Dictionary<string, int>();
    foreach(string s in Objects.Keys)
    {
        if(Objects.ContainKeys(g.name)))
        {
            Objects[g.name]++;
        }else
        {
            Objects.Add(g.name,0);
        }

    }
    foreach(string curobjects in Objects,Keys)
    {
        if(!tempdicts.ContainKey(curobjects))
        {
            Debug.Log(curobjects);
        }
    }

AND

http://answers.unity3d.com/questions/11324/move-gameobject-with-collider-without-rigidbody-co.html?sort=oldest

이유는 Rigidbody를 안붙인 콜라이더들은 모두 Static으로 간주하여, 물체가 이동되는 순간, 물체의 위치에 따른 충돌 정보를 재생성하기 때문에 생기는 현상이다. 따라서 collider를 움직이고 싶으면 rigidbody를 붙이고, kinematic을 켜서 움직이도록 하자.


'[Unity3D]' 카테고리의 다른 글

WWW관련 장애.  (1) 2013.04.29
[Unity3d] Memory Leak 총 정리.  (3) 2013.03.17
[Unity3d] Mesh Leaking 해결 방법  (2) 2013.03.11
[Unity3d] Singleton 사용시 주의사항  (0) 2013.03.11
[UNITY3d] EZGUI의 autosprite을 죽입시다.  (0) 2013.02.06
AND

충격적인 소식...

Unity는 게임오브젝트를 Destroy한다고 해서 해당 게임 오브젝트가 사용했던 메시 데이터를 지우지 않는답니다..

따라서 직적 FindObjectstypeof 를 사용하여 지워줘야된다고 합니다.. ㅡ.ㅡ;;


http://answers.unity3d.com/questions/9999/procedural-mesh-leaks-memory-everytime-the-game-ob.html

AND

전역변수로 class의 reference를 가지고 있으면, Scene이 바뀐다 한들, reference는 가지고 가기 때문에, 기존에 얽여있는 texture, prefab등이 모두 그대로 다음 Scene으로 넘어간다..

따라서 Scene이 바뀌거나, 파괴될때  instance = null을 해주도록 하자.

AND

ARTICLE CATEGORY

목록들 (118)
[Unity3D] (39)
그래픽관련 (13)
잉여잉여 (25)
프로그래밍 (27)
노래♬ (3)
Game_Design(기획) (3)

RECENT ARTICLE

RECENT COMMENT

RECENT TRACKBACK

CALENDAR

«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

ARCHIVE