Wednesday, December 12, 2012
언리얼 게임 엔진 UDK 3 출간 예정
드디어 출간 예정입니다. 레벨 디자이너, 게임 기획자들이 보기에 적당한 책이라고 봅니다. 프로그래머들에게는 UDK의 기능을 전체적으로 살펴보는데 한번쯤 볼만한 책이라고 봅니다.
http://www.acornpub.co.kr/book/udk3
Thursday, December 6, 2012
XCode에서 빌드 번호 자동으로 증가시키게 하기
프로그램을 개발하다 보면 버그를 발견하게 마련이다. 이때 발견한 버그가 현재 프로그래머가 작업하고 있는 버전에서 이미 고쳐져 있는 상태인지 아닌지 구분을 한다거나 버그가 나타난 빌드가 언제부터 생겨났었는지를 트래킹 하는데도 이 빌드 번호가 자주 사용된다.
이 글에서는 xcode에서 빌드 번호를 자동으로 증가시키는 방법에 대해 설명한다. (웹에 이미 내가 했던 방식과 똑같은 방식으로 글이 올라와 있는게 있다.) iOS프로그램은 plist를 이용해서 프로젝트에 관련된 정보를 저장하고 있는데 여기에 빌드 번호가 있다. CFBuildVersion이 바로 그것인데 나는 그것을 사용하지 않고 따로 변수를 하나 더 생성했다.
이 KBuildNumber를 화면에 표시만 해주면 실제로 누군가가 버그를 발견했을 때 빌드 번호를 체크함으로써 해결된 버그인지 아닌지 알 수 있다.
우리가 여기서 해결해야할 문제는 이 값이 plist안에 있고 이것을 자동으로 증가시키고 싶은 것이다. 이것은 bash를 이용해서 해결 가능하다.
프로젝트 속성에 들어가서 Build Phases에 들어간다. 그리고 새로운 Add Build Phase를 한 후 이름은 AutoBuildNumber로 한다. (뭐가 되던 상관은 없다)
그리고 그림과 같이 코드를 작성한다. 귀찮은 사람들을 위해서 코드를 적어 보면
빌드의 순서는 위에서 아래로 되는데 그렇기 때문에 실제 소스 파일들을 컴파일 하기 이전에 AutoBuildNumber를 실행해서 빌드 번호를 증가 시킨다. 실제로 이 값을 코드에서 사용하기 위해서는 다음과 같다.
이로써 컴파일을 할 때 마다 빌드 번호를 자동으로 증가 시킬 수 있게 되었다.
끝
이 글에서는 xcode에서 빌드 번호를 자동으로 증가시키는 방법에 대해 설명한다. (웹에 이미 내가 했던 방식과 똑같은 방식으로 글이 올라와 있는게 있다.) iOS프로그램은 plist를 이용해서 프로젝트에 관련된 정보를 저장하고 있는데 여기에 빌드 번호가 있다. CFBuildVersion이 바로 그것인데 나는 그것을 사용하지 않고 따로 변수를 하나 더 생성했다.
우리가 여기서 해결해야할 문제는 이 값이 plist안에 있고 이것을 자동으로 증가시키고 싶은 것이다. 이것은 bash를 이용해서 해결 가능하다.
프로젝트 속성에 들어가서 Build Phases에 들어간다. 그리고 새로운 Add Build Phase를 한 후 이름은 AutoBuildNumber로 한다. (뭐가 되던 상관은 없다)
그리고 그림과 같이 코드를 작성한다. 귀찮은 사람들을 위해서 코드를 적어 보면
#!/bin/bash
buildPlist=${INFOPLIST_FILE}
buildNumber=$(/usr/libexec/PlistBuddy -c "Print KBuildNumber" $buildPlist)
buildNumber=$(($buildNumber+1))
/usr/libexec/PlistBuddy -c "Set :KBuildNumber $buildNumber" $buildPlist
빌드의 순서는 위에서 아래로 되는데 그렇기 때문에 실제 소스 파일들을 컴파일 하기 이전에 AutoBuildNumber를 실행해서 빌드 번호를 증가 시킨다. 실제로 이 값을 코드에서 사용하기 위해서는 다음과 같다.
NSString* buildNumber = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"KBuildNumber"];
이로써 컴파일을 할 때 마다 빌드 번호를 자동으로 증가 시킬 수 있게 되었다.
끝
Tuesday, December 4, 2012
Thursday, November 22, 2012
코드 분석 : Mainloop를 찾는다.
어떠한 프로그램의 소스를 분석할 때 제일 처음으로 할 것은 바로 메인루프(Mainloop)을 찾는 것 입니다. 메인 루프의 구성법은 만들어낼 프로그램이 무엇인가에 따라 많이 다릅니다. 크게 나누어 보면 이벤트(혹은 메세지) 드리븐 방식과 폴링 방식이 있습니다.
제가 모든 소스를 곁들어 가면서 설명하기에는 시간이 많지 않기 때문에 살펴보면 좋은 소스들의 리스트를 나열하고 몇 가지는 제가 인용해서 설명하겠습니다. 이 작업을 할 때 잃어버리지 않아야 할 것은 절대로 다른 소스까지 읽어가면서 다 분석하려고 하지 말고 메인 루프의 구성이 어떻게 되어 있나만 살펴 보는 것입니다. 물론 시간이 많아서 모든 소스를 다 분석하면 좋겠지만요 :)
1. Win32 Application의 메인 루프 구성
2. GLUT의 메인 루프 구성
3. SDL의 메인 루프 구성
4. Quake3의 메인 루프 구성
5. GameEngine Architecture(책)의 메인 루프 부분 챕터
우선 3번 SDL의 메인 루프 구성을 살펴 보도록 하죠.
참고 링크
http://sourcecodebrowser.com/a7xpg/0.11.dfsg1/classabagames_1_1util_1_1sdl_1_1_main_loop_1_1_main_loop.html
Quake3의 메인 루프 부분
참고링크
http://fabiensanglard.net/quake3/index.php
마지막으로 GLUT의 메인 루프 구성
참고링크
http://graphics.stanford.edu/courses/cs248-01/OpenGLHelpSession/code_example.html
와 같습니다.리스트 5번에 말씀드린 책을 참고하시면 Uncharted의 경우도 비슷한 메인 루프를 구성하고 있습니다. 참고로 피파도 비슷합니다만 더 발전된 형태로 되어 있습니다. :)
여러 프로젝트의 메인 루프 구성을 살펴 보는것은 대단히 중요한데 그 이유는 이 메인 루프가 어떻게 구성되어 있는지 모르면 프로젝트의 전체를 볼 수 없기 때문입니다. 모든 프로젝트를 분석하기 이전에는 반드시 메인 루프 구성을 먼저 살펴 보는것이 분석을 순조롭게 하기 위해서 좋습니다.
제가 모든 소스를 곁들어 가면서 설명하기에는 시간이 많지 않기 때문에 살펴보면 좋은 소스들의 리스트를 나열하고 몇 가지는 제가 인용해서 설명하겠습니다. 이 작업을 할 때 잃어버리지 않아야 할 것은 절대로 다른 소스까지 읽어가면서 다 분석하려고 하지 말고 메인 루프의 구성이 어떻게 되어 있나만 살펴 보는 것입니다. 물론 시간이 많아서 모든 소스를 다 분석하면 좋겠지만요 :)
1. Win32 Application의 메인 루프 구성
2. GLUT의 메인 루프 구성
3. SDL의 메인 루프 구성
4. Quake3의 메인 루프 구성
5. GameEngine Architecture(책)의 메인 루프 부분 챕터
우선 3번 SDL의 메인 루프 구성을 살펴 보도록 하죠.
참고 링크
http://sourcecodebrowser.com/a7xpg/0.11.dfsg1/classabagames_1_1util_1_1sdl_1_1_main_loop_1_1_main_loop.html
while (!done) { SDL_PollEvent(&event); input.handleEvent(&event); if (input.keys[SDLK_ESCAPE] == SDL_PRESSED || event.type == SDL_QUIT) done = 1; nowTick = SDL_GetTicks(); frame = (int) (nowTick-prvTickCount) / interval; if (frame <= 0) { frame = 1; SDL_Delay(prvTickCount+interval-nowTick); if (accframe) { prvTickCount = SDL_GetTicks(); } else { prvTickCount += interval; } } else if (frame > maxSkipFrame) { frame = maxSkipFrame; prvTickCount = nowTick; } else { prvTickCount += frame * interval; } for (i = 0; i < frame; i++) { gameManager.move(); } screen.clear(); gameManager.draw(); screen.flip(); }
Quake3의 메인 루프 부분
참고링크
http://fabiensanglard.net/quake3/index.php
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { Com_Init NET_Init while( 1 ) { // Common code IN_Frame() // Add Win32 joystick and mouse inputs as event_t to unified event queue. { IN_JoyMove IN_ActivateMouse IN_MouseMove } Com_Frame { // Common code Com_EventLoop // Pump win32 message, UDP socket and console commands to the queue (sysEvent_t eventQue[256]) Cbuf_Execute // Server code SV_Frame { SV_BotFrame // Jump in bot.lib VM_Call( gvm, GAME_RUN_FRAME, svs.time ) // Jump in Game Virtual Machine where game logic is performed SV_CheckTimeouts SV_SendClientMessages // Send snapshot or delta snapshot to connected clients } // Common code Com_EventLoop Cbuf_Execute // Client code CL_Frame { CL_SendCmd // Pump the event queue and send commands to server. SCR_UpdateScreen VM_Call( cgvm, CG_DRAW_ACTIVE_FRAME); // Send message to the Client Virtual Machine (do Predictions). or VM_Call( uivm, UI_DRAW_CONNECT_SCREEN); // If a menu is visible a message is sent to the UI Virtual Machine. S_Update // Update sound buffers } } } }
마지막으로 GLUT의 메인 루프 구성
참고링크
http://graphics.stanford.edu/courses/cs248-01/OpenGLHelpSession/code_example.html
int main(int argc, char** argv) { // GLUT Window Initialization: glutInit (&argc, argv); glutInitWindowSize (g_Width, g_Height); glutInitDisplayMode ( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); glutCreateWindow ("CS248 GLUT example");
// Initialize OpenGL graphics state InitGraphics();
// Register callbacks: glutDisplayFunc (display); glutReshapeFunc (reshape); glutKeyboardFunc (Keyboard); glutMouseFunc (MouseButton); glutMotionFunc (MouseMotion); glutIdleFunc (AnimateScene);
// Create our popup menu BuildPopupMenu (); glutAttachMenu (GLUT_RIGHT_BUTTON);
// Get the initial time, for use by animation #ifdef _WIN32 last_idle_time = GetTickCount(); #else gettimeofday (&last_idle_time, NULL); #endif
// Turn the flow of control over to GLUT glutMainLoop (); return 0; }
그리고 렌더링, 키보드와 같은 것들은 다른 콜백 함수로 연결되어 있습니다.
가령 키보드를 처리하는 콜백 함수는
void Keyboard(unsigned char key, int x, int y) { switch (key) { case 27: // ESCAPE key exit (0); break;
case 'l': SelectFromMenu(MENU_LIGHTING); break;
case 'p': SelectFromMenu(MENU_POLYMODE); break;
case 't': SelectFromMenu(MENU_TEXTURING); break; } }
와 같습니다.리스트 5번에 말씀드린 책을 참고하시면 Uncharted의 경우도 비슷한 메인 루프를 구성하고 있습니다. 참고로 피파도 비슷합니다만 더 발전된 형태로 되어 있습니다. :)
여러 프로젝트의 메인 루프 구성을 살펴 보는것은 대단히 중요한데 그 이유는 이 메인 루프가 어떻게 구성되어 있는지 모르면 프로젝트의 전체를 볼 수 없기 때문입니다. 모든 프로젝트를 분석하기 이전에는 반드시 메인 루프 구성을 먼저 살펴 보는것이 분석을 순조롭게 하기 위해서 좋습니다.
생각해 볼 점.
1. SDL과 GLUT의 입력 처리를 하는 방식에 있어서 어떤 차이점이 존재하는가?
2. Win32 Application을 작성할 때 입력 처리를 하는 방식과 Quake3는 어떻게 다른가?
Wednesday, November 21, 2012
코드 분석 : 데이터의 표현법(자료구조), 알고리즘
코드 분석의 첫 번째 이야기를 해보려고 합니다.
우선 가장 기본은 자신이 생각하고 있는 것을 사용하는 프로그래밍 언어로 어떻게 데이터로 표현하고 그 데이터를 가공하기 위해 로직을 어떻게 작성해야 하는지만 알면 기본은 갖추어 졌다고 봅니다.
기본을 갖추고 나서 필요한 것은 지금까지 많은 선배 프로그래머들이 만들어 놓았던 자료구조, 알고리즘을 공부하는 것입니다. 결국 컴퓨터가 하는 것은 주어진 데이터를 조작하고 로직에 의해 변형하고 그 결과를 어떠한 형태로든 우리가 얻는 것입니다. 이때 데이터를 어떻게 표현하느냐, 알고리즘을 어떠한 것을 사용했느냐에 따라서 프로그램의 성능에 큰 차이를 만들게 됩니다.
데이터를 표현하는 방법 그리고 그 데이터를 효과적으로 사용하는 방법이 굉장히 많은데 이러한 방법들을 두루두루 알고 있을 때 다른 사람이 작성한 코드를 분석한다거나 큰 프로젝트에 임했을 때 많은 도움이 됩니다.
자료구조에서 특히 많이 사용되는 것은 배열, 리스트, 해쉬테이블, 스택입니다. 그 외에도 많은 것들이 있지만 4가지는 기본중의 기본입니다. 이러한 기본을 공부할 때 좋은 방법은 이러한 자료구조를 이용해서 실제 응용 프로그램에 적용하는 것입니다.
예를 들어 스택은 그림판의 Undo기능에 사용될 수 있습니다. (이 부분에 대한 자세한 내용은 제가 작성한 워드 문서가 따로 있습니다.) 가령 그림판에 A, B, C순으로 어떠한 도형을 그리고 Undo를 했을 때 최종적으로 그렸던 C는 사라지고 A, B만 화면에 나타나야 합니다. 그리고 이후 D, E를 그리고 다시 Undo를 하면 A, B, D만 화면에 나오게 됩니다. 이러한 것을 구현할 때 스택을 이용하면 됩니다.
그리는 동작(보통 command, action이라고 합니다.)을 스택에 넣어주고 Undo를 했을 때 해당 동작을 빼주기만 하면 됩니다. 중요한 것은 스택의 이러한 특성입니다. 스택의 구현법은 다양한데 그 특성은 변하지 않습니다. 그것만 기억한다면 다른 사람의 코드를 분석할 때 많은 도움이 됩니다. 가령 스택 자료구조를 사용한다면 해당 자료구조를 사용하는 로직들을 살펴 볼 때 많은 도움이 됩니다. 왜 배열, 리스트를 사용하지 않고 스택을 사용했는가? 라는 질문을 스스로 하면서 코드를 읽으면 더 이해가 쉽기 때문이죠.
나머지 리스트, 해쉬테이블, 배열 역시 마찬가지입니다. 각각의 자료구조 마다 특성이 있고 그것을 사용하는 로직을 분석할 때 그 특성을 인지하고 읽어 나가면 로직을 이해하기가 더 쉽습니다.
코드 분석이라 함은 로직의 이해입니다. 다른 사람이 어떠한 의도로 로직을 작성했는지 그리고 의도대로 돌아가는지는 증명하고 이해하는것이 코드 분석입니다.
그리고 이것을 잘하기 위해서는 기본적인 컴퓨터 자료구조, 알고리즘의 이해가 필요합니다.
우선 가장 기본은 자신이 생각하고 있는 것을 사용하는 프로그래밍 언어로 어떻게 데이터로 표현하고 그 데이터를 가공하기 위해 로직을 어떻게 작성해야 하는지만 알면 기본은 갖추어 졌다고 봅니다.
기본을 갖추고 나서 필요한 것은 지금까지 많은 선배 프로그래머들이 만들어 놓았던 자료구조, 알고리즘을 공부하는 것입니다. 결국 컴퓨터가 하는 것은 주어진 데이터를 조작하고 로직에 의해 변형하고 그 결과를 어떠한 형태로든 우리가 얻는 것입니다. 이때 데이터를 어떻게 표현하느냐, 알고리즘을 어떠한 것을 사용했느냐에 따라서 프로그램의 성능에 큰 차이를 만들게 됩니다.
데이터를 표현하는 방법 그리고 그 데이터를 효과적으로 사용하는 방법이 굉장히 많은데 이러한 방법들을 두루두루 알고 있을 때 다른 사람이 작성한 코드를 분석한다거나 큰 프로젝트에 임했을 때 많은 도움이 됩니다.
자료구조에서 특히 많이 사용되는 것은 배열, 리스트, 해쉬테이블, 스택입니다. 그 외에도 많은 것들이 있지만 4가지는 기본중의 기본입니다. 이러한 기본을 공부할 때 좋은 방법은 이러한 자료구조를 이용해서 실제 응용 프로그램에 적용하는 것입니다.
예를 들어 스택은 그림판의 Undo기능에 사용될 수 있습니다. (이 부분에 대한 자세한 내용은 제가 작성한 워드 문서가 따로 있습니다.) 가령 그림판에 A, B, C순으로 어떠한 도형을 그리고 Undo를 했을 때 최종적으로 그렸던 C는 사라지고 A, B만 화면에 나타나야 합니다. 그리고 이후 D, E를 그리고 다시 Undo를 하면 A, B, D만 화면에 나오게 됩니다. 이러한 것을 구현할 때 스택을 이용하면 됩니다.
그리는 동작(보통 command, action이라고 합니다.)을 스택에 넣어주고 Undo를 했을 때 해당 동작을 빼주기만 하면 됩니다. 중요한 것은 스택의 이러한 특성입니다. 스택의 구현법은 다양한데 그 특성은 변하지 않습니다. 그것만 기억한다면 다른 사람의 코드를 분석할 때 많은 도움이 됩니다. 가령 스택 자료구조를 사용한다면 해당 자료구조를 사용하는 로직들을 살펴 볼 때 많은 도움이 됩니다. 왜 배열, 리스트를 사용하지 않고 스택을 사용했는가? 라는 질문을 스스로 하면서 코드를 읽으면 더 이해가 쉽기 때문이죠.
나머지 리스트, 해쉬테이블, 배열 역시 마찬가지입니다. 각각의 자료구조 마다 특성이 있고 그것을 사용하는 로직을 분석할 때 그 특성을 인지하고 읽어 나가면 로직을 이해하기가 더 쉽습니다.
코드 분석이라 함은 로직의 이해입니다. 다른 사람이 어떠한 의도로 로직을 작성했는지 그리고 의도대로 돌아가는지는 증명하고 이해하는것이 코드 분석입니다.
그리고 이것을 잘하기 위해서는 기본적인 컴퓨터 자료구조, 알고리즘의 이해가 필요합니다.
코드 분석에 관한 글을 조금씩 써보려고 합니다.
앞으로 시간 날 때 마다 코드 분석이라는 주제로 글을 좀 써보려고 합니다.
본인이 직접 코드를 작성하는 것은 프로그래머의 기본이지만 남의 코드를 읽고
수정하고 발전 시키는것도 대단히 중요합니다. 그러한 능력을 배양하는데 있어
필요한 각종 팁이나 제가 자주 사용하는 방법들에 대해서 이야기 해보려고 합니다.
본인이 직접 코드를 작성하는 것은 프로그래머의 기본이지만 남의 코드를 읽고
수정하고 발전 시키는것도 대단히 중요합니다. 그러한 능력을 배양하는데 있어
필요한 각종 팁이나 제가 자주 사용하는 방법들에 대해서 이야기 해보려고 합니다.
Git에서 주어진 파일의 히스토리를 보고 싶다면
gitk -- filename
가령
gitk -- Project/Classes/Char/CharInfo.m
와 같이 하면 해당 파일의 모든 히스토리를 볼 수 있다. 퍼포스의 time lapse view기능과 비슷하다.
가령
gitk -- Project/Classes/Char/CharInfo.m
와 같이 하면 해당 파일의 모든 히스토리를 볼 수 있다. 퍼포스의 time lapse view기능과 비슷하다.
Tuesday, November 20, 2012
Thursday, November 8, 2012
C#의 Matrix Order는?
열 우선이다.
좀 더 보충해야 겠다.
가령 Matrix의 경우 6개의 요소를 1차원 배열로 가지고 있는데. 이때
0번요소가 M11이고, 1번 요소가 M21라는 소리다. Matrix의 4,5는 각각 X, Y축 이동이다.
행렬 곱 형태로 나타낼 수 없고 직접 계산해야 한다.
좀 더 보충해야 겠다.
가령 Matrix의 경우 6개의 요소를 1차원 배열로 가지고 있는데. 이때
0번요소가 M11이고, 1번 요소가 M21라는 소리다. Matrix의 4,5는 각각 X, Y축 이동이다.
행렬 곱 형태로 나타낼 수 없고 직접 계산해야 한다.
Wednesday, November 7, 2012
C#에서 지네릭 클래스 사용하기
C++에서 템플릿 클래스를 사용하듯이 C#에서도 지네릭 클래스라는 것이 있다.
문제는 지네릭 클래스가 C++의 템플릿 클래스와는 다르다는데 있다.
컨테이너를 만들 때 보통 템플릿을 사용하듯이 C#에서도 지네릭 클래스를 사용한다. 가령
List<int>
List<float>
와 같이 말이다.
혹은 Vector클래스를 만들 때도 지네릭화 할 수 있다.
가령
Vector<int>
Vector<float>
와 같이 쓸 수 있으면 얼마나 좋겠나? C#에서는 안타깝게도 이를 구현하기가 어렵다.
가능은 하다. 다음 문서를 읽어 보자.
http://geekswithblogs.net/Mathoms/archive/2008/08/26/applied-generics--vector-class.aspx
http://www.codeproject.com/Articles/10780/Operator-Overloading-with-Generics
읽고 나서 나는 Vector2DInt, Vector2DFloat를 따로 만들어서 썼다.
차라리 Copy and Paste가 훨씬 쉽고 나중에 C#에서 제대로 지원할 때 지네릭을 사용하는 편이 낫겠다.
문제는 지네릭 클래스가 C++의 템플릿 클래스와는 다르다는데 있다.
컨테이너를 만들 때 보통 템플릿을 사용하듯이 C#에서도 지네릭 클래스를 사용한다. 가령
List<int>
List<float>
와 같이 말이다.
혹은 Vector클래스를 만들 때도 지네릭화 할 수 있다.
가령
Vector<int>
Vector<float>
와 같이 쓸 수 있으면 얼마나 좋겠나? C#에서는 안타깝게도 이를 구현하기가 어렵다.
가능은 하다. 다음 문서를 읽어 보자.
http://geekswithblogs.net/Mathoms/archive/2008/08/26/applied-generics--vector-class.aspx
http://www.codeproject.com/Articles/10780/Operator-Overloading-with-Generics
읽고 나서 나는 Vector2DInt, Vector2DFloat를 따로 만들어서 썼다.
차라리 Copy and Paste가 훨씬 쉽고 나중에 C#에서 제대로 지원할 때 지네릭을 사용하는 편이 낫겠다.
Thursday, October 25, 2012
cocos2d 심각하네...
컨버팅 작업 때문에 cocos2d를 어쩔 수 없이 분석하게 되었는데 정말...
보면 볼 수록 너무 못만들었네요; 엔진이 명확하지 않으면 게임플레이
프로그래머가 얼마나 고생할 수 있는지 알 수 있는거 같습니다.
혹 사용하시려고 고민하고 계신다면 cocos2d는 똥이니까 쓰지 마세요.
Tuesday, October 23, 2012
Box2D로 ApplyLinearImpulse를 쓸 때 유의할 점.
반드시 Body에 Mass가 설정되어 있어야 한다. 가령
b2MassData massData;
massData.center = b2Vec2(0,0);
massData.I = 0;
massData.mass = 0.14f;
mBodyBall->SetMassData(&massData);
이렇게 Mass를 설정하고 나서 ApplyLinearImpulse를 사용해야 한다.
b2MassData massData;
massData.center = b2Vec2(0,0);
massData.I = 0;
massData.mass = 0.14f;
mBodyBall->SetMassData(&massData);
이렇게 Mass를 설정하고 나서 ApplyLinearImpulse를 사용해야 한다.
Friday, October 19, 2012
Thursday, October 4, 2012
Cocos2D의 간략한 소개
http://www.slideshare.net/frauen1/introduction-to-cocos2d
좌표 시스템, 컨셉에 대해 설명을 해놓았다. cocos2d를 사용하진 않지만 이번 작업 때문에 어느 정도 기본은 알아야 해서 읽어보았다.
좌표 시스템, 컨셉에 대해 설명을 해놓았다. cocos2d를 사용하진 않지만 이번 작업 때문에 어느 정도 기본은 알아야 해서 읽어보았다.
Wednesday, October 3, 2012
Tuesday, October 2, 2012
Thursday, September 20, 2012
iOS OpenGL ES1.0에서 ES2.0으로 갈아타기
ES1.0은 Fixed pipeline을 사용하고 ES2.0은 쉐이더를 사용한다. 그렇기 때문에 기존에 사용하던 OpenGL 일부 기능들을 사용할 수 없다.
가령 glShadeMode와 glPushMatrix, glPopMatrix와 같은 것들은 함수를 콜할 경우 unimplement에러를 얻거나 혹은 컴파일 자체가 되지 않는다.
내가 제작한 DeadEngine을 ES2.0으로 옮기면서 해결했던 문제들을 나열해 보고자 한다.
1. glPushMatrix, glPopMatrix와 같은 매트릭스 스택 개념이 사라졌기 때문에 직접 구현해서 사용해야 한다. 나는 간단하게 DePushMatrix, DePopMatrix와 같이 함수를 제작하고 내부 자료구조는 STL stack을 사용해서 간단하게 구현했다. 구현은 다음과 같다.
가령 glShadeMode와 glPushMatrix, glPopMatrix와 같은 것들은 함수를 콜할 경우 unimplement에러를 얻거나 혹은 컴파일 자체가 되지 않는다.
내가 제작한 DeadEngine을 ES2.0으로 옮기면서 해결했던 문제들을 나열해 보고자 한다.
1. glPushMatrix, glPopMatrix와 같은 매트릭스 스택 개념이 사라졌기 때문에 직접 구현해서 사용해야 한다. 나는 간단하게 DePushMatrix, DePopMatrix와 같이 함수를 제작하고 내부 자료구조는 STL stack을 사용해서 간단하게 구현했다. 구현은 다음과 같다.
void KRendering::DePushMatrix()
{
IvMatrix44* mat = new IvMatrix44();
// copy it.
*mat = *mMatStack.top();
mMatStack.push(mat);
}
void KRendering::DePopMatrix()
{
IvMatrix44* tm = mMatStack.top();
delete tm;
mMatStack.pop();
}
2. glColor와 같은 기능도 사용할 수 없다. 쉐이더에 직접 넘겨 주어야 한다.
3. PC에서 OpenGL을 사용할 때 in이라는 keyword를 사용할 수 없고 attribute를 사용해야 한다. out역시 uniform을 사용해야 한다. 간단한 구현 사항은 다음과 같다.
attribute vec2 VertexPosition;
attribute vec2 TexCoordIn;
varying vec2 TexCoordOut;
uniform mat4 Projection;
void main()
{
gl_Position = Projection * vec4(VertexPosition.x, VertexPosition.y, 0, 1);
TexCoordOut = TexCoordIn;
}
2D 부분이라 vec2로 사용하고 in 키워드가 아닌 attribute, out이 아닌 uniform을 사용했다.
4. vertex array object, vertex buffer object를 사용한다.
기존 고정 파이프라인을 사용하다가 쉐이더를 사용하면 이게 헷갈리기 쉽상인데 잘 정리된 문서가 이미 두 개나 존재한다. (한개도 아닌 두 개다!)
http://www.opengl.org/wiki/Vertex_Specification_Best_Practices
http://www.raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial
끝
Tuesday, September 18, 2012
xcode에서 전처리기로 프로그래머 골탕 먹이기
xcode에서 preprocessor를 설정할 때 다음과 같이
DE_IPHONE\n-
과 같이 작성하면 (DE_IPHONE은 다른것이 되어도 무방함) 컴파일할 때 쌩뚱 맞은 버그를 발견하게 된다. 게다가 xcode 툴만 사용하면 겉으로 보이기에는 아무런 문제가 없어 보이는데 그 이유는 preprocessor를 보여줄 때 \n 때문에 그 뒷 부분(다른 선언 부분)이 화면에 전혀 보이지 않기 때문이다.
올바른 전처리는 DE_IPHONE으로 설정해야만 하며 그렇게 해야 그 다음에 선언된 것이 제대로 처리 된다.
DE_IPHONE\n-
과 같이 작성하면 (DE_IPHONE은 다른것이 되어도 무방함) 컴파일할 때 쌩뚱 맞은 버그를 발견하게 된다. 게다가 xcode 툴만 사용하면 겉으로 보이기에는 아무런 문제가 없어 보이는데 그 이유는 preprocessor를 보여줄 때 \n 때문에 그 뒷 부분(다른 선언 부분)이 화면에 전혀 보이지 않기 때문이다.
올바른 전처리는 DE_IPHONE으로 설정해야만 하며 그렇게 해야 그 다음에 선언된 것이 제대로 처리 된다.
OpenGL ES2로 갈아타야 하나...
DeadEngine의 경우 OpenGL ES1을 사용하고 있었는데 다른 라이브러리와 연동하는걸 하려고 하니까 ES2 없이는 돌릴 수가 없다. 결국 내 엔진을 ES2로 바꾸어야 하는데 지금 거의 마무리 하고 있던 프로젝트를 바꿀 순 없을거 같다. 일단 스케쥴대로 현재 만들고 있는 것은 ES1으로 돌리고 이후에 엔진을 업그레이드 해야겠다.
ES1에서 ES2로 옮길 때 작업 상황을 블로그에 남겨보아야 겠다.
Monday, September 17, 2012
스타크래프트 인공지능
http://code.google.com/p/bwapi/wiki/UsingBWAPI
이 API를 이용해서 Custom AI를 만들어 볼 수 있다.
예전에 Paul이 알려줬던 내용인데 이제서야 보게됐다...
내가 생각했던 AI기술들을 이용해서 AI를 개발하는것도 재밌을 것 같다.
이 API를 이용해서 Custom AI를 만들어 볼 수 있다.
예전에 Paul이 알려줬던 내용인데 이제서야 보게됐다...
내가 생각했던 AI기술들을 이용해서 AI를 개발하는것도 재밌을 것 같다.
Tuesday, September 11, 2012
Monday, September 10, 2012
OpenGL es 16 bits 스크린 캡쳐하기 (iOS)
short* buffer = (short*)malloc(myDataLength);
glReadPixels(startx, starty, width, height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, buffer);
int* buffer2 = (int*)malloc(width * height * 4);
int table5[] = { 0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255 };
int table6[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255 };
for ( int y = 0; y < height; ++y )
{
for ( int x = 0; x < width; ++x )
{
int b8 = table5[buffer[y * width + x] & 0x001F];
int g8 = table6[(buffer[y * width + x] & 0x07E0) >> 5];
int r8 = table5[(buffer[y * width + x] & 0xF800) >> 11];
buffer2[((height-1) - y) * width + x] = b8 << 16 | g8 << 8 | r8;
}
}
buffer에는 RGB형태로 들어오고 buffer2에 넣어줄 때는 BGR형태로 넣어 주어야 한다. Alpha는 그냥 0으로 셋팅하게 되어 있다.
Thursday, September 6, 2012
Wednesday, September 5, 2012
Tuesday, September 4, 2012
git 브랜치(branch)에 대한 설명
http://git-scm.com/book/en/Git-Branching-What-a-Branch-Is
정말 잘 설명해 놓았다. 하지만 이 링크를 읽기 전에 최소한 1챕터는 완독해 주어야 제대로 이해 가능하다.
우선 1챕터에서 git이 다른 버전 컨트롤과 데이터를 다루는 면에 있어서 어떤 차이점이 있는지 알아야 한다. 그리고 요약해보면...
각각의 스냅샷 마다 트리의 노드고 최신 노드를 브랜치가 포인팅 하고 있다.
현재 작업하고 있는 브랜치를 변경하면 HEAD는 그림과 같이 master가 아닌 new branch가 되며 이때 새로운 snapshot 하나를 만들면 그림과 같이 new snapshot 3-1이 생긴다.
만일 이렇게 작업을 하다가 다시 master 브랜치로 옮겨오면 현재 master 브랜치가 포인팅하고 있는 노드는 Snapshot 3이기 때문에 working directory에서 작업하던 파일들은 이전 소스로 바뀐다.
정말 잘 설명해 놓았다. 하지만 이 링크를 읽기 전에 최소한 1챕터는 완독해 주어야 제대로 이해 가능하다.
우선 1챕터에서 git이 다른 버전 컨트롤과 데이터를 다루는 면에 있어서 어떤 차이점이 있는지 알아야 한다. 그리고 요약해보면...
각각의 스냅샷 마다 트리의 노드고 최신 노드를 브랜치가 포인팅 하고 있다.
현재 작업하고 있는 브랜치를 변경하면 HEAD는 그림과 같이 master가 아닌 new branch가 되며 이때 새로운 snapshot 하나를 만들면 그림과 같이 new snapshot 3-1이 생긴다.
만일 이렇게 작업을 하다가 다시 master 브랜치로 옮겨오면 현재 master 브랜치가 포인팅하고 있는 노드는 Snapshot 3이기 때문에 working directory에서 작업하던 파일들은 이전 소스로 바뀐다.
(모음집) xcode에서 architecture setting하기
armv6와 armv7이 있는데 이 두개는 차이점이 존재한다.
기존에 ipod 3rd에는 armv6를 사용하였고 double precision에
성능이 좋지 못하였다. ios 5.0 즉, iphone 4가 나오면서 armv7을 사용할 수 있는데 더 좋고 빠른 명령어를 탑재하고 있어 프로그램이 이 명령어들을 사용할 경우 더 빠르게 수행된다.
추가 정보
ios5.0기반으로 app을 돌릴 때 반드시 armv7으로 셋팅해야 한다. apple에서 강제적으로 사용하게 한다.
끝
기존에 ipod 3rd에는 armv6를 사용하였고 double precision에
성능이 좋지 못하였다. ios 5.0 즉, iphone 4가 나오면서 armv7을 사용할 수 있는데 더 좋고 빠른 명령어를 탑재하고 있어 프로그램이 이 명령어들을 사용할 경우 더 빠르게 수행된다.
추가 정보
ios5.0기반으로 app을 돌릴 때 반드시 armv7으로 셋팅해야 한다. apple에서 강제적으로 사용하게 한다.
끝
(모음집) NSObjectCRuntime.h에서 오류가 나올 때
NSObjectCRuntime.h에서 오류가 나올 때 십중팔구 cpp파일의 속성을 objective c++로 설정하지 않아서 생기는 문제이다.
끝.
끝.
(모음집) png를 iOS에서 사용할 때 주의할 점
이 글은 제가 예전에 메모해놓았던 글을 그대로 옮겨 적은글 입니다. 혹 다른 분들에게 도움이 될까 싶어서요. 개인적으로 작성했던글이라 반말입니다.
--
libpng가 PC에서는 돌아가고 iPhone에서 돌아가지 않는 현상이 있었는 데 그 이유는 iPhone에 png를 넣어줄 때 컨버팅이 되기 때문이다.
Apple의 png는 BGRA로 저장된다.
Apple에서 png의 chunk type은 CgBI로 된다. IHDR이 아니라.
해결 방법.
1. png의 확장자를 바꾸기
2. user define옵션으로 컨버팅 옵션을 끈다.
IPHONEOPTIMIZATIONS = -skip-PNGs
끝.
--
libpng가 PC에서는 돌아가고 iPhone에서 돌아가지 않는 현상이 있었는 데 그 이유는 iPhone에 png를 넣어줄 때 컨버팅이 되기 때문이다.
Apple의 png는 BGRA로 저장된다.
Apple에서 png의 chunk type은 CgBI로 된다. IHDR이 아니라.
해결 방법.
1. png의 확장자를 바꾸기
2. user define옵션으로 컨버팅 옵션을 끈다.
IPHONEOPTIMIZATIONS = -skip-PNGs
끝.
Monday, September 3, 2012
Saturday, August 25, 2012
OGRE 3D 1.7 Application Development Cookbook 1장 번역 완료
드디어 1장 번역을 완료했습니다. 오우거를 이용해 Win32, MFC, MFC(with ribbon), Plugin, custom resource manager를 만드는 내용이 1장의 내용입니다. 번역자가 아닌 독자로써 1장을 평가한다면
별점 3개 입니다. 저는 오우거를 단 한번도 사용해본적이 없는데 그래도 나름대로 오우거의 사용법에 대해서는 조금 알 것 같다는 느낌입니다. 반면에 궁금해진것은 scene, entities에 관해 조금 더 설명이 있었으면 어땠을까 하는 느낌입니다. (아무래도 책 컨셉상 모자란감이 있네요. 게다가 사실 이런 부분까지 다뤘으면 좀 책이 어려워지지 않았을까 싶기도 합니다.)
프로그래머라면 반드시 소스 코드를 살펴 보고 실제로 어떻게 처음부터 끝까지 구성되었는지 알아볼 필요가 있습니다. 그 정도 알아보면 많이 배울 수 있을꺼라고 생각합니다.
책 괜찮네요... 아직까지는 ㅎㅎㅎ
별점 3개 입니다. 저는 오우거를 단 한번도 사용해본적이 없는데 그래도 나름대로 오우거의 사용법에 대해서는 조금 알 것 같다는 느낌입니다. 반면에 궁금해진것은 scene, entities에 관해 조금 더 설명이 있었으면 어땠을까 하는 느낌입니다. (아무래도 책 컨셉상 모자란감이 있네요. 게다가 사실 이런 부분까지 다뤘으면 좀 책이 어려워지지 않았을까 싶기도 합니다.)
프로그래머라면 반드시 소스 코드를 살펴 보고 실제로 어떻게 처음부터 끝까지 구성되었는지 알아볼 필요가 있습니다. 그 정도 알아보면 많이 배울 수 있을꺼라고 생각합니다.
책 괜찮네요... 아직까지는 ㅎㅎㅎ
Wednesday, August 22, 2012
따끈따끈한 PHP, MySql 삽질기
데이터베이스 필드 타입중 date가 있어서 여기에 생년월일 데이터를 넣는 작업을 하고 있었습니다. 그런데 자꾸 실제 데이터를 보니 0000-00-00이 나오는겁니다.
클라이언트에서 생년월일 데이터를 년, 월, 일로 따로 넘기고 php의 mkdate를 써야 하나?
고민을 하고 있었는데 아무래도 이건 마음에 안드는겁니다. 왜냐면 클라이언트측에서 3개를 따로 넘겨야 하고 서버측에서도 굳이 date를 다시 구성해서 db에 넣어주어야 하니까요.
클라이언트에서는 yyyy-MM-dd형식으로 문자열을 만들고 서버로 넘겼는데 계속 0000-00-00으로 나왔었습니다.
회사 동료분께서 query문 자체로 넘겨보자고 해서 yyyy/MM/dd형식으로 넘겨보니... 어라? 제대로 나왔습니다.
문제가 해결되었는데 아무래도 찜찜해서 혹시 문자열 포맷 문제가 아니라 서버 코드랑 query문이랑 다른가? 하고 체크...
보니까 클라이언트에서 받은 문자열 데이터를 query문에 넣을 때 '...'으로 감싸지 않았더군요. 즉, 정수형태로 date에 들어간게 문제였습니다.
date의 문자열은 / 포맷도 괜찮고 - 포맷도 괜찮았던거였어요.
끝.
클라이언트에서 생년월일 데이터를 년, 월, 일로 따로 넘기고 php의 mkdate를 써야 하나?
고민을 하고 있었는데 아무래도 이건 마음에 안드는겁니다. 왜냐면 클라이언트측에서 3개를 따로 넘겨야 하고 서버측에서도 굳이 date를 다시 구성해서 db에 넣어주어야 하니까요.
클라이언트에서는 yyyy-MM-dd형식으로 문자열을 만들고 서버로 넘겼는데 계속 0000-00-00으로 나왔었습니다.
회사 동료분께서 query문 자체로 넘겨보자고 해서 yyyy/MM/dd형식으로 넘겨보니... 어라? 제대로 나왔습니다.
문제가 해결되었는데 아무래도 찜찜해서 혹시 문자열 포맷 문제가 아니라 서버 코드랑 query문이랑 다른가? 하고 체크...
보니까 클라이언트에서 받은 문자열 데이터를 query문에 넣을 때 '...'으로 감싸지 않았더군요. 즉, 정수형태로 date에 들어간게 문제였습니다.
date의 문자열은 / 포맷도 괜찮고 - 포맷도 괜찮았던거였어요.
끝.
Tuesday, August 21, 2012
iOS Top-level objects란?
프로그램에서 NIB를 로드할 때 Cocoa가 object graph를 다시 만든다. Object graph는 windows, views, controls, cells, menus, custom objects 모두를 말한다. 이때 Top-level objects는 부모를 가지지 않는 object 집합이다.
예를 들어 view하나와 button하나가 있다고 치자.
이때 view에 button이 자식으로 등록되어 있고 이때 view는 top-level objects이지만 button은 아니다. 만일 button이 outlet으로 등록되어 있지 않으면 button역시 top-level objects로 분류된다.
예를 들어 view하나와 button하나가 있다고 치자.
이때 view에 button이 자식으로 등록되어 있고 이때 view는 top-level objects이지만 button은 아니다. 만일 button이 outlet으로 등록되어 있지 않으면 button역시 top-level objects로 분류된다.
Monday, August 20, 2012
C++ 이디엄중에 두 개.
1. if ( object != NULL )과 같은 코드는 if ( !object )로 표기한다.
2. char *name은 코드는 char* name으로 *을 타입에 붙인다.
2. char *name은 코드는 char* name으로 *을 타입에 붙인다.
옵티마이즈를 하기 전에 무조건 프로파일링을 해야합니다.
이건 정말 간단한 룰인데 지켜지지 않아요. 저도 예전에는 코드만 보고 옵티마이즈 하려고 했었는데 제대로 옵티마이즈 하려면 무조건 프로파일링을 해보아야 합니다. 반드시 코드를 수정하기 이전에 프로파일링 해보도록 합시다.
Sunday, August 19, 2012
Ogre 3D 1.7 Application Development cookbook 번역 하기로 했습니다.
두 번째로 오우거 책을 번역하기로 했습니다. 이번에는 책 내용을 좀 미리 보고 괜찮겠다 싶어서 번역한 책이에요.
오우거 엔진을 이용해서 다양한 프로젝트를 만들어 보는 책 입니다. 저도 아직 번역을 다 안해서 전체 책 내용은 모르겠지만 대충 보아하니 오우거 엔진을 이용한 툴 프로그래밍에 관련된 이야기도 좀 나오는것 같습니다. 더 자세한 내용은 번역을 끝내고 글을 다시 쓰도록 해야겠군요 :)
빨리 보다는 최대한 잘 번역해 보도록 할 생각입니다.
강남역 11번 출구쪽에 알라딘 생겼습니다.
이쪽 자리가 서점이 3번째 바뀐거 같은데 지금은 알라딘이 생겼네요. 중고책 서점입니다.
오늘 잠시 들렸다가 제가 전에 회사에서 읽었던 책들 업어왔습니다. 어차피 읽은 책이긴 한데 소장하려고요 ㅎ
C Inerfaces and Implementations
이산 수학론
책 상태도 너무 좋아서 기쁘기도 한데 한편으로는 씁쓸하기도 했습니다.
시간 되시는 분들은 꼭 들려보세요 :)
참고할 점은 컴퓨터 카테고리보다는 웹 디자인이라는 카테고리에 컴퓨터 책들이 더 많이 있습니다.
Friday, August 17, 2012
인터페이스 빌더를 사용해서 UIControl을 배치하는 방법
iOS에서 인터페이스를 디자인할 때 2가지 방법이 있다.
1. IB(Interface builder)를 이용하는 방법
2. 코드로 디자인 하는 방법
IB를 사용할 경우 iOS에서 제공되는 컨트롤들은 클릭 앤 드래그로 쉽게 배치할 수 있는데 커스텀 컨트롤 같은 경우에는 IB의 컨트롤 리스트에 나오지 않으므로 클릭 앤 드래그로 배치할 수가 없다. 예를 들어 UIControl을 상속한 KSwitch라는 클래스가 있을 때 이것을 배치하는 방법에 대해 알아보자.
방법
UIView를 오브젝트 라이브러리에서 선택한 후 화면에 배치한다. 그리고 해당 컨트롤의 Identify inspector란에 들어가서 클래스 속성을 KSwitch로 바꾼다.
컨트롤의 배경색을 투명하게 만들어 주고 싶다면 코드에서 clear color를 셋팅해주거나 Attributes에서 background컬러 속성을 clear color로 설정해 주어도 된다.
끝.
1. IB(Interface builder)를 이용하는 방법
2. 코드로 디자인 하는 방법
IB를 사용할 경우 iOS에서 제공되는 컨트롤들은 클릭 앤 드래그로 쉽게 배치할 수 있는데 커스텀 컨트롤 같은 경우에는 IB의 컨트롤 리스트에 나오지 않으므로 클릭 앤 드래그로 배치할 수가 없다. 예를 들어 UIControl을 상속한 KSwitch라는 클래스가 있을 때 이것을 배치하는 방법에 대해 알아보자.
방법
UIView를 오브젝트 라이브러리에서 선택한 후 화면에 배치한다. 그리고 해당 컨트롤의 Identify inspector란에 들어가서 클래스 속성을 KSwitch로 바꾼다.
컨트롤의 배경색을 투명하게 만들어 주고 싶다면 코드에서 clear color를 셋팅해주거나 Attributes에서 background컬러 속성을 clear color로 설정해 주어도 된다.
끝.
Thursday, August 16, 2012
UIScrollView와 UILabel을 이용해서 스크롤 되는 긴 글 표현하기
UILabel은 멀티라인을 지원하고 있으나 스크롤을 하는 방법은 존재하지 않는다.
반면에 UIScrollView는 스크롤을 지원하는데 이 안에 UILabel을 넣어서 스크롤을 처리하면 된다. 이때 중요한 점은 UIScrollView에 contentSize를 제대로 설정해주어야 스크롤 처리가 된다.
가령 Height가 300인 이미지가 있을 때 UIScrollView의 Height가 100이라면 이미지가 잘려서 보일 것이다. 이때
mScrollView.contentSize = CGSizeMake(width, 300);
와 같이 이미지의 높이 사이즈를 지정해 주면 스크롤 처리가 제대로 된다.
반면에 UIScrollView는 스크롤을 지원하는데 이 안에 UILabel을 넣어서 스크롤을 처리하면 된다. 이때 중요한 점은 UIScrollView에 contentSize를 제대로 설정해주어야 스크롤 처리가 된다.
가령 Height가 300인 이미지가 있을 때 UIScrollView의 Height가 100이라면 이미지가 잘려서 보일 것이다. 이때
mScrollView.contentSize = CGSizeMake(width, 300);
와 같이 이미지의 높이 사이즈를 지정해 주면 스크롤 처리가 제대로 된다.
UIView에서 NSTimer를 쓸 때 Dealloc이 되지 않는 현상
그 이유는 NSTimer를 사용할 때 내부적으로 UIView의 레퍼런스 카운터를 올려주고 UIView가 SuperView에서 Remove되더라도 이때 레퍼런스 카운터가 0이 되지 않으므로 Dealloc되지 않는다.
해결 방법
SuperView에서 Remove해주기 전에 Timer역시 Invalidate해주어야 한다.
끝.
해결 방법
SuperView에서 Remove해주기 전에 Timer역시 Invalidate해주어야 한다.
끝.
블로그 다시 시작합니다.
예전에 날린 자료들을 생각하면 안타깝지만 다시 시작해 보려고 합니다~ :)
제가 주로 관심있어 하는 분야는 AI, 게임 엔진 디자인, 미들웨어 개발, 툴 프로그래밍입니다.
제가 주로 관심있어 하는 분야는 AI, 게임 엔진 디자인, 미들웨어 개발, 툴 프로그래밍입니다.
Subscribe to:
Posts (Atom)
Task in UnrealEngine
https://www.youtube.com/watch?v=1lBadANnJaw
-
Unity released very good FPS example for people and I decided to analysis how they make this. Personally I wanted to show you how I analys...
-
When we use DrawDebugSphere function for debugging, it is working well but when you are trying to use it in anim node's function it will...
-
If you press a key 'L' in the jupyter notebook then you can see the line number in the editor.