1. 먼저 쉐이더를 다음과 같이 입력하자.

Shader "TextureMask"
{
 Properties
 {
 _Mask("Culling Mask", 2D) = "white" {}
 }
 SubShader
 {
 Tags{ "Queue" = "Background" }
 Blend SrcAlpha OneMinusSrcAlpha
 Lighting Off
 ZWrite On
 ZTest Always
 Alphatest LEqual 0
 Pass
 {
 SetTexture[_Mask]{ combine texture }
 }
 }
}


2. Material 하나 만들어서 TextureMask 로 설정하자.
사용자 삽입 이미지
3. 인스펙터에서 다음과 같이 설정해주자.
사용자 삽입 이미지

3. 박스와 Quad를 생성하여 박스와 카메라 사이에 Quad가 위치하도록 한다.

4. Quad에다 위에서 생성한 메터리얼을 Drag&drop하거나, Texture를 Drag&drop 한후에 Shader를 TextureMask 로 설정한다

5. 끝.
사용자 삽입 이미지
* 블랙영역은 컬링되어 렌더링 되지 않는다. =)
2015/10/22 17:56 2015/10/22 17:56
NGUI에서 사소한 문제(?)는 한글 폰트 사용시 UI Atlas 메터리얼과 Font의 메터리얼이 2개 올라오면서 Drawcall이 1이 아니라 2로 잡히는 문제가 있다.
(Drawcall 줄이려고 뻘짓을 다 해하는 최적화 더쿠에게는 이러한 불편함도 참을 수 없는 것이다!)
이번에는 Font Data와 UI Sprite Atlas를 Texture Packer 로 합쳐보자.
(물론 NGUI Atlas도 불가능한 건 아니겠지만...)

1. BMFONT로 1024 사이즈 한장에 폰트를 다 뽑아주자.
* 상세내용은 http://www.wolfpack.pe.kr/806

2. Texture Packer에 다음과 같이 배치하자.
사용자 삽입 이미지

3. Texture Packer에서 Export하자.
사용자 삽입 이미지

4. Unity3D로 파일을 복사해 놓자.
사용자 삽입 이미지

5. Texture 파일을 다음과 같이 수정하자.
   * Font 파일을 만들 예정이므로 Read/Write Enabled 반듯이 체크!
사용자 삽입 이미지

6. Material을 생성하여 Texture를 추가하자.
   * 같은 폴더에 Material을 생성하고
사용자 삽입 이미지

   * CardUI라는 이름으로 변경, Shader를 Ulite/Transparent Colored 로 변경한 후, Texture를 Drag&drop으로 끌어다 놓았다.
사용자 삽입 이미지

7. 빈 게임오브젝트를 "Atlas"라는 이름으로 만들고 Atlas Script를 Attach하자.
   * 하이라키 탭에서 마우스 우클릭하면 Create Empty 메뉴가 보인다. 이걸 클릭하자.
사용자 삽입 이미지

   * 빈 게임오브젝트가 만들어지면 Atlas라는 이름으로 이름을 변경한다.
사용자 삽입 이미지

   * Component > NGUI > UI > Atlas를 클릭하여 Atlas 게임 오브젝트에 Script를 Attach 하자.
사용자 삽입 이미지

   * Script가 Attach된 모습
사용자 삽입 이미지

   * 아까 만든 Material을 "Material" 속성에 Drag&Drop하자.
사용자 삽입 이미지

   * TP Import라는 속성이 활성화 되면 여기에 "Texture Packer"에서 생성한 Data가 담긴 Text 파일을 Drag&Drop하자.
사용자 삽입 이미지

8. 만들어진 Atlas 게임 오브젝트를 Prefab으로 변환하자. (하이라키 탭에서 Project 탭으로 Drag&Drop하면 자동으로 Prefab으로 변한다.)
사용자 삽입 이미지

9. 빈 게임오브젝트를 "Font"라는 이름으로 만들고 UI Font Script를 Attach하자.
    * Atlas를 만들 때와 같이 빈 게임 오브젝트를 생성하고 이름을 Font로 바꾼다.
    * Component > NGUI > UI > NGUI Font 클릭!
