2016. 7. 27. 12:49



C++ 캐스팅(cast)에는 총 4가지 종류가 있습니다.


바로


static_cast

reinterpret_cast

const_cast

dynamic_cast 

입니다.


각각 무슨 기능을 하는지 알아 보자면


 

 static_cast


명시적 형 변환을 위한 캐스트 연산자


 reinterpret_cast


무조건 적으로 변환한다.(강제 변환)  ( reinterpret 다시 해석하다, 새로 해석하다.) 메모리 단위로 분해하여 재조립합니다. 굉장히 위험한 방법입니다.


 const_cast

 

const 즉 상수성을 제거 할때 사용됩니다.


 dynamic_cast 

 

RTTI( Run Time Type Information )를 위한 캐스팅 입니다.



하지만, 굳이 귀찮게 위의 방법을 써야하는 이유가 뭘까요?


저희가 C언어 쓸때는 그냥 (Type) 으로 캐스팅 연산을 했었습니다.


다음과 같은 경우를 봅시다.


1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
 
int main()
{
 
    int m_4byte = 0;
    double* m_pointer = (double*)&n;
    *m_pointer = 1.23;
 
    return -1;
}
cs


무엇이 문제 인지 보이시나요?


위와 같은 방법을 사용하면 어떻게 될까요?


에러가 납니다.  직접 VS를 열어서 빌드해보세요.


그럼 다음 경우를 보겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
 
int main()
{
 
    
    const int c_int = 50;
    int * p_int = (int*)&c_int;
    *p_int = 100;
 
    cout << c_int << endl;
 
    cout << *p_int << endl;
 
    return -1;
}
cs

다음과 같이 코드를 작성 한 후 실행하면 어떤 결과가 나올까요?
---------------------------
50
100
---------------------------
이 나오게 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
 
int main()
{
 
    
    int value = 50;
    const int c_int = value;
    int * p_int = (int*)&c_int;
    *p_int = 100;
 
    cout << c_int << endl;
 
    cout << *p_int << endl;
 
    return -1;
}
cs


하지만 다음과 같이 코드를 작성 한 후 실행 하게되면

-------------------------
100
100
-------------------------


이 나오게 됩니다.


이는 const의 값이 결정되는 시점에 따라 달라집니다만, 그건 나중에 const에 관련 글을 적을때 적도록 하겠습니다.


이 2개의 코드로 알아야 하는것은 C에서 지원하는 cast 방식은, 불안전 하다는 것입니다.


2개의 코드 다 에러를 나타내지 않습니다. 하지만 비정상적인 결과를 출력하죠.


과연 이게 올바른 걸까요?


그럼 static_cast로 변경을 해봅시다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
 
int main()
{
    int value = 50;
    const int c_int = value;
    int * p_int = static_cast<int*>(&c_int);
    *p_int = 100;
 
    cout << c_int << endl;
 
    cout << *p_int << endl;
 
    return -1;
}

cs


컴파일러는 const 또는 다른 형식 한정자로 캐스팅 할수없습니다. 라며 에러를 띄우고 빌드를 하지 않습니다.

불안전 하기 때문이죠.


만약 const값을 변하게 하려는 의도가 있다면, const_cast를 사용해야 할것입니다.


그렇기에 안정하고 정상적인 캐스팅을 위하면 C++에서는 기본적으로 명시적캐스팅인 static_cast를 사용하도록 합시다.


다음은 reinterpret_cast 입니다.


reinterpret_cast는 제가 위에 이렇게 적어 놨을겁니다.


무조건 적으로 변환한다.(강제 변환)  ( reinterpret 다시 해석하다, 새로 해석하다.) 메모리 단위로 분해하여 재조립합니다. 굉장히 위험한 방법입니다.


여기서 중요하게 보셔야 할 부분은 '메모리' 단위 입니다.


메모리 단위란 무엇일까요?


그럼 이 코드를 자세히 봅시다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
 
class A {public : int a;};
class B {public : int b;};
 
class C : public A, public B
{
    int c;
};
 
int main()
{
    C c;
    return -1;
}
cs


위의 코드에서 class C는 class A와 B를 다중 상속 받은 상태입니다. 그리고 A와 B는 각각 4byte짜리의 int를 가지고 있죠.

그럼 C를 선언 하는 순간 메모리는 어떻게 잡힐까요?


Class C

 Class A

 int a;

 4 Byte

 Class B

 int b;

 4 Byte

 C클래스 멤버

 int c;

 4 Byte


