티스토리 툴바


달력

01

« 2012/01 »

  • 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
  •  
  •  
  •  
  •  

XNA를 통해 개발하는 과정에서 제가 유일하게 커피 한잔을 마실 여유나, 웹서핑을 하는 시간이... 바로 "Rebuild All" 일때 입니다. 아마 대부분의 XNA 개발자분들이 그러시겠지만, 보통 프로젝트에 리소스를 붙여 넣고, 리소스 빌드 타입이 "Compile"이기 때문에 발생하는 문제이기도 합니다. (사실 이게 문제이지는 않습니다. ^^) 다만, 리소스의 갯수가 50개 이상이거나, 그리고 제 경우 처럼 리소스 컴파일 자체를 새롭게 만든 경우(컨텐츠 파이프라인)는 내부에서 뭔가 작업을 또 수행하기에 컴파일 타임이 정말 오래 걸립니다. (30분~1시간)

 

CleanUp을 만들때는 Maya로 만들어진 fbx파일을 읽어다가 내부에서 충돌맵을 컴파일 타임에 계산해서 만들도록 했는데요. 이것이 아주 대박입니다. 게임 맵이 30개를 넘어가니, 1시간 이상이 걸렸습니다. 줄이기 위해서 온갖 내부 최적화를 해서 30분으로 줄였지만, 지금 생각해보면 참 우매했던 것 같습니다. 왜냐하면, 한 솔루션에서 리소스 및 코드를 리빌드하느라, 개발 작업을 할 수 없었기 때문입니다.지금이였다면, 다른 솔루션파일에 리소스 전용 프로젝트를 만들어 놓고, 다른 PC를 이용해 빌드 시키고, 저는 그냥 게임 로직 작업을 진행 했을 것입니다.

 

<이런 메시 파일이 대략 100개 이상이었습니다. ㅠㅠ>

 

이는 얼마 전 K-Zune을 개발하면서, 실천할 기회를 맞이했습니다. K-Zune을 만들면서는 폰트 관련 컴파일에서 상당히 많은 시간을 소모했는데요. 저희 Naver XNA Cafe에 아네시아님이 올려주신 한글 폰트를 미리 컴파일해서 넣고 불러들여서 쓰는 방식을 해야 되지만, Zune에서는 지원이 완벽하지 않고, Zune 자체는 XNA 3.0기반인 지라 MS가 권장해 주는 방법으로 했습니다. 이러다보니!!! 컴파일 타임이 아무리 줄인다고 해도 최소 30분이 걸립니다. ㅠㅠ; 한글, 일어, 중국어, 영어, 아스키류 이렇게 지원하니 생기는 문제입니다.

 

그럼 이제, 리소스 분리를 간단히 알아 보겠습니다.

 

이 작업은 크게 2가지 일로 나눠 집니다. "새로운 프로젝트"와 "기존 프로젝트"에서 하는 일입니다.

 

< 새로운 프로젝트에서 할 일>

 

1. 새로운 프로젝트를 하나 만듭니다.

2. 새롭게 만든 프로젝트에 리소스들을 원래 하듯이 다 끌어다 놉니다.

3. 프로젝트 설정에서 "Build Events"에 가서 "Post-Build Event"를 아래와 같이 수정해 줍니다.

-> 이는 새로운 프로젝트에서 빌드된 리소스 파일들(.xnb)을 기존 프로젝트의 content 폴더로 복사해주기 위함입니다.

-> ex) copy "$(TargetDir)\content\*.xnb" "C:\OldProject\Content"
-> TargetDir는 Output Directory로 "debug/release"폴더가 보통 됩니다(Full Path를 가지고 있음). 이 폴더에 가보시면 content가 있고, 그 안에 xnb파일이 있습니다.

 

 

 

4. 설정 끝입니다. 이제 새로운 프로젝트를 빌드하면, "기존 폴더의 content폴더"에 .xnb인 리소스들이 있을 것입니다.

 

< 기존 프로젝트에서 할 일>

1. 기존 프로젝트의 Content 폴더를 보면, 빌드된 .xnb파일이 있을 것이므로, 그것을 content에 등록시킵니다.

 

 

2. 그리고 추가된 파일들의 파일 속성을 봅니다.

 

 

3. 여기서 "Build Action"을 "None"으로 설정해 줍니다. 

-> 이 의미는 리소스 자체가 이미 컴파일되어 있기 때문에, 기타 행동을 하지 않고, 빌드를 하지 않겠다는 것입니다.

-> 대신 debug/release폴더로의 복사는 되어야 합니다. 따라서 그 밑의 "copy to output directory"를 "Copy if newer"로 설정해 줍니다.

 

 

4. copy to output directory"를 "Copy if newer"로 설정합니다.

 

 

5. 끝입니다. 이제 평소 처럼 하시면 됩니다. ^^;

 

