레이블이 C#인 게시물을 표시합니다. 모든 게시물 표시
레이블이 C#인 게시물을 표시합니다. 모든 게시물 표시

2014년 1월 27일 월요일

C# 메모리 관리 기법 - WeakReference와 IDisposable

상식적으로 가비지 컬렉터가 작동된다면 메모리가 늘어나는 것에 대한 걱정은 없어야 하겠지만 실제로는 메모리가 늘어나기도 합니다. 
C#에서는 메모리 해제 명령이 없어서 메모리 릭이 발생하게 되면 당황스러울 수 밖에 없죠.

그러면 어떤 경우에 메모리가 늘어나게 될까요?

가비지는 더 이상 참조가 없는 메모리를 뜻합니다. 
메모리가 어디선가 늘어나고 있다는 뜻은 결국 어디선가 의도하지 않은 참조가 일어나고 있어서 가비지화 되지 못하고 계속 누적되고 있다는 말이 되겠죠.

어떤 경우에 그런 일이 발생할까요?


이렇게 캐릭터 매니져가 세개의 캐릭터를 만들었습니다. 


그리고 캐릭터의 위치를 보여주는 객체가 캐릭터 매니저에 접근해서 캐릭터를 모두 참조하게 됩니다. 


그 후에 필요 없어진 캐릭터를 캐릭터 매니저가 삭제하게 됩니다. 
그러면 가비지가 될것이라 생각하겠지만 여전히 지워진 캐릭터를 디스플레이 캐릭터 포지션 객체가 참조하고 있기때문에 가비지가 되지 않습니다. 
여전히 메모리에 남아서 메모리를 증가시키게 되죠.

이런 일을 만들지 않으려면 위의 경우처럼 의도치 않은 참조를 지워줘야 합니다. 

WeakReference는 가비지 컬렉션에 의한 객체 회수를 허용하면서 객체를 참조하게 됩니다. 
이때, 인스턴스를 참조하려면 WeakReference.Target을 사용하는데 해당 인스턴스가 가비지 컬렉터에게 회수되면 null값을 반환하게 됩니다. 
public class Sample
{
    private class Fruit
    {
        public Fruit(string name) 
        { 
            this.Name = name; 
        }

        public string Name 
        { 
            private set; 
            get; 
        }
    }

    public static void TestWeakRef()
    {
        Fruit apple     = new Fruit("Apple");
        Fruit orange    = new Fruit("Orange");
           
        Fruit fruit1    = apple;   // 강한 참조

        // WeakReference를 이용 
        WeakReference fruit2    = new WeakReference(orange); 

        Fruit target;
           
        target          = fruit2.Target as Fruit;

        // 이 경우 결과는 애플과 오렌지가 나오게 됩니다.
        Console.WriteLine(" (1) Fruit1 = \"{0}\", Fruit2 = \"{1}\"", 
            fruit1.Name, target == null ? "" : target.Name);

        // 모두 참조하지 않도록 null값을 넣어줍니다.
        apple   = null;
        orange  = null;

        // 가비지 컬렉터를 작동시킨다
        System.GC.Collect(0, GCCollectionMode.Forced);
        System.GC.WaitForFullGCComplete();

        // 그 후 같은 방법으로 결과를 확인해보면
        // fruit1과 fruit2의 값을 바꾼 적은 없지만, fruit2의 결과가 달라집니다.
        target          = fruit2.Target as Fruit;

        // 결과는 애플만 나오게 된다.
        // 오렌지는 가비지 컬렉터에게 회수되버렸기때문입니다
        Console.WriteLine(" (2) Fruit1 = \"{0}\", Fruit2 = \"{1}\"", 
            fruit1 == null ? "" : fruit1.Name,
            target == null ? "" : target.Name);
    }
}
매니저처럼 객체를 직접 생성하고 삭제하는 모듈이 아닌 이상 가능하다면 WeakReference를 사용하시는 것이 좋습니다. 
그렇게 해서 의도치 않은 참조로 인해 메모리가 누적되게 되는 실수를 방지할 수 있습니다. 

주의할 것은 WeakReference.Target의 값을 보관하면 안된다는 것입니다. 
이값을 보관하게 되면 강한 참조가 일어나 가비지 컬렉터가 회수를 하지 않게 됩니다. 

C#은 메모리를 원하는 시점에 정확히 해제하는 것이 불가능합니다만 C/C++처럼 원하는 시점에 삭제하기를 희망한다면 IDisposable을 사용할 수 있습니다. 

