[Unreal][C++] μ•„μ΄ν…œ νšλ“, 착용

2024. 3. 10. 21:47Β·πŸ“ Game/✏ Unreal

캐릭터에 μž₯μ°© κ°€λŠ₯ν•œ μ•„μ΄ν…œμ„ νšλ“ν•œ ν›„ μ°©μš©ν•˜λŠ” 것을 κ΅¬ν˜„ν•  것이닀.

 

1. μ•„μ΄ν…œ 생성

μ—¬λŸ¬ μ’…λ₯˜μ˜ μ•„μ΄ν…œμ„ 관리할 Base C++ Classλ₯Ό μƒμ„±ν–ˆλ‹€. 이 ν΄λž˜μŠ€μ—μ„  νƒ€μž…, 레벨, 머터리얼, μ½œλ¦¬μ „ λ“± κ³΅ν†΅μœΌλ‘œ μ‚¬μš©λ  κΈ°λŠ₯듀을 κ΄€λ¦¬ν•œλ‹€. 각 μ•„μ΄ν…œλ§ˆλ‹€ λ‹€λ₯΄κ²Œ κ΅¬ν˜„λ˜μ–΄μ•Ό ν•˜λŠ” 것(μŠ€νƒœν‹± λ©”μ‹œ λ“±)듀은 λΈ”λ£¨ν”„λ¦°νŠΈ 클래슀λ₯Ό μƒμ„±ν•˜μ—¬ κ·Έ μ•ˆμ—μ„œ κ΄€λ¦¬λ˜λ„λ‘ λ°©ν–₯을 μž‘μ•˜λ‹€.

 

μ•„μ΄ν…œλ§ˆλ‹€ νƒ€μž…μ΄ λ‹€λ₯΄κ³ , 같은 νƒ€μž…μ˜ μ•„μ΄ν…œμ΄λΌλ„ 레벨이 λ‹€λ₯΄κΈ° λ•Œλ¬Έμ— νƒ€μž…κ³Ό λ ˆλ²¨μ„ μ„ μ–Έν–ˆλ‹€.

 

UENUM(BlueprintType)
enum class EItemType : uint8
{
	HAT,
	BAG,
	KEY,
	GADGET,
	MAX
};
UPROPERTY(EditAnywhere)
EItemType Type = EItemType::HAT;

UPROPERTY()
int Level = 1;

 

κ·Έ 외에도 μŠ€νƒœν‹± λ©”μ‹œμ™€ μ½œλ¦¬μ „λ„ μΆ”κ°€ν–ˆλ‹€.

 

UPROPERTY(EditAnywhere)
UStaticMeshComponent* StaticMesh;

UPROPERTY(EditAnywhere)
UBoxComponent* CollisionBox;