이 간단한 것을 저의 특유의 귀차니즘과 마치 이런 것을 하면 기존 프로젝트가 무너지고 큰일이 날지도 모른다면, 조바심이..... 흑흑.

이제라도 이렇게 나마, 조금씩 개선시켜 나아가는 것이 좋은 것 같네요. 혹시 프로젝트 규모가 커서 고민이신 분도, 이런식으로 접근하셔서 꼭 시간 아끼시길 바랍니다. ~

 

 

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by GOMZ_동훈

요즘 저희 Cafe에서 기획중인 게임에는 아마도 게임패드와 키보드를 둘 다 지원하는 인터페이스가 들어 갈 것이라고 생각하는데요. 특히 게임 패드인 경우 진동 기능을 넣지 않을 수가 없습니다. 게임 패드의 진동기능은 정말 대단한 몰입감을 줍니다.

 

이번에는 진동기능과 관련되어서 꼭 알아야될 정보와 쉽게 사용가능하도록 만든 초간단 클래스도 같이 공개하도록 하겠습니다.

 

먼저 아래의 내용은 MSDN 내용과 제가 XBOX360 게임 개발시에 삽질한 것 내용을 정리한 것입니다. ^^;

XBOX360게임은 FPS가 25~30 사이를 왔다갔다 했습니다. 제작한 게임이 풀 3D게임이여서 60 Frame으로 돌리기에 벅찼습니다.

(한 화면에 3만~10만 폴리곤을 왔다갔다 했습니다. 이러다보니, 성능과 상황에 따른 진동처리 문제가 좀 더 현실적으로 다가 왔었습니다.)

 

<진동에 대한 이해>

 

1. GamePad 클래스 내부의 SetVibration 함수를 호출해서만 접근이 가능합니다. (이 외에는 방법이 없음) 

 

2. 한번 SetVibration 함수를 호출하면, 중지 명령을 내리기 전까지 무조건 지속됩니다. 

 

3. 중지명령을 내리는 것도 SetVibration을 통해서 가능. -> 진동 수치를 0.0으로 설정하면 됩니다.

 

4. 패드를 중심으로 왼쪽은 Low frequency, 오른쪽은 High frequency 입니다.

-> 보통 진동을 그냥 0.5,0.5 이렇게 주면 왼쪽 오른쪽 벨런스하게 진동이 올 것이라고 생각하지만, 실은 용도가 다릅니다.

-> 일단 (0.5,0.0) 이렇게 입력을 주면, 왼쪽의 Low frequency한 모터가 움직입니다. 이 의미는 심장박동 느낌처럼 진동의 강도와 주기가

강도는 강하고, 주기는 긴 느낌입니다. 반면 (0.0,0.5) 이렇게 입력을 주면, 면도기 진동 처럼.. 빠르고 진동의 감도가 약합니다.

-> 기어스오브워 같이 톱질 할때 수치를 생각해보면, 대략 (1.0, 0.6) 정도 인 것 같습니다. (추측)

-> 이 느낌은 밑에서 모터는 나름 빨리 돌고 있는 것이고, 위에서는 막 갈려고 힘이 들어가는 느낌이라고 할까요? ㅋㅋ

 

5. SetVibration함수가 항상 true가 되는 것이 아니라는 것도 매우 중요합니다. (얼마 전 게시판에서 나온 사운드 관련 질문과 같은 맥락입니다.)

-> 특히 진동인 경우 중간에 끊기게 되면, 손의 감각에 의해 금방 탄로가 납니다.

-> SetVibration함수가 일단 중첩되어서 들어가게 되면, false가 리턴될 확률이 높아집니다. (다른 것도 충분히 부하가 있는 상황을 가정)

-> 그리고 가비지 컬렉션이 일어나고 있는 도중이나, LOAD/SAVE 등 디스크 IO에 접근할때 진동기능을 호출하면, 끊길 확률이 높습니다.

-> Help 내용을 보면." Setvibration 함수의 리턴값이 true가 되도록 루프에서 wait하면서 기다리는 것은 추천되지 않습니다." 라고 되어있는데, 즉, 이 경우 다음 번 loop에서 다시 시도해야 됩니다. loop이 돌아오면서, IO의 pending상태나 이런 것들이 재 설정 될 수 있기 때문입니다.

-> 다행인 것은 Light한 게임을 만들때는 5번 케이스가 거의 안나온다는 것입니다. 하지만 XBOX360의 경우는 가비지 컬렉션 타임에 걸리면, 생각보다 fail이 잘 납니다. 또한 이 경우는 진동중지 명령이 바로 되는 것이 아니므로, 진동 상태로 1초 동안 머물러 있을 때도 있습니다. ^^;

 

