Rebooting Reiot
  • Archives
  • Tags
  • Random
  • 2006-07-06

    Visual Assist X의 리팩토링 기능을 활용해보자

    WholeTomato의 Visual Assist X 베타 버전을 아직도 안 써보셨다면 지금 당장 다운받은 후 설치하기 바란다. 최근 추가된 환상적인 C++ 리팩토링 기능 덕분에 최근 몇 주간 정말 행복했다. 그래서 드디어 오늘 몇 카피 사달라고 상부에 보고를 해서 내일 결제할 예정이다. 후훗.

    http://www.wholetomato.com/products/features/images/addMemberMenu.png

    기본적으로 VAX의 리팩토링은 위 그림처럼 심볼에 마우스를 갖다대면 나오는 버튼을 몇 번 누르는 것만으로 끝이 난다. 가장 짭짤하게 재미를 본 기능 위주로 한번 설명해본다면...

    Move Implementation to Source File

    UnitTest 를 기반으로 작업을 해보면, 일단 헤더 파일에 빈 함수를 만들고 컴파일을 시킨 후에야 실제 내용을 채워넣게 된다. 그러다보면 헤더 파일에 inline 으로 구현된 함수의 바디를 .cpp 로 손수 옮겨야 할 때가 많다. 지금까지는 이 작업이 귀찮다는 생각을 해 본적이 없는데, 가만히 분석해보니

    1. 멤버 함수 전체를 Copy
    2. 함수 바디를 삭제하고 맨 끝에 세미콜론 붙이기
    3. .cpp 로 이동해서 적당한 위치에 Paste
    4. 클래스명:: 을 긁어 붙이거나 타이핑한 후 코드를 적당히 꾸미기
    5. (옵션) 디폴트 파라미터가 있을 경우 삭제하기

    의 순서로 마우스와 키보드를 휘둘러야 했다는 것을 알 수 있었다. 단 지금부터는 클릭 두 번만으로 끝.

    Rename

    http://www.wholetomato.com/support/images/renameTempDialog.gif

    예전에는 클래스나 함수, 데이터 멤버의 이름을 짓는 데 많은 시간을 투자했다. 그 당시만 해도 이름의 메타포 기능을 매우 중시했기에, 시간이 걸리더라도 한번 정하면 끝까지 바꾸지 않을 정도로 좋은 이름을 붙여야 한다는 게 업계의 표준이었기 때문이다. 그러나, agile을 배우고 난 지금은 먼저 컴파일부터 시켜 놓고 천천히 좋은 이름을 찾아서 그때 그때 바꿔나가면 된다는 생각이 강해졌다.

    문제는 그 이름이 코드에 얼마나 많이 퍼져 있는가인데, 물론 정규식을 이용한 global replace를 써도 되지만 아무래도 불안한 게 사실. 결국에는 손수 하나씩 찾아서 고쳐나가다가 포기하고, 그냥 마음에 들지 않은 채로 내버려두는 경우가 많았다.

    VAX의 rename 기능은 대체로 잘 동작하지만, 불안할 때에는 Find References로 체크해보기에도 좋다. 더 바라는 게 있다면 클래스 이름을 바꿀 경우 파일명도 바꿔줬으면 좋겠다. :P

    Change Signature

    http://www.wholetomato.com/products/features/images/changeSignatureDialog.gif

    멤버 함수의 파라미터 추가 삭제 및 이름을 바꿀 때 사용한다. 굳이 더 설명하지 않아도 명명백백한 기능이다. 단, virtual 함수일 경우 하위 클래스에서 재정의한 멤버 함수도 바꿔주면 좋겠지만, 당연히 안된다. :)

    Encapsulate Field

    http://www.wholetomato.com/products/features/images/encapsulateFieldDone.gif

    데이터 멤버에 대고 실행하면 accessor(일명 Get/Set 함수)을 자동으로 만들어준다. 헝가리안 표기법도 잘 찾아서 이름만 똑똑하게 뽑아주는데, AutoText를 편집해두면 입맛대로 이름을 수정할 수 있다. 더이상 __PROPERTY 매크로로 Get/Set을 정의할 필요가 없어진 것이다. 만쉐~

    기타

    이 외에도 몇 가지 좋은 기능들이 많다.

    • Extract Method : 긴 코드를 함수로 한번만에 묶어내준다. 그런데 생각보다 많이 사용해보지는 못했다.
    • Create Implementation : 함수 선언에 대고 클릭하면 .cpp 에 구현부를 자동으로 만들어준다. 그 편리함은 이루 말할 수 없다. ㅠ_ㅠ
    • Create Declaration : 위 기능과 반대로 구현부부터 만들고 나서 헤더 파일에 선언문을 자동으로 추가해주는 기능이다. 보통은 extern 문을 생성할 때 가장 많이 사용된다.

    프로젝트가 커질수록 느려진다는 쑥갓군의 보고도 있지만, 작은 프로젝트에서는 속도 문제가 거슬리지는 않는 수준이다. 사소한 버그들만 고쳐진다면 정말 위대한 도구가 될 것 같다. 단돈 125$면 정말 편리한 개발이 가능해지니, 어서 어서 팀장/실장을 졸라서 결제하시기 바란다.

    Source: http://boxcatstudio.wordpress.com/2006/07/06/visual-assist-x%ec%9d%98-%eb%a6%ac%ed%8c%a9%ed%86%a0%eb%a7%81-%ea%b8%b0%eb%8a%a5%ec%9d%84-%ed%99%9c%ec%9a%a9%ed%95%b4%eb%b3%b4%ec%9e%90/
    Category:programming
  • 2006-07-05

    PCH(pre-compiled headers)를 이용해 빌드 시간을 최소화하기

    무엇을 PCH에 포함시킬 것인가?

    Noel Llopis의 The Care and Feeding of Pre-Compiled Headers에 의하면, 다음과 같은 파일들만이 stdafx.h 에 들어갈 수 있다고 한다.

    • 크기가 큰 시스템 헤더 파일 : windows.h, stdio.h, time.h, ...
    • 가장 많이 포함된 헤더 파일 : string, list, vector, map 같은 STL 헤더와 boost 헤더들
    • 자체 헤더 파일 : 그 어떤 자체 헤더 파일도 stdafx.h 에 들어가서는 안된다.

    문제는 이런 헤더를 찾아내는 게 참 애매하다는 점인데, 이 스크립트를 사용하면 stdafx.h 에 들어가기에 적합한 헤더들을 찾아준다. 빌드 시간이 오래 걸려서 고생하시는 분들에게 추천한다. 단 주의할 점은

    수동으로 PCH 추가하기

    • PCH 로 사용할 MyStdAfx.h 와 MyStdAfx.cpp 파일을 프로젝트에 추가한다.
    • 우선 프로젝트 설정(C/C++ - 미리 컴파일된 헤더)에서 PCH 사용하기를 선택하고 MyStdAfx.cpp 의 속성 메뉴에서 '''PCH 만들기'''로 지정한다.
    • 모든 .cpp 파일의 맨 위에 #include "MyStdAfx.h" 를 추가한다.

    외부 파일 따로 지정

    PCH를 사용하지 않는 외부 라이브러리의 .cpp를 현재 프로젝트에 추가해서 빌드해야 할 때가 있다. 이 경우 해당 파일의 속성 메뉴에서 "PCH 사용하기 - 사용하지 않음"을 선택하면 된다.

    see also:

    • SeriousCode.Net:PCH
    • GPGStudy:PCH
    Source: http://boxcatstudio.wordpress.com/2006/07/05/pchpre-compiled-headers%eb%a5%bc-%ec%9d%b4%ec%9a%a9%ed%95%b4-%eb%b9%8c%eb%93%9c-%ec%8b%9c%ea%b0%84%ec%9d%84-%ec%b5%9c%ec%86%8c%ed%99%94%ed%95%98%ea%b8%b0/
    Category:programming
  • 2006-07-05

    operator= 는 상속되지 않는다.

    
    template
    class Hello
    {
    public :
    void operator=( const T &val ) { value = val; }
    T value;
    };
    
    class HelloStr : public Hello {};
    
    TEST(TemplateAndOperator)
    {
    Hello i;
    i = 100;
    Hello s;
    s = "Hello"; // error
    }
    Source: http://boxcatstudio.wordpress.com/2006/07/05/operator-%eb%8a%94-%ec%83%81%ec%86%8d%eb%90%98%ec%a7%80-%ec%95%8a%eb%8a%94%eb%8b%a4/
    Category:programming
  • 2006-07-01

    FPS 게임의 복제 프레임워크 분석

    다음 글을 읽기 전에 우선 전통적인 FPS게임의 네트워크 구현부터 읽어보기를 권장한다. 참고한 원문은 하프2위키:Networking_Entities이며, 단순 번역이 아니라 코드를 기반으로 정리한 내용임을 미리 밝힌다.

    가장 먼저 알아야 할 점은, 소스 엔진에서는 서버에서 클라이언트로의 단방향 복제(replication)만이 일어난다는 점이다. 반대의 경우에는 입력 샘플링과 메시징 시스템만 사용할 수 있다. 아무래도 양방향 복제의 경우 경쟁 조건 같은 문제들이 골치 아프기 때문에, 자체적인 복제 프레임워크를 구축하는 분들에게도 단방향 복제만 구현하는 것을 권장한다.

    http://boxcatstudio.files.wordpress.com/2009/07/entity.png

    복제는 서버와 클라이언트에 정의된 엔티티(entity) 사이에서 이루어진다. 이때 동일한 클래스를 C/S 공통으로 사용하는 대신, 서버에서는 CBaseEntity 를, 클라이언트에서는 C_BaseEntity를 상속받은 엔티티를 각각 따로 정의한다.

    복제의 최소 단위는 엔티티 내부에 존재하는 네트워크 변수(CNetworkVar)이다. 단순히 이름이나 좌표 같은 visual 데이터 뿐만이 아니라 애니메이션 프레임이나 물리 엔진에서 사용하는 미시적인 데이터까지도 복제되는 것을 확인할 수 있다. 참고로 CBaseEntity -> C_BaseEntity 간에 복제되는 네트워크 변수가 26가지나 되는 걸로 봐서, 소스 엔진에서의 복제 프레임워크의 비중이 매우 크다는 것을 알 수 있다.

    
    // server base entity
    class CBaseEntity : public IServerEntity {
        CNetworkVector( m_vecOrigin );
        CNetworkQAngle( m_angRotation );
    };
    
    // client base entity
    class C_BaseEntity : public ICilentEntity {
        Vector m_vecOrigin;
        QAngle m_angRotation;
    };
    

    네트워크 변수들은 다양한 연산자 오버로딩을 지원하기 때문에 일반적인 빌트인 타입처럼 사용할 수 있다. 또한, 서버 엔티티의 특정 네트워크 변수가 바뀌게 되면 해당 엔티티의 dirty flag가 자동적으로 켜져서 다음 번 스냅샷에 포함되게 되어 있다. 최종적인 코드는 꽤 간단해보이지만, 이를 구현하기 위해서 매크로와 void * 를 이용한 offset 처리, 그리고 템플릿이 꽤나 복잡하게 얽혀 있어서, 분석에 애를 좀 먹었다. 관심 있는 사람은 내공 증진을 위해 한번 훑어 보는 것을 권장한다.

    네트워크 변수의 복제는 비트스트림(bitbuf)을 통해서 이루어진다. 각각의 엔티티에는 네트워크 변수들을 비트스트림으로 변환하는 방법을 담은 데이터 테이블(DataTable)이 클래스 static 변수로 정의되어 있다. 앞서 밝혔듯이 오직 단방향 복제만 지원되기 때문에, 서버 엔티티의 데이터 테이블은 Send Table, 클라이언트 엔티티의 데이터 테이블은 Recv Table 이라고 불린다. 데이터 테이블을 만드는 함수인 SendProp()과 RecvProp()들을 이용하면, 네트워크 변수를 주고 받을 때, 타입과 비트 크기, 복제용 플래그, 변경될 경우에 호출할 프록시 함수(==콜백 함수)등을 지정할 수 있다.

    
    // CBaseEntity Send Table
    
    IMPLEMENT_SERVERCLASS_ST_NOBASE( CBaseEntity, DT_BaseEntity )
        ...
        SendPropVector  (SENDINFO(m_vecOrigin), -1,  SPROP_COORD|SPROP_CHANGES_OFTEN,
            0.0f, HIGH_DEFAULT, SendProxy_Origin ),
        SendPropQAngles (SENDINFO(m_angRotation), 13, SPROP_CHANGES_OFTEN, SendProxy_Angles ),
        ...
    END_SEND_TABLE()
    
    // C_BaseEntity Recv Table
    
    BEGIN_RECV_TABLE_NOBASE(C_BaseEntity, DT_BaseEntity)
        ...
        RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ),
        RecvPropQAngles( RECVINFO_NAME( m_angNetworkAngles, m_angRotation ) ),
        ...
    END_RECV_TABLE()

    여기까지만 구현하면 기본적인 객체 및 데이터의 복제는 끝난다. 그러나 이것만으로 랙이나 손실 등의 다양한 예외 상황을 처리하기는 곤란하다. 이것이 바로 복제 프레임워크가 Interpolation 을 지원해야 하는 이유이다. 손쉽게 외삽과 내삽을 구현하려면 복제된 데이터의 히스토리를 일정 분량동안 저장한 후 다양한 보간 함수들을 이용해서 예측을 해야 하는데, 이런 기능을 도와주는 것이 바로 IInterpolatedVar 이다. 어떤 네트워크 변수가 Interpolate 를 지원하게 하려면 해당 엔티티에 CInterpolatedVar 를 함께 정의한 후, AddVar()를 이용해서 매핑을 시키면 된다. 그러면 네트워크 변수가 서버에 의해 업데이트 될 때마다 히스토리가 쌓이게 되며 필요할 때마다 적당히 보간된 값을 얻어올 수 있게 된다.

    
    // client base entity
    class C_BaseEntity : public ICilentEntity {
      Vector m_vecOrigin;
      CInterpolatedVar m_iv_vecOrigin;
      QAngle m_angRotation;
      CInterpolatedVar m_iv_angRotation;
    };
    
    C_BaseEntity::C_BaseEntity() :
        m_iv_vecOrigin( "m_iv_vecOrigin" ),
        m_iv_angRotation( "m_iv_angRotation" )
    {
        AddVar( &m_vecOrigin, &m_iv_vecOrigin, LATCH_SIMULATION_VAR );
        AddVar( &m_angRotation, &m_iv_angRotation, LATCH_SIMULATION_VAR );
    }

    정리하면, 소스 엔진의 복제 프레임워크는

    • 상속을 통해서 객체 복제를 구현한다. 반면 언리얼 엔진에서는 스크립트와 C++간의 바인딩을 이용한다. 아무래도 속도는 C++ 레벨에서 복제하는 소스 엔진 쪽이 더 우세할 것으로 추측한다.
    • 복제하려는 데이터의 선별은 C++ 클래스 디자인 단계에서 이루어진다. 데이터의 송수신은 매크로로 간단히 구현되며, 객체 단위가 아니라 데이터 단위로 콜백을 지정할 수 있다.
    • Interpolation은 히스토리를 관리할 객체를 더 필요로 하며, 원본 데이터가 바뀔 때마다 자동적으로 히스토리에 쌓이도록 되어 있어서, 개발자의 스트레스를 꽤 많이 덜어줄 것 같다.

    어제 위 내용을 토대로 기존에 작성된 복제 프레임워크를 뜯어 고치다가 영식군이 힐끗 보고 말하길 "도대체 우리 게임에 객체가 몇 개나 되길래 그렇게 최적화를 하냐?"는 이야기를 듣고 적당히 포기하기로 했다. 흑.

    Source: http://boxcatstudio.wordpress.com/2006/07/01/fps-%ea%b2%8c%ec%9e%84%ec%9d%98-%eb%b3%b5%ec%a0%9c-%ed%94%84%eb%a0%88%ec%9e%84%ec%9b%8c%ed%81%ac-%eb%b6%84%ec%84%9d/
  • 2006-06-23

    VS2005 & VS2003 함께 사용하기

    Visual Studio 2005를 설치한 다음 Visual Studio 2003을 설치하면, 우선 탐색기에서 솔루션과 프로젝트 파일에 대한 연결이 깨지며, 두번째로는 크래시 발생시 디버거 선택 창에서 VS2005 가 사라진다. 원래 VS2005에서는 이런 문제를 해결하기 위해서 Visual Studio Version Selector(%ProgramFiles%\Common Files\Microsoft Shared\MSEnv\VSLauncher.exe)를 제공하는데, 설치 순서가 바뀌는 바람에 이게 날아가는 바람에 생기는 문제들이다.

    파일 연결 복구

    파일 연결을 복구하는 것은 간단하다.

    • 솔루션이나 프로젝트 파일을 시프트+우클릭을 해서 연결 프로그램을 선택한 다음 Version Selector를 지정하면 된다.
    • 도구 - 옵션 - 환경 - 일반 에서 파일 연결 복원 버튼을 누른다.

    디버거 연결 복구

    디버거 연결을 복구하는 방법은 여러 가지가 있다.

    • 레지스트리 수정 : regedit 로 AeDebug 키를 찾은 다음 Debug 하위키를 아래와 같이 변경하면 된다.
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug\Debug
    "C:\WINDOWS\system32\vsjitdebugger.exe" -p %ld -e %ld
    • 도구 - 옵션 - 디버깅 - Just-In-Time 메뉴에서 적당히 선택한 후 저장한다.
    • 도구 - 설정 가져오기 및 내보내기에서 모두 다시 설정을 선택해도 된다.
    Source: http://boxcatstudio.wordpress.com/2006/06/23/vs2005-vs2003-%ed%95%a8%ea%bb%98-%ec%82%ac%ec%9a%a9%ed%95%98%ea%b8%b0/
    Category:programming
  • «
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • »

Author

Ray Yun(reiot)
game develper
cofounder of PICNEKO Creative

Recent Posts

  • Visual Assist X의 리팩토링 기능을 활용해보자
  • PCH(pre-compiled headers)를 이용해 빌드 시간을 최소화하기
  • operator= 는 상속되지 않는다.
  • FPS 게임의 복제 프레임워크 분석
  • VS2005 & VS2003 함께 사용하기

Recent Comments

    • Matheus Martins

      As a game developer and korean learner, i wish there was an english translation ^^

      Also, your work inspired me a lot, keep rocking!

      Rebooting Reiot · 8 years ago

    • 회멸

      좋은 글 감사합니다 =)

      Rebooting Reiot · 11 years ago

    • incago

      감사합니다

      Rebooting Reiot · 11 years ago

    • 병연 김

      와!! 감사합니다

      Rebooting Reiot · 11 years ago

    • 잉히

      잘보고 갑니다~!

      Rebooting Reiot · 11 years ago

Categories

  • blogging (1)
  • books (1)
  • columns (6)
  • database (12)
  • gamedev (15)
  • games (2)
  • link (1)
  • management (1)
  • programming (78)
  • regular (14)
  • stories (21)
  • stuff (1)
  • tip (1)
  • tip & tricks (1)

Copyright 2013 reiot.com powered by DropPress 0.2.0 and Wise Words Theme