이것은 관리되지 않는 메모리(리소스)들을 해제할때 사용하는 인터페이스입니다.
서로 다른 type의 객체라 하더라도 모든 type의 메모리를 정리할 수 있는 장점이 있습니다. 

WeakReference와 IDisposable을 같이 사용해서 원하는 시점에 메모리를 해제할 수 있습니다. 
아래의 예제는 Disposable 인터페이스를 상속받아 구현되었습니다.
namespace MyApp
{
    public class SampleChar : IDisposable
    {
        private IRenderObject m_Render = Renderer.CreateRenderObject();

        public void Dispose()
        {
            // 이후에 더이상 업데이트가 되지 않도록 여기서 제거하면
            SampleCharManager.Remove(this);

            m_Render = null;
        }

        public bool isRemoved 
        { 
            get 
            { 
                return m_Render == null; 
            } 
        }

        public void Render()
        {
            // 화면에서 그려지지 않도록 합니다. 
            if (m_Render == null) return;
        }

        public void Update() { }
    }
}
IRenderObject 인터페이스 구현은 아래와 같습니다.
namespace MyApp
{
    public interface IRenderObject
    {
        void Render();
    }

    public static class Renderer
    {
        public static IRenderObject CreateRenderObject()
        {
            // IRenderObject를 상속받은 더미 객체
            return new DumyRenderObject(); 
        }
    }
}
아래의 코드는 캐릭터 매니저가 등록된 캐릭터들을 일괄적으로 업데이트 시키고 렌더링하는 코드입니다. 
namespace MyApp 
{
    static class SampleCharManager
    {
        private static List<samplechar> m_list = new List<samplechar>();

        public static void Update()
        {
            foreach (SampleChar obj in m_list) 
            {
                obj.Update();
            }
        }

        public static void Render()
        {
            foreach (SampleChar obj in m_list)
            {
                obj.Render();
            }
        }

        public static void Add(SampleChar obj)
        {
            m_list.Add(obj); 
        }
        
        public static void Remove(SampleChar obj)
        {
            m_list.Remove(obj);
        }
    }
}
그 다음 디버깅을 위한 캐릭터의 위치를 표시하는 코드입니다. 
namespace MyDebug
{
    static class DisplayCharInfo
    {
        private static List<weakreference> m_list            = new List<weakreference>();
        private static Queue<weakreference> m_removeQueue    = new Queue<weakreference>();

        public static void Update()
        {
            foreach (WeakReference item in m_list)
            {
                MyApp.SampleChar obj = (item.Target != null) ? item.Target as MyApp.SampleChar : null;

                if (obj == null || obj.isRemoved)
                {
                    m_removeQueue.Enqueue(item);
                }
                // 삭제되지 않은 캐릭터의 정보만을 표시합니다.
                else 
                { 
                    /* 캐릭터 정보 표시 */ 
                }
            }

            // 삭제된 캐릭터는 목록에서 지워줍니다
            while(m_removeQueue.Count > 0)
            {
                WeakReference item = m_removeQueue.Dequeue();
                m_list.Remove(item);
            }
        }

        public static void Add(MyApp.SampleChar obj)
        {
            // WeakReference를 이용해 참조하도록 해줍니다.
            // SampleCharManager에서 캐릭터를 삭제하더라도 안전하게 가비지가 회수됩니다.
            m_list.Add(new WeakReference(obj));
        }
    }
}
Unity3D는 모노에서 관리하는 메모리와 엔진에서 관리하는 메모리로 나뉩니다. 
둘 다, 메모리가 부족하면 heap에 메모리를 할당하는데 이렇게 늘어난 메모리는 줄어들지 않습니다. 
heap에서 메모리가 재사용되므로 무작정 늘어날 일은 없지만 가비지가 늘어날수록 최대 메모리 사용량이 늘어나므로 가능하면 가비지가 덜 생성되록 코드를 짜는 것이 중요하겠죠.
메모리는 한번에 잡는 것이 좋고, caching이나 memory pool을 사용하는것이 좋습니다. 



2014년 1월 26일 일요일

C# 메모리 관리 기법 - Boxing

가비지로 인한 부하도 크지만 박싱으로 인한 부하도 무시할 수 없습니다. 

박싱이란 것은 Value type 객체를 Reference type객체로 바꾸는 것을 말하는데요.

C#에서는 모든 객체가 object로부터 상속됩니다. 
int, float같은 Value type조차도 object로부터 상속받은 것처럼 사용할 수 있습니다.

