GoW3 에서의 커버

GoW3 에서의 커버는 GoW2 것과 크게 다르지 않다. 기본적인 구조는 여기 를 보면 되고

대신 다음의 변경점이 생겼다.

  • CoverSlot 이 CoverSlotMarker 에 의해 옥트리에서 관리되던 것이 사라지고 NavMeshPolyBase 에서 관리되어진다. (CoverSlotMarker 가 삭제됨)
  • 커버에서 수행 가능한 액션의 여부를 Scout 가 판별한다. 이전엔 판별 로직이 CoverLink 안에 존재하였다.

커버의 Path Build

커버에서는 slip, mantle, swatturn, 등의 다양한 액션을 취할 수 있다. 하지만 설치된 커버와 주변 환경과의 이해관계에 따라 이 중에서 수행하지 못하는 액션도 있을 것이다.

예를 들어 높은 장애물에서는 mantle 을 하지 못할 것이고 장애물의 가장자리가 아니라면 slip 이나 swatturn 의 행동을 할 수 없을 것이다.

GoW3 에서는 이런 액션의 가능 여부를 실시간으로 계산하는 것이 아니라 에디터에서 미리 계산하여 해당 커버에 플래그 형태로 저장해 둔다.1)

그리고 런타임에는 이 플래그를 조회하여 현재 커버에서 수행할 수 있는 액션들을 가려낸다.

에디터에서 커버를 빌드하는 방법은 크게 두가지가 있는데

  • 상단에 위치한 PathBuild 버튼을 클릭했을 경우
    • WxEditorFrame::MeshBuild → FEditorBuildUtils::EditorBuild
    • FPathBuilder::BuildPaths → FPathBuild::Exec
    • AGearScout::Exec → AScout::Exec
    • AScout::BuildCover
    • ACoverLink::BuildSlotInfo → ACoverLink::BuildSlotInfoInternal
  • 마우스 Middle 버튼을 클릭했을 경우
    • FEditorModeTools::InputKey
    • FEdModeCoverEdit::InputKey
    • ACoverLink::BuildSlotInfo → ACoverLink::BuildSlotInfoInternal

두가지 경우 모두 ACoverLink::BuildSlotInfoInternal 함수로 들어오는데

UnCover.cpp
void ACoverLink::BuildSlotInfoInternal( ... )
{
    ...
    if ( Slot.bCanMantle )
    {
        Slot.bCanMantle = Scout->CanDoMove( TEXT("MANTLE"), this, SlotIdx, bSeedPylon );   // Scout 에게 mantle 액션 가능여부 판별토록 위임.
    }
 
    // 이하 다른 액션들도 마찬가지
    ...
}

위와 같이 Scout 에게 위임한다. 이어서 GearScout 를 보면

GearPath.cpp
UBOOL AGearScout::CanDoMove( ... )
{
    ...
    ACoverLink* Link = Cast<ACoverLink>( Nav );
    if ( ParseCommand( &Str, TEXT("MANTLE") ) )
    {
        ...
        return CanMantle( SlotLocation, SlotRotation, 0, Link );   // mantle 여부 체크
    }
    ...
}
 
UBOOL AGearScout::CanMantle( ... )
{
    ... // 블라블라
}

이런 식으로 되어 있다.

2012/02/07 00:19 · z3moon

Cover 의 Edit

에디터에서 커버를 편집하는 방식과 그에 따른 코드 흐름에 대해 알아본다.

편집 방식

코드 흐름

에디터에서 특정 대상을 편집하는 것에 대한 정의는 UnrealEd 프로젝트에 UnEdModes.h 와 UnEdModes.cpp 에 있다.

코드를 보면 알겠지만 Cover 이외 다양한 오브젝트들의 에디트 방식을 여기서 정의하고 있다.2)

UnEdModes.h
enum EEditorMode
{
    EM_None,
    EM_Default,
    EM_TerrainEdit,
    EM_Geometry,
    EM_StaticMesh,
    ...
    EM_CoverEdit,             // 여기서 에디트모드 타입 추가
    ...
};
 
...
 
class FEdModeCoverEdit : public FEdMode
{
private:
    UBOOL bCanAltDrag;
    UBOOL bTabDown;
    ACoverLink* LastSelectedCoverLink;
    FCoverSlot* LastSelectedCoverSlot;
 
public:
    FEdModeCoverEdit();
    virtual ~FEdModeCoverEdit();
 
    virtual void Enter();                          // 선택 되었을 경우 발생하는 이벤트.
    virtual void Exit();                           // (선택된 상태에서) 포커스가 해제된 경우 발생하는 이벤트
 
    virtual UBOOL InputKey( ... );                 // 키(마우스포함) 를 눌렀을 경우 발생하는 이벤트
    virtual UBOOL InputDelta( ... );               // 오브젝트를 이동/회전/확대 할 경우 발생하는 이벤트
    virtual void ActorSelectionChangeNotify();     // 선택 되었을 경우 발생하는 이벤트. 마지막으로 선택된 CoverLink 를 캐싱해둔다.
    virtual UBOOL UsesTransformWidget();
    virtual UBOOL UsesTransformWidget( ... );      // Space 로 에디트모드를 변경할 경우 (이동/회전/확대) 발생하는 이벤트
    virtual FVector GetWidgetLocation();           // 현재 오브젝트의 위치를 리턴.
    virtual UBOOL HandleDragDuplicate();           // Alt 드래그로 오브젝트를 복제할 경우 발생하는 이벤트
    virtual UBOOL HandleDuplicate();               // 오브젝트 복제가 일어날 때 발생하는 이벤트. UUnrealEdEngine::Exec_Actor 에서 "DUPLICATE" 신호
    virtual UBOOL HandleClick( ... );              // 화면에 마우스 클릭 시 발생하는 이벤트
    virtual void DrawHUD( ... );                   // UI 표시
};

GetWidgetLocation 함수는 화면에 위젯을 그리기 위해 현재 선택한 오브젝트의 위치를 얻기 위한 용도로 사용된다.

UnWidget.cpp
void FWidget::Render( ... )
{
    ...
 
    // 위치를 얻어서
    FVector Loc = GEditorModeTools().GetWidgetLocation();
 
    // 현재 에디트 모드에 따라 적당한 위젯을 그린다.
    switch ( GEditorModeTools().GetWidgetMode() )
    {
        case WM_Translate:
            Render_Translate( View, PDI, Loc, bDrawWidget );
            break;
 
        case WM_Rotate:
            Render_Rotate( View, PDI, Loc, bDrawWidget );
            break;
 
        case WM_Scale:
            Render_Scale( View, PDI, Loc, bDrawWidget );
            break;
 
            ...
    }
    ...
}
2012/02/07 01:15 · z3moon
1) CoverLink.uc 에 CoverSlot 구조체 참조
2) 새로운 타입의 오브젝트를 구현했고 이것을 에디터에서 편집하고 싶다면 Cover 에디트 방식을 참고하여 구현하면 될 것이다.