UE4에서 일반적으로 게임 캐릭터를 생성하려면 ACharacter를 그대로 이용하거나 상속하게 된다.


다 좋은데 가장 당황스러웠던 것 중 하나가 캐릭터의 Pivot이 발끝이 아닌 전체 Mesh의 중심이었다는 점이다. (엄밀하게 말하자면 CapsuleComponent의 중심)


즉 아래 그림처럼 보이는 것인데 이 때문에 ACharacter::SetActorLocation을 하면 캐릭터가 지면에 파뭍힌다. 이후 CapsuleComponent 물리에 의해서 Solving 되기는 하지만 경우에 따라서는 Spawn 자체가 안 될 때도 있다.


 


우선 이런 상황에서도 Spawn을 하기 위해서는 FActorSpawnParameters::SpawnCollisionHandlingOverride를 AlwaysSpawn으로 전달해주면 된다. 


        FActorSpawnParameters Param;

        Param.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;


        UWorld* World = GetWorld()->SpawnActor<ACharacter>(Location, Rotation, Param);

하지만 역시 Spawn에 성공했어도 SetActorLocation을 할 때 CapsuleComponent의 높이의 절반 정도를 오프셋으로 줘야 파뭍히지 않는다. 생성한 이후 CapsuleComponent에 LocalOffset을 추가해보기도 했지만 CapsuleComponent 자체가 이미 Root이기 때문에 이동할 때마다 파뭍히는 모습을 볼 수 있었다.

그래서 CapsuleComponent를 Root로 하지 말고 계층구조를 바꿔보기로 했고 현재까지는 별 문제 없이 성공한 것 같다.

  1. 아무 기능도 없는 UActorComponent를 만든다. (ex: UNullComponent)
  2. Tick 함수를 끄기 위해 PrimaryComponentTick.bCanEverTick를 false로 해준다. 
  3. ACharacter를 상속받은 C++ 클래스를 만든다. (ex: AMyCharacter)
  4. AMyCharacter 생성자에서 UNullComponent를 만든다.
  5. ACharacter 생성자에서 만들어졌던 Component들의 부모를 4에서 만든 UNullComponent로 변경한다.
  6. RootComponent를 UNullComponent로 변경한다.
  7. Blueprint나 코드에서 CapsuleComponent의 오프셋을 변경해준다.

 

    USceneComponent* OldRoot = RootComponent;


    TArray<UActorComponent*> ExistComponents = GetComponentsByClass(USceneComponent::StaticClass());

    RootComponent = Initializer.CreateDefaultSubobject<UNullComponent>(this, "Root");


    OldRoot->SetupAttachment(RootComponent);


    for (UActorComponent* P : ExistComponents)

    {

        USceneComponent* SceneComponent = Cast<USceneComponent>(P);

        if (SceneComponent->GetAttachParent() == OldRoot)

        {

            SceneComponent->DetachFromComponent(FDetachmentTransformRules::KeepRelativeTransform);

            SceneComponent->SetupAttachment(RootComponent);

        }

    }




정정

Mesh가 CapsuleComponent의 자식이 되지 않으면 CapsuleComponent가 물리에 의해 떨어지거나 할 때 Mesh가 따라가지 않는다. 따라서 기존의 Root였던 CapsuleComponent를 그대로 UNullComponent의 자식으로 변경하였다. 코드는 아래 3줄로...


    USceneComponent* OldRoot = RootComponent;

    RootComponent = Initializer.CreateDefaultSubobject<UWsNullComponent>(this, "Root");

    OldRoot->SetupAttachment(RootComponent);






2017.06.24 추가

CapsuleComponent가 물리에 의해 떨어져도 RootComponent 위치가 반영되지 않는듯
물리 위치 변경이 있을 때 Callback을 받을 수 있는지 확인 중


신고
받은 트랙백이 없고 , 댓글이 없습니다.
secret