다음과 같이 구조를 가질껍니다.


그럼 위와 같은 메모리 구조를 가졌을때 아래와 같이 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
 
class A {public : int a;};
class B {public : int b;};
 
class C : public A, public B
{
    int c;
};
 
int main()
{
    C c;
    A* p_a = &c;
 
    cout << &<< end;    
    cout << p_a << end;
 
    return -1;
}
cs


코드를 작성 한후 실행하면 2개의 결과 값은 똑같이 나올겁니다.


하지만 이 코드를 어떨까요?



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
 
class A {public : int a;};
class B {public : int b;};
 
class C : public A, public B
{
    int c;
};
 
int main()
{
    C c;
    B* p_b = &c;
 
    cout << &<< end;    
    cout << p_b << end;
 
    return -1;
}
cs


C클래스가 부모인 B클래스로 암시적 캐스팅이 된 형태 입니다.


실행 하면 결과는


------------------------------------

&c의 주소값

&c의 주소값 + 4byte 

------------------------------------


암시적 변환으로 메모리의 주소값이 바뀌었습니다.


물론 자식 -> 부모 변환이라 static_cast를 사용하셔도 됩니다.


하지만 reinterpret_cast를 사용하면 어떻게 될까요?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
 
class A {public : int a;};
class B {public : int b;};
 
class C : public A, public B
{
    int c;
};
 
int main()
{
    C c;
    B* p_b = reinterpret_cast<B*>(&c);
 
    cout << &<< end;    
    cout << p_b << end;
 
    return -1;
}
cs

놀랍게도 2개의 출력값이 같은 주솟값을 가지게 됩니다.


메모리 단위로 분해해서 재 생성 하기 때문이죠.


이와 같은 방법을 전 아직 어디서 잘 사용해야 할지 모르겠습니다. ( 나중에 알게되면 꼭 수정하겠습니다. ) 


하지만 저기서 p_b가 가진 멤버변수인 b를 수정하게 되면 A클래스가 가진 a가 수정이 된답니다.




Class C

 Class A

 int a;

 4 Byte

 Class B

 int b;

 4 Byte

 C클래스 멤버

 int c;

 4 Byte


위와 같은 구조가 

Class C

 Class B

 int b;

 4 Byte

 Class C

 int c;

 4 Byte


 ( )

 (4 Byte )


이렇게 조립 되었을뿐 메모리 주소를 변하지 않았기 때문이죠.


전 처음 이 사실을 알았을때는 정말 신기했습니다.  잘만 사용하면 메모리 단위로 잘 쪼개서 사용 할 수 있기 때문이죠.



마지막으로 dynamic_cast입니다.


dynamic_cast는 RTTI(Runtime Type Information)를 위한 캐스팅이라고 제가 위에 적었는데요.


런타임에 상속 계츨 관계를 가로지르거나 다운 캐스팅시 사용되는 캐스팅 연산자 라고 생각하시면 편합니다.


즉, 부모가 자식으로 캐스팅이 될 수 없는데, 런타임중 판단으로 가능하게 된다는거죠.


단 dynamic_cast는 다형성을 띄지 않은 객체간의 변환은 불가능하며, 컴파일이 에러를 낸답니다.


즉 다형성을 가지려면 클래스간 virtual 멤버 함수가 있어야 합니다.


코드로 표현하면 다음과 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;
 
class A {
public
    int a; 
 
    virtual void test(){}
};
 
class C : public A
{
    int c;
    virtual void test(){}
};
int main()
{
    C c;
    A* pA = &c; 
    C* c2 = dynamic_cast<C*>(pA);
    
    return -1;
}
cs


하지만 저 dynamic_cast가 올바르지 않았을경우는 null값을 반환하니 주의 하시기 바랍니다.


읽어주셔서 감사합니다

Posted by 시리시안
2016. 7. 27. 10:16

안녕하세요. 게임개발자놀이터 입니다.


오늘은 코드를 이쁘게 올리는 방법에 대해서 알려드리려고합니다.


제 블로그의 글들은 다 이 방법을 사용하고 있습니다.


http://colorscripter.com/


위 주소로 들어가시게 되면



다음과 같은 창이 뜨는데, 위에 언어 : 자동(text) 로 되어있는 부분을 자신에게 알맞은 내용으로 변경합니다.


그후 글 작성후 하단의 클립보드에 복사를 누른후 붙여넣으시면 됩니다.


참 간단하죠?




클립 보드에 복사를 누르신후..