이런것들을 주의하지 않고 코드를 짜게 될경우 의도치 않게 박싱이 일어나는 곳들이 생기게 되고 이것이 누적되면 무시할 수 없는 속도저하가 일어나게 됩니다. 

아래의 예를 보시면, 리스트에 서로 다른 여러 종류의 type 값을 추가하는데 foreach문 안에서 item을 object로만 받아서 처리하고 있는것을 보실 수 있습니다. 
class MyClass
{
    public override string ToString() 
    { 
        return "다섯"; 
    }

    static public void Sample()
    {
        ArrayList list = new ArrayList();

        // 리스트에 아래처럼 여러가지 타입의 값을 추가해 넣어줍니다.
        // int형 float형 string형 등등.....
        list.Add(1);
        list.Add(1.5f);
        list.Add(‘3’);
        list.Add("four");
        list.Add(new MyClass());

        // 리스트에서 값을 꺼낼때 오직 object로 받아서 처리하고 있습니다.
        // 이런 경우 Value type을 Reference type으로 바꿔주면서 시간이 오래 걸리고
        // 변환하면서 heap에 저장이 됩니다. 
        // 시간도 오래 걸리고 가비지도 생기게 되겠네요.
        foreach (object item in list)
        {
            Debug.log(item.ToString());
        }
    }
}
그래서 여러 type을 처리해야만 하는 경우가 아니라면 값의 type을 명시할 수 있는 Generic collection의 사용이 좋겠습니다. 
Generic은 C++의 template과 비슷해서 C++의 STL container와 비슷하게 생겼습니다. 

아래의 예제에서 잘 사용한 경우와 그렇지 않은 경우를 비교해서 보세요.
class Example
{
    // 일단은 여러가지 type을 사용하지 않도록 분리해서 작업하는것이 제일 좋습니다. 
    // 분리가 끝나면 적절한 type을 명시할 수 있는 Generic collection을 사용하구요.

    // 좋지 못한 경우
    static public void BadCase()
    {
        // type에 대한 명시가 없는 어레이 리스트를 사용합니다.
        ArrayList list = new ArrayList();

        // 값은 int형인데
        int evenSum = 0;
        int oddSum  = 0;

        for (int i = 0; i < 1000000; i++)
        {
            list.Add(i);
        }

        // item을 object로 받아서 처리하게 되네요
        // 박싱이 일어납니다.
        foreach (object item in list)
        {
            if (item is int)
            {
                int num = (int)item;

                if(num % 2 ==0)
                {
                    evenSum += num;
                }
                else 
                {
                    oddSum += num;
                }
            }
        }
           
        Console.WriteLine("EvenSum={0}, OddSum={1}", evenSum, oddSum);
    }

    // 적절하게 잘 사용한 경우
    static public void GoodCase()
    {
        // type을 명시해줬습니다.
        List<int> list = new List<int>();

        // int형을 사용했구요
        int evenSum = 0;
        int oddSum  = 0;

        for (int i = 0; i < 1000000; i++)
        {
            list.Add(i);
        }

        // num을 int형으로 받아서 처리합니다. 
        // 박싱이 일어나지 않습니다.
        foreach (int num in list)
        {
            if (num % 2 == 0)
            {
                evenSum += num;
            }
            else
            {
                oddSum += num;
            }
        }
           
        Console.WriteLine("EvenSum={0}, OddSum={1}", evenSum, oddSum);
    }
}





C# 메모리 관리 기법 - instance

C#에서 클래스를 인스턴싱할때는 new를 해서 할 수 있습니다. 그런데 이런 식으로 생성하게 되면 heap에 메모리가 할당됩니다. 

그리고 이런것들이 계속 누적이 되면 가비지가 작동하게 됩니다. 

아래 예를 보세요.
static class TestMyVector
{
    public static void PrintVectorLength(float x, float y, float z)
    {
        // 이런것들이 heap에 메모리가 할당됩니다. 
        Vector3 v = new Vector3(x, y, z);
        Debug.log("v의 값 X = " + v.x  + "V의 값 Y = " + v.y + "V의 값 Z = " + v.z);
    }
}
이런 경우에 Vector 클래스를 구조체로 바꾸면 new를 통해서 생성하게 되도 heap에 메모리가 할당되지 않게 됩니다. 
구조체는 Value type이기때문에 stack에 할당되기 때문입니다. 
이런식으로 해서 가비지를 조금이라도 줄일 수 있습니다. 
아래의 예처럼요.
public class MyVector
{
    // 이런식으로 구조체를 만들고
    public struct MyVector
    {
        public float x, y, z;

