Pawn에 Possess 하기

2025. 1. 31. 21:12·내배캠/Unreal Engine
플레이어가 드론을 조종하거나 탈 것을 타고 이동을 할 때, PlayerController가 다른 Pawn에 Possess해야 한다.
드론을 예시로 플레이어에게 Possess 되어있는 Controller를 드론으로 전환하는 과정을 정리하려한다.

 

📍AController::Possess(APawn* InPawn) 에 관하여

이 함수는 final로 선언되어 있기 때문에 자식 클래스에서 오버라이드 할 수 없다.

기본적인 소유권 전환 로직이 매우 중요하고, 이를 안전하게 보호하기 위해 엔진 레벨에서 변경이 불가능하도록 설계된 것이다.
언리얼 엔진은 Possess의 핵심로직(소유권 전환, 네트워크 복제, 상태 동기화 등)을 보장하기 위해 엔진 내부에서만 이로직이 작동하도록 제한했다.

이로 인해 직접 오버라이드할 수 없고, 대신 엔진이 제공하는 후처리 이벤트 함수 AController::OnPossess(APawn* InPawn)를 사용해야한다.
OnPossess함수는 Possess가 호출된 후 자동으로 호출되고, 이는 소유권 전환 이후의 로직을 여기서 처리하도록 유도하는 것이다.

 


📌 Player Chracter.cpp

APlayerCharacter::APlayerCharacter()
{
	InteractionSphere = CreateDefaultSubobject<USphereComponent>(TEXT("InteractionSphere"));
	InteractionSphere->SetupAttachment(RootComponent);
	InteractionSphere->OnComponentBeginOverlap.AddDynamic(this, &APlayerCharacter::OnOverlapBegin);
	InteractionSphere->OnComponentEndOverlap.AddDynamic(this, &APlayerCharacter::OnOverlapEnd);

	bIsPossess = true;
}

void APlayerCharacter::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (OtherActor && OtherActor->IsA(ADrone::StaticClass()))
	{
		Drone = Cast<ADrone>(OtherActor);
	}
}

void APlayerCharacter::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	if (OtherActor && OtherActor == Drone)
	{
		Drone = nullptr;
	}
}

✅ SphereComponent에 이벤트 바인딩

  1. 오버랩된 객체가 드론이라면, 멤버 변수 Drone에 OtherActor를 ADrone으로 캐스팅하여 저장
  2. 오버랩이 끝났을 때, Drone에 nullptr 저장

 

void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	if (UEnhancedInputComponent* EnhancedInput = Cast<UEnhancedInputComponent>(PlayerInputComponent))
	{
		if (AStrikeZonePlayerController* PlayerController = Cast<AStrikeZonePlayerController>(GetController()))
		{
			if (PlayerController->InteractAction)
			{
				EnhancedInput->BindAction(PlayerController->InteractAction, ETriggerEvent::Triggered, this, &APlayerCharacter::Interaction);
			}
		}
	}
}

void APlayerCharacter::Interaction(const FInputActionValue& Value)
{
	if (Drone)
	{
		Drone->Interact(this);
		bIsPossess = false;
	}
}

✅ 상호작용 키 바인딩

  1. Drone의 멤버함수 Interact에 PlayerCharacter을 매개변수로 전달하며 호출
  2. bIsPossess 변수는 캐릭터가 현재 PlayerController에 Possess된 상태인지 여부를 반환
더보기
UFUNCTION(BlueprintPure)
bool IsPlayerPossess() const { return bIsPossess; }
  • bIsPossess를 반환해, ABP의 Event Graph에서 현재 캐릭터에 Possess 되어있는 상태인지 확인
  • Possess 되어있지 않다면 드론 조종하는 애니메이션 적용

 


📌Drone.cpp

void ADrone::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	if (UEnhancedInputComponent* EnhancedInput = Cast<UEnhancedInputComponent>(PlayerInputComponent))
	{
			if (PlayerController->D_UnpossessAction)
			{
				EnhancedInput->BindAction(PlayerController->D_UnpossessAction, ETriggerEvent::Triggered, this, &ADrone::StopPossess);
			}
		}
	}
}

void ADrone::StopPossess()
{
	AController* PlayerController = GetController();
	if (PlayerController)
	{
		PlayerController->UnPossess();
		PlayerController->Possess(PlayerCharacter);
		PlayerCharacter->bIsPossess = true;
	}
}