사용자 삽입 이미지

   * UI Font Script가 Attach된 모습
사용자 삽입 이미지

   * Atlas 속성에 아까 만들어 놓은 "Atlas" 게임 오브젝트를 Drag&Drop 한뒤에...
사용자 삽입 이미지

   * Import Data 속성에 BMFont에서 만들어진 Data Text File을 Drag&drop으로 추가하면 끝!
사용자 삽입 이미지


10. 만들어진 Font 게임 오브젝트를 Prefab으로 변환하자.
    * 만드는 방법은 8번과 동일!

테스트!
사용자 삽입 이미지
* 카메라를 키면 올라가는 1과 폰트 Drawcal 1,  Sprite Drawcall 1 총 3개가 잡히던 Drawcall이 2로 줄어 들었다.


2015/10/06 04:27 2015/10/06 04:27
패친이신 Seungjee Baek 님이 알려주신 방법대로 BMFONT에서 RGB에 폰트 값을 넣고 Alpha를 재활용해서 처리하는 방식으로 해봤다.
이름하여 Alpha8bit로 굽기.

1. BM Font에서 다음과 같이 Font 설정 한다.
사용자 삽입 이미지
2. Export 설정을 다음과 같이 하되 포인트는 "White with Alpha"로 설정한다.
사용자 삽입 이미지

3. Export한 Texture를 Import 한 후에  Inspector에서 다음과 같이 설정한다. 중요한건 Format을 Alpha8로 설정하는 것이다.
(4MB짜리 텍스쳐가 1MB로 줄어드는 매직!)
사용자 삽입 이미지
4. 하지만, 쉐이더를 손보지 않고 NGUI Font Maker로 폰트를 만들어보면 이렇게 안나온다. OTL..
사용자 삽입 이미지
5. Material 쉐이더 속성을 NGUI에서 제공하는 Unlit/Text 로 설정하면... 
사용자 삽입 이미지
6. 짜잔~! (이팩트가 먹는다!)
사용자 삽입 이미지

* 이 방법은 2마리 토끼를 절충하는 방법 같다.
지금까지 내용을 정리하자면, 

1. 용량관점에서 "Packed Font" > "Alpha8" > "일반폰트"
2. 이팩트 설정등의 관점에서 "일반폰트" = "Alpha8" >>>넘사벽>>> "Packed Font" 

-_-a 상황에 맞춰서 사용하자.
2015/08/30 17:58 2015/08/30 17:58
BMFONT로 Font를 뽑으면 데이터가 커진하고 믿겠지만, RGBA 4개 채널에 폰트데이터를 넣으면 용량이 매우 작아진다.
단적인 예로 우리가 흔히 쓰는 나눔폰트나 Noto 폰트의 경우 각각 용량이 4M, 15~16M에 달한다.

* 나눔폰트 용량
사용자 삽입 이미지
* Google Noto sans CJK Kor 
사용자 삽입 이미지

그런데, Packed Font로 뽑으면...
사용자 삽입 이미지
1024*1024 텍스쳐 한장으로 딸랑 782KB 이다. 
(주의 : 유니티에 Import 하는순간 True Color Texture는 1024에서 4M가 소요된다. 하지만, 512라면 1M에 불과해진다. 폰트사이즈 32정도면 512에 떨어지니 실망하지 말자)
특히, Font 파일을 앱속에 탑재함으로써 발생하는 기타 여러 잡다한 문제도 없고 형좋고 매부 좋고, 암튼 사용하는 방법에 대해 알아보자.

먼저, BM Font 설치하고 한글 파일을 다운로드받자.

- BMFONT : http://www.angelcode.com/products/bmfont/
- 한글텍스트파일 : http://www.wolfpack.pe.kr/attachment/1142498515.txt

이제 BM Font를 실행하고 다음과 같이 설정한다.
* 자세한 BM Font 사용법은 http://www.wolfpack.pe.kr/806 