        public MyVector(float x, float y, float z) 
        { 
            this.x = x;
            this.y = y; 
            this.z = z;
        }
    }
}

static class TestMyVector
{
    public static void PrintVectorLength(float x, float y, float z)
    {
        // 구조체를 이용해서 인스터스하면 이것은 stack에 할당됩니다.
        MyVector v = new MyVector(x, y, z);
        Debug.log("v의 값 X = " + v.x  + "V의 값 Y = " + v.y + "V의 값 Z = " + v.z);
    }
}
그런데 경우에 따라서는 구조체로 만드는 것이 애매한 경우가 있습니다. 
이런 경우엔 멤버변수로 만들어서 사용하는 방법이 있습니다. 
저도 주로 이 방법을 사용하는데요.. 가장 간편하기도 하고 멤버변수로 만들 경우 메서드 인자를 줄일수도 있고 여기 저기 사용하기 편하다는 장점도 있습니다. 
대신 잘못했을 경우 값이 도중에 바뀌어서 애매한 버그를 만들기도 합니다. ^^;;
하지만 개인적으로는 이 방법을 추천합니다. 
아래와 같이 멤버변수로 만들어서 사용할 수 있습니다. 
static class TestMyVector
{
    // 멤버변수로 만들어 놓습니다. 
    Vector3 tempVector3 = new Vector3(0.0f, 0.0f, 0.0f);

    // 이해를 돕기 위해 위와같이 만들었지만 x, y, z의 값이 모두 0인 경우
    // new를 사용하지 않고 
    // Vector3 tempVector3 = Vector3.zero
    // 이와 같이 쓸수도 있습니다. 

    public static void PrintVectorLength(float x, float y, float z)
    {
        tempVector3.x = x;
        tempVector3.y = y;
        tempVector3.z = z;
        Debug.log("tempVector3의 값 X = " + tempVector3.x  + "tempVector3의 값 Y = " + tempVector3.y + "tempVector3의 값 Z = " + tempVector3.z);
    }
}


2014년 1월 23일 목요일

C# 메모리 관리 기법 - string

유니티는 다양한 언어를 지원해서 개발을 좀더 수월하게 해주는데 저는 주로 Java보다 C#을 애용합니다. 

Java가 주는 간결하고 자유로움이 매력적이긴 하지만 개발이 진행될수록 그 자유스러움이 오히려 독이 되는 경우가 많다고 느껴지기 때문인데요. 

C#을 다루면서 참 코딩이 쉽다라고 느낀적이 참 많을 정도로 좋은 언어인 것은 틀림없습니다.

C#의 장점이라 할수 있는 특징들을 보면

  • 메모리 해제에 신경 쓰지 않아도 됩니다.
  • 이미 삭제된 메모리에 접근하는 실수를 방지해줍니다.
  • 잘못된 캐스팅으로 엉뚱한 메모리에 접근하지 않게 합니다.
  • 배열 크기보다 큰 메모리에 접근하지 못합니다.
  • 메모리 단편화에 대해 신경 쓰지 않아도 됩니다.
등등이 있겠네요. 
이런 장점들때문에 메모리를 무시하고 막 만들다 보면 가비지 컬렉션때문에 랙이 발생하는 경우가 다들 한번씩은 있을거에요.

어쨌든 C#을 사용하면서 알아두면 좋을 메모리 관리 기법에 대해서 써볼께요.
앞으로 하드웨어가 더 발전하면 메모리 관리도 필요 없어지지 않을까 싶네요. ^^;;

주기적으로 랙이 막 생기는데 로직의 이상도 없고 다른 부분에서는 특정 이상이 발견되지 않는다. 


그런데!! 

프로파일러를 돌려보니 System.GC.Collect()에서 호출 시간이 오래걸린다!!!

이거 십중팔구 가비지 컬렉션 문제입니다.


그럼 가비지 컬렉션이 작동하는 횟수를 줄여서 랙 발생 횟수를 줄이면 되겠죠. 

그러려면 가비지가 최대한 발생하지 않도록 해주어야 합니다.

그렇게 하기 위한 방법들중 string에 대해서 살펴보겠습니다.


C#은 문자열 조합하는 방법이 너무 쉽습니다. 


그래서 아래처럼 무턱대고 '+' 연산자를 이용해서 문자열을 만드는 경우가 많은데 이렇게 하면 '+'할때마다 새로운 string 인스턴스가 생성됩니다. 


그리고 이게 곧 가비지가 됩니다.


class Names
{
    public string[] name   = new string[100];

