프로그래밍 공부
작성일
2024. 4. 30. 13:06
작성자
WDmil
728x90

캐릭터의 컴포넌트에 데이터를 추가하고 정리해서, 각 객체에 코드를 최소한으로 줄이고 같은 코드를 최소화 한다.

헬다이버2의 기본 시스템 중 하나인, 주변 상호작용 가능한 엑터를 참조하고 표시하는 바탕을 제작한다.


Component 제작

 

전에 만들었던 AttachComponent를 수정한다.

 

가방을 장착할 때, 굳이 사용할 필요 없는 필드 Actor를 제거하고, Component형태로 재제작 하여, 스폰할 필요 없이 그떄그때 바꾸는 식으로 처리한다.

 

스폰할 필요가 없는 객체는 굳이 스폰하려고 시도하지 않는다. 리소스 낭비다.

 

AttachmentComponent

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "AttachmentComponent.generated.h"

class ABaseCharacter;
class ABaseBackpack;

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class FTPSGAME_API UAttachmentComponent : public UActorComponent
{
	GENERATED_BODY()

	UPROPERTY(VisibleAnywhere, Category = "Onwer")
	TObjectPtr<ABaseCharacter> OwnerCharacter;

	UPROPERTY(VisibleAnywhere)
	TObjectPtr<ABaseBackpack> Backpack;

public:	
	// Sets default values for this component's properties
	UAttachmentComponent();

protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

	FORCEINLINE bool IsBackpackEquipeed() { return Backpack != nullptr; }
};

 

붙이는 컴포넌트의 데이터를 최적화한다. 들어가는 Backpack데이터와, Owner를 가지게 하여 가방이 있는지 없는지 등의 데이터를 반환한다.

 

컴포넌트 틱을 사용하여 현재 가방의 데이터를 갱신해주어야 하기 때문에, 컴포넌트 틱을 활성화 하고 추가해준다.

 

추가해주었던 A형태의 데이터들을 U로 바꾸어주어야 한다. 안그러면 컴파일 오류가 난다.

AAtachmentActor가 아니라 UAttachmentComponent로 바꾸어주어야 한다. 이제 Actor형태가 아니기 때문에 A를 사용하면 오류가 난다.


Interfaces

 

헬다이버2 의 시스템중 ,주변의 엑터가 가깝거나 멀때, 주변 엑터에 대한 강조표시를 나타내는 시스템이 있다.

해당 시스템을 구현하기 위한 바탕을 제작한다.

 

중앙 원이 Player이고, 주변 타원이 Collision이라고 할 때, Collision에 대한 충돌된 엑터를 탐색하고, 해당 엑터들을 배열로 가지게 한다음, 가진 엑터들에 대한 표시여부를 사용할 것 이다.

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Interfaces.generated.h"

// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UInterfaces : public UInterface
{
	GENERATED_BODY()
};

/**
 * 
 */
class FTPSGAME_API IInterfaces
{
	GENERATED_BODY()

	// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
	virtual void Interact() = 0;
};

 

인터페이스를 사용한다.

 

인터페이스를 상속받는 객체에 대해 모든 Interact함수 사용을 같은 이름으로 다른 함수작용을 할 수 있도록 한다.

 


UInteractComponunt

 

플레이어에 전부다 박아넣기에는, 모든 코드를 넣으면 500줄이 넘어버리고, 보기도 복잡해질것 이기 때문에, 각 컴포넌트 별로 기능을 나누어 저장한다.

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Components/CapsuleComponent.h"
#include "InteractComponunt.generated.h"

/**
 * 1. 상호작용 가능한 물체 감지
 * 2. 물체 중에서도 최우선 순위 알고리즘으로 객체 골라내기
 * 3. 그걸 리턴하기.
 * 4. UI 띄우기
 */

class ABaseCharacter;

UCLASS()
class FTPSGAME_API UInteractComponunt : public UCapsuleComponent
{
	GENERATED_BODY()

	UPROPERTY()
	TObjectPtr<ABaseCharacter> OwnerCharacter;

	UPROPERTY()
	TArray<AActor*> InteractObjects;

public:
	UInteractComponunt();
	virtual void BeginPlay() override;
	virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFuntion) override;

private:
	UFUNCTION()
	void AddInteractObject(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

	UFUNCTION()
	void RemoveInteractObject(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
};

 

 

캡슐컴포넌트를 상속받는 InteractComponunt 를 생성한다. 이 컴포넌트는 충돌된 엑터를 검사하고, 검사결과 해당되는 엑터일 경우, 유니크를 추가하여 중첩되지 않게 배열에 저장할것이다.

// Fill out your copyright notice in the Description page of Project Settings.


#include "Components/InteractComponunt.h"
#include "Actors/BaseCharacter.h"
#include "Interface/Interfaces.h"


UInteractComponunt::UInteractComponunt()
{
	PrimaryComponentTick.bCanEverTick = true;
}

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

	OwnerCharacter = Cast<ABaseCharacter>(GetOwner());

	const float Radius = OwnerCharacter->GetCapsuleComponent()->GetScaledCapsuleRadius() * 1.7;
	const float Height = OwnerCharacter->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() * 1.2f;

	SetCapsuleRadius(Radius);
	SetCapsuleHalfHeight(Height);

	{
		SetCollisionProfileName("InteractCollision");
	}

	OnComponentBeginOverlap.AddDynamic(this, &UInteractComponunt::AddInteractObject);
	OnComponentEndOverlap.AddDynamic(this, &UInteractComponunt::RemoveInteractObject);

}

void UInteractComponunt::AddInteractObject(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, 
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (Cast<IInterfaces>(OtherActor))
		InteractObjects.AddUnique(OtherActor);
}

void UInteractComponunt::RemoveInteractObject(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, 
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	InteractObjects.Remove(OtherActor);
}

void UInteractComponunt::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFuntion)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFuntion);
}

BeginPlay에서 캡슐컴포넌트의 크기를 지정해준다. 그리고, 충돌체를 수정해서 카메라가 충돌하지 않도록 지정해준다.

 

각 이벤트디스패처에 대해 함수를 지정하여, 충돌하였을 때, 객체를 넣고, 충돌에 벗어났을 때, 해당 엑터를 제거한다.


BaseCharacter 재설정

	UPROPERTY(EditDefaultsOnly, Category = Component)
	TObjectPtr<UWeaponComponent> WeaponComponent;

	UPROPERTY(EditDefaultsOnly, Category = Component)
	TObjectPtr<UAttachmentComponent> AttachmentComponent;

	UPROPERTY(EditDefaultsOnly, Category = Component)
	TObjectPtr<UInteractComponunt> InterfaceComponent;

기존에 작성했던 코드에서 BaseCharacter의 WeaponComponent를  Component분류로 바꾸어주고, 각 컴포넌트를 추가한다.

 

가방을 붙이기 위한 Attachment 컴포넌트와 주변 액터를 검색하기 위한 Interact 컴포넌트를 추가한다.

 

그리고 cpp에서 생성해준다.

	WeaponComponent = Helper::CreateActorComponent<UWeaponComponent>(this, "Weapon Component");
	AttachmentComponent = Helper::CreateActorComponent<UAttachmentComponent>(this, "Attachment Component");
	InterfaceComponent = Helper::CreateSceneComponent<UInteractComponunt>(this, "Interact Component", GetRootComponent());

 

728x90