UFUNCTION()
void OnBeginOverlap(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

UFUNCTION()
void OnEndOverlap(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
AItem::AItem()
{
    CollisionBox = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComponent"));
    RootComponent = CollisionBox;
    CollisionBox->SetBoxExtent(FVector(15, 15, 15));
    CollisionBox->SetCollisionProfileName(TEXT("OverlapOnlySurvivor"));
    CollisionBox->OnComponentBeginOverlap.AddDynamic(this, &AItem::OnBeginOverlap);
    CollisionBox->OnComponentEndOverlap.AddDynamic(this, &AItem::OnEndOverlap);

    StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ItemMesh"));
    StaticMesh->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
    StaticMesh->SetCollisionProfileName(TEXT("NoCollision"));
    StaticMesh->bReceivesDecals = false;
}
  • μ½œλ¦¬μ „μ˜ OverlapOnlySurvivor은 μ»€μŠ€ν…€ μ½œλ¦¬μ „ ν”„λ¦¬μ…‹μœΌλ‘œ μ˜€μ§ μΊλ¦­ν„°μ™€λ§Œ Overlap λ°˜μ‘μ„ ν•œλ‹€.
  • μŠ€νƒœν‹± λ©”μ‹œλŠ” μƒμ„±μžμ—μ„œ μ»΄ν¬λ„ŒνŠΈ μƒμ„±λ§Œ ν•˜κ³  μžˆμ–΄ λΈ”λ£¨ν”„λ¦°νŠΈ ν΄λž˜μŠ€μ—μ„œ μΆ”κ°€ 섀정이 ν•„μš”ν•˜λ‹€.
  • μƒμ„±μžμ—μ„œ μ½œλ¦¬μ „ μ»΄ν¬λ„ŒνŠΈ 생성 μ‹œ μ‚¬μ΄μ¦ˆλ₯Ό μ„€μ •ν–ˆμ§€λ§Œ, 각 μ•„μ΄ν…œλ§ˆλ‹€ 크기가 λ‹€λ₯Ό 수 μžˆμœΌλ―€λ‘œ λΈ”λ£¨ν”„λ¦°νŠΈ ν΄λž˜μŠ€μ—μ„œ μΆ”κ°€λ‘œ μŠ€νƒœν‹± λ©”μ‹œμ— 맞게 μˆ˜μ •μ΄ ν•„μš”ν•˜λ‹€.

 

2. μ•„μ΄ν…œ νšλ“

캐릭터와 μ•„μ΄ν…œμ΄ μΆ©λŒν•˜λ©΄ μ•„μ΄ν…œμ„ 캐릭터 λ‚΄ InventoryComponent에 λ„˜κΈ΄λ‹€. μ—¬λŸ¬ 개의 μ•„μ΄ν…œκ³Ό 좩돌될 κ°€λŠ₯성이 있기 λ•Œλ¬Έμ— InventoryComponent λ‚΄μ—μ„œ μˆœμ„œλ₯Ό κ΄€λ¦¬ν•˜κΈ° μœ„ν•΄ μ΄λŸ¬ν•œ ꡬ쑰둜 κ΅¬ν˜„ν–ˆλ‹€.

 

void AItem::OnBeginOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
    ASurvivorCharacter* OtherCharacter = Cast<ASurvivorCharacter>(OtherActor);
    if (OtherCharacter)
    {
        OtherCharacter->InventoryComponent->BeginOverlap(this);
    }
}

void AItem::OnEndOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
    ASurvivorCharacter* OtherCharacter = Cast<ASurvivorCharacter>(OtherActor);
    if (OtherCharacter)
    {
        OtherCharacter->InventoryComponent->EndOverlap(this);
    }
}

 

μ΄λ ‡κ²Œ 받은 μ•„μ΄ν…œμ„ InventoryComponent의 PickItemArray에 μ €μž₯ν•œ ν›„, 캐릭터가 νšλ“ λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ κ°€μž₯ λ¨Όμ € μ €μž₯된 μ•„μ΄ν…œμ΄ νšλ“λ˜κ²Œ λœλ‹€.

 

void UInventoryComponent::BeginOverlap(AItem* Item)
{
	PickItemArray.Add(Item);
}

void UInventoryComponent::EndOverlap(AItem* Item)
{
	PickItemArray.Remove(Item);
}

bool UInventoryComponent::Input()
{
	bool Pick = false;

	if (PickItemArray.Num() > 0)
	{
		AItem* OverlapItem = PickItemArray[0];
        
		...

		if (Pick)
		{
			PickItemArray.RemoveAt(0);
			OverlapItem->Destroy();
		}
	}

	return Pick;
}

 

이제 μ•„μ΄ν…œ νšλ“ μž…λ ₯ κ΅¬ν˜„μ΄ ν•„μš”ν•˜λ‹€. 캐릭터 μž…λ ₯은 이미 ν–₯μƒλœ μž…λ ₯을 μ‚¬μš©ν•˜μ—¬ κ΅¬ν˜„λ˜μ–΄ 있기 λ•Œλ¬Έμ— 여기에 μ•„μ΄ν…œ νšλ“ μž…λ ₯ μ•‘μ…˜λ§Œ μΆ”κ°€ν•  것이닀.

 

