UE5 Issues : 캐릭터 아이템 획득 로직 구현

2025. 2. 24. 23:53·Unreal Engine

이번 구현의 목적은 캐릭터가 화면의 중심으로 원하는 아이템을 하나만 선택해서 획득할 수 있도록 하는 것이다.

그림으로 나타내면 아래와 같은 느낌이다.

말로 정리해 보자면,

  • 아이템을 랜덤하게 스폰해주는 상자가 존재
    • 이 상자는 collision을 가지고 있어서 해당 collision 안으로 들어가게 되면, 캐릭터의 시점으로 line trace 시작
    • collision 밖으로 나오면 line trace 꺼주기
  • line trace를 통해서 아이템을 peeking 하게되면, 해당 아이템에 UI가 뜨게 되고 획득 가능한 상태가 된다.
    • 만약 아이템 peeking이 끝나면, UI도 꺼지고 아이템 획득도 불가능한 상태
  • 이후 F키를 누르면 아이템 획득이 가능한 시스템

 

1. 상자 로직


상자의 기본 로직은 다른 조원분이 구현해 주셨고, 나는 collision에 overlap된 순간 캐릭터가 linetrace를 시작할 수 있도록 함수를 추가해 주었다.

  • 아래 코드에서 overlap 시작 시 call되는 StartPeek()와 overlap이 끝날 때 call되는 StopPeek() 함수이다.
  • 각 함수는 캐릭터에서 linetrace가능 여부를 판단하는 bool 값 변수를 바꿔주는 함수이다.
void AChest::OnPlayerOverlapBegin(
	UPrimitiveComponent* OverlappedComponent,
	AActor* OtherActor,
	UPrimitiveComponent* OtherComp,
	int32 OtherBodyIndex,
	bool bFromSweep,
	const FHitResult& SweepResult)
{
	
	if (OtherActor && OtherActor->IsA(APlayerCharacter::StaticClass()))
	{
		
		bPlayerInRange = true;
		bCanOpenChest = true;
		OpenChest();
		APlayerCharacter* PlayerCharacter = Cast<APlayerCharacter>(OtherActor);

		if (PlayerCharacter)
		{
			PlayerCharacter->StartPeek();
		}
	}
}

void AChest::OnPlayerOverlapEnd(
	UPrimitiveComponent* OverlappedComponent,
	AActor* OtherActor,
	UPrimitiveComponent* OtherComp,
	int32 OtherBodyIndex)
{
	if (OtherActor && OtherActor->IsA(APlayerCharacter::StaticClass()))
	{
		bPlayerInRange = false; 
		bCanOpenChest = false;

		APlayerCharacter* PlayerCharacter = Cast<APlayerCharacter>(OtherActor);

		if (PlayerCharacter)
		{
			PlayerCharacter->StopPeek();
		}
	}
}
  • StopPeek 함수의 경우 추가적인 구현이 되어있는데, 이것은 UI 관련 예외처리를 위해서이다.
    • PeekingItem이 있는 경우 상자의 Collision을 벗어났을 때 linetrace는 끝나서 PeekingItem이 없어져야 하지만
    • if(PeekingItem) 아래 코드가 없는 경우 PeekingItem이 유지되는 버그를 수정한 내용이다.
void APlayerCharacter::StartPeek()
{
	bCanTraceForItemPeeking = true;
}

void APlayerCharacter::StopPeek()
{
	bCanTraceForItemPeeking = false;

	if (PeekingItem)
	{
		if (Cast<AWeapon>(PeekingItem))
		{
			Cast<AWeapon>(PeekingItem)->bIsPeeking = false;
		}
		if (Cast<ABaseItem>(PeekingItem))
		{
			Cast<ABaseItem>(PeekingItem)->bIsPeeking = false;
		}
	}
}

 

 

2. 캐릭터 로직


캐릭터는 Tick 에서 위에서 말한 bool 변수에 따라 line trace를 하게 된다.

void APlayerCharacter::Tick(float DeltaTime)
{
	if (bCanTraceForItemPeeking)
		BeginTraceForPickItem();
	....
}

 

line trace를 하는 함수는 아래와 같다. 이 함수는 화면의 중심점에서 시야 방향으로 linetrace를 쏘는 기능을 한다.

DeprojectScreenPositionToWorld() 와 LineTraceSingleByChannel()를 사용해서 구현하였다.

  • 해당 함수는 화면 중심에서 line trace를 쏴서 hit 되는 경우
  • PeekingItem 이라는 포인터 변수에 해당 Actor를 저장하게 된다.
  • 원래 if(bHit) 인 경우 각 아이템이 가지고 있는 ShowUI라는 함수를 통해 UI가 보이도록 구현하였다.
  • 그러나 이렇게 구현된 경우 peeking이 끝났을 때 UI가 꺼지지 않아 ShowUI를 각 아이템 클래스의Tick에서 Call하도록 수정하였다. (아래 코드가 수정된 버전의 코드)
