midas+son의 크리에이티브(creative) 이야기

오랜만에 유니티 글이네요.


오브젝트 비교하는 구문을 예로 들자면

if (player.gameobject == other.gameobject)
{

//코드...

}

위와 같이 == 로 비교 하는게 편했고 잘 사용해 왔다.


근데 이 간편한 구문보다 약 2배 빠른 비교 방법이 있다는걸 이제 알았다.

원래는 C#의 문법인데 아래 MSDN 참조해보자.

https://msdn.microsoft.com/ko-kr/library/system.object.referenceequals(v=vs.110).aspx


//이건 C# - if(Object.ReferenceEquals(player.gameobject, other.gameobject))

//유니티에선 아래

if(System.Object.ReferenceEquals(player.gameobject, other.gameobject))

{

//코드...

}

주의 할 점은 Reference에 대한 비교이다 보니 

값이 같아도 Reference위치가 다르거나 Value Type이면 False가 떨어진다는 점이다.

null 비교에도 좋다.//System.Object.ReferenceEquals(gameobject, null)

/*

UPlayerInput::AddEngineDefinedAxisMapping은 더이상 바꿀 수 없는 단일 엔진 키맵핑 설정이다. 

캐릭터 하나나 컨트롤 값을 단일로만 사용할 경우 사용한다.

*/

//UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("NpcMoveForward", EKeys::W, 1.f));

//UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("NpcMoveForward", EKeys::S, -1.f));

//UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("NpcMoveRight", EKeys::D, 1.f));

//UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("NpcMoveRight", EKeys::A, -1.f));

//UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("NpcLookUp", EKeys::E, 1.f));

//UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("NpcLookUp", EKeys::Q, -1.f));

//UPlayerInput::AddEngineDefinedActionMapping(FInputActionKeyMapping("NpcRightMouse", EKeys::Zero));

//UPlayerInput::AddEngineDefinedActionMapping(FInputActionKeyMapping("NpcDelete", EKeys::Delete));


/*

컨트롤러에 있는 PlayerInput에 있는 키맵핑수정 가능한 설정이다.

캐릭마다 여러 컨트롤 값을 사용할 경우 유용하다.

*/

UPlayerInput* PlayerInput = GetWorld()->GetFirstPlayerController()->PlayerInput;

PlayerInput->AddAxisMapping(FInputAxisKeyMapping("NpcMoveForward", EKeys::W, 1.f));

PlayerInput->AddAxisMapping(FInputAxisKeyMapping("NpcMoveForward", EKeys::S, -1.f));

PlayerInput->AddAxisMapping(FInputAxisKeyMapping("NpcMoveRight", EKeys::D, 1.f));

PlayerInput->AddAxisMapping(FInputAxisKeyMapping("NpcMoveRight", EKeys::A, -1.f));

PlayerInput->AddAxisMapping(FInputAxisKeyMapping("NpcLookUp", EKeys::E, 1.f));

PlayerInput->AddAxisMapping(FInputAxisKeyMapping("NpcLookUp", EKeys::Q, -1.f));

PlayerInput->AddActionMapping(FInputActionKeyMapping("NpcUnpossess", EKeys::Zero));

PlayerInput->AddActionMapping(FInputActionKeyMapping("NpcDelete", EKeys::Delete));


//인풋컴포넌트에 함수 바인딩

InputComponent->BindAxis("NpcMoveForward", this, &ANpcCharacter::MoveForward);

InputComponent->BindAxis("NpcMoveRight", this, &ANpcCharacter::MoveRight);

InputComponent->BindAxis("NpcLookUp", this, &APawn::AddControllerPitchInput);

InputComponent->BindAction("NpcUnpossess", IE_Pressed, this, &ANpcCharacter::NpcUnpossess);

InputComponent->BindAction("NpcDelete", IE_Pressed, this, &ANpcCharacter::NpcDelete);

프로젝트 설정에서 하나하나 지정하는 것 말고 

C++에서 처리 하는 방식을 찾아 정리하였다.


키맵핑을 삭제 하는 방법은 다음 글로 포스팅 하겠다.