1. 폰트 셋팅에서 Size를 62정도 입력했을때 1024사이즈에서 공간이 남았었다. (Super Sampling을 켜서 폰트가 이쁘게 나오게 하자.)
사용자 삽입 이미지
2. 익스포트 옵션에서 Bit Depth를 32로 변경하고 "Pack chars in multiple channels" 옵션을 켜자.
사용자 삽입 이미지
3. 이제 익스포트하고 Unity3d로 옮겨 놓자.
사용자 삽입 이미지
4. Texture Import 옵션을 다음과 같이 Advance로 바꾼후 변경하자.
사용자 삽입 이미지
5. NGUI Font Maker를 열어서 폰트를 만든다.
사용자 삽입 이미지
6. 파일이 생성된 모습. 하지만, 하나 더 남았다.
사용자 삽입 이미지
7. NotoFont 메터리얼을 Inspector 창에서 확인하면 쉐이더가 "Unlit/Transparent Colored"로 되어 있을텐데 이걸 "Unlit/Transparent Packed"로 변경해야 한다.
사용자 삽입 이미지
8. 적용결과
사용자 삽입 이미지

* 물론 Dynamic Font로 적용하면 편하다! 하지만, Texture Resize 될때 종종 스냅드래곤을 채용한 핸드폰에서 폰트가 사라지거나 별별 문제가 다 발생하고 그거 잡는 시간에 BMFont로 뽑는게 더 빠르다.
* Packed Font는 외곽 효과라던가... 이팩트 먹이기가 다음과 같이 잘 안된다. 
사용자 삽입 이미지


2015/08/28 17:11 2015/08/28 17:11
유니티가 지뢀같은건 아마도 많은 개발자들이 느끼겠지만, 소스 관리이다.

기본적으로 유니티는 GameObject라는 껍데기에 Transform / Sound / Animator 등의 Components 구조로 되어 있다보니..
UI 개발시 필연적으로 이런 모습의 UI를 만나면 신나게 개발해놓고 간혹 사운드를 바꿔 달라던가... 액션을 바꿔달라면 개 노가다를 해야 하는 문제가 생긴다.

* 예시 : ArmyAttack2
사용자 삽입 이미지
(저 수많은 버튼들을 보라... 죽음이 기다리고 있다!)

몇 번의 프로젝트에서 출시전 뜯어고치기 노가다 하다가 발견한 방법은 NGUI의 이벤트 핸들러를 직접 컨트롤 하는 것이다.

1. 먼저 UI를 만들고 Sprite 과 Label을 올려서 Button을 만든다.
사용자 삽입 이미지
* Collider를 반드시 붙여 주자.
사용자 삽입 이미지
* Label은 Font만 정의하였다.
사용자 삽입 이미지
* 최종 형태는 다음과 같다.
사용자 삽입 이미지

2. 공통 관리 Class를 다음과 같이 코딩해서 UI Root에 붙여 주자.
using UnityEngine;
using System.Collections;

public class UIManager : MonoBehaviour {

//싱글톤 선언 시작
 public static UIManager instance;
 public void Awake()
 {
 UIManager.instance = this;
 }
//싱글톤 선언 끝

//버튼별 이벤트 Method
 public void SetClickButton(GameObject _obj)
 {
 Debug.Log("Hello World!");
 Debug.Log(_obj.transform.name + " is Click!");
 }
//끝

}


3. 마지막으로 Button에 이벤트를 등록하는 Script를 만들고 Sprite 에 붙여주자.
using UnityEngine;
using System.Collections;

public class Behavior_Button1 : MonoBehaviour {


 void Start() {
 UIEventListener.Get(gameObject).onClick += UIManager.instance.SetClickButton;
 }

}

 

실행결과 버튼을 클릭하면 해당 문자가 출력된다.

이렇게 만드는 이유는 씬에 많은 버튼을 한꺼번에 코드로 관리하기 위함이다.

* 참고 이벤트를 받는 Method의 Arguments 값은 다음과 같이 UIEventListener에 정의되어 있다.

