인프런 커뮤니티 질문&답변

서한울님의 프로필 이미지
서한울

작성한 질문수

이득우의 언리얼 프로그래밍 Part2 - 언리얼 게임 프레임웍의 이해

3강 캐릭터 컨트롤 설정

3강에서 시점 변경 부분이요

작성

·

286

0

시점 변경 전까지 정상 적으로 작동 되었는데 변경 후부터
움직임도 먹통이고 해서 이것저것 수정하다가

 

ACharacterPlayer::ACharacterPlayer()
{
	// 카메라 붐 생성 (충돌이 있으면 플레이어 쪽으로 당겨짐)
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);
	CameraBoom->TargetArmLength = 400.0f; // 카메라가 캐릭터 뒤에서 이 거리만큼 따라갑니다
	CameraBoom->bUsePawnControlRotation = true; // 컨트롤러를 기반으로 암을 회전시킵니다

	// 팔로우 카메라 생성
	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
	FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // 카메라를 붐 끝에 부착하고 붐이 컨트롤러 방향에 맞춰 조정되도록 합니다
	FollowCamera->bUsePawnControlRotation = false; // 카메라는 암과 상대적으로 회전하지 않습니다
	
	//Jump Input Action을 찾습니다.
	static ConstructorHelpers::FObjectFinder<UInputAction> InputActionJumpRef(TEXT("/Script/EnhancedInput.InputAction'/Game/KoreaSoul/Input/Actions/IA_Jump.IA_Jump'"));
	if (nullptr != InputActionJumpRef.Object)
	{
		JumpAction = InputActionJumpRef.Object; 
	}
	static ConstructorHelpers::FObjectFinder<UInputAction> InputChangeActionControlRef(TEXT("/Script/EnhancedInput.InputAction'/Game/KoreaSoul/Input/Actions/IA_ChangeControl.IA_ChangeControl'"));
	if (nullptr != InputChangeActionControlRef.Object)
	{
	     ChangeControlAction = InputChangeActionControlRef.Object; 
	}
	// ShoulderMove Input Action
	static ConstructorHelpers::FObjectFinder<UInputAction> ShoulderMoveActionRef(TEXT("/Script/EnhancedInput.InputAction'/Game/KoreaSoul/Input/Actions/IA_ShoulderMove.IA_ShoulderMove'"));
	if (nullptr != ShoulderMoveActionRef.Object)
	{
		ShoulderMoveAction = ShoulderMoveActionRef.Object; 
	}

	// ShoulderMoveLook Input Action
	static ConstructorHelpers::FObjectFinder<UInputAction> ShoulderMoveActionLookRef(TEXT("/Script/EnhancedInput.InputAction'/Game/KoreaSoul/Input/Actions/IA_ShoulderLook.IA_ShoulderLook'"));
	if (nullptr != ShoulderMoveActionLookRef.Object)
	{
		ShoulderLookAction = ShoulderMoveActionLookRef.Object; 
	}

	// QuaterMove Input Action
	static ConstructorHelpers::FObjectFinder<UInputAction> QuaterMoveActionRef(TEXT("/Script/EnhancedInput.InputAction'/Game/KoreaSoul/Input/Actions/IA_QuaterMove.IA_QuaterMove'"));
	if (nullptr != QuaterMoveActionRef.Object)
	{
		QuaterMoveAction = QuaterMoveActionRef.Object; 
	}

	CurrentCharacterControlType = ECharacterControlType::Quater;
}

void ACharacterPlayer::BeginPlay()
{
	// 부모 클래스의 BeginPlay 함수를 호출합니다.
	Super::BeginPlay();

	SetCharacterControl(CurrentCharacterControlType);
}

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

	// PlayerInputComponent를 UEnhancedInputComponent로 캐스팅합니다.
	UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent);

	// 점프 액션을 트리거 이벤트에 바인딩합니다.
	// JumpAction이 발생하면 ACharacter의 Jump 함수를 호출합니다.
	EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &ACharacter::Jump);
	EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::StopJumping);

	EnhancedInputComponent->BindAction(ChangeControlAction, ETriggerEvent::Triggered, this, &ACharacterPlayer::ChangeCharacterControl);

	// MoveAction이 발생하면 ACharacterPlayer의 Move 함수를 호출합니다.
	EnhancedInputComponent->BindAction(ShoulderMoveAction, ETriggerEvent::Triggered, this, &ACharacterPlayer::ShoulderMove);
	EnhancedInputComponent->BindAction(ShoulderLookAction, ETriggerEvent::Triggered, this, &ACharacterPlayer::ShoulderLook);
	EnhancedInputComponent->BindAction(QuaterMoveAction, ETriggerEvent::Triggered, this, &ACharacterPlayer::QuaterMove);

	Controller = GetController();  // 컨트롤러 초기화

	// 바인딩 확인용 로그 추가
	UE_LOG(LogTemp, Warning, TEXT("InputComponent bound successfully"));
}