http://midason.tistory.com/420

GetWorld()->GetFirstPlayerController()->Possess(this); //현재 pawn으로 빙의. this는 pawn을 상속받은 클래스

Possess는 소유하다, 지니다는 뜻으로 Controller를 지니게되는 Pawn을 정해준다.

APawn*을 인자로 받는다.(APawn을 상속받은 하위 클래스 포함)

인자로 들어온 pawn으로 Controller와 카메라 시점을 이동할 수 있다.


이것에 대해 아래와 같은 연관되게 되는 함수가 있다.

//현재 Pawn에 대해

//SetupPlayerInputComponent(GetWorld()->GetFirstPlayerController()->InputComponent); //키맵핑 하는 함수

//Possess()함수를 실행하면서 SetupPlayerInputComponent 함수도 같이 실행됨. 그래서 따로 함수 호출을 안해도 된다.


//과거 Pawn에 대해

//GetWorld()->GetFirstPlayerController()->UnPossess();

//이전의 pawn에 있던 Controller가  nullptr이 된다.

위의 함수들은 Possess할 때 자동으로 불리우며

과거와의 연을 끊고 새로운 연을 잇는다고 생각하면 편하다.


정리

Possess()함수를 호출하면 

이전에 Controller가 빙의해있던 pawn은 UnPossess()가 실행 되면서 Controller가 nullptr이 된다.

현재 이동할 pawn이 Controller를 가지게 되고

자동으로 SetupPlayerInputComponent(UInputComponent*)함수를 호출한다.


SetupPlayerInputComponent()함수에서 키맵핑 하는 법은 다음 글에 이어서 하겠다.

어느 액터(그외 하위 클래스)가 가지고 있는 Component를

검색하기 위해 아래와 같은 코드를 많이 사용한다.

UMyComponent* MyComp = MyActor->FindComponentByClass<UMyComponent>();

하지만 당연히 될 줄 알았던게 안됐을 때의 통수란...많은 시간 낭비를 하게 만든다.(하루를 날렸다.)


다른 컴포넌트에서 Owner가 되는 액터의 내부 컴포넌트를 찾기 위해 사용했었는데

설마 여기서 nullptr이 나올 줄은 몰랐다.


FindComponentByClass에 대해서 찾아보니 설명에 떡하니 이렇게 나와있었다.

Searches components array and returns first encountered component of the specified class.

first encountered...처음 발견된 것만...가져온다...

그래서 상속을 계속 받다보니 할아버지, 증조 할아버지격 부모 클래스에서 

통일한 Component의 이름을 가진게 있었고

그 컴포넌트에는 비어있었기에 문제가 생겼었던 것이다.


이 문제를 해결하기 위해 find보다는 특정 변수에 값을 담아

Get함수로 가져오게 하였다.


엔진에서 제공해주는 함수라도 다시 알아보고 사용하자.

확실히 어떤 기능인지 알아보지 않고 사용하면 

실수하는 건 자신이라는 걸 생각하자.



packtpub 이라고 IT관련 외국 서적, 강의 판매 사이트가 있다.

구매하면 IT 서적 판매로 ebook이나, pdf로 다운 받을 수 있고

여러분야의 강좌들도 판매한다.(달러$ 결제)


이 사이트에서

4월 11일 부터 4월 30일 까지 하루에 한권씩 책을 무료 나눔한다.

https://www.packtpub.com/packt/offers/free-learning

가입은 이메일로 간편하게 할 수 있다.


오늘까지 3가지 책을 받아보니 

연차는 좀 있는 책들 위주인 것 같다.


원하는 언어나 프로그램에 대한 책이 나올 때가지 기다려보는 것도 괜찮고,

지금은 필요없더라도 하루에 하나씩 받아 가는 것도 나쁘지 않다고 생각한다.


이 사이트에서는 이번달 뿐만이 아니라 이런 이벤트를 종종한다는 것 같다.

파이썬 입문

공부/Python2017. 4. 11. 11:28

코다카데미 사이트(Pro는 유료지만 기본은 무료)에서 파이썬이 있어서 입문해 보았다.(이틀 전부터...)