void OnSubmit () { if (isColliderEnabled && onSubmit != null) onSubmit(gameObject); }
void OnClick () { if (isColliderEnabled && onClick != null) onClick(gameObject); }
void OnDoubleClick () { if (isColliderEnabled && onDoubleClick != null) onDoubleClick(gameObject); }
void OnHover (bool isOver) { if (isColliderEnabled && onHover != null) onHover(gameObject, isOver); }
void OnPress (bool isPressed) { if (isColliderEnabled && onPress != null) onPress(gameObject, isPressed); }
void OnSelect (bool selected) { if (isColliderEnabled && onSelect != null) onSelect(gameObject, selected); }
void OnScroll (float delta) { if (isColliderEnabled && onScroll != null) onScroll(gameObject, delta); }
void OnDragStart () { if (onDragStart != null) onDragStart(gameObject); }
void OnDrag (Vector2 delta) { if (onDrag != null) onDrag(gameObject, delta); }
void OnDragOver () { if (isColliderEnabled && onDragOver != null) onDragOver(gameObject); }
void OnDragOut () { if (isColliderEnabled && onDragOut != null) onDragOut(gameObject); }
void OnDragEnd () { if (onDragEnd != null) onDragEnd(gameObject); }
void OnDrop (GameObject go) { if (isColliderEnabled && onDrop != null) onDrop(gameObject, go); }
void OnKey (KeyCode key) { if (isColliderEnabled && onKey != null) onKey(gameObject, key); }
void OnTooltip (bool show) { if (isColliderEnabled && onTooltip != null) onTooltip(gameObject, show); }


2015/08/26 17:56 2015/08/26 17:56
게임의 재미와 게임을 어떻게 만들어야 하는지에 대한 고민을 저도 모르게 오늘 컨설팅을 진행하고 난 후에 보고서를 쓰며 나와버리고 말았다.

= 전략 =

거의 모든 게임은 생존에 대한 위협으로 인한 "공포"와 그것을 극복했을때의 "시원함"임
. 첫째, 공포는 적이 질적 또는 양적, 아니면 둘다가 압도적일때
. 둘째, 적으로부터 심리적 위협이 인지될때
. 셋째, 라스트 찬스일때
. 넷째, 의도적으로 느리지만 한방에 골로 가는 상황일때

또한, 게임은 core Loop에서는 "준비" => "시도"("정보인식" => "전력적 의사결정" => "행위" => "정보인식") => "보상" => "준비"의 Loop
. 정보인식이 실패한 경우 "어? 거기 있었어?" 학습후 "재시도"
. 올바른 정보인식이나 전략적 의사결정이 실패한 경우 "앗!"하는 학습후 "재시도"
. 올바른 정보인식, 올바른 전략적 의사결정후 "행위"가 실패한 경우 "손가락 짤라버리 싶은" 후회후 "재시도"
. 이후 기대한 결과에 충족하지 않으면(버그, 반응 더딤 등) "개발자 병신" 쌍욕하고 포기

= 후략 =

표현이 거칠기는 하나, 그리고 이러한 주장을 한다고 알아주는 사람은 없겠지만 (지랄하네? 하는 인간들은 많겠다)
게임공부한지 6년정도 삽질과 삽질의 연속에서 무언가 손에 잡힌 느낌이랄까?

-_-a
2015/08/26 03:54 2015/08/26 03:54
흠?


