Project에 저장된 Json 스크립트 읽기

Unity에서 Project에 포함된 Json 스크립트를 읽어들이는 방법입니다.

첫번째는 C#에서 기본적으로 지원해주지 않는 Json 파서를 구해야 합니다.

Json 파서는 여러가지가 있으나 C#에서 편리하게 사용할 수 있는 파서일 수록 iOS에서 문제가 발생하기 때문에 사용하기가 어렵습니다. 그 이유는 C#의 Reflection 기능에 의한 것이라고 하는데 자세한 설명은 다음의 링크를 참고하면됩니다.

http://www.unitystudy.net/bbs/board.php?bo_table=dustin&wr_id=365&sca=&sfl=wr_subject&stx=ios&sop=and

그래서 저는 SimpleJSON을 사용하기로 결정하였습니다. SimpleJSON 관련 링크는 아래와 같습니다.

http://wiki.unity3d.com/index.php/SimpleJSON#Download

 

이제 Project에 Json 파일을 추가하고 읽어서 사용하는 방법입니다.

게임에서 외부 파일을 가져다 사용하기 위해서는 Project에 Resources 라는 폴더를 생성해야 합니다. 이 폴더는 Asset 폴더 아무곳에나 생성해도 된다고 합니다. 그에 관련한 내용은 다음의 링크를 참고하면 됩니다.

http://docs.unity3d.com/ScriptReference/Resources.html

Resources 폴더를 추가한 후 내부에 폴더를 서 생성하거나 직접 파일을 추가하면 됩니다. 사용 시 Resources 폴더를 기준으로 Path가 시작되며 파일의 확장자는 생략해야 합니다.

즉 Resources/Data/Level.txt 라는 파일이 존재한다면

Resources.Load("Data/Level") as TextAsset

이런 형태로 사용할 수 있습니다.

멀쩡한 std::string에서 std::length_error 예외가 발생하면?

오늘 멀쩡하게 돌아가던 코드에서 std::length_error 예외가 발생해서 원인을 알아보았습니다.

std::length_error는 vector, string에서 발생하는 예외이고 string의 경우 std::string::max_size() 보다 큰 문자열을 할당하려고 했을 때 발생한다고 합니다.

디버그를 해보니 멀쩡한 string객체를 string::operator = 에 넘기는데 파라메터로 넘기기 전의 string객체를 보면 정상이고 파라메터로 넘어온 string 객체는 쓰레기 값으로 채워져 있었습니다.

해결방법은 프로젝트를 Cleanup 하고 다시 빌드하면 됩니다.

string 이 포함된 obj가 어떠한 이유로 빌드가 제대로 되지 않을 때 발생하는 문제였습니다. 일부 obj는 최신이고 일부 obj는 예전 버전으로 빌드된 상태에서 link가 이루어지고 실행이 되면 이런 이상한 상태가 되어 버립니다. 이런 문제로 시간을 버리다니... ㅠㅠ

type_index 예제

std::type_index를 사용하면 타입을 id로 사용한 container를 사용할 수 있습니다.

#include <iostream>
#include <unordered_map>
#include <type_traits>
#include <typeindex>
#include <functional>

using namespace std;

unordered_map<type_index, function<void()>> mapType;

template<typename T>
void WhatIsThis(T) {
	mapType[typeid(T)]();
}
int main() {
	mapType.emplace(typeid(int), []{cout << "this is int" << endl;});
	mapType.emplace(typeid(float), []{cout << "this is float" << endl;});
	mapType.emplace(typeid(double), []{cout << "this is double" << endl;});
	mapType.emplace(typeid(const char*), []{cout << "this is const char*" << endl;});
	
	WhatIsThis(1);
	WhatIsThis(0.5f);
	WhatIsThis(0.5);
	WhatIsThis("Hello world");
	return 0;
}

 

is_function 에서 함수를 구분하기

C++에서 std::is_function 함수를 다음과 같이 사용해 보면 예상된 결과를 반환해 주지 않습니다.

#include <iostream>
#include <type_traits>

using namespace std;

class A {
	public:
	static void static_member_function() {
		cout << "hello world!!" << endl;
	}
};

int main() {
	cout << (is_function<decltype(&A::static_member_function)>::value ? "true" : "false") << endl;
	return 0;
}

위 코드의 결과는 "false" 입니다. 함수와 함수 포인터의 차이로 인해서 생기는 이슈 입니다.

is_pointer는 true를 반환하지만 is_function은 false를 반환합니다. 따라서 필요하다면 is_function_pointer 같은 템플릿 함수를 만들어 줄 필요가 있습니다. 물론 예제코드에서 &A::static_member_function 에서 &를 뺀 A::static_member_function을 넘길 경우에는 is_function이 true를 반환합니다. 문제는 함수 포인터를 넘기는 많은 경우 함수 포인터를 받아서 다른 위치에서 함수 포인터를 이용한 호출을 하기 위함입니다.

제가 만난 케이스는 Lua에 값을 바인딩 할 때 함수일 경우와 값일 경우를 구분하기 위해서 사용하는 과정에서 만난 이슈입니다.

template<typename T>
void SetGlobal(const char* name, T arg) {
    std::_If<std::is_function<T>::value,
        FunctionBinder<T>,  // lua에 함수를 바인딩 하는 functor
        ValueBinder<T>      // lua에 변수를 바인딩 하는 functor
    >::type() (L, name, arg);
}

위의 경우 T로 함수 포인터가 넘어오게 되는데 만들고 보니 is_function에서 false가 넘어오길래 다음과 같이 수정하여 해결하였습니다.

template<typename T>
void SetGlobal(const char* name, T arg) {
    std::_If<std::is_pinter<T>::value&&std::is_function<std::remove_pointer<T>::type>::value,
        FunctionBinder<T>,  // lua에 함수를 바인딩 하는 functor
        ValueBinder<T>      // lua에 변수를 바인딩 하는 functor
    >::type() (L, name, arg);
}

 

2D에서 Raycast를 통한 오브젝트 선택

Unity3D에서 2D 환경에서의 Object 선택을 위한 방법을 소개합니다.

    void Update() {
        if (Input.GetMouseButtonDown(0))
        {
            Vector2 wp = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            Ray2D ray = new Ray2D(wp, Vector2.zero);
            RaycastHit2D[] hits = Physics2D.RaycastAll(ray.origin, ray.direction);

            foreach (var hit in hits)
            {
                if (!hit.collider.gameObject.CompareTag("Coin"))
                    continue;

                GameObject can = hit.collider.gameObject;

                can.GetComponent<Animator>().SetTrigger("Disapear");
            }
        }
    }

 

WordPress를 설치

네이버 블로그에서 WordPress로 갈아타기로 했습니다.

이유는 Code syntax highlighting 등 개발자용 블로깅이 힘들었기 때문입니다.

WordPress, T-Story 등 자유도가 다소 높은 블로그 시스템들을 보고 개발자가 사용하기 편하고 확장성이나 유지보수 하기가 그나마 편리한 시스템을 찾다보니 이걸로 오네요.

개인적으로 사용하던 유료 Linux 웹서버가 있어서 거기에 설치했습니다.