1
2
3
4
5
6
7
8
9
10
11
//이렇게 작성하시고
//붙여 넣으면 됩니다
 
 
#include<stdio.h>
 
int main()
{
 
    return -1;
}
cs

붙여 넣으시면 위와 같이 나오게 됩니다.



감사합니다

Posted by 시리시안
2016. 4. 20. 13:23


저희가 상속을 사용하여 클래스를 구성할때 최상위 부모 소멸자에는 Virtual을 넣어 주어야 합니다.

그 이유가 뭘까요?

이유를 알기위해선 상속을 받은 클래스의 생성과 소멸의 순서를 알아야합니다.

생성을 할경우 부모클래스의 생성자부터 호출되며 차례로 자식의 생성자를 호출하게 됩니다.

반대로 소멸자는 자식클래스의 소멸자를 먼저 호출하고 부모클래스의 소멸자가 호출됩니다.

이렇게 생각하면 아무런 문제없습니다. 

단, 우리가 비교적 자주 상속을 사용하여 선언할경우 부모클래스의 포인터로 자식클래스를 정의하여 사용하게 될것입니다.

이경우, 부모클래스로부터 자식 클래스를 호출할때 가상 함수로 정의되지 않은 자식 클래스의 오버라이딩된 함수를 호출하면 주체가 선언된 인자형이 부모이기 때문에 부모클래스의 멤버함수가 호출됩니다.

이렇게 생각했을때 소멸자 또한 오버라이딩된 멤버함수라 볼 수 있기 때문에, 만약에 부모 포인터로 객체를 삭제하면 부모클래스의 소멸자가 호출되며 정의된 자식의 나머지 공간의 메모리 만큼 누수되어 버립니다.

따라서 소멸자를 가상 함수로 선언하지 않으면 자식클래스의 소멸자가 결코 호출되지 않습니다. 

virtual을 사용하였다면 이것은 자식클래스에서 재정의 될 수 있음을 명시 하기 때문에 포인터의 종류와 상관없이 자식 클래스의 멤버함수가 호출되게 답니다. 즉, 자식 클래스의 소멸자가 호출되고 부모 클래스의 소멸자가 호출되게 됩니다.

따라서 상속관계를 이용하였고 소멸자에서 리소스를 해제해야 한다면 반드시 소멸자를 가상함수로 선언해주어야 합니다.

예제 코드
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
#include <iostream>
using namespace std;
 
class classA
{
    public:
      classA(){  cout << "A 생성" << endl;}
       virtual ~classA(){  cout << "~A 소멸" << endl;}
};
 
class classB : public classA
{
    public:
      classB(){cout << "B 생성"<< endl;}
      ~classB(){cout << "~B 소멸" << endl;}
};
 
 
int main()
{
  cout << "== 소멸자 테스트 시작 ==" << endl;
  classB *= new classB;
  classA *= B;
  delete A;
  return 0;
}
cs



실행 결과는 다음과 같습니다


ClassA에서 소멸자에 virtual을 사용하지 않았을 경우

===================================================================

START

A

B

~A

===================================================================


ClassA에서 소멸자에 virtual을 사용했을 경우

===================================================================

START

A

B

~B

~A

===================================================================


Posted by 시리시안
2016. 4. 14. 11:09

오버라이딩(Overriding)


※ 오버라이딩은 함수의 재정의를 말합니다.

※ 상속받은 자식 클래스에서 부모 클래스의 멤버 함수를 재정의 하는것을 말합니다.


오버로딩(Overloading)


※ 오버로딩은 함수의 중복 선언을 말합니다.

※ 같은 함수에서 인수만 다르면 얼마든지 정의할 수 있습니다.



===============================================

오버라이딩의 예


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
31
32
33
34
35
36
 
class _Parent{
public:
    void Something()
    {
        cout << "_Parent Shomthing Function" << endl;
    }
};
 
//자식클래스01
class _Children:public pitching
{
};
 
//자식클래스02
class _OtherChildren:public pitching
{
public:
    //함수 재정의(오버라이딩)
    void Something()
    {
        cout << "_OtherChildren Shomthing Function" << endl;
    }
};
 
void main()
{
    //_Children 객체생성 후 함수호출
    _Children *Children = NULL;
    Children->Something();
 
    //_OtherChildren 객체 생성 후 함수호출
    _OtherChildren *OtherChildren=NULL;
    OtherChildren->Something();
}
 
cs


위 함수의 결과가 어떻게 나올까요?


결과는

-----------------------------------------------