Shader "Custom/Translucent" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_BumpMap ("Normal (Normal)", 2D) = "bump" {}
		_Color ("Main Color", Color) = (1,1,1,1)
		_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
		_Shininess ("Shininess", Range (0.03, 1)) = 0.078125

		//_Thickness = Thickness texture (invert normals, bake AO).
		//_Power = "Sharpness" of translucent glow.
		//_Distortion = Subsurface distortion, shifts surface normal, effectively a refractive index.
		//_Scale = Multiplier for translucent glow - should be per-light, really.
		//_SubColor = Subsurface colour.
		_Thickness ("Thickness (R)", 2D) = "bump" {}
		_Power ("Subsurface Power", Float) = 1.0
		_Distortion ("Subsurface Distortion", Float) = 0.0
		_Scale ("Subsurface Scale", Float) = 0.5
		_SubColor ("Subsurface Color", Color) = (1.0, 1.0, 1.0, 1.0)
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200

		CGPROGRAM
		#pragma surface surf Translucent
		#pragma exclude_renderers flash

		sampler2D _MainTex, _BumpMap, _Thickness;
		float _Scale, _Power, _Distortion;
		fixed4 _Color, _SubColor;
		half _Shininess;

		struct Input {
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o) {
			fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
			o.Albedo = tex.rgb * _Color.rgb;
			o.Alpha = tex2D(_Thickness, IN.uv_MainTex).r;
			o.Gloss = tex.a;
			o.Specular = _Shininess;
			o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
		}

		inline fixed4 LightingTranslucent (SurfaceOutput s, fixed3 lightDir, fixed3 viewDir, fixed atten)
		{		
			// You can remove these two lines,
			// to save some instructions. They're just
			// here for visual fidelity.
			viewDir = normalize ( viewDir );
			lightDir = normalize ( lightDir );

			// Translucency.
			half3 transLightDir = lightDir + s.Normal * _Distortion;
			float transDot = pow ( max (0, dot ( viewDir, -transLightDir ) ), _Power ) * _Scale;
			fixed3 transLight = (atten * 2) * ( transDot ) * s.Alpha * _SubColor.rgb;
			fixed3 transAlbedo = s.Albedo * _LightColor0.rgb * transLight;

			// Regular BlinnPhong.
			half3 h = normalize (lightDir + viewDir);
			fixed diff = max (0, dot (s.Normal, lightDir));
			float nh = max (0, dot (s.Normal, h));
			float spec = pow (nh, s.Specular*128.0) * s.Gloss;
			fixed3 diffAlbedo = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten * 2);

			// Add the two together.
			fixed4 c;
			c.rgb = diffAlbedo + transAlbedo;
			c.a = _LightColor0.a * _SpecColor.a * spec * atten;
			return c;
		}

		ENDCG
	}
	FallBack "Bumped Diffuse"
}


출처 : http://www.farfarer.com/blog/2012/09/11/translucent-shader-unity3d/
2015/08/13 17:05 2015/08/13 17:05
오늘은 지난시간에 이어 Json.net으로 Serialize와 Deserialize에 대해 알아보자.

Serialize는 흔히 직렬화라 이야기하기도 한다. 네트워크상에서 Class를 전송하는 등의 입출력을 위한 데이터의 배열 형태로 변환하는 과정을 직렬화라 하며,
반대의 경우 데이터의 배열 형태를 Class로 변환화는 과정을 Deserialize(역직렬화)라 한다.

이때의 데이터 형태는 Byte 또는 string 등의 형식으로 변환 될 수 있다.

암튼 각설하여 지난 시간에 이어서 JSON.NET 모듈을 구해서 Import 하던가 기타 등등의 Json Parser를 구하자.
(코딩 노가다 안하려면 Serialize / Deserialize 지원이 잘되는 모듈로 구하자. 안그럼 개고생은 예약해 놓은 거다)

Import가 완료 되었다면 지난시간에 사용한 Entity Class를 다음과 같이 고쳐주자. (본 예제는 JSON.NET을 사용한다. Windows어플에서 가장 많이 쓰이는 모듈이라서...)
using System.Collections.Generic;
using System.Collections;
using Newtonsoft.Json;

public class TestEntityRoot
{
//JsonProperty로 설정하였다.
 [JsonProperty("SubEntity")]
//Static이므로 Get; Set; 선언으로 입출력이 가능하도록 하였다.
 public static List<SubEntity> SubEntity { get; set; }
}

public class SubEntity
{
 public string x { get; set; }
 public string y { get; set; }
 public List<Sub2Entity> sub { get; set; }
}

public class Sub2Entity
{
 public int z;
}


이제 Json Code가 포함된 Scene 0 에 사용할 코드를 작성하자.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Newtonsoft.Json;