2년 전에 cocos2D 처음 설치해볼 때 python이 필요해서

그 때 처음 존재를 알았고 관심이 있었지만 이제서야 입문한다.


이틀동안 잠자기 전에 조금씩 다루면서

다르다고 느낀 점은

자료형 지정이 없다,

;(세미콜론)사용안해도 된다,

whitespace에 민감하다,

지수 연산은 ^이 아니라 **이다.

정도? 

개인적으론 var나 auto 자료형도 좋아하지 않는데 

자료형 자체가 없다니 참 재미진 언어다.


회사에 찌들고 

개인 프로젝트 하느라 시간이 없어도

꾸준하게 잠자기 전에 조금씩 해볼 생각이다.

http://blog.naver.com/moeblog/220976604276

참고 사이트 : 대한민국 교육부 공식 블로그


위 url을 통해서 직접 블로그 기자단의 글을 보시기 바랍니다.

글 마지막 부분의 무료 소프트웨어교육 사이트 소개 되었습니다.

하지만 블로그 글에 걸려 있는 링크들이 주소가 잘못되어져 있으므로

아래에 정상 링크로 나열하겠습니다.


∎ 칸아카데미 (https://ko.khanacademy.org/)


∎ 구름EDU (http://edu.goorm.io/)


∎ Swift Playground (ios 애플리케이션 http://www.apple.com/swift/playgrounds/)


∎ MakeCode (https://makecode.com/)


∎ Codecademy (https://www.codecademy.com/)


'공부 > 기타' 카테고리의 다른 글

캐릭터 제작론  (0) 2017.04.24
IT관련 무료 책 받기 - packtpub  (0) 2017.04.13
assimp 라이브러리 만드는 방법  (0) 2017.03.14
소스 정적분석툴 비교 참고사이트  (0) 2017.02.12
한글 유니코드에 대해  (0) 2017.01.11

https://wiki.unrealengine.com/Iterators:_Object_%26_Actor_Iterators,_Optional_Class_Scope_For_Faster_Search

참고 사이트


UWorld* myWorld = nullptr;

UDataSingleton* dataSingleton = Cast<UDataSingleton>(GEngine->GameSingleton);

if (dataSingleton)

{

AGameMode* gameMode = dataSingleton->gameMode;

if (gameMode)

{

myWorld = gameMode->GetWorld();

}

}


if (myWorld == nullptr) return;


for (TActorIterator<AItemActor> ActorItr(myWorld); ActorItr; ++ActorItr)

{

AItemActor *Mesh = *ActorItr;

if (Mesh && Mesh->inventoryIndex != -1)

{

this->ApplyItemInInventory(Mesh, Mesh->inventoryIndex);

}

}

UWorld를 받아와서 TActorIterator<액터클래스명>을 받아와 반복문을 돌리는 형태이다.

현재 레벨의 World에서 Spwan된 모든 Actor를 검사하여 <AItemActor>로 캐스팅 되는 것을 찾아

이터레이터 형식으로 변환된다고 생각된다.(내부 코드를 보지 않아 정확하진 않다.)

//4.12.5에서 사용한 코드

//FString path;//인자값

//std::string filename(TCHAR_TO_UTF8(*path));

//인코딩 문제 발생 : https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/StringHandling/CharacterEncoding/


const wchar_t* ptr = *path;

int csize = 1024; //글자 바이트 제한

char* tempFileName = new char[csize];

char def = '?';


//함수 참고 Url : https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130(v=vs.85).aspx

WideCharToMultiByte(CP_ACP, 0, ptr, -1, tempFileName, csize, &def, NULL);


std::string fileName(tempFileName);

delete[] tempFileName;

4.12.5 버전에서는 #include <Windows.h>를 하여 

WideCharToMultiByte를 사용하였었다.

하지만 4.15.1로 오면서 #include <Windows.h> 를 사용하면

Winnt.h 에서 TEXT 매크로 재정의 Warning이 발생하는 등

여러 문제가 발생하여 #include <Windows.h>를 사용하지 않게 바꾸기로 했다.


wchar_t를 char*나 string으로 바꾸는 방법을 구글링으로 열심히 찾았으나

다 의미없는 소스와 블로그 글들 뿐이었다.

한글에 대한 처리가 고려되지 않는 글들도 많았다.

공식 MSDN이나 언리얼에서도 명확한 해결법을 주지 않았다.


UTF-16과 UTF-8에 대한 컨버팅 구조는 찾았으나

CP949로 가는 구조는 못찾았다.


2일째 고민하던 중 찾은 방법은 codecvt을 사용한 방법이었다.

저 헤더는 처음 봤다.(자세한 설명은 맨 위의 참고사이트 링크에 들어가보자.)

컨버트용 헤더로 생각된다.


//include해야 하는 헤더들

#include <string> 

#include <vector> 

#include <codecvt> 

#include <locale>

//4.15.1에서 새로 작성한 코드

std::wstring str = *FilePath;

typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_t;

//std::locale loc = std::locale("ko_KR.UTF-8"); // windows 에서는 사용이 안됨

std::locale loc = std::locale("Korean"); // windows 용

codecvt_t const& codecvt = std::use_facet<codecvt_t>(loc);

std::mbstate_t state = std::mbstate_t();

std::vector<char> buf((str.size() + 1) * codecvt.max_length());

wchar_t const* in_next = str.c_str();

char* out_next = &buf[0];

std::codecvt_base::result r = codecvt.out(state,

str.c_str(), str.c_str() + str.size(), in_next,

&buf[0], &buf[0] + buf.size(), out_next);

if (r == std::codecvt_base::error)

throw std::runtime_error("can't convert wstring to string");    //실제 에러가 난다. 언리얼 로그로 바꾸어도 된다.

std::string fileName(&buf[0]);

위와 같이 바꾸니 Warning없이 정상적으로 동작한다.

복잡해보이니 아래와 같이 함수로 바꾸어 사용했다.(참고사이트에 있는 것 복붙 + 약간 수정)

std::string CommonFunc::WCStoMBCS(std::wstring const& str, std::locale const& loc /*= std::locale("")*/)

{

//loc에 std::locale("")로 들어오면 자동으로 OS의 locale을 찾는것 같다.(확인 필요), std::locale()로 하면 에러 난다.

typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_t;

codecvt_t const& codecvt = std::use_facet<codecvt_t>(loc);

std::mbstate_t state = std::mbstate_t();

std::vector<char> buf((str.size() + 1) * codecvt.max_length());

wchar_t const* in_next = str.c_str();

char* out_next = &buf[0];

std::codecvt_base::result r = codecvt.out(state,

str.c_str(), str.c_str() + str.size(), in_next,

&buf[0], &buf[0] + buf.size(), out_next);

if (r == std::codecvt_base::error)

throw std::runtime_error("can't convert wstring to string");    //실제 에러가 난다. UELOG로 바꾸어도 된다.

return std::string(&buf[0]);

}

마이그레이션 하던 것 중 제일 골치 아팠던 게 해결 되었다.

굿굿!!

cpp클래스는 마이그레이션과 리팩토링이 완료되어 
BP에서만 건드리면 될 줄 알았는데
싱글톤 클래스가 BP에서 불러올때 nullptr로 받아오는 문제가 발생했다. 

무엇이 문제인가 봤더니 
프로젝트 설정에 빠진 부분이 있었다.


일반 설정에서 기본 클래스에 싱글톤 클래스를 잡는 부분이 있다.

그래야지 cpp에서 GEngine->GameSingleton으로 받아와 캐스팅 할 수 있다.


VS에서 바로 수정하려면 Config 디렉터리에 DefaultEngine.ini 파일을 열어서 아래와 같이 하면 된다.

[/Script/Engine.Engine]

GameSingletonClassName=/Script/프로젝트이름(or상위티렉터리이름).싱글톤클래스파일이름

이름쓰다가 실수할 수도 있고 잘 모를 수도 있으니

실수 방지를 위해서 UE 에디터 열어 프로젝트 설정에서 바꾸자.

자세한건 참고 사이트를 확인하자.