    public void Print()  
    {
        for (int index = 0; index < name.Length; index++)
        {
            // 아래처럼 '+'를 마구 쓰면 이게 다 가비지가 됩니다.
            string output  = "[" + index + "]" + name;
            Console.WriteLine(output);
        }
    }
}
이럴때 아래처럼 System.Text.StringBuilder를 사용하면 이런 문제를 해결 할 수 있습니다.

class NewNames
{
    public string[] name              = new string[100];
    private StringBuilder sb          = new StringBuilder();

    public void Print()
    {
        sb.Clear(); 

        for (int index = 0; index < name.Length; index++)
        {
            sb.Append("[");
            sb.Append(index);
            sb.Append("] ");
            sb.Append(name);
            sb.AppendLine();
        }
        
        Console.WriteLine(sb.ToString());
    }
}
이미 잡아 놓은 메모리 공간에 문자열을 복사해서 한번에 ToString()으로 string 객체를 생성해내기 때문에 가비지가 발생하지 않습니다.

Append()가 너무 많아 코드가 드럽다고 느껴지면 AppendFormat()을 사용할 수 도 있습니다.


class NewNamesOther
{
    public string[] name              = new string[100];
    private StringBuilder sb          = new StringBuilder();

    public void Print()
    {
        sb.Clear(); 

        for (int index = 0; index < name.Length; index++)
        {
            sb.AppendFormat("[{0}] {1}", index, name.ToString());
        }
        
        Console.WriteLine(sb.ToString());
    }
}
string처럼 Immutable pattern을 사용한 객체들의 값은 기존 메모리를 수정하지 않고 새로운 메모리를 만들어 반환하므로 주의해야합니다.

2013년 12월 26일 목요일

Encrypt and Decrypt the XML file(XML 데이터 암호화)

// 데이터 암호화
public static string Encrypt (string toEncrypt)
{
  byte[] keyArray  = UTF8Encoding.UTF8.GetBytes ("12345678901234567890123456789012");

  // 256-AES key
  byte[] toEncryptArray   = UTF8Encoding.UTF8.GetBytes (toEncrypt);

  RijndaelManaged rDel  = new RijndaelManaged ();
  rDel.Key              = keyArray;
  rDel.Mode             = CipherMode.ECB;

  // http://msdn.microsoft.com/en-us/library/system.security.cryptography.ciphermode.aspx
  rDel.Padding   = PaddingMode.PKCS7;

  // better lang support
  ICryptoTransform cTransform  = rDel.CreateEncryptor ();

  byte[] resultArray   = cTransform.TransformFinalBlock (toEncryptArray, 0, toEncryptArray.Length);

  return Convert.ToBase64String (resultArray, 0, resultArray.Length);
}
 
 // 데이터 암호 해독
public static string Decrypt (string toDecrypt)
{
  byte[] keyArray  = UTF8Encoding.UTF8.GetBytes ("12345678901234567890123456789012");

  // AES-256 key
  byte[] toEncryptArray   = Convert.FromBase64String (toDecrypt);

  RijndaelManaged rDel  = new RijndaelManaged ();
  rDel.Key              = keyArray;
  rDel.Mode             = CipherMode.ECB;

  // http://msdn.microsoft.com/en-us/library/system.security.cryptography.ciphermode.aspx
  rDel.Padding    = PaddingMode.PKCS7;

  // better lang support
  ICryptoTransform cTransform  = rDel.CreateDecryptor ();

  byte[] resultArray   = cTransform.TransformFinalBlock (toEncryptArray, 0, toEncryptArray.Length);

  return UTF8Encoding.UTF8.GetString (resultArray);
}

2013년 12월 17일 화요일

Excel 데이터를 XML로 변환하기

씬의 저장이나 레벨 디자인 등을 만들때 XML을 사용하는 경우가 있는데 XML을 직접 손으로 수정하다 보면 너무 고된 작업이 될수 있죠.

Xcode로 작업할때도 비슷하게 plist로 작업을 했었는데 다시는 그 작업을 하고 싶지 않네요.

생각도 하기 싫군요.....

이런 작업에서는 Excel만한게 없죠.

Excel로 간단하고 보기 쉽게 작업을 하고 이것을 XML로 변환하는 법에 대해서 써볼께요.

일단 새 메모장을 열어요.

그리고 만들고 싶은 XML의 노드 구성을 만들어야 하는데 최소 두개 이상은 만드셔야 합니다.
아래처럼요.

아래는 id와 text라는 컬럼을 두개 갖는 데이터를 만든것입니다.

  
    
    
  
  
    
    
  