_Parent Shomthing Function

_OtherChildren Shomthing Function

-----------------------------------------------


이렇게 나온답니다.

이유는 Children객체는 상속받은 부모의 함수를 실행하지만, OtherChildren은 클래스내에서 재 정의한 함수를 호출하기 때문입니다.


이처럼 부모와 똑같은 함수명, 파라미터를 가지고 자식클래스에서 새롭게 정의하여 사용하는것을 오버라이딩이라고합니다.


===============================================


오버 로딩의 예


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
class Overload{
    public void Something()
    {
        cout << "Shomthing() Function" << endl;
    }
    public void Something(int _cnt,int _cnt)
    {
        cout << "Shomthing(int _cnt,int _cnt) Function" << endl;
    }
    public void Something(double _num)
    {
        cout << "Shomthing(double _num) Function" << endl;
    }
}
 
void main() {
        Overload ob = new Over();
        ob.Something(1,2);
        ob.Something(3);
}
cs


출력결과는

-----------------------------------------------

Shomthing() Function

Shomthing(int _cnt,int _cnt) Function

Shomthing(double _num) Function

-----------------------------------------------


입니다.

이유는 함수의 인자가 다르기 때문입니다. 각각의 맞는 인자로 알아서 호출된답니다.

이처럼 같은 함수내에서 인자로 구분되어 정의하는것을 오버로딩 이라고 합니다.



Posted by 시리시안
2016. 4. 14. 10:46
밑의 코드처럼 선언하시면 됩니다.
상속받아 사용할 때는 소멸자를 꼭 포함 시켜야 한다는점을 잊지마세요~

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
31
#include "stdafx.h"
#include <iostream>
 
class _IRef{
public:
    virtual ~_IRef(){}
    virtual void _Update() = 0;
};
 
class Node : public _IRef{
public:
    ~Node(){}
    void _Update(){ std::cout << "Node Update" << std::endl; }
};
 
class user{
public:
    void Something(_IRef* Ir){ Ir->_Update(); }
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    Node* c = new Node;
    user u;
    u.Something(c);
 
    return 0;
}
 
 
 
cs



Posted by 시리시안
2016. 4. 14. 10:39

인터페이스(Interface)란 컴퓨터 용어에서 많이 등장합니다.

대표적으로 User Interface 입니다. 줄여서 UI라고 자주 부릅니다.

Interface를 어원을 찾아보면 Inter(중간) + face(맞대고 있다)입니다. 즉, 어느 중간 사이에서 맞대고 있는 부분을 의미를 가집니다.

User Interface, UI란 사용자 그러니까 플레이어와 컴퓨터 '중간' 사이에서 '맞대고 있어' 일어나는 상호작용을 매개하는 것을 말합니다.


지금부터 설명할 객체 지향 언어에서도 인터페이스란 객체와 객체 '중간' 사이에서 '맞대고 있어' 일어나는 사이에서 상호 작용의 매개로 쓰인답니다.


Java에서는 Interface라는 키워드를 통해서 Interface를 바로 생성할 수 있습니다.

interface로 할 수 있는 일이 무엇이냐 하면 클래스의 기본적인 틀을 제공하면서 다른 객체 사이에서의 '중간' 매개 역할도 담당한다는 것입니다.

그럼 자바를 이용해서 직접 인터페이스를 선언해 봅시다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
public interface Book{    //여기서 I는 인터페이스의 i입니다.
    private String _author;    //작가
    private String _title;    //제목
    private String _text;    //본문
    public void Show_Information(){
    }
}
public class Cartoon implements Book{
    //_author와 _title, _text에 접근 할 수 있음
    public void Show_Information(){
        // 꼭 구현해야함
    }
}
public class Novel implements Book{
    //_author와 _title, _text에 접근 할 수 있음
    public void Show_Information(){
        // 꼭 구현해야함
    }
}
cs


이처럼 인터페이스 선언하고 클래스를 선언할 수 있습니다.

이경우는 즉 Book 클래스가 인터페이스 클래스가 된것입니다.

즉 다음과 같이 사용 할 수 있습니다.


1
2
3
4
5
6
7
void main(){
    Book mCartoon = new Cartoon();
    mCartoon.Show_Information();//만화책 정보
    Book mNovel = new Novel();
    mNovel.Show_Information();//소설책 정보
}
 
cs


즉, 이렇게 Book이라는 클래스 하나로, Cartoon과 Novel을 선언하여 공통된 함수를 불러서 관리 할수있습니다.