μ•„μ΄ν…œ νšλ“ μž…λ ₯ μ•‘μ…˜μ€ ν‚€λ₯Ό λˆŒλ €λŠ”μ§€ μ—¬λΆ€λ§Œ ν•„μš”ν•΄μ„œ bool νƒ€μž…μœΌλ‘œ μ„€μ •ν–ˆλ‹€.

 

μ•„μ΄ν…œ νšλ“ μž…λ ₯ μ•‘μ…˜

 

μƒμ„±ν•œ μž…λ ₯ μ•‘μ…˜μ„ 캐릭터에 μ μš©ν•  것이닀. νšλ“ μž…λ ₯이 λ“€μ–΄μ˜€λ©΄, 캐릭터에 땅에 μ„œμžˆκ±°λ‚˜ κ±·κ³  μžˆλŠ” μƒνƒœμΈμ§€ μ²΄ν¬ν•œλ‹€. νšλ“ κ°€λŠ₯ν•œ μƒνƒœλΌλ©΄ InventoryComponent의 Input() ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κ³  μ •μƒμ μœΌλ‘œ νšλ“μ΄ λ˜μ—ˆλ‹€λ©΄ trueλ₯Ό λ°˜ν™˜λ°›λŠ”λ‹€. κ·Έ ν›„ μ• λ‹ˆλ©”μ΄μ…˜ μž¬μƒμ„ μœ„ν•΄ 캐릭터 μƒνƒœλ₯Ό ITEM_PICK둜 λ³€κ²½ν•œλ‹€.

 

μ•„μ΄ν…œ νšλ“ μ• λ‹ˆλ©”μ΄μ…˜

 

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
UInputMappingContext* DefaultMappingContext;

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
UInputAction* ItemPickAction;
void ASurvivorCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	// Set up action bindings
	if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent)) {

		EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ASurvivorCharacter::Look);
		EnhancedInputComponent->BindAction(WalkAction, ETriggerEvent::Triggered, this, &ASurvivorCharacter::Walk);
		EnhancedInputComponent->BindAction(RunAction, ETriggerEvent::Started, this, &ASurvivorCharacter::Run);
		EnhancedInputComponent->BindAction(RunAction, ETriggerEvent::Completed, this, &ASurvivorCharacter::Run);
		EnhancedInputComponent->BindAction(ItemPickAction, ETriggerEvent::Started, this, &ASurvivorCharacter::ItemPick);
        ...
	}
	else
	{
		UE_LOG(LogTemplateCharacter, Error, TEXT("'%s' Failed to find an Enhanced Input component! This template is built to use the Enhanced Input system. If you intend to use the legacy system, then you will need to update this C++ file."), *GetNameSafe(this));
	}
}

void ASurvivorCharacter::ItemPick(const FInputActionValue& Value)
{
	if (State == ECharacterState::LAND)
	{
		if (InventoryComponent->Input())
		{
			SetECharacterState(ECharacterState::ITEM_PICK);
		}
	}
}

 

3. μ•„μ΄ν…œ μž₯μ°©

UInventoryComponent λ‚΄λΆ€μ—μ„œ μ•„μ΄ν…œ νšλ“ ν›„ μž₯μ°© μ•„μ΄ν…œμ΄λ©΄ μΊλ¦­ν„°μ—κ²Œ μž₯μ°© μš”μ²­μ„ ν•œλ‹€. 캐릭터 λ‚΄ μ•„μ΄ν…œ λ©”μ‹œμ˜ Visible을 ν™œμ„±ν™”ν•˜κ³  νšλ“ν•œ μ•„μ΄ν…œ λ ˆλ²¨μ— 맞게 Matarial을 λ³€κ²½ν•œλ‹€.

 