public class Scene0Behavior : MonoBehaviour {
 // Use this for initialization
 void Start () {
//JSON 데이터를 정의한다. x는 a, y는 b로 선언했다.
 string _json = @"{
           ""SubEntity"": [
            {
                       ""x"": ""a"",
                       ""y"": ""b"",
                       ""sub"" : [
                       {""z"" : 0 },
                       {""z"" : 1 }
                       ]
                      }
            ]
            }";
 //할당할때는 아무런 클래스를 선언하고 할당한다.
 var _e = JsonConvert.DeserializeObject<TestEntityRoot>(_json);
 
//접근할때는 엔티티 클래스를 직접 호출한다.
 Debug.Log("Scene 0 입력값시작##############");
 foreach (SubEntity _s in TestEntityRoot.SubEntity)
 {
            Debug.Log(_s.x);
 }
 Debug.Log("Scene 0 입력값끝##############");
//저장된 Json 데이터를 출력하고 다음 레벨을 로딩한다.
 Application.LoadLevel(1);
 }

}


Scene1에 사용될 소스를 다음과 같이 입력한다. Scene0과 다른점은 Json데이터 외에 변하는 것은 없다.
(단지 씬이 변경되더라도 데이터가 살아 있고 새로운 데이터를 넣었을때 어떻게 되는지 보여준는데 그 역할이 있다.)

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

public class Scene1Behavior : MonoBehaviour {

 // Use this for initialization
 void Start () {

 string _json = @"{
            ""SubEntity"": [
            {
                       ""x"": ""c"",
                       ""y"": ""d"",
                       ""sub"" : [
                       {""z"" : 2 },
                       {""z"" : 3 }
                       ]
                       }
            ]
            }";
 //할당할때는 아무런 클래스를 선언하고 할당한다.
 var _e = JsonConvert.DeserializeObject<TestEntityRoot>(_json);
 //접근할때는 엔티티 클래스를 직접 호출한다.
 Debug.Log("Scene 1 입력값시작##############");
 foreach (SubEntity _s in TestEntityRoot.SubEntity)
 {
 Debug.Log(_s.x);
 }
 Debug.Log("Scene 1 입력값끝##############");

 Application.LoadLevel(2);

 }

}


마지막으로 Scene2에서 사용될 소스는 데이터를 클리어 하고 입력된 값을 출력하는 코드이다.
using UnityEngine;
using System.Collections;

public class Scene2Behavior : MonoBehaviour {

 // Use this for initialization
 void Start () {
//시작과 동시에 데이터를 날려버린다.
 TestEntityRoot.SubEntity.Clear();
 Debug.Log("Scene 2 입력값시작##############");
 foreach (SubEntity _s in TestEntityRoot.SubEntity)
 {
 Debug.Log(_s.x);
 }
 Debug.Log("Scene 2 입력값끝##############");

 }

}


결과는 다음과 같다.
사용자 삽입 이미지
정상적으로 씬이 변경되더라도 데이터가 살아 있고, 새로운 Serialize 된 데이터가 들어오면 추가된다.

2015/08/11 01:47 2015/08/11 01:47
유니티 3D로 개발하다보면, 파편화된 데이터때문에 유지보수나 관리에 어려움을 겪게 되는데,
그러다 보니 Entity Class를 만들고 Dontdestroy 옵션으로 삭제되지 않는 불멸의 데이터 클래스를 생성해서 사용하는 개발자 분들이 많이 보인다.
그런데, 이렇게 하다보면 결국 소스가 꼬여서 오작동 하거나 관리상 문제로 인해 불편함을 가지고 가는 경우도 많은데 그럴 필요 없이 Static 으로 설정하여 Scene을 넘어가더라도 Data가 살아 있는 Class를 만들고 관리하는 것을 목표로 한다.
(물론 Json을 Serialize 하거나 Deserialize 하는건 다음 편에서 보자)

EntityMaster.cs파일을 하나 만들어서 다음과 같이 추가해두자.
(폴더위치는 관계없다.)

using System.Collections.Generic;
using System.Collections;

//테이블과 같은 클래스이다.
public class TestEntity
{
 public static List<SubEntity> _sub = new List<SubEntity>();
}