void ADrone::Interact(APlayerCharacter* Player)
{
	PlayerCharacter = Player;
	AController* PlayerController = Player->GetController();
	if (PlayerController)
	{
		PlayerController->Possess(this);
	}
}

✅ Drone에게 Player가 상호작용

  1. 캐릭터에서 Interact 함수 호출
  2. 멤버변수 PlayerCharacter에 매개변수로 전달받은 Player저장
  3. 컨트롤러에 Drone을 Possess

✅ Drone에서 컨트롤러 해제 후 플레이어에게  Possess

  1. UnPossess 함수를 호출해 연결 해제
  2. 저장되있는 PlayerCharacter에게 Possess
  3. 원래의 애니메이션으로 돌아올 수 있도록 캐릭터의 멤버변수 bIsPossess에 true 저장

📌PlayerController.cpp

void APlayerController::BeginPlay()
{
	Super::BeginPlay();

	InitalizeDefaultInputContext();
}

void APlayerController::OnPossess(APawn* InPawn)
{
	Super::OnPossess(InPawn);

	UpdateInputPriority(InPawn);
}

void APlayerController::InitalizeDefaultInputContext()
{
	if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem =
			LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
		{
			if (PlayerInputMappingContext)
			{
				Subsystem->AddMappingContext(PlayerInputMappingContext, 0);
			}
		}
	}
}

void APlayerController::UpdateInputPriority(APawn* ControlledPawn)
{
	if (!ControlledPawn) return;

	if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem =
			LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
		{
			if (ControlledPawn->IsA<APlayerCharacter>())
			{
				Subsystem->RemoveMappingContext(DroneInputMappingContext);
				Subsystem->AddMappingContext(PlayerInputMappingContext, 0);
			}
			else if (ControlledPawn->IsA<ADrone>())
			{
				Subsystem->RemoveMappingContext(PlayerInputMappingContext);
				Subsystem->AddMappingContext(DroneInputMappingContext, 0);
			}
		}
	}
}

✅ Possess된 대상에 맞춰 Input Mapping Context 변경

  1. 게임이 시작되면 InitializeDefaultInputContext 함수로 플레이어 IMC를 등록
  2. AController::Possess → 컨트롤러가 새로운 Pawn을 소유하도록 설정하는 함수
  3. AController::OnPossess → Possess가 성공적으로 실행된 후에 자동으로 호출되는 콜백 함수
    Possess 과정에서 소유권이 변경 완료된 직후 호출되기 때문에, 초기화 작업이나 입력설정 같은 작업 이후 로직에 적합
  4. UpdateInputPriority 함수로 IMC 전환

📍 애니메이션 적용

UFUNCTION(BlueprintPure)
bool IsPlayerPossess() const { return bIsPossess; }

PlayerCharacter에서 만들어둔 IsPlayerPossess 함수로 현재 컨트롤러가 캐릭터에게 Possess가 되어있는지 확인하고, 맞다면 Remote Drone 애니메이션을 적용

 

'내배캠 > Unreal Engine' 카테고리의 다른 글

캐릭터 데미지 적용  (0) 2025.02.04
가비지 컬렉션과 메모리 관리  (0) 2025.01.31
데이터 에셋과 데이터 테이블  (0) 2025.01.28
인터페이스 기반 아이템 클래스 구현_2_아이템 스폰 및 레벨 데이터 관리  (0) 2025.01.27
데이터 테이블에 사용할 구조체 만들기  (0) 2025.01.27
'내배캠/Unreal Engine' 카테고리의 다른 글
  • 캐릭터 데미지 적용
  • 가비지 컬렉션과 메모리 관리
  • 데이터 에셋과 데이터 테이블
  • 인터페이스 기반 아이템 클래스 구현_2_아이템 스폰 및 레벨 데이터 관리
동그래님
동그래님
  • 동그래님
    개발자 동그래
    동그래님
  • 전체
    오늘
    어제
    • 분류 전체보기 (210)
      • 공부 (51)
        • Code Cata (50)
      • 내배캠 (151)
        • TIL (50)
        • C++ (37)
        • Unreal Engine (48)
        • GAS(Gameplay Ability System.. (16)
      • Project (7)
        • Gunfire Paragon (5)
        • Arena Fighters (1)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.3
    동그래님
    Pawn에 Possess 하기
    상단으로

    티스토리툴바