void ACharacterPlayer::ChangeCharacterControl()
{
	UE_LOG(LogTemp, Warning, TEXT("ChangeCharacterControl called"));

	if (CurrentCharacterControlType == ECharacterControlType::Quater)
	{
		SetCharacterControl(ECharacterControlType::Shoulder);
	}
	else if (CurrentCharacterControlType == ECharacterControlType::Shoulder)
	{
		SetCharacterControl(ECharacterControlType::Quater);
	}

	// SetupPlayerInputComponent를 다시 호출하여 새로운 입력 맵핑을 적용합니다.
	SetupPlayerInputComponent(InputComponent);
	// 상태 변경 로그 추가
	UE_LOG(LogTemp, Warning, TEXT("Control type changed to %s"), CurrentCharacterControlType == ECharacterControlType::Quater ? TEXT("Quater") : TEXT("Shoulder"));
}


void ACharacterPlayer::SetCharacterControl(ECharacterControlType NewCharacterControlType)
{
	// CharacterControlManager 맵에서 NewCharacterControlType 키에 해당하는 값을 검색합니다.
	UCharacterControlData* NewCharacterControl = CharacterControlManager[NewCharacterControlType];

	// 검색된 NewCharacterControl이 유효한 값인지 확인합니다.
	check(NewCharacterControl);

	// 가져온 CharacterControlData를 적용합니다.
	SetCharacterControlData(NewCharacterControl);

	APlayerController* PlayerController = CastChecked<APlayerController>(GetController());
	if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
	{
		Subsystem->ClearAllMappings();
		UInputMappingContext* NewMappingContext = NewCharacterControl->InputMappingContext;
		if (NewMappingContext)
		{
			Subsystem->AddMappingContext(NewMappingContext, 0);
		}
	}

	// 현재 캐릭터 컨트롤 타입을 새로운 타입으로 설정합니다.
	CurrentCharacterControlType = NewCharacterControlType;

	UE_LOG(LogTemp, Warning, TEXT("Character control changed to %s"), NewCharacterControlType == ECharacterControlType::Quater ? TEXT("Quater") : TEXT("Shoulder"));
}

void ACharacterPlayer::SetCharacterControlData(const UCharacterControlData* CharacterControlData)
{
	// 각 프로퍼티를 CharacterControlData 값으로 설정합니다.
	Super::SetCharacterControlData(CharacterControlData);

	CameraBoom->TargetArmLength = CharacterControlData->TargetArmLength; // 대상의 팔 길이를 설정합니다.
	CameraBoom->SetRelativeRotation(CharacterControlData->RelativeRotator); // 상대 각도를 설정합니다.
	CameraBoom->bUsePawnControlRotation = CharacterControlData->bUsePawnControlRotation; // 폰의 제어 회전을 사용하는지 설정합니다.
	CameraBoom->bInheritPitch = CharacterControlData->bInheritPitch; // Pitch 상속을 사용하는지 설정합니다.
	CameraBoom->bInheritYaw = CharacterControlData->bInheritYaw; // Yaw 상속을 사용하는지 설정합니다.
	CameraBoom->bInheritRoll = CharacterControlData->bInheritRoll; // Roll 상속을 사용하는지 설정합니다.
	CameraBoom->bDoCollisionTest = CharacterControlData->bDoCollisionTest; // 충돌 검사를 수행하는지 설정합니다.

	UE_LOG(LogTemp, Warning, TEXT("Character control data set"));
}