//1개 Row라고 생각하면 비교가 쉽다.
public class SubEntity
{
 public string _x;
 public string _y;
//Row안에 또 하나의 테이블을 가질 수 있다.
 public List<Sub2Entity> _sub = new List<Sub2Entity>();
}
//SubEntity에 포함된 클래스이다.
public class Sub2Entity
{
 public int _z;
}


이제 Scene0를 만들어서 MainCamera에 다음과 같은 Script를 만들어 Attach하자.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Scene0Behavior : MonoBehaviour {
 // Use this for initialization
 void Start () {
//새로운 Sub2Entity 객체를 만든다.
 List<Sub2Entity> _sub2 = new List<Sub2Entity>();
//Sub2Entity 타입의 객체에 데이터를 넣는다.
_sub2.Add ( new Sub2Entity { _z = 1 });
//테스트엔티티 테이블에 Row를 추가하고 다음 씬을 호출한다.
 TestEntity._sub.Add(new SubEntity { _x = "a", _y = "b", _sub = _sub2 });
 Application.LoadLevel(1);
 }

}


이제 2번째 씬을 만들고 다음과 같이 코딩한후 MainCamera에 Attach하자.
* 위에서 데이터를 추가한 것이라 별도 설명은 생략한다.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Scene1Behavior : MonoBehaviour {

 // Use this for initialization
 void Start () {
 Debug.Log(TestEntity._sub[0]._x);
 List<Sub2Entity> _sub2 = new List<Sub2Entity>();
 _sub2.Add(new Sub2Entity { _z = 2 });
 TestEntity._sub.Add(new SubEntity { _x = "c", _y = "d", _sub = _sub2 });
 Application.LoadLevel(2);
 }
 
}


마지막으로 3번째 씬을 만들어서 다음과 같이 코딩후 Attach하자.
using UnityEngine;
using System.Collections;

public class Scene2Behavior : MonoBehaviour {

 // Use this for initialization
 void Start () {
//시작하면 데이터를 찍는 역할이 전부다.
 Debug.Log(TestEntity._sub[1]._x);
 Debug.Log(TestEntity._sub[1]._sub[0]._z);
 }
 
}


최종 결과는 다음과 같다.

* 씬을 다음과 같이 3개로 구성했고, MainCamera에는 각각의 Script가 Attach되어 있다.
사용자 삽입 이미지
* 최종 결과는 Debug.Log로 다음과 같이 출력된다.
사용자 삽입 이미지
2015/08/07 02:14 2015/08/07 02:14
아오~ 개고생을 했군요.
모바일에서는 잘입력되는데 PC등의 플랫폼으로 되어 있을때, IME 문제로 인해 입력한 한글이 제대로 입력이 안될때 사용하시기 바랍니다.

Case 1. 한글이 입력이 안되고 계속 한글자만 나올때...
UIInput.cs 파일의 710번째 줄에 보시면...

"if (string.IsNullOrEmpty(ime) && !string.IsNullOrEmpty(Input.inputString))"
이라고 된 부분을 

if (!string.IsNullOrEmpty(Input.inputString))

으로 고쳐주세요.

원본 : http://www.tasharen.com/forum/index.ph ··· msg38990Case 2. 한글의 마지막 글자가 짤릴때... (다른곳에 클릭하는 등의 이벤트)
UIInput.cs 파일에서 OnDeselectEvent 찾아서 value = label.text; 추가

 protected void OnDeselectEvent ()
 {
 if (mDoInit) Init();

 if (label != null) label.overflowEllipsis = mEllipsis;

 if (label != null && NGUITools.GetActive(this))
 {
 value = label.text; //추가
 mValue = value;
#if MOBILE
 if (mKeyboard != null)
 {
 mWaitForKeyboard = false;
 mKeyboard.active = false;
 mKeyboard = null;
 }
#endif
 if (string.IsNullOrEmpty(mValue))
 {
 label.text = mDefaultText;
 label.color = mDefaultColor;
 }
 else label.text = mValue;

 Input.imeCompositionMode = IMECompositionMode.Auto;
 RestoreLabelPivot();
 }

 selection = null;
 UpdateLabel();
 }
2015/06/29 01:15 2015/06/29 01:15
TAG ,