이제 확장자를 xml로 바꾸고 저장합니다.(test.xml 이런식으로요.)

다음은 아래 그림 순서대로 해주세요.





그러면 메뉴 탭에 'Developer'라는 메뉴가 생기게 되죠.
여기서 아래 그림처럼 'Import'와 'Export'를 이용해서 작업하게 됩니다.



이제 새 문서를 만들고 위의 그림의 'Import'를 이용해서 아까 만들었던 'test.xml'을 열어주세요.


메세지 박스가 나오면 그냥 확인해주세요.
아래 그림처럼 나온다면 성공입니다.


참고로 'Import'할때 현재 선택되어 있는 위치로 'Import'되니까 원하는 위치를 선택해 놓으세요.

이제 원하는 데이터를 넣어서 문서를 수정하시고 'Import' 아래에 있던 'Export' 버튼을 눌러서 저장하시면 끝입니다.

저장한 파일을 열어서 확인해보시면 제대로 되어 있습니다. 



Converting Excel data to XML

You may want to use the XML when you create level design and save the scene. However, it is difficult to fix directly by hand.

Even when I was working plist in Xcode, it was difficult for the same reason as this. I do not want to work about plist again.

I hate also be considered.

In such this work, Excel is very useful.

Let write an post about how to using Excel and how to convert to XML .

The first thing most, will launch a new Notepad.

And you must create two of the minimum required to create a node configuration of the XML you want to create.
As shown below.

The following figure is what you have created a data that has two columns of text and id.

  
    
    
  
  
    
    
  

Change the extension to XML now and save. (Write like test.xml.)

And please the order shown in the figure below.






Then, the menu in the menu tab called "Developer" comes out.
Here, you will want to work with the "Import" and "Export" as shown below.





Now, create a new document. And use the 'Import' button,  please open "test.xml".

Message box appears. Please press OK.

if you see as in the figure below, you are success.


Please select the desired location. because When you push "Import" button, appeared currently location.

Now you modify the document to put the desired data. And push "Export" button under 'Import' button.


If open the saved file, you will know that the data is inserted correctly.


ExcelデータをXMLに変換する

シーンの保存やレベルデザインなどを作成するときにXMLを使用する場合があります。しかし、XMLを直接手で修正してみると作業が困難である。

Xcodeで作業するときも、これと同様の理由でplistを利用して作業をしました。再びその作業をしたくありません。

考えることも嫌いです。

この作業では、Excelは非常に便利です。

Excelを利用して簡単に作業をして、これをXMLに変換する方法についての記事を書いてみましょう。

一番最初にすることは、新しいメモ帳を起動します。

そして作りたいXMLのノード構成を作成する必要最小限の二つ以上は、作成する必要があります。
下のようにね。

以下は、idとtextというカラムを二つ持つデータを作成したものです。

  
    
    
  
  
    
    
  

今の拡張子をxmlに変更し、保存します。(test.xmlこのようにするとされます。)

そして、下図の順にしてください。





そうすると、メニュータブの「Developer」というメニューが出てきます。
ここでは、下の図のように「Import」と「Export」を使用して作業することになります。



これで、新しいドキュメントを作成し、上の図の「Import」を使用して、さっき作った「test.xml」を開いてください。

メッセージボックスが出ます。ただ、OKを押してください。

下の図のように出たら成功です。


ちなみに「Import」するときに、現在選択されている場所に「Import」になるから、目的の場所を選択して置いてください。

これで、目的のデータを入れて文書を修正し、「Import」の下にあった「Export」ボタンを押して保存していただく終わりです。

保存したファイルを開けてみれば、データが正しく入っています。


Unity3Dでコードを使用してパーティクルを開始および停止する方法

Unity3Dでパーティクルを作成して使用する際に必要に応じて再生したり、停止してくれることをコードで制御する方法です。

現在パーティクルを使用していないときに再生している必要はないのだから必要なときに再生させることです。

次の事項を考慮して製作します。


  1. 粒子は、ParticleSystem Componentを使用して製作します。
  2. パーティクルを停止するときに画面に消えるためには、Stop()およびClear()関数の両方を使用しします。
  3. パーティクルを開始するには、Play()関数を使用します。

サンプルコードは以下のとおりです。

ParticleSystem testParticle         = null;