void ASurvivorCharacter::ItemPutOn(EItemType Type, int Level)
{
	if (GetItemCount(Type, Level) == 0)
		return;

	...

	if (Type == EItemType::HAT) {
		HatMesh->SetVisibility(true);
		HatMesh->SetMaterial(0, ItemMaterials[Level - 1]);
	}
	else if (Type == EItemType::BAG) {
		BagMesh->SetVisibility(true);
		BagMesh->SetMaterial(0, ItemMaterials[Level - 1]);
		...
	}
}

 

μ—¬κΈ°μ„œ HatMesh와 BagMeshλŠ” μ†ŒμΌ“μ— 뢙도둝 섀정이 ν•„μš”ν•˜λ‹€. κ·Έλž˜μ•Ό 캐릭터 μ• λ‹ˆλ©”μ΄μ…˜μ— 맞게 μ•„μ΄ν…œ λ©”μ‹œλ„ μ›€μ§μ΄κ²Œ λœλ‹€.

 

HatMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("HatMesh"));
HatMesh->SetupAttachment(GetMesh(), FName("Hat"));
HatMesh->SetCollisionProfileName(TEXT("NoCollision"));
HatMesh->SetVisibility(false);
HatMesh->bReceivesDecals = false;

BagMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BagMesh"));
BagMesh->SetupAttachment(GetMesh(), FName("Bag"));
BagMesh->SetCollisionProfileName(TEXT("NoCollision"));
BagMesh->SetVisibility(false);
BagMesh->bReceivesDecals = false;

 

μ•„μ΄ν…œ κ·Όμ²˜μ—μ„œ ν‚€λ₯Ό λˆ„λ₯΄λ©΄ ν•΄λ‹Ή μ•„μ΄ν…œμ„ μ°©μš©ν•œλ‹€.

 

μ•„μ΄ν…œ μž₯μ°© μ™„λ£Œ

μ €μž‘μžν‘œμ‹œ (μƒˆμ°½μ—΄λ¦Ό)
'πŸ“ Game/✏ Unreal' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€
  • [Unreal] νƒ€μž„λΌμΈ(Timeline)
  • [Unreal][C++] AI 캐릭터
  • [Unreal][C++] ν”Œλ ˆμ΄μ–΄ 캐릭터
  • [Unreal][C++] 1인칭 μŠˆνŒ… νŠœν† λ¦¬μ–Ό
Blxxming
Blxxming
CS 지식과 κ³΅λΆ€ν•˜λ‹€ 배운 것, κ²½ν—˜ν•œ 것 등을 κΈ°λ‘ν•˜λŠ” λΈ”λ‘œκ·Έμž…λ‹ˆλ‹€.
  • Blxxming
    πŸ’‘λ²ˆλœ©πŸ’‘
    Blxxming
  • 전체
    였늘
    μ–΄μ œ
  • 곡지사항

    • Tech Interview
    • πŸ“š Tech (246)
      • πŸ“ Computer Science (96)
        • ✏ OS (12)
        • ✏ Network & Web (10)
        • ✏ Database (11)
        • ✏ Data Structure (6)
        • ✏ Algorithm (40)
        • ✏ Design Pattern (9)
        • ✏ Cloud Computing (3)
        • ✏ (5)
      • πŸ“ Language (73)
        • ✏ Language (6)
        • ✏ C & C++ (11)
        • ✏ C# (19)
        • ✏ JAVA (37)
      • πŸ“ Game (43)
        • ✏ Computer Graphics (2)
        • ✏ Unity (14)
        • ✏ Unreal (26)
        • ✏ (1)
      • πŸ“ Book (34)
        • ✏ Effective (3)
        • ✏ Game Server (16)
        • ✏ Clean Code (14)
        • ✏ (1)
  • hELLOΒ· Designed Byμ •μƒμš°.v4.10.0
Blxxming
[Unreal][C++] μ•„μ΄ν…œ νšλ“, 착용
μƒλ‹¨μœΌλ‘œ

ν‹°μŠ€ν† λ¦¬νˆ΄λ°”