6. 마지막으로 진동 호출 함수는 가능하면 Update 함수에서만 처리되어야 합니다. Draw 함수보다는 Update에 넣는 것이 더 안정적입니다. Update -> Draw 시, Update와 Draw 중간에서 IO 처리가 일어날 것입니다.  이때 Draw는 보통 부하가 크기 때문에 호출했다고 해도, Update때 보다는 느리므로, 진동이 lack이 걸리는 것 처럼 올 수도 있습니다.

 

<따라서 추가로 필요한 기능>

 

1. 시간관리 기능이 하나 필요합니다. (몇 초 동안 만 진동해라.. 이런 것이죠.)

2. 진동 강도 조절 기능이 필요합니다. (1.0의 강도가 진행되고 있었는데, 0.1 강도가 들어왔다고, 0.1로 설정하면 안됩니다.)

 

<실제 구현 코드>

위의 추가로 필요한 기능까지를 포함해서, 새로운 클래스를 2개를 만들었는데요. 아래와 같습니다. (초 간단입니다. ^^;)

 

<cVibration.cs>

    // cVibration의 list에서 사용되는 data.

   publicclasscVibrationData

    {

       publicfloatm_Duration;

       publicfloatm_LeftMoter;

       publicfloatm_RightMoter;

 

       publiccVibrationData(floatduration_ms,floatleftMoter,floatrightMoter)

        {

           m_Duration=duration_ms;

           m_LeftMoter=leftMoter;

           m_RightMoter=rightMoter;

        }

    }

 

   publicclasscVibration

    {

       privatefloatm_TotalLeftMoter;

       privatefloatm_TotalRightMoter;

 

       privateList<cVibrationData>m_listVibration;

 

        #regionTest를 위한 property

 

       publicfloatTotalLeftMoter_ForTest

        {

           get{returnm_TotalLeftMoter; }

        }

 

       publicfloatTotalRightMoter_ForTest

        {

           get{returnm_TotalRightMoter; }

        }

        #endregion

 

        ~cVibration()

        {

           m_listVibration.Clear();

           m_listVibration=null;

        }

 

       publiccVibration()

        {

           m_TotalLeftMoter= 0.0f;

           m_TotalRightMoter= 0.0f;

 

           m_listVibration=newList<cVibrationData>();

        }

 

       publicboolAddVibration(floatduration_ms,floatleftMoter,floatrightMoter)

        {

           intbeforeCount=m_listVibration.Count;

 

           // add함수는 리턴값이 void이기에 true/false를 판단하기 위해, 갯수로 판단함.

           m_listVibration.Add(newcVibrationData(duration_ms,leftMoter,rightMoter));

 

           if(beforeCount+ 1 ==m_listVibration.Count)

            {

               // 일단 시작해야 함. 시작하지 않으면, 일정 시간이 지나가 버림.

               constfloatdefaultTime= 0.0f;

               DoUpdate(defaultTime);

               returntrue;

            }

 

           returnfalse;

        }

 

       privatevoidDoUpdate(floatupdatedTime)

        {

           floattempTotalLeft= 0.0f;

           floattempTotalRight= 0.0f;

 

           for(inti= 0;i<m_listVibration.Count;i++)

            {

               // 시간 체크 루틴.

               m_listVibration[i].m_Duration=m_listVibration[i].m_Duration-updatedTime;

 

               if(m_listVibration[i].m_Duration> 0.0f)

                {

                   if(tempTotalLeft<m_listVibration[i].m_LeftMoter)

                       tempTotalLeft=m_listVibration[i].m_LeftMoter;

 

                   if(tempTotalRight<m_listVibration[i].m_RightMoter)

                       tempTotalRight=m_listVibration[i].m_RightMoter;

                }

               else

                {

                   m_listVibration.RemoveAt(i);

                   i--;// m_listVibration.Count 값이 하나 작아짐., 다시 i번째를 수행하게 한다.

                }

            }

 

           // 기존 값과 값을 경우, SetVibration을 할 필요가 없다.

           if(tempTotalLeft!=m_TotalLeftMoter||tempTotalRight!=m_TotalRightMoter)

            {

               m_TotalLeftMoter=tempTotalLeft;

               m_TotalRightMoter=tempTotalRight;

 

               GamePad.SetVibration(Microsoft.Xna.Framework.PlayerIndex.One,tempTotalLeft,tempTotalRight);

            }

        }

 

       publicvoidUpdate(floatupdatedTime_ms)

        {

           DoUpdate(updatedTime_ms);

        }

    }

 

 

자, 실제 사용을 해보겠습니다.

 

1.  선언

publicclassGame1:Microsoft.Xna.Framework.Game

{

      GraphicsDeviceManagergraphics;

      SpriteBatchspriteBatch;

      cVibrationm_Vibration;

}

 

2. 초기화

protectedoverridevoidInitialize()

{

      m_Vibration=newcVibration();

       base.Initialize();

}

 

3. 사용 및 업데이트