void ACharacterPlayer::ShoulderMove(const FInputActionValue& Value)
{
	// 입력 값에서 2D 이동 벡터를 가져옵니다.
	FVector2D MovementVector = Value.Get<FVector2D>();

	// 컨트롤러가 유효한지 확인합니다.
	if (Controller)
	{
		// 컨트롤러의 현재 회전값을 가져옵니다.
		const FRotator Rotation = Controller->GetControlRotation();
		// Yaw(좌우 회전)만 사용하여 회전 값을 만듭니다.
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		// 회전 매트릭스를 사용하여 전방 방향 벡터를 구합니다.
		const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		// 회전 매트릭스를 사용하여 오른쪽 방향 벡터를 구합니다.
		const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);

		// 입력 값에 따라 전방 방향으로 이동을 추가합니다.
		AddMovementInput(ForwardDirection, MovementVector.X);
		// 입력 값에 따라 오른쪽 방향으로 이동을 추가합니다.
		AddMovementInput(RightDirection, MovementVector.Y);
	}

	UE_LOG(LogTemp, Warning, TEXT("ShoulderMove called"));
}

void ACharacterPlayer::ShoulderLook(const FInputActionValue& Value)
{
	// 입력 값에서 2D 회전 벡터를 가져옵니다.
	FVector2D LookVector = Value.Get<FVector2D>();

	// 컨트롤러가 유효한지 확인합니다.
	if (Controller)
	{
		// 입력 값에 따라 컨트롤러의 회전 값을 변경합니다.
	
		AddControllerYawInput(LookVector.Y);
		AddControllerPitchInput(LookVector.X);
	}

	UE_LOG(LogTemp, Warning, TEXT("ShoulderLook called: Yaw=%f, Pitch=%f"), LookVector.X, LookVector.Y);

}

void ACharacterPlayer::QuaterMove(const FInputActionValue& Value)
{
	// 이동 벡터를 생성합니다. 입력 값으로부터 FVector2D 타입을 가져옵니다.
	FVector2D MovementVector = Value.Get<FVector2D>();

	// 입력 값의 제곱의 크기입니다.
	float InputSizeSquared = MovementVector.SquaredLength();

	// 이동 벡터의 크기를 기본값 1로 설정합니다.
	float MovementVectorSize = 1.f;

	// 이동 벡터의 제곱 크기입니다.
	float MovementVectorSizeSquared = MovementVector.SquaredLength();

	// 이동 벡터의 제곱 크기가 1을 초과하는 경우
	if (MovementVectorSizeSquared > 1.0f)
	{
		// 이동 벡터를 정규화합니다.
		MovementVector.Normalize();
        
		// 이동 벡터의 제곱 크기를 1로 설정합니다.
		MovementVectorSizeSquared = 1.f;
	}
	else
	{
		// 이동 벡터의 크기를 이동 벡터의 제곱 크기의 제곱근으로 설정합니다.
		MovementVectorSize = FMath::Sqrt(MovementVectorSizeSquared);
	}

	// 이동 방향을 설정합니다. 입력 벡터의 x, y를 사용하고 z를 0으로 설정합니다.
	FVector MoveDirection = FVector(MovementVector.X, MovementVector.Y, 0.0f);

	// 캐릭터 생성자의 컨트롤러에 이동 방향의 로테이터를 설정합니다.
	GetController()->SetControlRotation(FRotationMatrix::MakeFromX(MoveDirection).Rotator());

	// 이동 입력을 추가합니다. 이동 방향과 이동 벡터의 크기를 인자로 사용합니다.
	AddMovementInput(MoveDirection, MovementVectorSize);

	UE_LOG(LogTemp, Warning, TEXT("QuaterMove called: X=%f, Y=%f"), MovementVector.X, MovementVector.Y);
}

일단 여기까지 고쳤는데 마우스 동작도 안되고
방향키는 전부 반대로 되어있고
v키를 눌러도 숄더로 돌아가서 다시 안돌아옵니다
3시간동안 헤맸는데 도저히 모르겠어요

답변 1

0

이득우님의 프로필 이미지
이득우
지식공유자

아.. 코드가 너무 길어서 저도 이렇게만 봐서는 문제를 찾기가 어렵네요.
우선 3강에 대한 완성된 소스가 있으니 받으신 후에 비교해보심이 어떠실까요?
https://github.com/ideugu/UnrealProgrammingPart2/tree/3

서한울님의 프로필 이미지
서한울
질문자

네 감사합니다

 

서한울님의 프로필 이미지
서한울

작성한 질문수

질문하기