// 버튼이 눌러졌을때
if (Input.GetMouseButtonUp(0) == true)
{
    // 파티클이 있고
    if (testParticle)
    {
        // 파티클이 재생중이면 재생을 멈추고 지워줍니다
        if (testParticle.isPlaying == true)
        {
            testParticle.Stop();
            testParticle.Clear();   

            //Debug.Log("STOP");
        }
        // 재생중이 아니라면 재생해주고요
        else
        {
            testParticle.Play();

            //Debug.Log("PLAY");
        }
    }
    // 파티클이 없다면 새로 만들어주구요
    else
    {
        Vector3 pos       = Vector3.zero;
        pos.y               = 3;
        pos.x               = 3 - 30.0f;

        Transform particleObject        = (Transform)Instantiate(Resources.Load("Prefabs/Effects/pfBlockBomb", typeof(Transform)), pos, Quaternion.identity);

        testParticle        = (ParticleSystem)particleObject.GetComponent(typeof(ParticleSystem));

        //Debug.Log("CREATE");
    }

    return;
}

How to start and stop the particle by using code in Unity3D

Method of controlling by code for particle when create a particle at Unity3D....  If necessary, you can stop or play by code. 

It do not need play when never used. So, I will want play when is used.

When you produce particle, consider as following.

Particles must fabricated using ParticleSystem Component.
Use both Clear() and Stop() function for In order to disappear on the screen when stopping the particles.
If you want to start a particle, use the Play () function.

Sample code is as follows.

ParticleSystem testParticle         = null;

// 버튼이 눌러졌을때
if (Input.GetMouseButtonUp(0) == true)
{
    // 파티클이 있고
    if (testParticle)
    {
        // 파티클이 재생중이면 재생을 멈추고 지워줍니다
        if (testParticle.isPlaying == true)
        {
            testParticle.Stop();
            testParticle.Clear();   

            //Debug.Log("STOP");
        }
        // 재생중이 아니라면 재생해주고요
        else
        {
            testParticle.Play();

            //Debug.Log("PLAY");
        }
    }
    // 파티클이 없다면 새로 만들어주구요
    else
    {
        Vector3 pos       = Vector3.zero;
        pos.y               = 3;
        pos.x               = 3 - 30.0f;

        Transform particleObject        = (Transform)Instantiate(Resources.Load("Prefabs/Effects/pfBlockBomb", typeof(Transform)), pos, Quaternion.identity);

        testParticle        = (ParticleSystem)particleObject.GetComponent(typeof(ParticleSystem));

        //Debug.Log("CREATE");
    }

    return;
}

Unity3D에서 파티클의 시작과 정지를 코드로 제어하기

Unity3D에서 파티클을 만들어 사용할때 필요에 의해 재생하거나 멈춰주는 것을 코드로 제어하는 법입니다. 

현재 파티클을 사용하지 않는데도 재생중일 필요는 없으니까 필요할때만 재생시키는거죠.

아래 사항을 고려해서 제작하면 됩니다.


  1. 파티클은 ParticleSystem Component로 제작해야 함.
  2. 파티클을 정지함과 동시에 화면에서 사라지게 하기 위해서는 Stop()과 Clear() 함수를  모두 사용할 것.
  3. 파티클을 시작하기 위해서는 Play()함수를 사용할 것


예제 코드는 아래와 같아요. 
ParticleSystem testParticle         = null;

// 버튼이 눌러졌을때
if (Input.GetMouseButtonUp(0) == true)
{
    // 파티클이 있고
    if (testParticle)
    {
        // 파티클이 재생중이면 재생을 멈추고 지워줍니다
        if (testParticle.isPlaying == true)
        {
            testParticle.Stop();
            testParticle.Clear();   

            //Debug.Log("STOP");
        }
        // 재생중이 아니라면 재생해주고요
        else
        {
            testParticle.Play();

            //Debug.Log("PLAY");
        }
    }
    // 파티클이 없다면 새로 만들어주구요
    else
    {
        Vector3 pos       = Vector3.zero;
        pos.y               = 3;
        pos.x               = 3 - 30.0f;

        Transform particleObject        = (Transform)Instantiate(Resources.Load("Prefabs/Effects/pfBlockBomb", typeof(Transform)), pos, Quaternion.identity);

        testParticle        = (ParticleSystem)particleObject.GetComponent(typeof(ParticleSystem));

        //Debug.Log("CREATE");
    }

    return;
}

2013년 12월 16일 월요일

Tips Korean cracking problem in MonoDevelop





1. If you are using MonoDevelop of windows os, input of Korean is possible.

However, in the case of the source file that you work with Visual studio, there is a case to be able to see Korean is garbled in MonoDevelop.