protectedoverridevoidUpdate(GameTimegameTime)

{

// Allows the game to exit

        if(GamePad.GetState(PlayerIndex.One).Buttons.Back==ButtonState.Pressed)

           this.Exit();

 

       if(GamePad.GetState(PlayerIndex.One).Buttons.A==ButtonState.Pressed)

        {

           constfloatduration_ms= 200;

           constfloatleftMoter= 0.5f;

           constfloatrightMoter= 0.5f;

 

           m_Vibration.AddVibration(duration_ms,leftMoter,rightMoter);

       }

 

        if(GamePad.GetState(PlayerIndex.One).Buttons.B==ButtonState.Pressed)

        {

           constfloatduration_ms= 200;

           constfloatleftMoter= 0.75f;

           constfloatrightMoter= 0.75f;

 

           m_Vibration.AddVibration(duration_ms,leftMoter,rightMoter);

        }

 

        // 이렇게 Update를 호출해 주면 됩니다.

        m_Vibration.Update((float)gameTime.ElapsedGameTime.TotalMilliseconds);

 

        base.Update(gameTime);

}

 

<추가 프로젝트>

cVibration이 잘 작동하는지, 또 제 의도가 명확했는지 테스트 하기 위해서, 테스트 프레임 워크(NUnit)를 사용했습니다. 실제 Test코드를 보시면 어떤 의도로 작업을 했는지 명확하게 확인하실 수 있습니다. (cVibration_Test.cs)

 

특히 '사과'님 께서 일전에 물어보셨던 TDD와 관련된 내용을 넣으려고 조금 더 평소보다 디테일 하게 했으니 참고하세요 ^^;

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by GOMZ_동훈

요즘 세계적인 경기침체로 그런지, 어제는 Microsoft가 Zune쪽 인력을 많이 구조조정시켰다는 기사를 봤었습니다. 그리고 오늘 Gamasutra에 가서 Industry News를 보니, MS의 게임개발관련 제일 큰 행사라고 할 수 있는 Gamefest가 2009년에 하지않고, 2010년으로 옮겼다는 소식이 있어서, 열심히 읽어 보았습니다.

 

다행인것은 옮긴 이유가 경기침체라는 이유가 아닌, 참여하는 게임업체(partner)들이 올해 여름까지 데드라인을 맞추기가 빡시다는 것이었습니다. 따라서 내년 초라면 충분히 가능하겠다.. 이런 것이죠. 사실 이러한 이유가 중요한게 대부분은 gamefest에 참여하시는 분들 중 게임 자체에 관심이 있어서 오신 분들도 많습니다. 이런 분들이 자신들이 좋아하는 게임이 gamefest에 출품되지 않았다면 우울하겠죠.. 이런저런 이유로 결국 내년 초로 옮겨졌습니다. (제게는 다행입니다. 내년이면 충분히 준비해서 나가볼만 합니다. ^.^; 저는 익스포터/3D공개엔진 개발을 가지고 참여해볼 생각입니다.)

 

참고로, 저희 GOMZ팀이 만든 "CleanUp"이라는 게임이 Gamefest 2008에 XNA 부분에 기술데모로 전시되어서, 제게는 정말 애착과 관심이 정말 많은 행사였습니다. 그리고 올해와 내년에도 꼭 작품을 출품하고, 또한 기술적인 부분을 강화하여 행사에 발표와 토론 참여도 하고 싶었구요.

(http://creators.xna.com/en-us/press/gamefest)

 

참고로 Gamefest는 Microsoft에서 주관하는 MS관련 기술을 가지고 게임을 개발하는데 필요한 기술이나 동향, 그리고 만들어진 게임에 대해 발표하고... 기타 등등 여러가지를 하는 행사입니다. GDC/KGC와 유사하다고 보시면 됩니다.

 

역시나 작년 제 관심은 XNA / DirectX 11 였으므로, 그 쪽 기술을 열심히 공부하기도 했었습니다. 아래 링크를 보시면 XNA의 기술동향도 파악하실 수 있습니다.

 

http://www.xnagamefest.com/presentations.htm#XNA_GAME_STUDIO_

 

현재 제가 기획중인 새로운 엔진에서도 위의 presentation에서 설명된 멀티스레드 방식 이나, GPU를 더 효율적으로 사용하는 방법.. 좀 더 XBOX360에 최적화된 방법등을 적용하려고 하고 있습니다. 특히 DX11의 멀티스레드 트렌드를 XNA에서도 가져가려고 한다는 것은 재미있는 것 같습니다. 역시나 DX와 XNA는 서로 땔래야 땔수 없는 그런 사이인가 봅니다. ^.^;

 

GameFest 일정 연기와 관련된 링크는 아래와 같습니다.

http://www.gamasutra.com/php-bin/news_index.php?story=21996

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by GOMZ_동훈