void APlayerCharacter::BeginTraceForPickItem()
{
	//trace 하기
	APlayerCharacterController* PlayerController = Cast<APlayerCharacterController>(GetController());
	if (PlayerController)
	{
		int32 ScreenWidth;
		int32 ScreenHeight;

		PlayerController->GetViewportSize(ScreenWidth, ScreenHeight);
		const FVector2D ScreenCenter(ScreenWidth * 0.5f, ScreenHeight * 0.5f);

		FVector WorldLocation;
		FVector WorldDirection;
		if (PlayerController->DeprojectScreenPositionToWorld(ScreenCenter.X, ScreenCenter.Y, WorldLocation, WorldDirection))
		{
			FVector TraceStart = WorldLocation + WorldDirection * 100.f;
			FVector TraceEnd = TraceStart + (WorldDirection * 10000.f);

			FHitResult HitResult;
			FCollisionQueryParams TraceParams;
			TraceParams.AddIgnoredActor(this);

			bool bHit = GetWorld()->LineTraceSingleByChannel(HitResult, TraceStart, TraceEnd, ECC_Visibility, TraceParams);

			/*FColor LineColor = bHit ? FColor::Red : FColor::Blue;
			DrawDebugLine(GetWorld(), TraceStart, TraceEnd, LineColor, false, 2.0f, 0, 2.0f);*/

			if (bHit)
			{						
				PeekingItem = HitResult.GetActor();				
			}
		}
	}
}

 

어려움을 겪었던 부분이 캐릭터가 peeking을 하지 않는 아이템은 UI를 꺼주는 부분인데 이 부분은 아이템의 Tick을 활용해서 구현하였다.

 

 

3. 아이템 로직


아이템에서는 Tick함수를 통해 ShowUI와 StopUI를 사용하게 된다.

  • 주의점은 계속해서 bIsPeeking = false 를 해주어야 한다는 점이다.
void AWeapon::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    if (bIsPeeking)
        ShowUI();
    else
        StopUI();

    bIsPeeking = false;
}
  • bIsPeeking 변수는 캐릭터에서 Tick을 통해 변경해준다. (아래 캐릭터 Tick 함수 코드 참고)
void APlayerCharacter::Tick(float DeltaTime)
{
	if (bCanTraceForItemPeeking)
		BeginTraceForPickItem();

	if (PeekingItem && bCanTraceForItemPeeking)
	{
		if (PeekingItem->ActorHasTag("Weapon"))
			Cast<AWeapon>(PeekingItem)->bIsPeeking = true;
		if (PeekingItem->ActorHasTag("Item"))
			Cast<ABaseItem>(PeekingItem)->bIsPeeking = true;
	}
}

 

 

4. 최종 로직


마지막으로 캐릭터가 PeekingItem이 있는 경우 캐릭터의 Input Action과 연동되어있는 PickUp 함수를 call해주면 된다.

void APlayerCharacter::PickUp(const FInputActionValue& value)
{
	if (PeekingItem != nullptr)
	{
		if (PeekingItem->ActorHasTag("Weapon"))
		{
			EquipWeaponBack();
			PeekingItem->Destroy();
		}
		else if(PeekingItem->ActorHasTag("Item"))
		{
			PickUpItem();
			PeekingItem->Destroy();
		}
	}
}

 

정리하자면,

  • 캐릭터는 상자 Collision과 overlap 된 상황에 따라 bCanTraceForItemPeeking 값이 변하게 되고
  • bCanTraceForItemPeeking 값에 따라 BeginTraceForPickItem() 함수를 실행한다.
  • 만약 BeginTraceForPickItem 함수 안에서 hit된 물체가 있는 경우 PeekingItem 이라는 변수에 해당 Actor값을 저장한다.
  • 이후 캐릭터 Tick에서 PeekingItem이 존재하고, BeginTraceForPickItem함수가 실행되는 도중이라면, 아이템이 가지고 있는 bIsPeeking 변수를 true로 만들어 준다.
  • 아이템의 Tick에서는 bIsPeeking 변수가 true인 경우 ShowUI 함수를 통해 UI를 켜주고, 바로 bIsPeeking을 false로 바꿔준다.
  • 캐릭터의 경우 PeekingItem이 존재하고, F 키를 눌러 PickUp함수가 실행된 경우 아이템
    • 캐릭터에 부착하거나 -> EquipWeaponback() 함수
    • 획득한다. -> PickUpItem() 함수

최종 동작 모습

 

 

'Unreal Engine' 카테고리의 다른 글

UE5 Issues : 총기 스폰 및 포인터  (0) 2025.02.27
UE5 Issues : 인벤토리 UI  (0) 2025.02.26
UE5 Issues : Enhanced Input (Triggered & Started)  (0) 2025.02.23
UE5 Issues : 애니메이션 (Motion Matching, Blend Pose)  (0) 2025.02.21
UE5 Issues : 이모저모  (0) 2025.02.13
'Unreal Engine' 카테고리의 다른 글
  • UE5 Issues : 총기 스폰 및 포인터
  • UE5 Issues : 인벤토리 UI
  • UE5 Issues : Enhanced Input (Triggered & Started)
  • UE5 Issues : 애니메이션 (Motion Matching, Blend Pose)
gbleem
gbleem
gbleem 님의 블로그 입니다.
  • gbleem
    gbleem 님의 블로그
    gbleem
  • 전체
    오늘
    어제
    • 분류 전체보기 (177)
      • Unreal Engine (66)
      • C++ (19)
      • 알고리즘(코딩테스트) (27) N
      • TIL (60)
      • CS (4)
      • 툴 (1)
  • 블로그 메뉴

    • 홈
    • 카테고리
  • 링크

    • 과제용 깃허브
    • 깃허브
    • velog
  • 공지사항

  • 인기 글

  • 태그

    character animation
    C++
    상속
    BFS
    Vector
    cin함수
    map을 vector로 복사
    enhanced input system
    매크로 지정자
    addonscreendebugmessage
    additive animation
    motion matching
    actor 클래스
    blend pose
    싱글턴
    gamestate
    applydamage
    const
    DP
    템플릿
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
gbleem
UE5 Issues : 캐릭터 아이템 획득 로직 구현
상단으로

티스토리툴바