When you save a file in visual studio, this is encoded set - occurs when you want to save with the settings (Korean - code page 949) incorrect.

Thus, "(UTF-8 signature) Unicode - code page 65001" as shown in the figure above When you save in, garbage Korean is resolved.

2. If you want to use MonoDevelop in mac os, it is output to normal if MonoDevelop's Font does not support Korean even file encoding option on the file are set correctly as No. 1 above not, it will appears garbled.

Therefore, it is resolved by setting to AppleGothic is a basic fonts of mac fonts MonoDevelop.

3. If you want to use MonoDevelop in mac os, Korean input can not be resolved still be set as No. 2 above.

In this way, you will need to use the text editor, you can use cmd + c, cmd + v to enter the Korean, and copy and paste.

It should also be noted here is that the input mode that is attached to normal only in the case of English input mode when you paste.



Correlation of Awake & Start & Update

Awake (once) -> Start (once/enabled) -> [loop : Update]

1. Regardless of the enabled, Awake is the initialization, to call once. In addition, call the script even if it is not enable.

2. Moment it became enable true Awake or later, you call once Start. You need to call script is to enable.

3. (Tick to each fixed) Update is to continually call after Start is called. (Update type applies all)


4. FixedUpdate is called after the Update.


5. Awake function of the Game Object, where they will be called at random between Game Objects.

6. Be specified to force the calling sequence of the Game Objects seems to be impossible.


MonoBehaviour Lifecycle

Awake (once) -> Start (once/enabled) -> [loop : Update]

1. Regardless of the enabled, Awake is the initialization, to call once. In addition, call the script even if it is not enable.

2. Moment it became enable true Awake or later, you call once Start. You need to call script is to enable.

3. (Tick to each fixed) Update is to continually call after Start is called. (Update type applies all)


4. FixedUpdate is called after the Update.


5. Awake function of the Game Object, where they will be called at random between Game Objects.

6. Be specified to force the calling sequence of the Game Objects seems to be impossible.


2013년 10월 16일 수요일

Awake & Start & Update의 상관관계


MonoBehaviour Lifecycle

Awake (once) -> Start (once/enabled) -> [loop : Update]

1. Awake 는 enabled와 상관없이 initialization 되면 한번 호출이 됩니다. 또한 script가 enable이 안되어 있어도 호출은 됩니다.

2. Start 는 Awake 이후 enable true 가 되는 순간 한번 호출이 됩니다. script가 enable이 되어 있어야만 호출이 됩니다.

3. Update 는 Start 가 호출 된 다음 지속적으로(일정 Tick마다) 호출이 됩니다.(Update 류 들은 전부 해당)

4. FixedUpdate는 Update 이후에 호출 됩니다.

5. 게임 오브젝트의 Awake 는 object 들 간에 랜덤으로 호출 되도록 되어있습니다.

6. 게임 오브젝트 간에 호출 순서를 강제로 지정하는 것은 아무래도 불가능 한것 같습니다.

MonoDevelop에서 한글 깨지는 문제에 대한 팁





1. windows os에서 MonoDevelop을 사용할 때, 한글 입력이 가능하지만, visual studio 에서 작업한 소스 파일의 경우  MonoDevelop에서 한글이 깨져보이는 경우가 있는데요.

    이것은 visual studio 에서 파일을 저장할 때, 인코딩 설정이 한국어 - 코드페이지 949와 같이 잘못된 설정으로 저장하는 경우에 발생합니다. 

    따라서, 위의 그림처럼 "유니코드(서명 있는 UTF-8) - 코드페이지 65001"로 저장하면 한글 깨짐 현상이 해결됩니다.

2. mac os에서 MonoDevelop을 사용할 때, 위의 1번과 같이 파일의 인코딩 옵션만 제대로 설정되어 있는 파일이라고 하더라도 MonoDevelop 의 폰트가 한글을 인식하지 못하면 제대로 출력되지 않고 깨져서 나옵니다.

   따라서, MonoDevelop 의 폰트를 mac의 기본 폰트인 AppleGothic으로 세팅하면 해결됩니다.

3. mac os에서 MonoDevelop을 사용할 때, 위의 2번처럼 설정하더라도 한글 입력은 여전히 해결이 안됩니다.

   따라서, 텍스트 편집기를 이용하여 한글을 입력 후 cmd + c, cmd + v를 이용하여 복사해 붙여넣어야 합니다.

   여기서 또 주의할 점은 붙여넣을 때 입력 모드가 영문입력 모드인 경우에만 제대로 붙여넣어진다는 것입니다.