손쉽게 표현하면 위처럼 사용하는게 아니라,


1
2
3
4
5
6
7
8
9
 
 
void main(){
    Book[] mBooks = new Book[2];
    mBooks[0= new Cartoon();
    mBooks[1= new Novel();
    for(int i=0; i<2++i)
        mBooks[i].Show_Information();//책정보 
}
cs


이처럼 한가지의 클래스로 묶어서 사용할 수 있습니다.


사용 용도 및 방법은 무궁무진합니다.


게임에서 적이 가진 모든 총알을 _IBullet 이라 선언하고 관리해도 되고, 모든 오브젝트를 _IObject 라고 하여 관리해도됩니다.

이 모든걸 다합쳐서 _IRef 로 인터페이스 선언하여 관리하면 정말 간단하겠죠?



C++에서 선언법은 다음과 같습니다.


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
31
#include "stdafx.h"
#include <iostream>
 
class _IRef{
public:
    virtual ~_IRef(){}
    virtual void _Update() = 0;
};
 
class Node : public _IRef{
public:
    ~Node(){}
    void _Update(){ std::cout << "Node Update" << std::endl; }
};
 
class user{
public:
    void Something(_IRef* Ir){ Ir->_Update(); }
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    Node* c = new Node;
    user u;
    u.Something(c);
 
    return 0;
}
 
 
 
cs






Posted by 시리시안
2016. 3. 17. 12:58

DirectX SDK (June 2010) 을 Windows 7 에 설치하던 중에 Error Code S1023 이 뜰때 해결법입니다.


윈도우 + R을 눌러서


CMD를 입력해 도스창을 실행합니다.


다음과 같이 입력하세요.


MsiExec.exe /passive /X{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}


MsiExec.exe /passive /X{1D8E6291-B0D5-35EC-8441-6616F567A0F7}



2가지 전부 삭제후, DirectX SDK를 재설치 하시면 됩니다.


Posted by 시리시안
2016. 3. 3. 14:25


안녕하세요.


xml데이터를 만들어야하는데, 손으로 일일히 메모장에 전체를 적을수는 없으니..


제일 간단한 엑셀로 만드는법을 적어보겠습니다.


제일 먼저 엑셀로 만들기 위하면 스키마를 작성해주어야 하는데요


스키마 작성은 노트패드(메모장 또는 기타등등)을 열어서 다음과 같이 적습니다.


한국어, 영어, 중국어 3개로 로컬라이징을 하기위한 언어 스키마입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<root>
             <texts>                           
                           <index/>
                           <menu/>
                           <kor/>
                           <eng/>
                           <chi/>
             </texts>
             <texts>                           
                           <index/>
                           <menu/>
                           <kor/>
                           <eng/>
                           <chi/>
             </texts>
</root>
cs

꼭 texts는 마음대로 변경하셔도 되지만, 스키마에 한글을 적으시면 안됩니다.

그리고 반복된다는것을 알리기위해 꼭 2번 적어야합니다.


자 이렇게 작성했다면, 이를 저장합니다.


단, 저장시 확장자명을 .xml로 저장해주셔야합니다.


자 이제 엑셀을 켜봅시다.


먼저 엑셀의 개발도구를 열어야하는데요.


개발도구를 왼쪽 리본의서 메뉴에서 설정가능합니다..


모르면 구글링하면 친절한 블로그들이 있을꺼애요



개발도구에서 원본을 클릭합시다.



그러면 우측에  XML원본이라는 창이 뜰텐데요.

 그밑에 XML맵을 누르면 다음과 같은 창이 뜹니다.



그러면 밑에 추가를 누르신후 아까 저장한 xml파일을 눌러 줍시다.

그럼 다음과 같은 경고창이 하나 뜰텐데. 바로 확인 눌러줍니다.



그러면 아까 만든 맵이 이곳에 이렇게 뜰꺼애요! 아까 적은 글자 대로 뜰껍니다. 그럼 확인을 누릅시다.



그럼 우측에 다음과 같이 생성된걸 볼수있습니다.


그럼 위에 데이터를 넣기위해 간단하게 엑셀에 데이터를 적어봅시다.


첫줄은 아무상관없으니, 적기 편하게 구분을 지어주시고, 그다음부터 데이터를 적어나가면 됩니다.



자 저는 이렇게 적었어요. 정말 간단하죠?


그다음 첫열 즉 A열을 전부 드래그 한후 우측의 인덱스를 더블클릭합니다.


그러면 값들이 알아서 매핑됩니다.


이처럼 말이죠.


그럼 남은 값들도 전부 매핑 해봅시다.



자 이제 저장만 하면 됩니다.


주의할점은 엑셀로 저장하는것이 아닌 xml로 저장하는겁니다.


역시 저장할때 경고창이 뜰텐데 무시하고 저장합시다.


(나중에 수정을 하려면 엑셀파일로도 저장해두는게 좋아요, 어차피 스키마는 유지됩니다.)


그리고 저장한 파일을 열어보면

짜잔, 다음과같이 값이 알맞게 매핑되어 저장된것을 볼수있습니다.

Posted by 시리시안
2016. 2. 29. 16:11
XML만들기는 다음 포스팅을 확인해주세요


이미 만들어진 XML은 다음과 같은 코드로 불러올수있습니다.
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using UnityEngine;
using System.Collections;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Text;
using System.Collections.Generic;
/**
@date 2016/02/29
@author 조원우(jjgaa2@naver.com)
@brief App에서 관리해야하는 모든 텍스트를, 처음에 XMl파일을 읽어와 알맞은 텍스트를 반환합니다.
*/
public class TextManager : MonoBehaviour
{
 
    void Awake()
    {
        LoadingText();
    }
 
    List<LocalWord> AllText = new List<LocalWord>();    ///< 이곳에 모든 Text가 쌓입니다.
    /**
@brief 변수 AllText에 xml로 만들어진 데이터를 불러와 짚어 넣습니다.
*/
    void LoadingText()
    {
        TextAsset textAsset = (TextAsset)Resources.Load("Texts");
        XmlDocument xmldoc = new XmlDocument();
        xmldoc.LoadXml(textAsset.text);
        //xml생성
        XmlNodeList Index_Table = xmldoc.GetElementsByTagName("index");
        XmlNodeList menu_Table = xmldoc.GetElementsByTagName("menu");
        XmlNodeList kor_Table = xmldoc.GetElementsByTagName("kor");
        XmlNodeList eng_Table = xmldoc.GetElementsByTagName("eng");
        XmlNodeList chi_Table = xmldoc.GetElementsByTagName("chi");
        for (int i = 0; i < Index_Table.Count; i++)
        {
            LocalWord mWord = new LocalWord();
            mWord.Index = System.Convert.ToInt32(Index_Table[i].InnerText);
            mWord.kor = kor_Table[i].InnerText;
            mWord.eng = eng_Table[i].InnerText;
            mWord.chi = chi_Table[i].InnerText;
            AllText.Add(mWord);
        }
    }
 
    public enum Enum_Language { kor, eng, chi };
    public Enum_Language Language = Enum_Language.kor;
 
    public string GetLocalizingText(int Index)
    {
        if (AllText[Index].Index == Index)
        {
            switch (Language)
            {
                case Enum_Language.kor:
                    return AllText[Index].kor;
                case Enum_Language.eng:
                    return AllText[Index].eng;
                case Enum_Language.chi:
                    return AllText[Index].chi;
            }
        }
        for (int i = 0; i < AllText.Count; i++)
        {
            if (AllText[i].Index == Index)
            {
                switch (Language)
                {
                    case Enum_Language.kor:
                        return AllText[Index].kor;
                    case Enum_Language.eng:
                        return AllText[Index].eng;
                    case Enum_Language.chi:
                        return AllText[Index].chi;
                }
            }
        }
 
        Debug.Log("[Error] 반환된 Text가 없습니다.");
        return "[Error] 반환된 Text가 없습니다.";
    }
 
}
 
/**
@date 2016/02/29
@author 조원우(jjgaa2@naver.com)
@brief 텍스트 데이터 클래스.    
*/
public class LocalWord
{
    public int Index;
    public string kor;
    public string eng;
    public string chi;
}
 
 
cs

.



Posted by 시리시안
2016. 2. 28. 23:41



가장 먼저 상단에 

using UnityEngine.SceneManagement;

을 추가 해줍니다.



유니티는 더이상 Application.LoadLevel 을 사용하지 않습니다.


대신 밑의 코드를 참고하세요




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
 
/**
@class SceneExample.cpp
@Date 2016/02/28
@author 조원우(jjgaa2@naver.com)
@brief 씬 매니저 사용
*/
public class SceneExample: MonoBehaviour {
 
    public void NextScene()
    {
        SceneManager.LoadScene("SceneName");
    }
 
}
 
 
cs


Posted by 시리시안